Ujian Tengah Semester 2

Data Science Programming

Isnaini Nur Hasanah (52240005)

April 18, 2025

Logo

1 Operasi dan Tipe Data Dasar

Buat program sederhana dalam R yang melakukan hal berikut:

  1. Menerima dua bilangan dari pengguna

  2. Menghitung dan menampilkan hasil:

  • Penjumlahan
  • Perkalian
  • Pembagian
  • Bilangan pertama pangkat bilangan kedua
  1. Menampilkan tipe data masing-masing hasil operasi
# Fungsi untuk masing-masing operasi
penjumlahan <- function(a, b) {
  return(a + b)
}

perkalian <- function(a, b) {
  return(a * b)
}

pembagian <- function(a, b) {
  if (is.na(b) || b == 0) {
    return("Tidak bisa dibagi dengan nol atau input tidak valid")
  } else {
    return(a / b)
  }
}

pangkat <- function(a, b) {
  return(a ^ b)
}

# Minta input dari pengguna
a <- as.numeric(readline(prompt = "Masukkan bilangan pertama: "))
## Masukkan bilangan pertama:
b <- as.numeric(readline(prompt = "Masukkan bilangan kedua: "))
## Masukkan bilangan kedua:
# Lakukan operasi
hasil_tambah <- penjumlahan(a, b)
hasil_kali <- perkalian(a, b)
hasil_bagi <- pembagian(a, b)
hasil_pangkat <- pangkat(a, b)

# Tampilkan hasil dan tipe datanya
cat("\n=== HASIL OPERASI ===\n")
## 
## === HASIL OPERASI ===
cat("Penjumlahan:", hasil_tambah, "| Tipe:", class(hasil_tambah), "\n")
## Penjumlahan: NA | Tipe: numeric
cat("Perkalian:", hasil_kali, "| Tipe:", class(hasil_kali), "\n")
## Perkalian: NA | Tipe: numeric
cat("Pembagian:", hasil_bagi, "| Tipe:", class(hasil_bagi), "\n")
## Pembagian: Tidak bisa dibagi dengan nol atau input tidak valid | Tipe: character
cat("Pangkat:", hasil_pangkat, "| Tipe:", class(hasil_pangkat), "\n")
## Pangkat: NA | Tipe: numeric

2 Struktur Kendali (Control Flow)

Tulislah program dalam R yang:

  1. Menerima input nilai ujian dari pengguna (0–100)

  2. Menampilkan keterangan berdasarkan ketentuan berikut:

  • Nilai ≥ 85: “Sangat Baik”
  • Nilai 70–84: “Baik”
  • Nilai 60–69: “Cukup”
  • Nilai < 60: “Perlu Perbaikan”
# Menerima input dari pengguna
nilai <- as.numeric(readline(prompt = "Masukkan nilai ujian (0-100): "))
## Masukkan nilai ujian (0-100):
# Mengecek apakah input valid
if (is.na(nilai) || nilai < 0 || nilai > 100) {
  cat("Input tidak valid. Harap masukkan angka antara 0 dan 100.\n")
} else {
  # Menentukan keterangan berdasarkan nilai
  if (nilai >= 85) {
    keterangan <- "Sangat Baik"
  } else if (nilai >= 70) {
    keterangan <- "Baik"
  } else if (nilai >= 60) {
    keterangan <- "Cukup"
  } else {
    keterangan <- "Perlu Perbaikan"
  }

  # Menampilkan hasil
  cat("Nilai:", nilai, "\n")
  cat("Keterangan:", keterangan, "\n")
}
## Input tidak valid. Harap masukkan angka antara 0 dan 100.

3 Fungsi dan Perulangan

Buatlah fungsi dalam R bernama kelipatan_genap(n) yang:

  1. Menerima input integer n

  2. Menggunakan loop untuk mencetak semua bilangan genap kelipatan 4 dari 1 hingga n

  3. Contoh output jika n = 20: 4, 8, 12, 16, 20

kelipatan_genap <- function(n) {
  # Validasi input: harus bilangan bulat positif
  if (is.na(n) || !is.numeric(n) || n <= 0 || n != floor(n)) {
    cat("Input harus berupa bilangan bulat positif.\n")
    return()
  }

  cat("Bilangan genap kelipatan 4 dari 1 hingga", n, ":\n")
  
  hasil <- c()  # vektor penampung hasil
  for (i in 1:n) {
    if (i %% 4 == 0) {
      hasil <- c(hasil, i)
    }
  }
  
  # Tampilkan hasil sebagai daftar angka yang dipisah koma
  cat(paste(hasil, collapse = ", "), "\n")
}

4 Studi Kasus

Sebuah perusahaan e-commerce ingin menganalisis performa penjualannya berdasarkan data transaksi selama 3 bulan terakhir. Namun, data yang tersedia berasal dari berbagai sumber dan memiliki kualitas yang beragam. Anda diminta untuk melakukan Data Wrangling sebelum dianalisis lebih lanjut.

Bagian 1: Data Collection

Asumsikan data berasal dari 3 file CSV berbeda (januari.csv, februari.csv, maret.csv).

Tugas Anda:

  1. Gabungkan ketiga file menjadi satu dataset.

  2. Tampilkan jumlah total baris dan kolom setelah digabung.

## Jumlah Baris: 150
## Jumlah Kolom: 9

Interpretasi

Setelah proses penggabungan data dari tiga file transaksi bulanan (Januari, Februari, dan Maret), diperoleh total 150 entri transaksi atau baris data. Ini menunjukkan bahwa masing-masing file kemungkinan berisi sekitar 50 transaksi. Sementara itu, terdapat 9 kolom pada dataset gabungan, yang mengindikasikan bahwa setiap transaksi tercatat dengan 9 atribut atau variabel — seperti tanggal transaksi, nama produk, jumlah, harga, kota, dan kategori.

Bagian 2: Data Cleaning

