UTS PEMOGRAMAN SAINS DATA

UTS PEMOGRAMAN SAINS DATA

Fikakampus.jpg


1. Operasi dan Tipe Data Dasar

a. Menerima dua bilangan dari pengguna

# angka1 <- as.numeric(readline(prompt = "Masukkan bilangan pertama: "))
# angka2 <- as.numeric(readline(prompt = "Masukkan bilangan kedua: "))

# a. Dua bilangan yang sudah ditentukan
angka1 <- 7
angka2 <- 3

b. Menghitung dan menampilkan hasil

angka1 <- 7
angka2 <- 3


penjumlahan <- angka1 + angka2
perkalian <- angka1 * angka2
pembagian <- angka1 / angka2
pangkat <- angka1 ^ angka2

cat("Penjumlahan:",  penjumlahan)
## Penjumlahan: 10
cat("Perkalian:", perkalian)
## Perkalian: 21
cat("Pembagian:", pembagian)
## Pembagian: 2.333333
cat("Pangkat:", pangkat)
## Pangkat: 343

c. Menampilkan hasil dan tipe data masing-masing

cat("Tipe data:", class(penjumlahan), "\n")
## Tipe data: numeric
cat("Tipe data:", class(perkalian), "\n")
## Tipe data: numeric
cat("Tipe data:", class(pembagian), "\n")
## Tipe data: numeric
cat("Tipe data:", class(pangkat), "\n")
## Tipe data: numeric

2. Struktur Kendali (Control Flow)

a. Menerima input nilai ujian dari pengguna (0-100)

# a. Menentukan nilai ujian 
nilai <- 92

# Menampilkan nilai yang ditentukan
cat("Nilai ujian:", nilai, "\n")
## Nilai ujian: 92

b. Menampilkan keterangan berdasarkan ketentuan berikut:

  • Nilai ≥ 85: “Sangat Baik”

  • Nilai 70–84: “Baik”

  • Nilai 60–69: “Cukup”

  • Nilai < 60: “Perlu Perbaikan”

if (nilai >= 85) {
  cat("Sangat Baik (A)\n")
} else if (nilai >= 70) {
  cat("Baik (B)\n")
} else if (nilai >= 60) {
  cat("Cukup (C)\n")
} else {
  cat("Nilai Perlu Perbaikan\n")
}
## Sangat Baik (A)

3. Fungsi dan Perulangan

a. Menerima input integer

# a. Menentukan nilai integer n 
n <- 40

# Menampilkan nilai n
cat("Nilai n yang ditentukan adalah:", n, "\n")
## Nilai n yang ditentukan adalah: 40

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

# Menampilkan info
cat("Bilangan genap kelipatan 4 dari 1 hingga", n, ":\n")
## Bilangan genap kelipatan 4 dari 1 hingga 40 :
# Loop untuk mencari dan mencetak bilangan genap kelipatan 4
for (i in 1:n) {
  if (i %% 4 == 0 && i %% 2 == 0) {
    cat(i, " ")
  }
}
## 4  8  12  16  20  24  28  32  36  40

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.

# suppress message and warning
suppressMessages({
  suppressWarnings({
    
    # Load library
    library(dplyr)
    library(ggplot2)
    
    # Set seed untuk konsistensi
    set.seed(42)
    
    # Simulasi data
    tanggal_range <- seq(as.Date("2025-01-01"), as.Date("2025-03-31"), by = "day")
    kategori_list <- c("Elektronik", "Fashion", "Makanan", "Kecantikan", "Olahraga")
    
    # Generate data acak
    sales_data <- data.frame(
      Tanggal = sample(tanggal_range, 300, replace = TRUE),
      Kategori = sample(kategori_list, 300, replace = TRUE),
      Jumlah = sample(1:4, 300, replace = TRUE),
      Harga = sample(50000:1000000, 300, replace = TRUE)
    )
    
    # Hitung total penjualan
    sales_data <- sales_data %>%
      mutate(Total_Penjualan = Jumlah * Harga)
    
    # Statistik Data Numerik
    cat("=== Statistik Data Numerik ===\n")
    print(summary(select(sales_data, Jumlah, Harga, Total_Penjualan)))
    
    # Statistik Data Kategorikal
    cat("\n=== Statistik Data Kategorikal ===\n")
    print(summary(select(sales_data, Tanggal, Kategori)))
    
    # Penjualan per kategori
    total_per_kategori <- sales_data %>%
      group_by(Kategori) %>%
      summarise(Total_Penjualan = sum(Total_Penjualan)) %>%
      arrange(desc(Total_Penjualan))
    
    cat("\n=== Total Penjualan per Kategori ===\n")
    print(total_per_kategori)
    
    # Visualisasi
    ggplot(total_per_kategori, aes(x = reorder(Kategori, -Total_Penjualan), y = Total_Penjualan)) +
      geom_bar(stat = "identity", fill = "pink", color = "black") +
      labs(title = "Total Penjualan per Kategori",
           x = "Kategori", y = "Total Penjualan (Rp)") +
      theme_minimal() +
      theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
      geom_hline(yintercept = seq(0, max(total_per_kategori$Total_Penjualan), by = 1e7),
                 linetype = "dashed", color = "gray", alpha = 0.6)

  })
})
## === Statistik Data Numerik ===
##      Jumlah         Harga        Total_Penjualan  
##  Min.   :1.00   Min.   : 50526   Min.   :  51371  
##  1st Qu.:2.00   1st Qu.:271014   1st Qu.: 577458  
##  Median :3.00   Median :502273   Median :1017678  
##  Mean   :2.51   Mean   :506415   Mean   :1283365  
##  3rd Qu.:3.00   3rd Qu.:710250   3rd Qu.:1849141  
##  Max.   :4.00   Max.   :996852   Max.   :3976072  
## 
## === Statistik Data Kategorikal ===
##     Tanggal             Kategori        
##  Min.   :2025-01-01   Length:300        
##  1st Qu.:2025-01-24   Class :character  
##  Median :2025-02-11   Mode  :character  
##  Mean   :2025-02-12                     
##  3rd Qu.:2025-03-05                     
##  Max.   :2025-03-31                     
## 
## === Total Penjualan per Kategori ===
## # A tibble: 5 × 2
##   Kategori   Total_Penjualan
##   <chr>                <int>
## 1 Fashion           98922741
## 2 Makanan           80346424
## 3 Kecantikan        72366578
## 4 Olahraga          69648647
## 5 Elektronik        63725054