Lakukan pembersihan data berikut:

  1. Standarkan format tanggal ke bentuk YYYY-MM-DD.

  2. Ubah kolom Harga dan Jumlah menjadi format numerik.

  3. Hitung ulang nilai kolom Total = Harga * Jumlah.

  4. Ganti nilai yang tidak valid (contoh: -, “dua”, “Rp”, “anonymous”) dengan nilai yang sesuai atau NA.

  5. Hapus baris yang tidak memiliki nama produk (Produk kosong atau -).

Interpretasi

Pada tahap ini, dilakukan proses pembersihan data untuk memastikan kualitas dan konsistensi dataset sebelum dianalisis lebih lanjut. Pertama, format tanggal diseragamkan ke bentuk standar YYYY-MM-DD, agar mudah diolah dalam analisis waktu. Kedua, kolom Harga dan Jumlah yang sebelumnya mengandung teks atau simbol tidak valid seperti “Rp”, “dua”, atau “-” dikonversi ke format numerik menggunakan fungsi pembersih khusus. Kemudian, nilai pada kolom Total dihitung ulang sebagai hasil perkalian antara Harga dan Jumlah, memastikan akurasi data transaksi. Selanjutnya, entri dengan nilai tidak valid secara otomatis diganti dengan NA, sehingga tidak mengganggu perhitungan statistik. Terakhir, baris-baris yang tidak memiliki nama produk (misalnya Produk kosong atau tanda “-”) dihapus agar hanya data yang relevan yang dipertahankan. Hasilnya, dataset menjadi lebih bersih, rapi, dan siap untuk dianalisis lebih lanjut.

Bagian 3: Data Transformation

Lakukan transformasi data sebagai berikut:

  1. Buat kolom baru Bulan berdasarkan tanggal transaksi.

  2. Hitung total penjualan (Total) per kategori produk.

  3. Hitung jumlah transaksi dari setiap kota.

  4. Buat ringkasan jumlah total penjualan per bulan.

Output yang Diharapkan:

  1. Dataset yang sudah bersih dan rapi.

  2. Tabel agregat: total penjualan per kategori, kota, dan bulan.

  3. Visualisasi opsional: grafik batang, grafik lingkaran dan grafik garis penjualan per kategori.

Total Penjualan per Kategori
Kategori Total Penjualan
123009750
Aksesoris 331762000
Elektronik 167006750
Fashion 225006750
Jumlah Transaksi per Kota
Kota Jumlah Transaksi
- 30
Bandung 33
Jakarta 29
Surabaya 30
Ringkasan Penjualan per Bulan
Bulan Total Penjualan
2024-01 195757500
2024-02 286761250
2024-03 318008250
2024-04 46258250

Visualisasi

Interpretasi

Berdasarkan output yang didapatkan, dapat disimpulkan beberapa hal penting terkait performa penjualan dan distribusi transaksi:

  1. Kategori Produk: Kategori Aksesoris mencatat total penjualan tertinggi sebesar Rp331.762.000, disusul oleh Fashion sebesar Rp225.006.750, dan Elektronik sebesar Rp167.006.750. Terdapat pula data penjualan sebesar Rp123.009.750 yang tidak tercatat dalam kategori tertentu (kemungkinan akibat data tidak lengkap atau kategori kosong). Hal ini menunjukkan bahwa produk Aksesoris paling mendominasi dalam penjualan selama periode yang dianalisis.

  2. Distribusi Kota: Kota dengan jumlah transaksi terbanyak adalah Bandung (33 transaksi), diikuti oleh Surabaya (30 transaksi) dan Jakarta (29 transaksi). Namun, terdapat pula 30 transaksi yang tidak memiliki informasi kota (dilambangkan dengan tanda “-”), yang perlu ditelusuri lebih lanjut karena bisa memengaruhi analisis geografis secara akurat.

  3. Tren Penjualan Bulanan: Penjualan tertinggi terjadi pada bulan Maret 2024 dengan total Rp318.008.250, diikuti oleh Februari (Rp286.761.250) dan Januari (Rp195.757.500). Namun, terjadi penurunan tajam pada April 2024, di mana total penjualan hanya mencapai Rp46.258.250. Penurunan ini dapat menjadi perhatian, apakah disebabkan oleh musim, promosi yang berkurang, atau faktor eksternal lainnya.

LS0tDQp0aXRsZTogIlVqaWFuIFRlbmdhaCBTZW1lc3RlciAyIg0Kc3VidGl0bGU6ICJEYXRhIFNjaWVuY2UgUHJvZ3JhbW1pbmciDQphdXRob3I6IA0KICAiSXNuYWluaSBOdXIgSGFzYW5haCAoNTIyNDAwMDUpIg0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6ZG93bmN1dGU6ICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICB0aHVtYm5haWxzOiB0cnVlDQogICAgbGlnaHRib3g6IHRydWUNCiAgICBnYWxsZXJ5OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgbGliX2RpcjogbGlicw0KICAgIGRmX3ByaW50OiAicGFnZWQiDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyINCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjc3M6ICJzdHlsZSAoMSkuY3NzIg0KICAgIHBhcmFtczoNCiAgZWNobzogZmFsc2UNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KPGltZyBpZD0iSXNuYSIgc3JjPSJDOlxVc2Vyc1xBU1VTXERlc2t0b3BcU3RhdGlzdGlrYSBEYXNhclxJc25hLnBuZyIgYWx0PSJMb2dvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KIyBPcGVyYXNpIGRhbiBUaXBlIERhdGEgRGFzYXINCg0KQnVhdCBwcm9ncmFtIHNlZGVyaGFuYSBkYWxhbSBSIHlhbmcgbWVsYWt1a2FuIGhhbCBiZXJpa3V0Og0KDQphLiBNZW5lcmltYSBkdWEgYmlsYW5nYW4gZGFyaSBwZW5nZ3VuYQ0KDQpiLiBNZW5naGl0dW5nIGRhbiBtZW5hbXBpbGthbiBoYXNpbDoNCi0gUGVuanVtbGFoYW4NCi0gUGVya2FsaWFuDQotIFBlbWJhZ2lhbg0KLSBCaWxhbmdhbiBwZXJ0YW1hIHBhbmdrYXQgYmlsYW5nYW4ga2VkdWENCg0KYy4gTWVuYW1waWxrYW4gdGlwZSBkYXRhIG1hc2luZy1tYXNpbmcgaGFzaWwgb3BlcmFzaQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KIyBGdW5nc2kgdW50dWsgbWFzaW5nLW1hc2luZyBvcGVyYXNpDQpwZW5qdW1sYWhhbiA8LSBmdW5jdGlvbihhLCBiKSB7DQogIHJldHVybihhICsgYikNCn0NCg0KcGVya2FsaWFuIDwtIGZ1bmN0aW9uKGEsIGIpIHsNCiAgcmV0dXJuKGEgKiBiKQ0KfQ0KDQpwZW1iYWdpYW4gPC0gZnVuY3Rpb24oYSwgYikgew0KICBpZiAoaXMubmEoYikgfHwgYiA9PSAwKSB7DQogICAgcmV0dXJuKCJUaWRhayBiaXNhIGRpYmFnaSBkZW5nYW4gbm9sIGF0YXUgaW5wdXQgdGlkYWsgdmFsaWQiKQ0KICB9IGVsc2Ugew0KICAgIHJldHVybihhIC8gYikNCiAgfQ0KfQ0KDQpwYW5na2F0IDwtIGZ1bmN0aW9uKGEsIGIpIHsNCiAgcmV0dXJuKGEgXiBiKQ0KfQ0KDQojIE1pbnRhIGlucHV0IGRhcmkgcGVuZ2d1bmENCmEgPC0gYXMubnVtZXJpYyhyZWFkbGluZShwcm9tcHQgPSAiTWFzdWtrYW4gYmlsYW5nYW4gcGVydGFtYTogIikpDQpiIDwtIGFzLm51bWVyaWMocmVhZGxpbmUocHJvbXB0ID0gIk1hc3Vra2FuIGJpbGFuZ2FuIGtlZHVhOiAiKSkNCg0KIyBMYWt1a2FuIG9wZXJhc2kNCmhhc2lsX3RhbWJhaCA8LSBwZW5qdW1sYWhhbihhLCBiKQ0KaGFzaWxfa2FsaSA8LSBwZXJrYWxpYW4oYSwgYikNCmhhc2lsX2JhZ2kgPC0gcGVtYmFnaWFuKGEsIGIpDQpoYXNpbF9wYW5na2F0IDwtIHBhbmdrYXQoYSwgYikNCg0KIyBUYW1waWxrYW4gaGFzaWwgZGFuIHRpcGUgZGF0YW55YQ0KY2F0KCJcbj09PSBIQVNJTCBPUEVSQVNJID09PVxuIikNCmNhdCgiUGVuanVtbGFoYW46IiwgaGFzaWxfdGFtYmFoLCAifCBUaXBlOiIsIGNsYXNzKGhhc2lsX3RhbWJhaCksICJcbiIpDQpjYXQoIlBlcmthbGlhbjoiLCBoYXNpbF9rYWxpLCAifCBUaXBlOiIsIGNsYXNzKGhhc2lsX2thbGkpLCAiXG4iKQ0KY2F0KCJQZW1iYWdpYW46IiwgaGFzaWxfYmFnaSwgInwgVGlwZToiLCBjbGFzcyhoYXNpbF9iYWdpKSwgIlxuIikNCmNhdCgiUGFuZ2thdDoiLCBoYXNpbF9wYW5na2F0LCAifCBUaXBlOiIsIGNsYXNzKGhhc2lsX3BhbmdrYXQpLCAiXG4iKQ0KYGBgDQoNCiMgU3RydWt0dXIgS2VuZGFsaSAoQ29udHJvbCBGbG93KQ0KDQpUdWxpc2xhaCBwcm9ncmFtIGRhbGFtIFIgeWFuZzoNCg0KYS4gTWVuZXJpbWEgaW5wdXQgbmlsYWkgdWppYW4gZGFyaSBwZW5nZ3VuYSAoMOKAkzEwMCkNCg0KYi4gTWVuYW1waWxrYW4ga2V0ZXJhbmdhbiBiZXJkYXNhcmthbiBrZXRlbnR1YW4gYmVyaWt1dDoNCi0gTmlsYWkg4omlIDg1OiDigJxTYW5nYXQgQmFpa+KAnQ0KLSBOaWxhaSA3MOKAkzg0OiDigJxCYWlr4oCdDQotIE5pbGFpIDYw4oCTNjk6IOKAnEN1a3Vw4oCdDQotIE5pbGFpIDwgNjA6IOKAnFBlcmx1IFBlcmJhaWthbuKAnQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KIyBNZW5lcmltYSBpbnB1dCBkYXJpIHBlbmdndW5hDQpuaWxhaSA8LSBhcy5udW1lcmljKHJlYWRsaW5lKHByb21wdCA9ICJNYXN1a2thbiBuaWxhaSB1amlhbiAoMC0xMDApOiAiKSkNCg0KIyBNZW5nZWNlayBhcGFrYWggaW5wdXQgdmFsaWQNCmlmIChpcy5uYShuaWxhaSkgfHwgbmlsYWkgPCAwIHx8IG5pbGFpID4gMTAwKSB7DQogIGNhdCgiSW5wdXQgdGlkYWsgdmFsaWQuIEhhcmFwIG1hc3Vra2FuIGFuZ2thIGFudGFyYSAwIGRhbiAxMDAuXG4iKQ0KfSBlbHNlIHsNCiAgIyBNZW5lbnR1a2FuIGtldGVyYW5nYW4gYmVyZGFzYXJrYW4gbmlsYWkNCiAgaWYgKG5pbGFpID49IDg1KSB7DQogICAga2V0ZXJhbmdhbiA8LSAiU2FuZ2F0IEJhaWsiDQogIH0gZWxzZSBpZiAobmlsYWkgPj0gNzApIHsNCiAgICBrZXRlcmFuZ2FuIDwtICJCYWlrIg0KICB9IGVsc2UgaWYgKG5pbGFpID49IDYwKSB7DQogICAga2V0ZXJhbmdhbiA8LSAiQ3VrdXAiDQogIH0gZWxzZSB7DQogICAga2V0ZXJhbmdhbiA8LSAiUGVybHUgUGVyYmFpa2FuIg0KICB9DQoNCiAgIyBNZW5hbXBpbGthbiBoYXNpbA0KICBjYXQoIk5pbGFpOiIsIG5pbGFpLCAiXG4iKQ0KICBjYXQoIktldGVyYW5nYW46Iiwga2V0ZXJhbmdhbiwgIlxuIikNCn0NCmBgYA0KDQojIEZ1bmdzaSBkYW4gUGVydWxhbmdhbg0KDQpCdWF0bGFoIGZ1bmdzaSBkYWxhbSBSIGJlcm5hbWEga2VsaXBhdGFuX2dlbmFwKG4pIHlhbmc6DQoNCmEuIE1lbmVyaW1hIGlucHV0IGludGVnZXIgbg0KDQpiLiBNZW5nZ3VuYWthbiBsb29wIHVudHVrIG1lbmNldGFrIHNlbXVhIGJpbGFuZ2FuIGdlbmFwIGtlbGlwYXRhbiA0IGRhcmkgMQ0KaGluZ2dhIG4NCg0KYy4gQ29udG9oIG91dHB1dCBqaWthIG4gPSAyMDogNCwgOCwgMTIsIDE2LCAyMA0KDQpgYGB7ciBrZWxpcGF0YW4tNCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0Ka2VsaXBhdGFuX2dlbmFwIDwtIGZ1bmN0aW9uKG4pIHsNCiAgIyBWYWxpZGFzaSBpbnB1dDogaGFydXMgYmlsYW5nYW4gYnVsYXQgcG9zaXRpZg0KICBpZiAoaXMubmEobikgfHwgIWlzLm51bWVyaWMobikgfHwgbiA8PSAwIHx8IG4gIT0gZmxvb3IobikpIHsNCiAgICBjYXQoIklucHV0IGhhcnVzIGJlcnVwYSBiaWxhbmdhbiBidWxhdCBwb3NpdGlmLlxuIikNCiAgICByZXR1cm4oKQ0KICB9DQoNCiAgY2F0KCJCaWxhbmdhbiBnZW5hcCBrZWxpcGF0YW4gNCBkYXJpIDEgaGluZ2dhIiwgbiwgIjpcbiIpDQogIA0KICBoYXNpbCA8LSBjKCkgICMgdmVrdG9yIHBlbmFtcHVuZyBoYXNpbA0KICBmb3IgKGkgaW4gMTpuKSB7DQogICAgaWYgKGkgJSUgNCA9PSAwKSB7DQogICAgICBoYXNpbCA8LSBjKGhhc2lsLCBpKQ0KICAgIH0NCiAgfQ0KICANCiAgIyBUYW1waWxrYW4gaGFzaWwgc2ViYWdhaSBkYWZ0YXIgYW5na2EgeWFuZyBkaXBpc2FoIGtvbWENCiAgY2F0KHBhc3RlKGhhc2lsLCBjb2xsYXBzZSA9ICIsICIpLCAiXG4iKQ0KfQ0KYGBgDQoNCiMgU3R1ZGkgS2FzdXMNCg0KU2VidWFoIHBlcnVzYWhhYW4gZS1jb21tZXJjZSBpbmdpbiBtZW5nYW5hbGlzaXMgcGVyZm9ybWEgcGVuanVhbGFubnlhIGJlcmRhc2Fya2FuDQpkYXRhIHRyYW5zYWtzaSBzZWxhbWEgMyBidWxhbiB0ZXJha2hpci4gTmFtdW4sIGRhdGEgeWFuZyB0ZXJzZWRpYSBiZXJhc2FsIGRhcmkgYmVyYmFnYWkNCnN1bWJlciBkYW4gbWVtaWxpa2kga3VhbGl0YXMgeWFuZyBiZXJhZ2FtLiBBbmRhIGRpbWludGEgdW50dWsgbWVsYWt1a2FuIERhdGENCldyYW5nbGluZyBzZWJlbHVtIGRpYW5hbGlzaXMgbGViaWggbGFuanV0Lg0KDQoqKkJhZ2lhbiAxOiBEYXRhIENvbGxlY3Rpb24qKg0KDQpBc3Vtc2lrYW4gZGF0YSBiZXJhc2FsIGRhcmkgMyBmaWxlIENTViBiZXJiZWRhIChqYW51YXJpLmNzdiwgZmVicnVhcmkuY3N2LCBtYXJldC5jc3YpLg0KDQpUdWdhcyBBbmRhOg0KDQphLiBHYWJ1bmdrYW4ga2V0aWdhIGZpbGUgbWVuamFkaSBzYXR1IGRhdGFzZXQuDQoNCmIuIFRhbXBpbGthbiBqdW1sYWggdG90YWwgYmFyaXMgZGFuIGtvbG9tIHNldGVsYWggZGlnYWJ1bmcuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBhLiBNZW1iYWNhIGRhbiBtZW5nZ2FidW5na2FuIGtldGlnYSBmaWxlDQpkYXRhX2phbnVhcmkgPC0gcmVhZC5jc3YoIkphbnVhcmkuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KZGF0YV9mZWJydWFyaSA8LSByZWFkLmNzdigiRmVicnVhcmkuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KZGF0YV9tYXJldCA8LSByZWFkLmNzdigiTWFyZXQuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIEdhYnVuZ2thbiBzZW11YSBkYXRhIG1lbmdndW5ha2FuIHJiaW5kDQpkYXRhX2dhYnVuZ2FuIDwtIHJiaW5kKGRhdGFfamFudWFyaSwgZGF0YV9mZWJydWFyaSwgZGF0YV9tYXJldCkNCg0KIyBiLiBNZW5hbXBpbGthbiBqdW1sYWggdG90YWwgYmFyaXMgZGFuIGtvbG9tDQpjYXQoIkp1bWxhaCBCYXJpczoiLCBucm93KGRhdGFfZ2FidW5nYW4pLCAiXG4iKQ0KY2F0KCJKdW1sYWggS29sb206IiwgbmNvbChkYXRhX2dhYnVuZ2FuKSwgIlxuIikNCg0KIyBNZW5hbXBpbGthbiBkYXRhDQpoZWFkKGRhdGFfZ2FidW5nYW4sMTApDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKg0KDQpTZXRlbGFoIHByb3NlcyBwZW5nZ2FidW5nYW4gZGF0YSBkYXJpIHRpZ2EgZmlsZSB0cmFuc2Frc2kgYnVsYW5hbiAoSmFudWFyaSwgRmVicnVhcmksIGRhbiBNYXJldCksIGRpcGVyb2xlaCB0b3RhbCAxNTAgZW50cmkgdHJhbnNha3NpIGF0YXUgYmFyaXMgZGF0YS4gSW5pIG1lbnVuanVra2FuIGJhaHdhIG1hc2luZy1tYXNpbmcgZmlsZSBrZW11bmdraW5hbiBiZXJpc2kgc2VraXRhciA1MCB0cmFuc2Frc2kuIFNlbWVudGFyYSBpdHUsIHRlcmRhcGF0IDkga29sb20gcGFkYSBkYXRhc2V0IGdhYnVuZ2FuLCB5YW5nIG1lbmdpbmRpa2FzaWthbiBiYWh3YSBzZXRpYXAgdHJhbnNha3NpIHRlcmNhdGF0IGRlbmdhbiA5IGF0cmlidXQgYXRhdSB2YXJpYWJlbCDigJQgc2VwZXJ0aSB0YW5nZ2FsIHRyYW5zYWtzaSwgbmFtYSBwcm9kdWssIGp1bWxhaCwgaGFyZ2EsIGtvdGEsIGRhbiBrYXRlZ29yaS4gDQoNCioqQmFnaWFuIDI6IERhdGEgQ2xlYW5pbmcqKg0KDQpMYWt1a2FuIHBlbWJlcnNpaGFuIGRhdGEgYmVyaWt1dDoNCg0KYS4gU3RhbmRhcmthbiBmb3JtYXQgdGFuZ2dhbCBrZSBiZW50dWsgWVlZWS1NTS1ERC4NCg0KYi4gVWJhaCBrb2xvbSBIYXJnYSBkYW4gSnVtbGFoIG1lbmphZGkgZm9ybWF0IG51bWVyaWsuDQoNCmMuIEhpdHVuZyB1bGFuZyBuaWxhaSBrb2xvbSBUb3RhbCA9IEhhcmdhICogSnVtbGFoLg0KDQpkLiBHYW50aSBuaWxhaSB5YW5nIHRpZGFrIHZhbGlkIChjb250b2g6IC0sICJkdWEiLCAiUnAiLCAiX2Fub255bW91c18iKSBkZW5nYW4gbmlsYWkNCnlhbmcgc2VzdWFpIGF0YXUgTkEuDQoNCmUuIEhhcHVzIGJhcmlzIHlhbmcgdGlkYWsgbWVtaWxpa2kgbmFtYSBwcm9kdWsgKFByb2R1ayBrb3NvbmcgYXRhdSAtKS4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShEVCkNCg0KIyBhLiBTdGFuZGFya2FuIGZvcm1hdCB0YW5nZ2FsIGtlIFlZWVktTU0tREQNCmRhdGFfZ2FidW5nYW4kVGFuZ2dhbCA8LSBhcy5EYXRlKGRhdGFfZ2FidW5nYW4kVGFuZ2dhbCwgZm9ybWF0ID0gIiVkLSVtLSVZIikNCg0KIyBiLiBVYmFoIGtvbG9tIEhhcmdhIGRhbiBKdW1sYWggbWVuamFkaSBudW1lcmlrDQojIEZ1bmdzaSB1bnR1ayBtZW1iZXJzaWhrYW4gZGF0YSBudW1lcmlrDQpjbGVhbl9udW1lcmljIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeCA8LSBhcy5jaGFyYWN0ZXIoeCkNCiAgeCA8LSBzdHJfcmVwbGFjZV9hbGwoeCwgIlJwfCx8XFwtfGR1YXxhbm9ueW1vdXN8X2Fub255bW91c198ICIsICIiKQ0KICBpZiAodG9sb3dlcih4KSAlaW4lIGMoIiIsICJuYSIsICJuYW4iKSkgcmV0dXJuKE5BX3JlYWxfKQ0KICBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoeCkpDQp9DQoNCmRhdGFfZ2FidW5nYW4gPC0gZGF0YV9nYWJ1bmdhbiAlPiUNCiAgbXV0YXRlKA0KICAgIEhhcmdhID0gc2FwcGx5KEhhcmdhLCBjbGVhbl9udW1lcmljKSwNCiAgICBKdW1sYWggPSBzYXBwbHkoSnVtbGFoLCBjbGVhbl9udW1lcmljKQ0KICApDQoNCiMgYy4gSGl0dW5nIHVsYW5nIG5pbGFpIGtvbG9tIFRvdGFsID0gSGFyZ2EgKiBKdW1sYWgNCmRhdGFfZ2FidW5nYW4gPC0gZGF0YV9nYWJ1bmdhbiAlPiUNCiAgbXV0YXRlKFRvdGFsID0gSGFyZ2EgKiBKdW1sYWgpDQoNCiMgZC4gR2FudGkgbmlsYWkgeWFuZyB0aWRhayB2YWxpZCAoLSwgImR1YSIsICJScCIsICJfYW5vbnltb3VzXyIpIHN1ZGFoIGRpdGFuZ2FuaSBkaSBmdW5nc2kgY2xlYW5fbnVtZXJpYw0KDQojIGUuIEhhcHVzIGJhcmlzIHlhbmcgdGlkYWsgbWVtaWxpa2kgbmFtYSBwcm9kdWsgKFByb2R1ayBrb3NvbmcgYXRhdSAiLSIpDQpkYXRhX2dhYnVuZ2FuIDwtIGRhdGFfZ2FidW5nYW4gJT4lDQogIGZpbHRlcighKFByb2R1ayAlaW4lIGMoIiIsICItIiwgTkEpKSkNCg0KIyBUYW1waWxrYW4gaGFzaWwgc2ViYWdhaSB0YWJlbCBpbnRlcmFrdGlmDQpkYXRhdGFibGUoaGVhZChkYXRhX2dhYnVuZ2FuLCAxMCksIGNhcHRpb24gPSAiVGFiZWwgSW50ZXJha3RpZjogMTAgQmFyaXMgUGVydGFtYSBEYXRhIFNldGVsYWggUGVtYmVyc2loYW4iKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKioNCg0KUGFkYSB0YWhhcCBpbmksIGRpbGFrdWthbiBwcm9zZXMgcGVtYmVyc2loYW4gZGF0YSB1bnR1ayBtZW1hc3Rpa2FuIGt1YWxpdGFzIGRhbiBrb25zaXN0ZW5zaSBkYXRhc2V0IHNlYmVsdW0gZGlhbmFsaXNpcyBsZWJpaCBsYW5qdXQuIFBlcnRhbWEsIGZvcm1hdCB0YW5nZ2FsIGRpc2VyYWdhbWthbiBrZSBiZW50dWsgc3RhbmRhciBZWVlZLU1NLURELCBhZ2FyIG11ZGFoIGRpb2xhaCBkYWxhbSBhbmFsaXNpcyB3YWt0dS4gS2VkdWEsIGtvbG9tIEhhcmdhIGRhbiBKdW1sYWggeWFuZyBzZWJlbHVtbnlhIG1lbmdhbmR1bmcgdGVrcyBhdGF1IHNpbWJvbCB0aWRhayB2YWxpZCBzZXBlcnRpICJScCIsICJkdWEiLCBhdGF1ICItIiBkaWtvbnZlcnNpIGtlIGZvcm1hdCBudW1lcmlrIG1lbmdndW5ha2FuIGZ1bmdzaSBwZW1iZXJzaWgga2h1c3VzLiBLZW11ZGlhbiwgbmlsYWkgcGFkYSBrb2xvbSBUb3RhbCBkaWhpdHVuZyB1bGFuZyBzZWJhZ2FpIGhhc2lsIHBlcmthbGlhbiBhbnRhcmEgSGFyZ2EgZGFuIEp1bWxhaCwgbWVtYXN0aWthbiBha3VyYXNpIGRhdGEgdHJhbnNha3NpLiBTZWxhbmp1dG55YSwgZW50cmkgZGVuZ2FuIG5pbGFpIHRpZGFrIHZhbGlkIHNlY2FyYSBvdG9tYXRpcyBkaWdhbnRpIGRlbmdhbiBOQSwgc2VoaW5nZ2EgdGlkYWsgbWVuZ2dhbmdndSBwZXJoaXR1bmdhbiBzdGF0aXN0aWsuIFRlcmFraGlyLCBiYXJpcy1iYXJpcyB5YW5nIHRpZGFrIG1lbWlsaWtpIG5hbWEgcHJvZHVrIChtaXNhbG55YSBQcm9kdWsga29zb25nIGF0YXUgdGFuZGEgIi0iKSBkaWhhcHVzIGFnYXIgaGFueWEgZGF0YSB5YW5nIHJlbGV2YW4geWFuZyBkaXBlcnRhaGFua2FuLiBIYXNpbG55YSwgZGF0YXNldCBtZW5qYWRpIGxlYmloIGJlcnNpaCwgcmFwaSwgZGFuIHNpYXAgdW50dWsgZGlhbmFsaXNpcyBsZWJpaCBsYW5qdXQuDQoNCioqQmFnaWFuIDM6IERhdGEgVHJhbnNmb3JtYXRpb24qKg0KDQpMYWt1a2FuIHRyYW5zZm9ybWFzaSBkYXRhIHNlYmFnYWkgYmVyaWt1dDoNCg0KYS4gQnVhdCBrb2xvbSBiYXJ1IEJ1bGFuIGJlcmRhc2Fya2FuIHRhbmdnYWwgdHJhbnNha3NpLg0KDQpiLiBIaXR1bmcgdG90YWwgcGVuanVhbGFuIChUb3RhbCkgcGVyIGthdGVnb3JpIHByb2R1ay4NCg0KYy4gSGl0dW5nIGp1bWxhaCB0cmFuc2Frc2kgZGFyaSBzZXRpYXAga290YS4NCg0KZC4gQnVhdCByaW5na2FzYW4ganVtbGFoIHRvdGFsIHBlbmp1YWxhbiBwZXIgYnVsYW4uDQoNCioqT3V0cHV0IHlhbmcgRGloYXJhcGthbjoqKg0KDQphLiBEYXRhc2V0IHlhbmcgc3VkYWggYmVyc2loIGRhbiByYXBpLg0KDQpiLiBUYWJlbCBhZ3JlZ2F0OiB0b3RhbCBwZW5qdWFsYW4gcGVyIGthdGVnb3JpLCBrb3RhLCBkYW4gYnVsYW4uDQoNCmMuIFZpc3VhbGlzYXNpIG9wc2lvbmFsOiBncmFmaWsgYmF0YW5nLCBncmFmaWsgbGluZ2thcmFuIGRhbiBncmFmaWsgZ2FyaXMgcGVuanVhbGFuIHBlcg0Ka2F0ZWdvcmkuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KERUKQ0KDQojIFBhc3Rpa2FuIGtvbG9tICdUYW5nZ2FsJyBzdWRhaCBkYWxhbSBmb3JtYXQgRGF0ZQ0KZGF0YV9nYWJ1bmdhbiRUYW5nZ2FsIDwtIGFzLkRhdGUoZGF0YV9nYWJ1bmdhbiRUYW5nZ2FsKQ0KDQojIGEuIEJ1YXQga29sb20gQnVsYW4NCmRhdGFfZ2FidW5nYW4kQnVsYW4gPC0gZm9ybWF0KGRhdGFfZ2FidW5nYW4kVGFuZ2dhbCwgIiVZLSVtIikNCg0KIyBiLiBUb3RhbCBwZW5qdWFsYW4gcGVyIGthdGVnb3JpDQppZiAoYWxsKGMoIkthdGVnb3JpIiwgIlRvdGFsIikgJWluJSBuYW1lcyhkYXRhX2dhYnVuZ2FuKSkpIHsNCiAgdG90YWxfcGVyX2thdGVnb3JpIDwtIGRhdGFfZ2FidW5nYW4gJT4lDQogICAgZ3JvdXBfYnkoS2F0ZWdvcmkpICU+JQ0KICAgIHN1bW1hcmlzZShgVG90YWwgUGVuanVhbGFuYCA9IHN1bShUb3RhbCwgbmEucm0gPSBUUlVFKSkNCn0gZWxzZSB7DQogIHRvdGFsX3Blcl9rYXRlZ29yaSA8LSBkYXRhLmZyYW1lKCkNCn0NCg0KIyBjLiBKdW1sYWggdHJhbnNha3NpIHBlciBrb3RhDQppZiAoIktvdGEiICVpbiUgbmFtZXMoZGF0YV9nYWJ1bmdhbikpIHsNCiAgdHJhbnNha3NpX3Blcl9rb3RhIDwtIGRhdGFfZ2FidW5nYW4gJT4lDQogICAgY291bnQoS290YSwgbmFtZSA9ICJKdW1sYWggVHJhbnNha3NpIikNCn0gZWxzZSB7DQogIHRyYW5zYWtzaV9wZXJfa290YSA8LSBkYXRhLmZyYW1lKCkNCn0NCg0KIyBkLiBSaW5na2FzYW4gcGVuanVhbGFuIHBlciBidWxhbg0KaWYgKGFsbChjKCJCdWxhbiIsICJUb3RhbCIpICVpbiUgbmFtZXMoZGF0YV9nYWJ1bmdhbikpKSB7DQogIHBlbmp1YWxhbl9wZXJfYnVsYW4gPC0gZGF0YV9nYWJ1bmdhbiAlPiUNCiAgICBncm91cF9ieShCdWxhbikgJT4lDQogICAgc3VtbWFyaXNlKGBUb3RhbCBQZW5qdWFsYW5gID0gc3VtKFRvdGFsLCBuYS5ybSA9IFRSVUUpKQ0KfSBlbHNlIHsNCiAgcGVuanVhbGFuX3Blcl9idWxhbiA8LSBkYXRhLmZyYW1lKCkNCn0NCg0KIyBUYW1waWxrYW4gc2ViYWdhaSB0YWJlbCBzdGF0aXMNCmthYmxlKHRvdGFsX3Blcl9rYXRlZ29yaSwgY2FwdGlvbiA9ICJUb3RhbCBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIikNCmthYmxlKHRyYW5zYWtzaV9wZXJfa290YSwgY2FwdGlvbiA9ICJKdW1sYWggVHJhbnNha3NpIHBlciBLb3RhIikNCmthYmxlKHBlbmp1YWxhbl9wZXJfYnVsYW4sIGNhcHRpb24gPSAiUmluZ2thc2FuIFBlbmp1YWxhbiBwZXIgQnVsYW4iKQ0KYGBgDQoNCioqVmlzdWFsaXNhc2kqKg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkocGxvdGx5KQ0KDQojIGEuIEdyYWZpayBiYXRhbmcgaW50ZXJha3RpZiAtIFBlbmp1YWxhbiBwZXIga2F0ZWdvcmkNCmlmIChucm93KHRvdGFsX3Blcl9rYXRlZ29yaSkgPiAwKSB7DQogIGZpZzEgPC0gcGxvdF9seSgNCiAgICB0b3RhbF9wZXJfa2F0ZWdvcmksDQogICAgeCA9IH5LYXRlZ29yaSwNCiAgICB5ID0gfmBUb3RhbCBQZW5qdWFsYW5gLA0KICAgIHR5cGUgPSAnYmFyJywNCiAgICBjb2xvciA9IH5LYXRlZ29yaQ0KICApICU+JQ0KICAgIGxheW91dCh0aXRsZSA9ICJUb3RhbCBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIFByb2R1ayIpDQogIGZpZzENCn0NCg0KIyBiLiBHcmFmaWsgcGllIChkb251dCkgaW50ZXJha3RpZiAtIFRyYW5zYWtzaSBwZXIga290YQ0KaWYgKG5yb3codHJhbnNha3NpX3Blcl9rb3RhKSA+IDApIHsNCiAgZmlnMiA8LSBwbG90X2x5KA0KICAgIHRyYW5zYWtzaV9wZXJfa290YSwNCiAgICBsYWJlbHMgPSB+S290YSwNCiAgICB2YWx1ZXMgPSB+YEp1bWxhaCBUcmFuc2Frc2lgLA0KICAgIHR5cGUgPSAncGllJywNCiAgICBob2xlID0gMC40DQogICkgJT4lDQogICAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1c2kgVHJhbnNha3NpIHBlciBLb3RhIikNCiAgZmlnMg0KfQ0KDQojIGMuIEdyYWZpayBnYXJpcyBpbnRlcmFrdGlmIC0gUGVuanVhbGFuIHBlciBidWxhbg0KaWYgKG5yb3cocGVuanVhbGFuX3Blcl9idWxhbikgPiAwKSB7DQogIGZpZzMgPC0gcGxvdF9seSgNCiAgICBwZW5qdWFsYW5fcGVyX2J1bGFuLA0KICAgIHggPSB+QnVsYW4sDQogICAgeSA9IH5gVG90YWwgUGVuanVhbGFuYCwNCiAgICB0eXBlID0gJ3NjYXR0ZXInLA0KICAgIG1vZGUgPSAnbGluZXMrbWFya2VycycsDQogICAgbGluZSA9IGxpc3QoY29sb3IgPSAnZ3JlZW4nKQ0KICApICU+JQ0KICAgIGxheW91dCh0aXRsZSA9ICJUcmVuIFRvdGFsIFBlbmp1YWxhbiBwZXIgQnVsYW4iKQ0KICBmaWczDQp9DQpgYGANCg0KKipJbnRlcnByZXRhc2kqKg0KDQpCZXJkYXNhcmthbiBvdXRwdXQgeWFuZyBkaWRhcGF0a2FuLCBkYXBhdCBkaXNpbXB1bGthbiBiZWJlcmFwYSBoYWwgcGVudGluZyB0ZXJrYWl0IHBlcmZvcm1hIHBlbmp1YWxhbiBkYW4gZGlzdHJpYnVzaSB0cmFuc2Frc2k6DQoNCjEuIEthdGVnb3JpIFByb2R1azogS2F0ZWdvcmkgQWtzZXNvcmlzIG1lbmNhdGF0IHRvdGFsIHBlbmp1YWxhbiB0ZXJ0aW5nZ2kgc2ViZXNhciBScDMzMS43NjIuMDAwLCBkaXN1c3VsIG9sZWggRmFzaGlvbiBzZWJlc2FyIFJwMjI1LjAwNi43NTAsIGRhbiBFbGVrdHJvbmlrIHNlYmVzYXIgUnAxNjcuMDA2Ljc1MC4gVGVyZGFwYXQgcHVsYSBkYXRhIHBlbmp1YWxhbiBzZWJlc2FyIFJwMTIzLjAwOS43NTAgeWFuZyB0aWRhayB0ZXJjYXRhdCBkYWxhbSBrYXRlZ29yaSB0ZXJ0ZW50dSAoa2VtdW5na2luYW4gYWtpYmF0IGRhdGEgdGlkYWsgbGVuZ2thcCBhdGF1IGthdGVnb3JpIGtvc29uZykuIEhhbCBpbmkgbWVudW5qdWtrYW4gYmFod2EgcHJvZHVrIEFrc2Vzb3JpcyBwYWxpbmcgbWVuZG9taW5hc2kgZGFsYW0gcGVuanVhbGFuIHNlbGFtYSBwZXJpb2RlIHlhbmcgZGlhbmFsaXNpcy4NCg0KMi4gRGlzdHJpYnVzaSBLb3RhOiBLb3RhIGRlbmdhbiBqdW1sYWggdHJhbnNha3NpIHRlcmJhbnlhayBhZGFsYWggQmFuZHVuZyAoMzMgdHJhbnNha3NpKSwgZGlpa3V0aSBvbGVoIFN1cmFiYXlhICgzMCB0cmFuc2Frc2kpIGRhbiBKYWthcnRhICgyOSB0cmFuc2Frc2kpLiBOYW11biwgdGVyZGFwYXQgcHVsYSAzMCB0cmFuc2Frc2kgeWFuZyB0aWRhayBtZW1pbGlraSBpbmZvcm1hc2kga290YSAoZGlsYW1iYW5na2FuIGRlbmdhbiB0YW5kYSAiLSIpLCB5YW5nIHBlcmx1IGRpdGVsdXN1cmkgbGViaWggbGFuanV0IGthcmVuYSBiaXNhIG1lbWVuZ2FydWhpIGFuYWxpc2lzIGdlb2dyYWZpcyBzZWNhcmEgYWt1cmF0Lg0KDQozLiBUcmVuIFBlbmp1YWxhbiBCdWxhbmFuOiBQZW5qdWFsYW4gdGVydGluZ2dpIHRlcmphZGkgcGFkYSBidWxhbiBNYXJldCAyMDI0IGRlbmdhbiB0b3RhbCBScDMxOC4wMDguMjUwLCBkaWlrdXRpIG9sZWggRmVicnVhcmkgKFJwMjg2Ljc2MS4yNTApIGRhbiBKYW51YXJpIChScDE5NS43NTcuNTAwKS4gTmFtdW4sIHRlcmphZGkgcGVudXJ1bmFuIHRhamFtIHBhZGEgQXByaWwgMjAyNCwgZGkgbWFuYSB0b3RhbCBwZW5qdWFsYW4gaGFueWEgbWVuY2FwYWkgUnA0Ni4yNTguMjUwLiBQZW51cnVuYW4gaW5pIGRhcGF0IG1lbmphZGkgcGVyaGF0aWFuLCBhcGFrYWggZGlzZWJhYmthbiBvbGVoIG11c2ltLCBwcm9tb3NpIHlhbmcgYmVya3VyYW5nLCBhdGF1IGZha3RvciBla3N0ZXJuYWwgbGFpbm55YS4=