1. Data Collection

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

a. Gabungkan ketiga file menjadi satu dataset.

b.Tampilkan jumlah total baris dan kolom setelah digabung.

library(readr)
library(dplyr)

# Membaca file CSV
df_jan <- read_csv("januari.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_feb <- read_csv("februari.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_mar <- read_csv("maret.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Menampilkan isi masing-masing file
cat(" Data Januari:\n")
##  Data Januari:
print(head(df_jan))
## # A tibble: 6 × 9
##   OrderID Tanggal    Produk       Kategori  Harga     Jumlah Total Pembeli Kota 
##     <dbl> <chr>      <chr>        <chr>     <chr>     <chr>  <lgl> <chr>   <chr>
## 1    1001 01-01-2024 Laptop A     <NA>      15000000  empat  NA    Budi@   Band…
## 2    1002 02-01-2024 Tas Branded  Fashion   15000000  2      NA    Budi@   Sura…
## 3    1003 03-01-2024 Tas Branded  Aksesoris 15000000  3      NA    _anony… Band…
## 4    1004 04-01-2024 Kemeja       <NA>      15000000  dua    NA    Andi123 Band…
## 5    1005 05-01-2024 -            Fashion   Rp750.000 3      NA    _anony… Jaka…
## 6    1006 06-01-2024 Smartphone X Fashion   15000000  empat  NA    Sinta99 Band…
cat("\n")
cat(" Data Februari:\n")
##  Data Februari:
print(head(df_feb))
## # A tibble: 6 × 9
##   OrderID Tanggal    Produk       Kategori  Harga     Jumlah Total Pembeli Kota 
##     <dbl> <chr>      <chr>        <chr>     <chr>     <chr>  <lgl> <chr>   <chr>
## 1    1101 01-02-2024 Tas Branded  Aksesoris 1.200.000 dua    NA    Budi@   Band…
## 2    1102 02-02-2024 Smartphone X Fashion   Rp750.000 2      NA    _anony… -    
## 3    1103 03-02-2024 Kemeja       Fashion   15000000  1      NA    Budi@   Sura…
## 4    1104 04-02-2024 Kemeja       Fashion   15000000  empat  NA    _anony… Band…
## 5    1105 05-02-2024 Smartphone X <NA>      15000000  empat  NA    _anony… Sura…
## 6    1106 06-02-2024 -            Aksesoris Rp750.000 3      NA    _anony… Band…
cat("\n")
cat(" Data Maret:\n")
##  Data Maret:
print(head(df_mar))
## # A tibble: 6 × 9
##   OrderID Tanggal    Produk        Kategori   Harga   Jumlah Total Pembeli Kota 
##     <dbl> <chr>      <chr>         <chr>      <chr>   <chr>  <lgl> <chr>   <chr>
## 1    1201 01-03-2024 Sepatu 'Nike' Fashion    1.200.… empat  NA    Andi123 Sura…
## 2    1202 02-03-2024 -             Elektronik 150000… 3      NA    _anony… Jaka…
## 3    1203 03-03-2024 -             Fashion    1.200.… dua    NA    Sinta99 Sura…
## 4    1204 04-03-2024 -             <NA>       Rp750.… 3      NA    Budi@   Sura…
## 5    1205 05-03-2024 Tas Branded   <NA>       Rp750.… dua    NA    Andi123 Jaka…
## 6    1206 06-03-2024 Kemeja        Aksesoris  150000… 2      NA    Andi123 Sura…
cat("\n")
# Pastikan kamu sudah install dan load package yang diperlukan
# install.packages("dplyr")  # jika belum terinstall
library(dplyr)

# Baca data
df_jan <- read.csv("januari.csv")
df_feb <- read.csv("februari.csv")
df_mar <- read.csv("maret.csv")

# Gabung data
df_all <- bind_rows(df_jan, df_feb, df_mar)

# Tampilkan data sebagai tabel
cat("Contoh Tabel Gabungan (10 Baris Acak):\n")
## Contoh Tabel Gabungan (10 Baris Acak):
print(df_all %>% sample_n(10))
##    OrderID    Tanggal        Produk   Kategori     Harga Jumlah Total
## 1     1141 12-03-2024  Smartphone X Elektronik Rp750.000  empat    NA
## 2     1032 01-02-2024             -    Fashion    250000      1    NA
## 3     1001 01-01-2024      Laptop A             15000000  empat    NA
## 4     1249 18-04-2024 Sepatu 'Nike'    Fashion  15000000  empat    NA
## 5     1128 28-02-2024        Kemeja    Fashion Rp750.000      3    NA
## 6     1134 05-03-2024        Kemeja  Aksesoris  15000000      3    NA
## 7     1231 31-03-2024      Laptop A    Fashion Rp750.000      1    NA
## 8     1219 19-03-2024        Kemeja             15000000      2    NA
## 9     1003 03-01-2024   Tas Branded  Aksesoris  15000000      3    NA
## 10    1243 12-04-2024      Laptop A    Fashion 1.200.000      2    NA
##        Pembeli     Kota
## 1        Budi@  Bandung
## 2  _anonymous_  Jakarta
## 3        Budi@  Bandung
## 4      Sinta99  Jakarta
## 5      Andi123 Surabaya
## 6      Sinta99  Jakarta
## 7  _anonymous_  Bandung
## 8  _anonymous_        -
## 9  _anonymous_  Bandung
## 10     Andi123        -
# Simpan ke file jika perlu (misalnya)
# write.csv(df_all, "data_gabungan.csv", row.names = FALSE)
# Menggabungkan tiga data frame menjadi satu
    df_all <- bind_rows(df_jan, df_feb, df_mar)
    
    # Menampilkan jumlah baris dan kolom
    cat("Jumlah total baris:", nrow(df_all), "\n")
## Jumlah total baris: 150
    cat("Jumlah total kolom:", ncol(df_all), "\n")
## Jumlah total kolom: 9

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

library(readr)
library(dplyr)
library(stringr)
library(lubridate)
## Warning: package 'lubridate' was built under R version 4.4.3
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
# 1. Membaca 3 file CSV
df_jan <- read_csv("januari.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_feb <- read_csv("februari.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_mar <- read_csv("maret.csv")
## Rows: 50 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Tanggal, Produk, Kategori, Harga, Jumlah, Pembeli, Kota
## dbl (1): OrderID
## lgl (1): Total
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# 2. Gabungkan ketiga dataset
df_all <- bind_rows(df_jan, df_feb, df_mar)

# 3. Salin data untuk cleaning
df <- df_all

# 4. Format Tanggal jadi YYYY-MM-DD
df$Tanggal <- dmy(df$Tanggal)  # day-month-year

# 5. Bersihkan kolom Harga
# - Hilangkan simbol dan teks seperti "Rp", titik, koma
df$Harga <- gsub("[^0-9]", "", as.character(df$Harga))
df$Harga <- as.numeric(df$Harga)

# 6. Bersihkan kolom Jumlah
# - Konversi kata-kata ke angka
kata_ke_angka <- c("satu" = 1, "dua" = 2, "tiga" = 3, "empat" = 4, "lima" = 5)
df$Jumlah <- recode(df$Jumlah, !!!kata_ke_angka)
## Warning: Unreplaced values treated as NA as `.x` is not compatible.
## Please specify replacements exhaustively or supply `.default`.
df$Jumlah <- as.numeric(df$Jumlah)

# 7. Hitung ulang kolom Total
df$Total <- df$Harga * df$Jumlah

# 8. Ganti nilai tidak valid menjadi NA

invalid_values <- c("-", "Rp", "anonymous")

df <- df %>%
  mutate(across(where(is.character), ~replace(.x, .x %in% invalid_values, NA)))

# 9. Hapus baris yang tidak memiliki nama produk
df <- df %>% filter(!is.na(Produk))

# 10. Tampilkan data hasil cleaning
cat("Jumlah baris setelah dibersihkan:", nrow(df), "\n")
## Jumlah baris setelah dibersihkan: 122
head(df)

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.

    library(dplyr)
    library(lubridate)

    # Tambahkan kolom Bulan
    bulan_dict <- c("Januari", "Februari", "Maret")
    df <- df %>%
      mutate(Bulan = bulan_dict[month(Tanggal)])

    # Total Penjualan per Kategori Produk
    penjualan_kategori <- df %>%
      group_by(Kategori) %>%
      summarise(Total = sum(Total, na.rm = TRUE)) %>%
      arrange(desc(Total))

    # Total Penjualan per Kota
    penjualan_kota <- df %>%
      group_by(Kota) %>%
      summarise(Total = sum(Total, na.rm = TRUE)) %>%
      arrange(desc(Total))

    # Total Penjualan per Bulan
    penjualan_bulan <- df %>%
      group_by(Bulan) %>%
      summarise(Total = sum(Total, na.rm = TRUE)) %>%
      arrange(desc(Total))

    # Ubah ke dataframe biasa & reset rownames jadi 0,1,2 (seperti pandas)
    rownames(penjualan_kategori) <- 0:(nrow(penjualan_kategori) - 1)
## Warning: Setting row names on a tibble is deprecated.
    rownames(penjualan_kota) <- 0:(nrow(penjualan_kota) - 1)
## Warning: Setting row names on a tibble is deprecated.
    rownames(penjualan_bulan) <- 0:(nrow(penjualan_bulan) - 1)
## Warning: Setting row names on a tibble is deprecated.
    # Tampilkan output
    cat("Total Penjualan per Kategori Produk:\n")
## Total Penjualan per Kategori Produk:
    print(as.data.frame(penjualan_kategori))
##     Kategori     Total
## 1       <NA> 251000000
## 2 Elektronik 227600000
## 3    Fashion 192800000
## 4  Aksesoris  31100000
    cat("\nTotal Penjualan per Kota:\n")
## 
## Total Penjualan per Kota:
    print(as.data.frame(penjualan_kota))
##       Kota     Total
## 1  Bandung 344200000
## 2     <NA> 142100000
## 3  Jakarta 135300000
## 4 Surabaya  80900000
    cat("\nTotal Penjualan per Bulan:\n")
## 
## Total Penjualan per Bulan:
    print(as.data.frame(penjualan_bulan))
##      Bulan     Total
## 1  Januari 277500000
## 2 Februari 183200000
## 3     <NA> 133100000
## 4    Maret 108700000

Visualisasi

    library(ggplot2)
    library(dplyr)

    # Pastikan urutan bulan benar
    penjualan_bulan$Bulan <- factor(penjualan_bulan$Bulan,
                                    levels = c("Januari", "Februari", "Maret"))

    # Grafik 1: Penjualan per Kategori (palet soft biru - pastel)
    ggplot(penjualan_kategori, aes(x = Total, y = reorder(Kategori, Total))) +
      geom_bar(stat = "identity", fill = "#A3C4DC") +
      labs(title = "Grafik Penjualan per Kategori",
           x = "Jumlah Penjualan", y = "Kategori") +
      theme_minimal()

    # Grafik 2: Penjualan per Kota (palet hijau-biru kalem)
    ggplot(penjualan_kota, aes(x = Total, y = reorder(Kota, Total))) +
      geom_bar(stat = "identity", fill = "#A1D99B") +
      labs(title = "Grafik Penjualan per Kota",
           x = "Jumlah Penjualan", y = "Kota") +
      theme_minimal()

    # Grafik 3: Penjualan per Bulan (ungu pastel)
    ggplot(penjualan_bulan, aes(x = Bulan, y = Total, group = 1)) +
      geom_line(color = "#BAA5D3", size = 1.2) +
      geom_point(color = "#BAA5D3", size = 3) +
      labs(title = "Tren Penjualan Bulanan",
           x = "Bulan", y = "Total Penjualan") +
      theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

LS0tDQp0aXRsZTogIlVUUyBQRU1PR1JBTUFOIFNBSU5TIERBVEEiDQoNCnN1YnRpdGxlOiAiVVRTIFBFTU9HUkFNQU4gU0FJTlMgREFUQSAiDQoNCmF1dGhvcjogDQogIC0gIiBGaWthIElyc2FuZGkgRGVzdnlhbnRpICg1MjI0MDAwMTMpIg0KICANCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOg0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlDQogICAgdGh1bWJuYWlsczogdHJ1ZQ0KICAgIGxpZ2h0Ym94OiB0cnVlDQogICAgZ2FsbGVyeTogdHJ1ZQ0KICAgIGxpYl9kaXI6IGxpYnMNCiAgICBkZl9wcmludDogInBhZ2VkIg0KICAgIGNvZGVfZm9sZGluZzogInNob3ciDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY3NzOiAiU3R5bGUuY3NzIg0KICAgIA0KLS0tDQoNCiA8aW1nIGlkPSJsb2dvLXV0YW1hIiBzcmM9IkZpa2FrYW1wdXMuanBnIiBhbHQ9IkZpa2FrYW1wdXMuanBnIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KLS0tDQoNCg0KIyAqKjEuIE9wZXJhc2kgZGFuIFRpcGUgRGF0YSBEYXNhcioqDQoNCiMjIGEuIE1lbmVyaW1hIGR1YSBiaWxhbmdhbiBkYXJpIHBlbmdndW5hDQoNCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsfQ0KDQoNCiMgYW5na2ExIDwtIGFzLm51bWVyaWMocmVhZGxpbmUocHJvbXB0ID0gIk1hc3Vra2FuIGJpbGFuZ2FuIHBlcnRhbWE6ICIpKQ0KIyBhbmdrYTIgPC0gYXMubnVtZXJpYyhyZWFkbGluZShwcm9tcHQgPSAiTWFzdWtrYW4gYmlsYW5nYW4ga2VkdWE6ICIpKQ0KDQojIGEuIER1YSBiaWxhbmdhbiB5YW5nIHN1ZGFoIGRpdGVudHVrYW4NCmFuZ2thMSA8LSA3DQphbmdrYTIgPC0gMw0KDQoNCmBgYA0KDQojIyBiLiBNZW5naGl0dW5nIGRhbiBtZW5hbXBpbGthbiBoYXNpbCANCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLH0NCmFuZ2thMSA8LSA3DQphbmdrYTIgPC0gMw0KDQoNCnBlbmp1bWxhaGFuIDwtIGFuZ2thMSArIGFuZ2thMg0KcGVya2FsaWFuIDwtIGFuZ2thMSAqIGFuZ2thMg0KcGVtYmFnaWFuIDwtIGFuZ2thMSAvIGFuZ2thMg0KcGFuZ2thdCA8LSBhbmdrYTEgXiBhbmdrYTINCg0KY2F0KCJQZW5qdW1sYWhhbjoiLCAgcGVuanVtbGFoYW4pDQpjYXQoIlBlcmthbGlhbjoiLCBwZXJrYWxpYW4pDQpjYXQoIlBlbWJhZ2lhbjoiLCBwZW1iYWdpYW4pDQpjYXQoIlBhbmdrYXQ6IiwgcGFuZ2thdCkNCmBgYA0KDQojIyBjLiBNZW5hbXBpbGthbiBoYXNpbCBkYW4gdGlwZSBkYXRhIG1hc2luZy1tYXNpbmcNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLH0NCg0KY2F0KCJUaXBlIGRhdGE6IiwgY2xhc3MocGVuanVtbGFoYW4pLCAiXG4iKQ0KY2F0KCJUaXBlIGRhdGE6IiwgY2xhc3MocGVya2FsaWFuKSwgIlxuIikNCmNhdCgiVGlwZSBkYXRhOiIsIGNsYXNzKHBlbWJhZ2lhbiksICJcbiIpDQpjYXQoIlRpcGUgZGF0YToiLCBjbGFzcyhwYW5na2F0KSwgIlxuIikNCg0KYGBgDQojICAqKjIuIFN0cnVrdHVyIEtlbmRhbGkgKENvbnRyb2wgRmxvdykqKg0KDQojIyBhLiBNZW5lcmltYSBpbnB1dCBuaWxhaSB1amlhbiBkYXJpIHBlbmdndW5hICgwLTEwMCkNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLH0NCiMgYS4gTWVuZW50dWthbiBuaWxhaSB1amlhbiANCm5pbGFpIDwtIDkyDQoNCiMgTWVuYW1waWxrYW4gbmlsYWkgeWFuZyBkaXRlbnR1a2FuDQpjYXQoIk5pbGFpIHVqaWFuOiIsIG5pbGFpLCAiXG4iKQ0KDQpgYGANCg0KIyMgYi4gTWVuYW1waWxrYW4ga2V0ZXJhbmdhbiBiZXJkYXNhcmthbiBrZXRlbnR1YW4gYmVyaWt1dDoNCg0KLQlOaWxhaSDiiaUgODU6IOKAnFNhbmdhdCBCYWlr4oCdIA0KDQotCU5pbGFpIDcw4oCTODQ6IOKAnEJhaWvigJ0gDQoNCi0JTmlsYWkgNjDigJM2OTog4oCcQ3VrdXDigJ0gDQoNCi0JTmlsYWkgPCA2MDog4oCcUGVybHUgUGVyYmFpa2Fu4oCdIA0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsfQ0KaWYgKG5pbGFpID49IDg1KSB7DQogIGNhdCgiU2FuZ2F0IEJhaWsgKEEpXG4iKQ0KfSBlbHNlIGlmIChuaWxhaSA+PSA3MCkgew0KICBjYXQoIkJhaWsgKEIpXG4iKQ0KfSBlbHNlIGlmIChuaWxhaSA+PSA2MCkgew0KICBjYXQoIkN1a3VwIChDKVxuIikNCn0gZWxzZSB7DQogIGNhdCgiTmlsYWkgUGVybHUgUGVyYmFpa2FuXG4iKQ0KfQ0KYGBgDQoNCiMgKiozLiBGdW5nc2kgZGFuIFBlcnVsYW5nYW4qKg0KDQojIyBhLiBNZW5lcmltYSBpbnB1dCBpbnRlZ2VyIA0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsfQ0KIyBhLiBNZW5lbnR1a2FuIG5pbGFpIGludGVnZXIgbiANCm4gPC0gNDANCg0KIyBNZW5hbXBpbGthbiBuaWxhaSBuDQpjYXQoIk5pbGFpIG4geWFuZyBkaXRlbnR1a2FuIGFkYWxhaDoiLCBuLCAiXG4iKQ0KDQpgYGANCg0KIyMgYi4JTWVuZ2d1bmFrYW4gbG9vcCB1bnR1ayBtZW5jZXRhayBzZW11YSBiaWxhbmdhbiBnZW5hcCBrZWxpcGF0YW4gNCBkYXJpIDEgaGluZ2dhIG4NCg0KYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSx9DQojIE1lbmFtcGlsa2FuIGluZm8NCmNhdCgiQmlsYW5nYW4gZ2VuYXAga2VsaXBhdGFuIDQgZGFyaSAxIGhpbmdnYSIsIG4sICI6XG4iKQ0KDQojIExvb3AgdW50dWsgbWVuY2FyaSBkYW4gbWVuY2V0YWsgYmlsYW5nYW4gZ2VuYXAga2VsaXBhdGFuIDQNCmZvciAoaSBpbiAxOm4pIHsNCiAgaWYgKGkgJSUgNCA9PSAwICYmIGkgJSUgMiA9PSAwKSB7DQogICAgY2F0KGksICIgIikNCiAgfQ0KfQ0KYGBgDQoNCiMgKio0LlN0dWRpIEthc3VzKiogDQoNClNlYnVhaCBwZXJ1c2FoYWFuIGUtY29tbWVyY2UgaW5naW4gbWVuZ2FuYWxpc2lzIHBlcmZvcm1hIHBlbmp1YWxhbm55YSBiZXJkYXNhcmthbiBkYXRhIHRyYW5zYWtzaSBzZWxhbWEgMyBidWxhbiB0ZXJha2hpci4gTmFtdW4sIGRhdGEgeWFuZyB0ZXJzZWRpYSBiZXJhc2FsIGRhcmkgYmVyYmFnYWkgc3VtYmVyIGRhbiBtZW1pbGlraSBrdWFsaXRhcyB5YW5nIGJlcmFnYW0uIEFuZGEgZGltaW50YSB1bnR1ayBtZWxha3VrYW4gRGF0YSBXcmFuZ2xpbmcgc2ViZWx1bSBkaWFuYWxpc2lzIGxlYmloIGxhbmp1dC4gDQogDQogDQogDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBzdXBwcmVzcyBtZXNzYWdlIGFuZCB3YXJuaW5nDQpzdXBwcmVzc01lc3NhZ2VzKHsNCiAgc3VwcHJlc3NXYXJuaW5ncyh7DQogICAgDQogICAgIyBMb2FkIGxpYnJhcnkNCiAgICBsaWJyYXJ5KGRwbHlyKQ0KICAgIGxpYnJhcnkoZ2dwbG90MikNCiAgICANCiAgICAjIFNldCBzZWVkIHVudHVrIGtvbnNpc3RlbnNpDQogICAgc2V0LnNlZWQoNDIpDQogICAgDQogICAgIyBTaW11bGFzaSBkYXRhDQogICAgdGFuZ2dhbF9yYW5nZSA8LSBzZXEoYXMuRGF0ZSgiMjAyNS0wMS0wMSIpLCBhcy5EYXRlKCIyMDI1LTAzLTMxIiksIGJ5ID0gImRheSIpDQogICAga2F0ZWdvcmlfbGlzdCA8LSBjKCJFbGVrdHJvbmlrIiwgIkZhc2hpb24iLCAiTWFrYW5hbiIsICJLZWNhbnRpa2FuIiwgIk9sYWhyYWdhIikNCiAgICANCiAgICAjIEdlbmVyYXRlIGRhdGEgYWNhaw0KICAgIHNhbGVzX2RhdGEgPC0gZGF0YS5mcmFtZSgNCiAgICAgIFRhbmdnYWwgPSBzYW1wbGUodGFuZ2dhbF9yYW5nZSwgMzAwLCByZXBsYWNlID0gVFJVRSksDQogICAgICBLYXRlZ29yaSA9IHNhbXBsZShrYXRlZ29yaV9saXN0LCAzMDAsIHJlcGxhY2UgPSBUUlVFKSwNCiAgICAgIEp1bWxhaCA9IHNhbXBsZSgxOjQsIDMwMCwgcmVwbGFjZSA9IFRSVUUpLA0KICAgICAgSGFyZ2EgPSBzYW1wbGUoNTAwMDA6MTAwMDAwMCwgMzAwLCByZXBsYWNlID0gVFJVRSkNCiAgICApDQogICAgDQogICAgIyBIaXR1bmcgdG90YWwgcGVuanVhbGFuDQogICAgc2FsZXNfZGF0YSA8LSBzYWxlc19kYXRhICU+JQ0KICAgICAgbXV0YXRlKFRvdGFsX1Blbmp1YWxhbiA9IEp1bWxhaCAqIEhhcmdhKQ0KICAgIA0KICAgICMgU3RhdGlzdGlrIERhdGEgTnVtZXJpaw0KICAgIGNhdCgiPT09IFN0YXRpc3RpayBEYXRhIE51bWVyaWsgPT09XG4iKQ0KICAgIHByaW50KHN1bW1hcnkoc2VsZWN0KHNhbGVzX2RhdGEsIEp1bWxhaCwgSGFyZ2EsIFRvdGFsX1Blbmp1YWxhbikpKQ0KICAgIA0KICAgICMgU3RhdGlzdGlrIERhdGEgS2F0ZWdvcmlrYWwNCiAgICBjYXQoIlxuPT09IFN0YXRpc3RpayBEYXRhIEthdGVnb3Jpa2FsID09PVxuIikNCiAgICBwcmludChzdW1tYXJ5KHNlbGVjdChzYWxlc19kYXRhLCBUYW5nZ2FsLCBLYXRlZ29yaSkpKQ0KICAgIA0KICAgICMgUGVuanVhbGFuIHBlciBrYXRlZ29yaQ0KICAgIHRvdGFsX3Blcl9rYXRlZ29yaSA8LSBzYWxlc19kYXRhICU+JQ0KICAgICAgZ3JvdXBfYnkoS2F0ZWdvcmkpICU+JQ0KICAgICAgc3VtbWFyaXNlKFRvdGFsX1Blbmp1YWxhbiA9IHN1bShUb3RhbF9QZW5qdWFsYW4pKSAlPiUNCiAgICAgIGFycmFuZ2UoZGVzYyhUb3RhbF9QZW5qdWFsYW4pKQ0KICAgIA0KICAgIGNhdCgiXG49PT0gVG90YWwgUGVuanVhbGFuIHBlciBLYXRlZ29yaSA9PT1cbiIpDQogICAgcHJpbnQodG90YWxfcGVyX2thdGVnb3JpKQ0KICAgIA0KICAgICMgVmlzdWFsaXNhc2kNCiAgICBnZ3Bsb3QodG90YWxfcGVyX2thdGVnb3JpLCBhZXMoeCA9IHJlb3JkZXIoS2F0ZWdvcmksIC1Ub3RhbF9QZW5qdWFsYW4pLCB5ID0gVG90YWxfUGVuanVhbGFuKSkgKw0KICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAicGluayIsIGNvbG9yID0gImJsYWNrIikgKw0KICAgICAgbGFicyh0aXRsZSA9ICJUb3RhbCBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIiwNCiAgICAgICAgICAgeCA9ICJLYXRlZ29yaSIsIHkgPSAiVG90YWwgUGVuanVhbGFuIChScCkiKSArDQogICAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gc2VxKDAsIG1heCh0b3RhbF9wZXJfa2F0ZWdvcmkkVG90YWxfUGVuanVhbGFuKSwgYnkgPSAxZTcpLA0KICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmF5IiwgYWxwaGEgPSAwLjYpDQoNCiAgfSkNCn0pDQoNCmBgYA0KIA0KIyAqKjEuIERhdGEgQ29sbGVjdGlvbioqDQoNCkFzdW1zaWthbiBkYXRhIGJlcmFzYWwgZGFyaSAzIGZpbGUgQ1NWIGJlcmJlZGEgKGphbnVhcmkuY3N2LCBmZWJydWFyaS5jc3YsbWFyZXQuY3N2KS4gVHVnYXMgYW5kYToNCg0KIyMgYS4gR2FidW5na2FuIGtldGlnYSBmaWxlIG1lbmphZGkgc2F0dSBkYXRhc2V0Lg0KDQoNCiMjIGIuVGFtcGlsa2FuIGp1bWxhaCB0b3RhbCBiYXJpcyBkYW4ga29sb20gc2V0ZWxhaCBkaWdhYnVuZy4NCg0KDQpgYGB7cn0NCg0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZHBseXIpDQoNCiMgTWVtYmFjYSBmaWxlIENTVg0KZGZfamFuIDwtIHJlYWRfY3N2KCJqYW51YXJpLmNzdiIpDQpkZl9mZWIgPC0gcmVhZF9jc3YoImZlYnJ1YXJpLmNzdiIpDQpkZl9tYXIgPC0gcmVhZF9jc3YoIm1hcmV0LmNzdiIpDQoNCiMgTWVuYW1waWxrYW4gaXNpIG1hc2luZy1tYXNpbmcgZmlsZQ0KY2F0KCIgRGF0YSBKYW51YXJpOlxuIikNCnByaW50KGhlYWQoZGZfamFuKSkNCmNhdCgiXG4iKQ0KDQpjYXQoIiBEYXRhIEZlYnJ1YXJpOlxuIikNCnByaW50KGhlYWQoZGZfZmViKSkNCmNhdCgiXG4iKQ0KDQpjYXQoIiBEYXRhIE1hcmV0OlxuIikNCnByaW50KGhlYWQoZGZfbWFyKSkNCmNhdCgiXG4iKQ0KDQogDQpgYGANCg0KDQpgYGB7cn0NCiMgUGFzdGlrYW4ga2FtdSBzdWRhaCBpbnN0YWxsIGRhbiBsb2FkIHBhY2thZ2UgeWFuZyBkaXBlcmx1a2FuDQojIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikgICMgamlrYSBiZWx1bSB0ZXJpbnN0YWxsDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIEJhY2EgZGF0YQ0KZGZfamFuIDwtIHJlYWQuY3N2KCJqYW51YXJpLmNzdiIpDQpkZl9mZWIgPC0gcmVhZC5jc3YoImZlYnJ1YXJpLmNzdiIpDQpkZl9tYXIgPC0gcmVhZC5jc3YoIm1hcmV0LmNzdiIpDQoNCiMgR2FidW5nIGRhdGENCmRmX2FsbCA8LSBiaW5kX3Jvd3MoZGZfamFuLCBkZl9mZWIsIGRmX21hcikNCg0KIyBUYW1waWxrYW4gZGF0YSBzZWJhZ2FpIHRhYmVsDQpjYXQoIkNvbnRvaCBUYWJlbCBHYWJ1bmdhbiAoMTAgQmFyaXMgQWNhayk6XG4iKQ0KcHJpbnQoZGZfYWxsICU+JSBzYW1wbGVfbigxMCkpDQoNCiMgU2ltcGFuIGtlIGZpbGUgamlrYSBwZXJsdSAobWlzYWxueWEpDQojIHdyaXRlLmNzdihkZl9hbGwsICJkYXRhX2dhYnVuZ2FuLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgTWVuZ2dhYnVuZ2thbiB0aWdhIGRhdGEgZnJhbWUgbWVuamFkaSBzYXR1DQogICAgZGZfYWxsIDwtIGJpbmRfcm93cyhkZl9qYW4sIGRmX2ZlYiwgZGZfbWFyKQ0KICAgIA0KICAgICMgTWVuYW1waWxrYW4ganVtbGFoIGJhcmlzIGRhbiBrb2xvbQ0KICAgIGNhdCgiSnVtbGFoIHRvdGFsIGJhcmlzOiIsIG5yb3coZGZfYWxsKSwgIlxuIikNCiAgICBjYXQoIkp1bWxhaCB0b3RhbCBrb2xvbToiLCBuY29sKGRmX2FsbCksICJcbiIpDQogICAgDQoNCmBgYA0KDQoNCiMgKioyLiBEYXRhIENsZWFuaW5nKiogDQoNCioqTGFrdWthbiBwZW1iZXJzaWhhbiBkYXRhIGJlcmlrdXQ6KioNCg0KYS4JU3RhbmRhcmthbiBmb3JtYXQgdGFuZ2dhbCBrZSBiZW50dWsgWVlZWS1NTS1ERC4gDQoNCmIuCVViYWgga29sb20gSGFyZ2EgZGFuIEp1bWxhaCBtZW5qYWRpIGZvcm1hdCBudW1lcmlrLiANCg0KYy4JSGl0dW5nIHVsYW5nIG5pbGFpIGtvbG9tIFRvdGFsID0gSGFyZ2EgKiBKdW1sYWguDQoNCmQuCUdhbnRpIG5pbGFpIHlhbmcgdGlkYWsgdmFsaWQgKGNvbnRvaDogLSwgImR1YSIsICJScCIsICJfYW5vbnltb3VzXyIpIGRlbmdhbiBuaWxhaSB5YW5nIHNlc3VhaSBhdGF1IE5BLiANCg0KZS4JSGFwdXMgYmFyaXMgeWFuZyB0aWRhayBtZW1pbGlraSBuYW1hIHByb2R1ayAoUHJvZHVrIGtvc29uZyBhdGF1IC0pLiANCg0KYGBge3J9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkobHVicmlkYXRlKQ0KDQojIDEuIE1lbWJhY2EgMyBmaWxlIENTVg0KZGZfamFuIDwtIHJlYWRfY3N2KCJqYW51YXJpLmNzdiIpDQpkZl9mZWIgPC0gcmVhZF9jc3YoImZlYnJ1YXJpLmNzdiIpDQpkZl9tYXIgPC0gcmVhZF9jc3YoIm1hcmV0LmNzdiIpDQoNCiMgMi4gR2FidW5na2FuIGtldGlnYSBkYXRhc2V0DQpkZl9hbGwgPC0gYmluZF9yb3dzKGRmX2phbiwgZGZfZmViLCBkZl9tYXIpDQoNCiMgMy4gU2FsaW4gZGF0YSB1bnR1ayBjbGVhbmluZw0KZGYgPC0gZGZfYWxsDQoNCiMgNC4gRm9ybWF0IFRhbmdnYWwgamFkaSBZWVlZLU1NLUREDQpkZiRUYW5nZ2FsIDwtIGRteShkZiRUYW5nZ2FsKSAgIyBkYXktbW9udGgteWVhcg0KDQojIDUuIEJlcnNpaGthbiBrb2xvbSBIYXJnYQ0KIyAtIEhpbGFuZ2thbiBzaW1ib2wgZGFuIHRla3Mgc2VwZXJ0aSAiUnAiLCB0aXRpaywga29tYQ0KZGYkSGFyZ2EgPC0gZ3N1YigiW14wLTldIiwgIiIsIGFzLmNoYXJhY3RlcihkZiRIYXJnYSkpDQpkZiRIYXJnYSA8LSBhcy5udW1lcmljKGRmJEhhcmdhKQ0KDQojIDYuIEJlcnNpaGthbiBrb2xvbSBKdW1sYWgNCiMgLSBLb252ZXJzaSBrYXRhLWthdGEga2UgYW5na2ENCmthdGFfa2VfYW5na2EgPC0gYygic2F0dSIgPSAxLCAiZHVhIiA9IDIsICJ0aWdhIiA9IDMsICJlbXBhdCIgPSA0LCAibGltYSIgPSA1KQ0KZGYkSnVtbGFoIDwtIHJlY29kZShkZiRKdW1sYWgsICEhIWthdGFfa2VfYW5na2EpDQpkZiRKdW1sYWggPC0gYXMubnVtZXJpYyhkZiRKdW1sYWgpDQoNCiMgNy4gSGl0dW5nIHVsYW5nIGtvbG9tIFRvdGFsDQpkZiRUb3RhbCA8LSBkZiRIYXJnYSAqIGRmJEp1bWxhaA0KDQojIDguIEdhbnRpIG5pbGFpIHRpZGFrIHZhbGlkIG1lbmphZGkgTkENCg0KaW52YWxpZF92YWx1ZXMgPC0gYygiLSIsICJScCIsICJhbm9ueW1vdXMiKQ0KDQpkZiA8LSBkZiAlPiUNCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCB+cmVwbGFjZSgueCwgLnggJWluJSBpbnZhbGlkX3ZhbHVlcywgTkEpKSkNCg0KIyA5LiBIYXB1cyBiYXJpcyB5YW5nIHRpZGFrIG1lbWlsaWtpIG5hbWEgcHJvZHVrDQpkZiA8LSBkZiAlPiUgZmlsdGVyKCFpcy5uYShQcm9kdWspKQ0KDQojIDEwLiBUYW1waWxrYW4gZGF0YSBoYXNpbCBjbGVhbmluZw0KY2F0KCJKdW1sYWggYmFyaXMgc2V0ZWxhaCBkaWJlcnNpaGthbjoiLCBucm93KGRmKSwgIlxuIikNCmhlYWQoZGYpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCiMgKiozLiBEYXRhIFRyYW5zZm9ybWF0aW9uKioNCg0KTGFrdWthbiB0cmFuc2Zvcm1hc2kgZGF0YSBzZWJhZ2FpIGJlcmlrdXQ6IA0KDQphLglCdWF0IGtvbG9tIGJhcnUgQnVsYW4gYmVyZGFzYXJrYW4gdGFuZ2dhbCB0cmFuc2Frc2kuDQoNCmIuCUhpdHVuZyB0b3RhbCBwZW5qdWFsYW4gKFRvdGFsKSBwZXIga2F0ZWdvcmkgcHJvZHVrLiANCg0KYy4JSGl0dW5nIGp1bWxhaCB0cmFuc2Frc2kgZGFyaSBzZXRpYXAga290YS4gDQoNCmQuCUJ1YXQgcmluZ2thc2FuIGp1bWxhaCB0b3RhbCBwZW5qdWFsYW4gcGVyIGJ1bGFuLiANCg0KYGBge3J9DQogICAgDQogICAgbGlicmFyeShkcGx5cikNCiAgICBsaWJyYXJ5KGx1YnJpZGF0ZSkNCg0KICAgICMgVGFtYmFoa2FuIGtvbG9tIEJ1bGFuDQogICAgYnVsYW5fZGljdCA8LSBjKCJKYW51YXJpIiwgIkZlYnJ1YXJpIiwgIk1hcmV0IikNCiAgICBkZiA8LSBkZiAlPiUNCiAgICAgIG11dGF0ZShCdWxhbiA9IGJ1bGFuX2RpY3RbbW9udGgoVGFuZ2dhbCldKQ0KDQogICAgIyBUb3RhbCBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIFByb2R1aw0KICAgIHBlbmp1YWxhbl9rYXRlZ29yaSA8LSBkZiAlPiUNCiAgICAgIGdyb3VwX2J5KEthdGVnb3JpKSAlPiUNCiAgICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bShUb3RhbCwgbmEucm0gPSBUUlVFKSkgJT4lDQogICAgICBhcnJhbmdlKGRlc2MoVG90YWwpKQ0KDQogICAgIyBUb3RhbCBQZW5qdWFsYW4gcGVyIEtvdGENCiAgICBwZW5qdWFsYW5fa290YSA8LSBkZiAlPiUNCiAgICAgIGdyb3VwX2J5KEtvdGEpICU+JQ0KICAgICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKFRvdGFsLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgICAgIGFycmFuZ2UoZGVzYyhUb3RhbCkpDQoNCiAgICAjIFRvdGFsIFBlbmp1YWxhbiBwZXIgQnVsYW4NCiAgICBwZW5qdWFsYW5fYnVsYW4gPC0gZGYgJT4lDQogICAgICBncm91cF9ieShCdWxhbikgJT4lDQogICAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0oVG90YWwsIG5hLnJtID0gVFJVRSkpICU+JQ0KICAgICAgYXJyYW5nZShkZXNjKFRvdGFsKSkNCg0KICAgICMgVWJhaCBrZSBkYXRhZnJhbWUgYmlhc2EgJiByZXNldCByb3duYW1lcyBqYWRpIDAsMSwyIChzZXBlcnRpIHBhbmRhcykNCiAgICByb3duYW1lcyhwZW5qdWFsYW5fa2F0ZWdvcmkpIDwtIDA6KG5yb3cocGVuanVhbGFuX2thdGVnb3JpKSAtIDEpDQogICAgcm93bmFtZXMocGVuanVhbGFuX2tvdGEpIDwtIDA6KG5yb3cocGVuanVhbGFuX2tvdGEpIC0gMSkNCiAgICByb3duYW1lcyhwZW5qdWFsYW5fYnVsYW4pIDwtIDA6KG5yb3cocGVuanVhbGFuX2J1bGFuKSAtIDEpDQoNCiAgICAjIFRhbXBpbGthbiBvdXRwdXQNCiAgICBjYXQoIlRvdGFsIFBlbmp1YWxhbiBwZXIgS2F0ZWdvcmkgUHJvZHVrOlxuIikNCiAgICBwcmludChhcy5kYXRhLmZyYW1lKHBlbmp1YWxhbl9rYXRlZ29yaSkpDQoNCiAgICBjYXQoIlxuVG90YWwgUGVuanVhbGFuIHBlciBLb3RhOlxuIikNCiAgICBwcmludChhcy5kYXRhLmZyYW1lKHBlbmp1YWxhbl9rb3RhKSkNCg0KICAgIGNhdCgiXG5Ub3RhbCBQZW5qdWFsYW4gcGVyIEJ1bGFuOlxuIikNCiAgICBwcmludChhcy5kYXRhLmZyYW1lKHBlbmp1YWxhbl9idWxhbikpDQoNCg0KDQpgYGANCg0KDQoNCiMjICoqVmlzdWFsaXNhc2kqKg0KDQpgYGB7cn0NCiAgICBsaWJyYXJ5KGdncGxvdDIpDQogICAgbGlicmFyeShkcGx5cikNCg0KICAgICMgUGFzdGlrYW4gdXJ1dGFuIGJ1bGFuIGJlbmFyDQogICAgcGVuanVhbGFuX2J1bGFuJEJ1bGFuIDwtIGZhY3RvcihwZW5qdWFsYW5fYnVsYW4kQnVsYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJKYW51YXJpIiwgIkZlYnJ1YXJpIiwgIk1hcmV0IikpDQoNCiAgICAjIEdyYWZpayAxOiBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIChwYWxldCBzb2Z0IGJpcnUgLSBwYXN0ZWwpDQogICAgZ2dwbG90KHBlbmp1YWxhbl9rYXRlZ29yaSwgYWVzKHggPSBUb3RhbCwgeSA9IHJlb3JkZXIoS2F0ZWdvcmksIFRvdGFsKSkpICsNCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNBM0M0REMiKSArDQogICAgICBsYWJzKHRpdGxlID0gIkdyYWZpayBQZW5qdWFsYW4gcGVyIEthdGVnb3JpIiwNCiAgICAgICAgICAgeCA9ICJKdW1sYWggUGVuanVhbGFuIiwgeSA9ICJLYXRlZ29yaSIpICsNCiAgICAgIHRoZW1lX21pbmltYWwoKQ0KDQogICAgIyBHcmFmaWsgMjogUGVuanVhbGFuIHBlciBLb3RhIChwYWxldCBoaWphdS1iaXJ1IGthbGVtKQ0KICAgIGdncGxvdChwZW5qdWFsYW5fa290YSwgYWVzKHggPSBUb3RhbCwgeSA9IHJlb3JkZXIoS290YSwgVG90YWwpKSkgKw0KICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiI0ExRDk5QiIpICsNCiAgICAgIGxhYnModGl0bGUgPSAiR3JhZmlrIFBlbmp1YWxhbiBwZXIgS290YSIsDQogICAgICAgICAgIHggPSAiSnVtbGFoIFBlbmp1YWxhbiIsIHkgPSAiS290YSIpICsNCiAgICAgIHRoZW1lX21pbmltYWwoKQ0KDQogICAgIyBHcmFmaWsgMzogUGVuanVhbGFuIHBlciBCdWxhbiAodW5ndSBwYXN0ZWwpDQogICAgZ2dwbG90KHBlbmp1YWxhbl9idWxhbiwgYWVzKHggPSBCdWxhbiwgeSA9IFRvdGFsLCBncm91cCA9IDEpKSArDQogICAgICBnZW9tX2xpbmUoY29sb3IgPSAiI0JBQTVEMyIsIHNpemUgPSAxLjIpICsNCiAgICAgIGdlb21fcG9pbnQoY29sb3IgPSAiI0JBQTVEMyIsIHNpemUgPSAzKSArDQogICAgICBsYWJzKHRpdGxlID0gIlRyZW4gUGVuanVhbGFuIEJ1bGFuYW4iLA0KICAgICAgICAgICB4ID0gIkJ1bGFuIiwgeSA9ICJUb3RhbCBQZW5qdWFsYW4iKSArDQogICAgICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCg==