UTS Pemrograman Sains Data I

1 SECTION A – DATA COLLECTION USING PROGRAMMING

# Mendefinisikan nama file agar konsisten dan menghindari error "cannot open connection"
file_csv  <- "CSVecommerce.csv"
file_json <- "JSONecommerce.json"
file_txt  <- "TXTecommerce.txt"
file_xml  <- "XMLecommerce.xml"
file_xlsx <- "XLSXecommerce.xlsx - ecommerce_raw.csv"

# Fungsi pembacaan data dengan pengecekan keberadaan file
read_safe <- function(file_path, type = "csv") {
  if (!file.exists(file_path)) {
    stop(paste("File tidak ditemukan:", file_path, "- Pastikan file ada di folder yang sama dengan .Rmd ini."))
  }
  
  if (type == "csv") return(read.csv(file_path))
  if (type == "json") return(fromJSON(file_path))
  if (type == "txt") return(read.delim(file_path, sep = "|"))
  if (type == "xml") {
    doc <- read_xml(file_path)
    records <- xml_find_all(doc, ".//Record")
    # Mengambil semua kolom secara dinamis dari XML
    df <- map_df(records, function(x) {
      nodes <- xml_children(x)
      res <- as.list(xml_text(nodes))
      names(res) <- xml_name(nodes)
      return(as.data.frame(res, stringsAsFactors = FALSE))
    })
    return(df)
  }
}
# Proses eksekusi pembacaan
df_csv  <- read_safe(file_csv, "csv")
df_json <- read_safe(file_json, "json")
df_txt  <- read_safe(file_txt, "txt")
df_xml  <- read_safe(file_xml, "xml")
df_xlsx <- read_safe(file_xlsx, "csv")

# Fungsi untuk mengekstrak metadata
get_meta <- function(df, filename) {
  data.frame(
    "Nama_File" = filename,
    "Jumlah_Baris" = nrow(df),
    "Jumlah_Kolom" = ncol(df),
    "Nama_Kolom" = paste(colnames(df), collapse = ", ")
  )
}

# Menggabungkan semua metadata ke dalam satu tabel
summary_table <- rbind(
  get_meta(df_csv, "ecommerce.csv"),
  get_meta(df_json, "ecommerce.json"),
  get_meta(df_txt, "ecommerce.txt"),
  get_meta(df_xml, "ecommerce.xml"),
  get_meta(df_xlsx, "ecommerce.xlsx")
)

# Menampilkan tabel dengan kableExtra
kable(summary_table, format = "html", caption = "Tabel 1: Ringkasan Struktur Data Ecommerce") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), 
                full_width = F, 
                position = "left") %>%
  column_spec(4, width = "40em", italic = T, color = "#555") %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50")
Tabel 1: Ringkasan Struktur Data Ecommerce
Nama_File Jumlah_Baris Jumlah_Kolom Nama_Kolom
ecommerce.csv 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.json 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.txt 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.xml 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.xlsx 2000 1 order_id.order_date.ship_date.platform.category.product_name.unit_price.quantity.gross_sales.campaign.voucher_code.discount_pct.discount_value.shipping_cost.net_sales.payment_method.customer_segment.region.stock_status.order_status.customer_rating.priority_flag

# 1. List semua file di direktori aktif yang memiliki ekstensi tertentu
# Pattern ini mencari file yang berakhiran .csv, .json, .txt, atau .xml
daftar_file <- list.files(pattern = "\\.(csv|json|txt|xml)$")

# 2. Fungsi kustom untuk menentukan cara baca berdasarkan ekstensi
baca_file_otomatis <- function(nama_file) {
  ekstensi <- tools::file_ext(nama_file)
  
  tryCatch({
    data <- switch(ekstensi,
      "csv"  = read.csv(nama_file),
      "json" = fromJSON(nama_file),
      "txt"  = read.delim(nama_file, sep = "|"),
      "xml"  = {
          doc <- read_xml(nama_file)
          records <- xml_find_all(doc, ".//Record")
          map_df(records, function(x) {
            nodes <- xml_children(x)
            res <- as.list(xml_text(nodes))
            names(res) <- xml_name(nodes)
            as.data.frame(res, stringsAsFactors = FALSE)
          })
      },
      NULL
    )
    return(data)
  }, error = function(e) return(NULL))
}

# 3. Looping menggunakan lapply untuk membaca semua file sekaligus ke dalam sebuah LIST
list_data <- lapply(daftar_file, baca_file_otomatis)
names(list_data) <- daftar_file # Memberi nama list sesuai nama filenya
# Membuat tabel summary menggunakan looping map_df
tabel_metadata <- map2_df(list_data, names(list_data), function(df, nama) {
  if (!is.null(df)) {
    data.frame(
      Nama_File = nama,
      Baris = nrow(df),
      Kolom = ncol(df),
      Daftar_Kolom = paste(colnames(df)[1:5], collapse = ", ") # Tampilkan 5 kolom pertama
    )
  }
})

kable(tabel_metadata, "html") %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
Nama_File Baris Kolom Daftar_Kolom
CSVecommerce.csv 2000 22 order_id, order_date, ship_date, platform, category
JSONecommerce.json 2000 22 order_id, order_date, ship_date, platform, category
TXTecommerce.txt 2000 22 order_id, order_date, ship_date, platform, category
XLSXecommerce.xlsx - ecommerce_raw.csv 2000 1 order_id.order_date.ship_date.platform.category.product_name.unit_price.quantity.gross_sales.campaign.voucher_code.discount_pct.discount_value.shipping_cost.net_sales.payment_method.customer_segment.region.stock_status.order_status.customer_rating.priority_flag, NA, NA, NA, NA
XMLecommerce.xml 2000 22 order_id, order_date, ship_date, platform, category
# Contoh: Mengambil data dari file CSV yang ada di dalam list
head(list_data[["CSVecommerce.csv"]], 3)

# 1. Identifikasi file di direktori
files_to_read <- list.files(pattern = "\\.(csv|json|txt|xml)$")

# 2. Fungsi pembacaan dinamis
read_data_auto <- function(file) {
  ext <- tools::file_ext(file)
  tryCatch({
    switch(ext,
      "csv"  = read.csv(file),
      "json" = fromJSON(file),
      "txt"  = read.delim(file, sep = "|"),
      "xml"  = {
          doc <- read_xml(file)
          records <- xml_find_all(doc, ".//Record")
          map_df(records, function(x) {
            nodes <- xml_children(x)
            res <- as.list(xml_text(nodes))
            names(res) <- xml_name(nodes)
            as.data.frame(res, stringsAsFactors = FALSE)
          })
      }
    )
  }, error = function(e) return(NULL))
}

# 3. Eksekusi looping
list_dataset <- lapply(files_to_read, read_data_auto)
names(list_dataset) <- files_to_read
# Mengambil nama kolom dari file pertama sebagai standar referensi
baseline_cols <- colnames(list_dataset[[1]])

# Membuat tabel validasi menggunakan looping dan if-else
validation_results <- map2_df(list_dataset, names(list_dataset), function(df, name) {
  current_cols <- colnames(df)
  
  # LOGIKA IF-ELSE: Mengecek kesamaan struktur kolom
  if (identical(sort(baseline_cols), sort(current_cols))) {
    status <- "Ready to merge"
    color  <- "green"
  } else {
    status <- "Need adjustment"
    color  <- "red"
  }
  
  data.frame(
    Nama_File = name,
    Jumlah_Kolom = ncol(df),
    Status = status,
    Catatan = ifelse(status == "Ready to merge", "Struktur Identik", "Ada perbedaan nama/jumlah kolom")
  )
})
kable(validation_results, "html", escape = F, caption = "Validasi Kesiapan Penggabungan Data") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  column_spec(3, bold = T, 
              color = ifelse(validation_results$Status == "Ready to merge", "white", "white"),
              background = ifelse(validation_results$Status == "Ready to merge", "#27ae60", "#e74c3c"))
Validasi Kesiapan Penggabungan Data
Nama_File Jumlah_Kolom Status Catatan
CSVecommerce.csv 22 Ready to merge Struktur Identik
JSONecommerce.json 22 Ready to merge Struktur Identik
TXTecommerce.txt 22 Ready to merge Struktur Identik
XLSXecommerce.xlsx - ecommerce_raw.csv 1 Need adjustment Ada perbedaan nama/jumlah kolom
XMLecommerce.xml 22 Ready to merge Struktur Identik

# 1. List semua file data yang relevan
files_to_process <- list.files(pattern = "\\.(csv|json|txt|xml)$")

# 2. Fungsi pembacaan data dinamis
read_ecommerce_data <- function(file) {
  ext <- tools::file_ext(file)
  tryCatch({
    switch(ext,
      "csv"  = read.csv(file, stringsAsFactors = FALSE),
      "json" = fromJSON(file),
      "txt"  = read.delim(file, sep = "|", stringsAsFactors = FALSE),
      "xml"  = {
          doc <- read_xml(file)
          records <- xml_find_all(doc, ".//Record")
          map_df(records, function(x) {
            nodes <- xml_children(x)
            res <- as.list(xml_text(nodes))
            names(res) <- xml_name(nodes)
            as.data.frame(res, stringsAsFactors = FALSE)
          })
      }
    )
  }, error = function(e) return(NULL))
}

# 3. Looping untuk membaca semua file ke dalam list
all_data_list <- lapply(files_to_process, read_ecommerce_data)
names(all_data_list) <- files_to_process

# 4. Validasi dan Penggabungan menggunakan Logika IF-ELSE
# Kita gunakan file pertama sebagai standar kolom (Master Template)
master_columns <- colnames(all_data_list[[1]])
main_dataset <- data.frame()
log_proses <- data.frame()

for (i in seq_along(all_data_list)) {
  current_data <- all_data_list[[i]]
  current_name <- names(all_data_list)[i]
  
  # Logika IF-ELSE untuk cek kesamaan struktur
  if (identical(sort(master_columns), sort(colnames(current_data)))) {
    # Jika struktur sama, gabungkan ke dataset utama
    # Pastikan urutan kolom sama sebelum rbind
    current_data <- current_data[, master_columns]
    main_dataset <- rbind(main_dataset, current_data)
    
    status <- "Ready to merge"
    tindakan <- "Berhasil Digabungkan"
  } else {
    # Jika struktur berbeda, jangan digabungkan
    status <- "Need adjustment"
    tindakan <- "Dilewati (Struktur Berbeda)"
  }
  
  # Simpan log status
  log_proses <- rbind(log_proses, data.frame(
    File = current_name,
    Status = status,
    Tindakan = tindakan
  ))
}
kable(log_proses, caption = "Log Validasi Struktur Kolom") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  column_spec(2, bold = T, 
              color = "white",
              background = ifelse(log_proses$Status == "Ready to merge", "#27ae60", "#e74c3c"))
Log Validasi Struktur Kolom
File Status Tindakan
CSVecommerce.csv Ready to merge Berhasil Digabungkan
JSONecommerce.json Ready to merge Berhasil Digabungkan
TXTecommerce.txt Ready to merge Berhasil Digabungkan
XLSXecommerce.xlsx - ecommerce_raw.csv Need adjustment Dilewati (Struktur Berbeda)
XMLecommerce.xml Ready to merge Berhasil Digabungkan
# Menampilkan 5 baris pertama dari dataset yang sudah digabung
dim(main_dataset)
## [1] 8000   22
kable(head(main_dataset, 5), caption = "Preview 5 Baris Pertama Dataset Utama") %>%
  kable_styling(bootstrap_options = c("striped", "condensed"), font_size = 11)
Preview 5 Baris Pertama Dataset Utama
order_id order_date ship_date platform category product_name unit_price quantity gross_sales campaign voucher_code discount_pct discount_value shipping_cost net_sales payment_method customer_segment region stock_status order_status customer_rating priority_flag
ORD00612 2024-04-19 2024-04-24 Tokopedia Home Living Table Lamp 188905 4 755620 Flash Sale DISC10 10 75562 12000 680058 E-Wallet VIP Bekasi Preorder Completed 5.0 Y
ORD00112 2024-01-24 2024-01-29 Tiktok Shop Electronics Power Bank 1476873 1 1476873 Normal Day NONE 0 0 18000 1476873 Cod Returning Makassar In Stock Completed 5.0 N
ORD01186 2024-12-06 2024-06-19 Tokopedia Fashion Women Dress 231072 2 462144 Mega Campaign DISC20 20 92429 15000 369715 Virtual Account Returning Surabaya In Stock Delivered 3.0 Yes
ORD01511 2024-07-08 2024-08-14 Tokopedia Home Living Vacuum Cleaner 512063 3 1536189 Flash Sale DISC10 10 153619 0 1382570 Transfer Bank New Yogyakarta In Stock Delivered 4 No
ORD00772 2024-08-12 Tokopedia Beauty Body Lotion 221586 2 443172 0 DISC15 15 Rp 66.476 0 376696 0 Returning Surabaya In Stock DELIVERED 5.0 normal

2 SECTION B – DATA HANDLING

# Menghitung dimensi
dimensi_df <- data.frame(
  Deskripsi = c("Total Baris", "Total Kolom"),
  Nilai = c(nrow(main_dataset), ncol(main_dataset))
)

# Menampilkan tabel dimensi
kable(dimensi_df, caption = "Dimensi Dataset Utama") %>%
  kable_styling(bootstrap_options = "bordered", full_width = F)
Dimensi Dataset Utama
Deskripsi Nilai
Total Baris 8000
Total Kolom 22
# Mengambil tipe data
tipe_data_df <- data.frame(
  Kolom = names(sapply(main_dataset, class)),
  Tipe_Data = as.character(sapply(main_dataset, class))
)

# Menampilkan tabel tipe data
kable(tipe_data_df, caption = "Tipe Data Setiap Kolom") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F)
Tipe Data Setiap Kolom
Kolom Tipe_Data
order_id character
order_date character
ship_date character
platform character
category character
product_name character
unit_price character
quantity character
gross_sales character
campaign character
voucher_code character
discount_pct character
discount_value character
shipping_cost character
net_sales character
payment_method character
customer_segment character
region character
stock_status character
order_status character
customer_rating character
priority_flag character
# --- 1. Identifikasi Missing Values ---
# Menghitung NA per kolom
na_count <- sapply(main_dataset, function(x) sum(is.na(x) | x == "" | x == "null"))
na_summary <- data.frame(
  Kolom = names(na_count),
  Jumlah_Missing = na_count
) %>% filter(Jumlah_Missing > 0)

# Menampilkan tabel Missing Values
kable(na_summary, caption = "Identifikasi Kolom dengan Missing Values") %>%
  kable_styling(bootstrap_options = c("striped", "danger"), full_width = F)
Identifikasi Kolom dengan Missing Values
Kolom Jumlah_Missing
ship_date ship_date 600
campaign campaign 1
voucher_code voucher_code 148
discount_pct discount_pct 207
payment_method payment_method 105
stock_status stock_status 1
order_status order_status 18
customer_rating customer_rating 1434
priority_flag priority_flag 1265
# --- 2. Identifikasi Duplikat ---
# Menghitung jumlah baris yang merupakan duplikat
total_duplikat <- sum(duplicated(main_dataset))

# Menampilkan hasil duplikat dalam bentuk teks atau box
if(total_duplikat > 0) {
  print(paste("Ditemukan", total_duplikat, "baris duplikat dalam dataset."))
  # Menampilkan baris yang duplikat untuk diperiksa
  duplikat_data <- main_dataset[duplicated(main_dataset), ]
} else {
  print("Tidak ada baris duplikat yang terdeteksi.")
}
## [1] "Ditemukan 143 baris duplikat dalam dataset."
  1. Inconsistency (Inkonsistensi Data) Terdapat perbedaan format dan penulisan teks untuk informasi yang seharusnya sama. Hal ini akan menyulitkan proses pengelompokan (grouping) data.

Format Tanggal: Ada kolom tanggal yang menggunakan format YYYY-MM-DD, DD/MM/YYYY, dan MM-DD-YYYY. Contoh: 2024-04-19, 22/05/2024, dan 10-28-2024.

Penulisan Teks (Case Sensitivity): Nama platform atau kategori ditulis dengan cara berbeda-beda, seperti Tokopedia, tokopedia, TikTok Shop, dan Tiktok Shop.

Simbol Mata Uang: Pada beberapa file (terutama .txt), kolom numerik seperti gross_sales mengandung teks tambahan seperti “Rp 488.918”, sedangkan di file lain hanya berupa angka.

  1. Missing Values (Data Hilang) Ditemukan banyak data yang kosong atau tidak terisi di beberapa kolom penting.

Kolom customer_rating: Banyak baris yang memiliki nilai null atau kosong.

Kolom voucher_code: Banyak transaksi yang tidak memiliki kode voucher namun tidak diberikan nilai standar (seperti “None”).

Kolom priority_flag: Ditemukan nilai kosong (empty string) di beberapa record dari file XML dan JSON.

  1. Duplicate Data (Duplikasi) Terdapat baris data yang identik atau memiliki Order ID yang sama yang muncul berulang kali di berbagai format file.

Karena file berasal dari format yang berbeda (CSV, JSON, XML) namun berisi data transaksi yang sama, saat digabungkan muncul baris duplikat. Contohnya, transaksi dengan ID ORD00612 muncul di hampir semua file dengan informasi yang sama persis.

  1. Data Out of Range / Invalid (Nilai Tidak Logis) Ditemukan nilai numerik yang tidak masuk akal jika ditinjau dari logika bisnis.

Net Sales Negatif: Pada record ORD01706, ditemukan nilai net_sales sebesar -398648.0. Secara logika, nilai penjualan bersih tidak mungkin negatif kecuali jika sistem retur tidak dikelola dengan benar dalam data tersebut.


3 SECTION C – DATA CLEANING

# Fungsi standardisasi menggunakan logika IF
standardize_platform <- function(p) {
  # Menghilangkan spasi di awal/akhir dan mengubah ke lowercase untuk mempermudah pengecekan
  p_clean <- trimws(tolower(p))
  
  if (p_clean == "shopee" | p_clean == " shopee ") {
    return("Shopee")
  } else if (p_clean == "tokped" | p_clean == "tokopedia") {
    return("Tokopedia")
  } else if (p_clean == "tiktok shop" | p_clean == "tiktokshop") {
    return("TikTok Shop")
  } else if (p_clean == "lazada") {
    return("Lazada")
  } else if (p_clean == "blibli") {
    return("Blibli")
  } else {
    # Mengembalikan teks asli dengan huruf kapital di awal jika tidak ada kecocokan khusus
    return(tools::toTitleCase(p_clean))
  }
}

# Menerapkan fungsi ke kolom platform di dataset utama
main_dataset$platform_cleaned <- sapply(main_dataset$platform, standardize_platform)
# Mengambil sampel data sebelum dan sesudah untuk pembuktian
platform_comparison <- main_dataset %>%
  select(platform, platform_cleaned) %>%
  distinct() %>%
  head(10)

kable(platform_comparison, 
      col.names = c("Platform Asli", "Platform Terstandardisasi"),
      caption = "Hasil Standardisasi Nama Platform menggunakan Logika IF") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = F, 
                position = "center") %>%
  column_spec(2, bold = T, color = "#2c3e50")
Hasil Standardisasi Nama Platform menggunakan Logika IF
Platform Asli Platform Terstandardisasi
Tokopedia Tokopedia
Tiktok Shop TikTok Shop
Beauty Beauty
Fashion Fashion
Blibli Blibli
Lazada Lazada
Shopee Shopee
Sports Sports
Home_Living Home_living
Home Living Home Living
# Fungsi untuk membersihkan nilai harga/sales
clean_currency <- function(x) {
  # 1. Cek jika input adalah karakter dan mengandung "Rp"
  if (is.character(x)) {
    # Hapus "Rp", spasi, dan titik ribuan
    x <- gsub("Rp", "", x)
    x <- gsub("\\.", "", x)
    x <- gsub(",", "", x) # Jaga-jaga jika ada koma
    x <- as.numeric(trimws(x))
  }
  
  # 2. Logika IF untuk menangani nilai negatif
  if (!is.na(x) && x < 0) {
    return(0)
  } else {
    return(x)
  }
}

# Menerapkan fungsi ke kolom gross_sales dan net_sales
main_dataset$gross_sales_cleaned <- sapply(main_dataset$gross_sales, clean_currency)
main_dataset$net_sales_cleaned <- sapply(main_dataset$net_sales, clean_currency)
# Menampilkan baris yang sebelumnya memiliki masalah (Negatif atau format Rp)
sales_check <- main_dataset %>%
  select(order_id, gross_sales, gross_sales_cleaned, net_sales, net_sales_cleaned) %>%
  filter(grepl("Rp", gross_sales) | net_sales < 0)

kable(sales_check, 
      col.names = c("Order ID", "Gross (Lama)", "Gross (Baru)", "Net (Lama)", "Net (Baru)"),
      caption = "Hasil Pembersihan Nilai Sales (Standardisasi Rp dan Handling Nilai Negatif)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(c(3, 5), bold = T, color = "darkgreen")
Hasil Pembersihan Nilai Sales (Standardisasi Rp dan Handling Nilai Negatif)
Order ID Gross (Lama) Gross (Baru) Net (Lama) Net (Baru)
ORD01865 3276555 3276555 -2785072 0
ORD00211 379963 379963 -322969 0
ORD01024 663280 663280 -663280 0
ORD01122 467220 467220 -467220 0
ORD00951 500302 500302 -450272 0
ORD01867 5033730 5033730 -4026984 0
ORD00439 1074026 1074026 -912922 0
ORD00614 394025 394025 -354623 0
ORD00939 690794 690794 -587175 0
ORD00421 1886994 1886994 -1603945 0
ORD01970 486098 486098 -486098 0
ORD00893 554616 554616 -471424 0
ORD01406 1698780 1698780 -1528902 0
ORD01879 629820 629820 -503856 0
ORD00195 3078486 3078486 -2616713 0
ORD00786 1414785 1414785 -1273307 0
ORD00437 1167657 1167657 -1167657 0
ORD00446 2875880 2875880 -2300704 0
ORD01241 831044 831044 -747940 0
ORD01847 1770678 1770678 -1505076 0
ORD00620 412756 412756 -412756 0
ORD00312 1049475 1049475 -1049475 0
ORD01728 1309806 1309806 -1178825 0
ORD00778 82961 82961 -74665 0
ORD01904 2152996 2152996 -2152996 0
ORD01037 891796 891796 -713437 0
ORD00937 307188 307188 -276469 0
ORD00087 886976 886976 -798278 0
ORD01862 613274 613274 -490619 0
ORD01008 2594745 2594745 -2205533 0
ORD01005 1001429 1001429 -1001429 0
ORD00210 695504 695504 -486853 0
ORD01111 391657 391657 -391657 0
ORD01547 6705798 6705798 -6705798 0
ORD00422 1905188 1905188 -1524150 0
ORD00918 2687538 2687538 -2687538 0
ORD01965 973720 973720 -876348 0
ORD00868 94828 94828 -85345 0
ORD00894 645006 645006 -516005 0
ORD00026 562365 562365 -562365 0
ORD00194 2625036 2625036 -1837525 0
ORD01689 1150162 1150162 -977638 0
ORD00899 1567790 1567790 -1411011 0
ORD00623 308976 308976 -278078 0
ORD01541 1497341 1497341 -1497341 0
ORD00984 1998216 1998216 -1998216 0
ORD00268 412581 412581 -412581 0
ORD00083 2382884 2382884 -2144596 0
ORD01607 232135 232135 -232135 0
ORD01733 190315 190315 -152252 0
ORD00540 1181468 1181468 -1181468 0
ORD00358 315109 315109 -267843 0
ORD00895 709649 709649 -709649 0
ORD01150 1068307 1068307 -1068307 0
ORD00039 1538100 1538100 -1076670 0
ORD01972 714210 714210 -642789 0
ORD00954 1231564 1231564 -1231564 0
ORD00895 709649 709649 -709649 0
ORD01569 1933086 1933086 -1353160 0
ORD01175 7475946 7475946 -7475946 0
ORD01914 458843 458843 -458843 0
ORD00617 915984 915984 -915984 0
ORD01953 449366 449366 -314556 0
ORD01776 539615 539615 -458673 0
ORD01915 1095916 1095916 -931529 0
ORD01712 1291032 1291032 -1032826 0
ORD01985 335018 335018 -335018 0
ORD00154 1212856 1212856 -970285 0
ORD00560 1519122 1519122 -1519122 0
ORD01572 898220 898220 -763487 0
ORD01151 2224536 2224536 -2224536 0
ORD00370 60648 60648 -60648 0
ORD01004 536082 536082 -482474 0
ORD00512 191631 191631 -162886 0
ORD00570 54210 54210 -46078 0
ORD00018 538245 538245 -538245 0
ORD00993 1181160 1181160 -1003986 0
ORD00914 7965000 7965000 -6372000 0
ORD00587 9579416 9579416 -7663533 0
ORD00881 127149 127149 -114434 0
ORD00151 755520 755520 -755520 0
ORD00929 168560 168560 -151704 0
ORD01964 274686 274686 -233483 0
ORD00660 575364 575364 -517828 0
ORD00884 794754 794754 -675541 0
ORD01292 31646 31646 -25317 0
ORD01701 1685176 1685176 -1348141 0
ORD01307 1156062 1156062 -924850 0
ORD00398 228270 228270 -194030 0
ORD00503 2254624 2254624 -1916430 0
ORD01864 73317 73317 -51322 0
ORD01523 520333 520333 -416266 0
ORD01368 191141 191141 -162470 0
ORD01065 1990042 1990042 -1393029 0
ORD00338 2978187 2978187 -2978187 0
ORD01773 591605 591605 -502864 0
ORD01749 3834976 3834976 -3834976 0
ORD01887 148244 148244 -126007 0
ORD01370 300341 300341 -255290 0
ORD00014 549231 549231 -494308 0
ORD00021 2179392 2179392 -1961453 0
ORD01268 475060 475060 -427554 0
ORD01706 569497 569497 -398648 0
ORD00423 996736 996736 -697715 0
ORD01865 3276555 3276555 -2785072 0
ORD00539 Rp 1.336.408 1336408 Rp 1.202.767 1202767
ORD00211 379963 379963 -322969 0
ORD01264 Rp 1.337.862 1337862 1337862 1337862
ORD01616 754341 754341 -603473 0
ORD01203 Rp 1.442.406 1442406 Rp 1.153.925 1153925
ORD01024 663280 663280 -663280 0
ORD01122 467220 467220 -467220 0
ORD01421 Rp 2.092.566 2092566 1464796 1464796
ORD01772 Rp 2.103.294 2103294 0 0
ORD01462 710967 710967 -568774 0
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01125 Rp 5.328.636 5328636 4795772 4795772
ORD00951 500302 500302 -450272 0
ORD01589 Rp 3.361.875 3361875 3025687 3025687
ORD01867 5033730 5033730 -4026984 0
ORD01095 Rp 2.354.340 2354340 2001189 2001189
ORD01709 Rp 1.721.956 1721956 Rp 1.205.369 1205369
ORD00439 1074026 1074026 -912922 0
ORD00611 Rp 4.300.266 4300266 0 0
ORD01035 Rp 2.339.628 2339628 2339628 2339628
ORD00614 394025 394025 -354623 0
ORD01804 1004550 1004550 -904095 0
ORD00939 690794 690794 -587175 0
ORD00421 1886994 1886994 -1603945 0
ORD01451 Rp 1.790.066 1790066 1790066 1790066
ORD01970 486098 486098 -486098 0
ORD00893 554616 554616 -471424 0
ORD01866 1615011 1615011 -1615011 0
ORD01300 Rp 1.262.586 1262586 1073198 1073198
ORD01406 1698780 1698780 -1528902 0
ORD01879 629820 629820 -503856 0
ORD00195 3078486 3078486 -2616713 0
ORD00241 Rp 1.521.600 1521600 1521600 1521600
ORD00786 1414785 1414785 -1273307 0
ORD00437 1167657 1167657 -1167657 0
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01028 Rp 1.300.738 1300738 1040590 1040590
ORD00446 2875880 2875880 -2300704 0
ORD01910 Rp 7.687.416 7687416 7687416 7687416
ORD01576 Rp 1.429.452 1429452 1429452 1429452
ORD01241 831044 831044 -747940 0
ORD01847 1770678 1770678 -1505076 0
ORD00620 412756 412756 -412756 0
ORD00745 Rp 1.478.412 1478412 1330571 1330571
ORD00312 1049475 1049475 -1049475 0
ORD00778 82961 82961 -74665 0
ORD01872 640584 640584 -544496 0
ORD01904 2152996 2152996 -2152996 0
ORD00359 Rp 1.692.327 1692327 1692327 1692327
ORD00119 Rp 1.945.677 1945677 1361974 1361974
ORD01037 891796 891796 -713437 0
ORD00937 307188 307188 -276469 0
ORD00087 886976 886976 -798278 0
ORD01862 613274 613274 -490619 0
ORD01008 2594745 2594745 -2205533 0
ORD00084 Rp 1.663.854 1663854 1663854 1663854
ORD01919 Rp 1.166.486 1166486 933189 933189
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01005 1001429 1001429 -1001429 0
ORD00683 Rp 1.447.302 1447302 1447302 1447302
ORD00210 695504 695504 -486853 0
ORD01111 391657 391657 -391657 0
ORD00292 Rp 1.365.636 1365636 1160791 1160791
ORD00627 Rp 5.951.728 5951728 5951728 5951728
ORD01547 6705798 6705798 -6705798 0
ORD01453 1675902 1675902 -1508312 0
ORD00422 1905188 1905188 -1524150 0
ORD01085 Rp 1.635.954 1635954 1472359 1472359
ORD01799 248212 248212 -248212 0
ORD00918 2687538 2687538 -2687538 0
ORD01814 Rp 1.234.790 1234790 987832 987832
ORD01965 973720 973720 -876348 0
ORD00868 94828 94828 -85345 0
ORD00894 645006 645006 -516005 0
ORD00026 562.365 562365 -562365 0
ORD01689 1150162 1150162 -977638 0
ORD00899 1567790 1567790 -1411011 0
ORD01357 Rp 1.674.312 1674312 1339450 1339450
ORD00315 Rp 5.174.592 5174592 0 0
ORD00623 308976 308976 -278078 0
ORD00812 Rp 1.078.783 1078783 0 0
ORD00365 Rp 4.139.662 4139662 0 0
ORD00337 Rp 4.242.150 4242150 3817935 3817935
ORD00350 Rp 2.926.045 2926045 2633441 2633441
ORD01541 1497341 1497341 -1497341 0
ORD00081 2183448 2183448 -2183448 0
ORD00984 1998216 1998216 -1998216 0
ORD01700 Rp 1.063.038 1063038 850430 850430
ORD00268 412581 412581 -412581 0
ORD00250 609868 609868 -518388 0
ORD01607 232135 232135 -232135 0
ORD01733 190315 190315 -152252 0
ORD00461 Rp 4.621.560 4621560 3697248 3697248
ORD00540 1181468 1181468 -1181468 0
ORD00358 315109 315109 -267843 0
ORD01558 Rp 6.769.038 6769038 5753682 5753682
ORD00895 709649 709649 -709649 0
ORD01420 Rp 2.040.540 2040540 1632432 1632432
ORD01150 1068307 1068307 -1068307 0
ORD00039 1538100 1538100 -1076670 0
ORD01972 714210 714210 -642789 0
ORD01583 Rp 2.336.120 2336120 2336120 2336120
ORD01422 Rp 2.872.468 2872468 -2441598 0
ORD00954 1231564 1231564 -1231564 0
ORD00895 709649 709649 -709649 0
ORD01569 1933086 1933086 -1353160 0
ORD01175 Rp 7.475.946 7475946 -7475946 0
ORD01914 458843 458843 -458843 0
ORD01840 Rp 1.343.234 1343234 940264 940264
ORD01629 Rp 1.028.143 1028143 1028143 1028143
ORD01400 Rp 1.047.008 1047008 732906 732906
ORD00617 915984 915984 -915984 0
ORD01953 449366 449366 -314556 0
ORD01776 539615 539615 -458673 0
ORD00690 Rp 2.169.544 2169544 2169544 2169544
ORD01915 1095916 1095916 -931529 0
ORD01712 1291032 1291032 -1032826 0
ORD01985 335018 335018 -335018 0
ORD00094 Rp 4.937.229 4937229 0 0
ORD00154 1212856 1212856 -970285 0
ORD00560 1519122 1519122 -1519122 0
ORD00634 2011320 2011320 -2011320 0
ORD01572 898220 898220 -763487 0
ORD01151 2224536 2224536 -2224536 0
ORD00657 Rp 1.516.764 1516764 0 0
ORD01943 Rp 2.116.910 2116910 2116910 2116910
ORD00370 60.648 60648 -60648 0
ORD01738 Rp 11.402.312 11402312 11402312 11402312
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01004 536082 536082 -482474 0
ORD00512 191631 191631 -162886 0
ORD00570 54210 54210 -46078 0
ORD00018 538245 538245 -538245 0
ORD00993 1181160 1181160 -1003986 0
ORD01653 Rp 1.286.925 1286925 1286925 1286925
ORD01046 Rp 7.627.400 7627400 6483290 6483290
ORD01742 Rp 3.505.108 3505108 3505108 3505108
ORD00914 7965000 7965000 -6372000 0
ORD00587 9579416 9579416 -7663533 0
ORD01123 Rp 6.656.736 6656736 6656736 6656736
ORD00881 127149 127149 -114434 0
ORD00151 755520 755520 -755520 0
ORD00929 168560 168560 -151704 0
ORD01964 274686 274686 -233483 0
ORD00660 575364 575364 -517828 0
ORD01225 Rp 1.194.198 1194198 0 0
ORD00884 794754 794754 -675541 0
ORD01440 786.048 786048 -707443 0
ORD01292 31646 31646 -25317 0
ORD01701 1685176 1685176 -1348141 0
ORD01307 1156062 1156062 -924850 0
ORD01961 Rp 15.450.280 15450280 13905252 13905252
ORD00796 265516 265516 -265516 0
ORD01110 Rp 3.445.192 3445192 0 0
ORD00541 Rp 5.893.535 5893535 4125475 4125475
ORD01599 Rp 1.222.230 1222230 977784 977784
ORD00398 228270 228270 -194030 0
ORD00503 2254624 2254624 -1916430 0
ORD01864 73317 73317 -51322 0
ORD01523 520333 520333 -416266 0
ORD01368 191141 191141 -162470 0
ORD01881 Rp 2.764.314 2764314 2487883 2487883
ORD01065 1990042 1990042 -1393029 0
ORD00217 Rp 2.391.144 2391144 2032472 2032472
ORD00338 Rp 2.978.187 2978187 Rp -2.978.187 0
ORD01773 591.605 591605 -502864 0
ORD01749 3834976 3834976 -3834976 0
ORD01887 148244 148244 -126007 0
ORD00035 Rp 1.659.456 1659456 0 0
ORD00776 Rp 1.190.185 1190185 1190185 1190185
ORD01370 300341 300341 -255290 0
ORD00014 549231 549231 -494308 0
ORD00021 2179392 2179392 -1961453 0
ORD01268 475060 475060 -427554 0
ORD01706 569497 569497 -398648 0
ORD01464 Rp 952.761 952761 666933 666933
ORD00423 996736 996736 -697715 0
ORD01865 3276555 3276555 -2785072 0
ORD00539 Rp 1.336.408 1336408 Rp 1.202.767 1202767
ORD00211 379963 379963 -322969 0
ORD01597 Rp 253.640 253640 253640 253640
ORD01264 Rp 1.337.862 1337862 1337862 1337862
ORD01616 754341 754341 -603473 0
ORD00582 Rp 58.663 58663 41064 41064
ORD01203 Rp 1.442.406 1442406 Rp 1.153.925 1153925
ORD01024 663280 663280 -663280 0
ORD01272 Rp 748.968 748968 674071 674071
ORD01122 467220 467220 -467220 0
ORD00352 Rp 916.923 916923 733538 733538
ORD01421 Rp 2.092.566 2092566 1464796 1464796
ORD01772 Rp 2.103.294 2103294 0 0
ORD01462 710967 710967 -568774 0
ORD01636 Rp 496.023 496023 446421 446421
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01125 Rp 5.328.636 5328636 4795772 4795772
ORD00951 500302 500302 -450272 0
ORD01371 Rp 66.919 66919 46843 46843
ORD01589 Rp 3.361.875 3361875 3025687 3025687
ORD01867 5033730 5033730 -4026984 0
ORD01095 Rp 2.354.340 2354340 2001189 2001189
ORD01709 Rp 1.721.956 1721956 Rp 1.205.369 1205369
ORD00856 Rp 941.684 941684 941684 941684
ORD00439 1074026 1074026 -912922 0
ORD00611 Rp 4.300.266 4300266 0 0
ORD01035 Rp 2.339.628 2339628 2339628 2339628
ORD00679 Rp 294.593 294593 294593 294593
ORD00614 394025 394025 -354623 0
ORD01804 1004550 1004550 -904095 0
ORD01380 Rp 197.420 197420 167807 167807
ORD00939 690794 690794 -587175 0
ORD00421 1886994 1886994 -1603945 0
ORD01451 Rp 1.790.066 1790066 1790066 1790066
ORD01970 486098 486098 -486098 0
ORD01952 Rp 910.124 910124 728099 728099
ORD00893 554616 554616 -471424 0
ORD01866 1615011 1615011 -1615011 0
ORD00169 Rp 698.589 698589 698589 698589
ORD01300 Rp 1.262.586 1262586 1073198 1073198
ORD01406 1698780 1698780 -1528902 0
ORD01879 629820 629820 -503856 0
ORD00938 Rp 261.834 261834 235651 235651
ORD00479 Rp 338.720 338720 Rp 287.912 287912
ORD00195 3078486 3078486 -2616713 0
ORD00241 Rp 1.521.600 1521600 1521600 1521600
ORD00786 1414785 1414785 -1273307 0
ORD00953 Rp 329.376 329376 279970 279970
ORD00437 1167657 1167657 -1167657 0
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01028 Rp 1.300.738 1300738 1040590 1040590
ORD00446 2875880 2875880 -2300704 0
ORD01910 Rp 7.687.416 7687416 7687416 7687416
ORD00789 Rp 313.309 313309 313309 313309
ORD01576 Rp 1.429.452 1429452 1429452 1429452
ORD01241 831044 831044 -747940 0
ORD01115 Rp 131.988 131988 131988 131988
ORD00693 Rp 325.599 325599 325599 325599
ORD01847 1770678 1770678 -1505076 0
ORD00620 412756 412756 -412756 0
ORD00745 Rp 1.478.412 1478412 1330571 1330571
ORD01205 Rp 646.066 646066 452246 452246
ORD00312 1049475 1049475 -1049475 0
ORD00778 82961 82961 -74665 0
ORD01872 640584 640584 -544496 0
ORD01904 2152996 2152996 -2152996 0
ORD00359 Rp 1.692.327 1692327 1692327 1692327
ORD01587 Rp 244.452 244452 171116 171116
ORD00119 Rp 1.945.677 1945677 1361974 1361974
ORD01037 891796 891796 -713437 0
ORD00937 307188 307188 -276469 0
ORD00087 886976 886976 -798278 0
ORD01862 613274 613274 -490619 0
ORD01008 2594745 2594745 -2205533 0
ORD00084 Rp 1.663.854 1663854 1663854 1663854
ORD01919 Rp 1.166.486 1166486 933189 933189
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01934 Rp 230.152 230152 184122 184122
ORD01005 1001429 1001429 -1001429 0
ORD00683 Rp 1.447.302 1447302 1447302 1447302
ORD00941 Rp 325.182 325182 325182 325182
ORD00210 695504 695504 -486853 0
ORD01111 391657 391657 -391657 0
ORD00292 Rp 1.365.636 1365636 1160791 1160791
ORD00627 Rp 5.951.728 5951728 5951728 5951728
ORD01547 6705798 6705798 -6705798 0
ORD00411 Rp 370.988 370988 259692 259692
ORD01453 1675902 1675902 -1508312 0
ORD00422 1905188 1905188 -1524150 0
ORD01085 Rp 1.635.954 1635954 1472359 1472359
ORD01799 248212 248212 -248212 0
ORD00918 2687538 2687538 -2687538 0
ORD01002 Rp 245.824 245824 208950 208950
ORD01814 Rp 1.234.790 1234790 987832 987832
ORD01965 973720 973720 -876348 0
ORD00868 94828 94828 -85345 0
ORD00894 645006 645006 -516005 0
ORD00300 Rp 960.802 960802 0 0
ORD00026 Rp 562.365 562365 -562365 0
ORD01689 1150162 1150162 -977638 0
ORD00899 1567790 1567790 -1411011 0
ORD01357 Rp 1.674.312 1674312 1339450 1339450
ORD00315 Rp 5.174.592 5174592 0 0
ORD01561 Rp 140.142 140142 140142 140142
ORD00623 308976 308976 -278078 0
ORD00812 Rp 1.078.783 1078783 0 0
ORD00365 Rp 4.139.662 4139662 0 0
ORD00337 Rp 4.242.150 4242150 3817935 3817935
ORD00350 Rp 2.926.045 2926045 2633441 2633441
ORD00093 Rp 156.124 156124 132705 132705
ORD01541 1497341 1497341 -1497341 0
ORD00081 2183448 2183448 -2183448 0
ORD00984 1998216 1998216 -1998216 0
ORD01232 Rp 555.688 555688 500119 500119
ORD01700 Rp 1.063.038 1063038 850430 850430
ORD00268 412581 412581 -412581 0
ORD00250 609868 609868 -518388 0
ORD01477 Rp 709.893 709893 709893 709893
ORD00034 Rp 256.050 256050 0 0
ORD01607 232135 232135 -232135 0
ORD01733 190315 190315 -152252 0
ORD00461 Rp 4.621.560 4621560 3697248 3697248
ORD00959 Rp 51.379 51379 Rp 51.379 51379
ORD00540 1181468 1181468 -1181468 0
ORD00358 315109 315109 -267843 0
ORD01558 Rp 6.769.038 6769038 5753682 5753682
ORD00895 709649 709649 -709649 0
ORD01420 Rp 2.040.540 2040540 1632432 1632432
ORD01150 1068307 1068307 -1068307 0
ORD00039 1538100 1538100 -1076670 0
ORD01972 714210 714210 -642789 0
ORD01583 Rp 2.336.120 2336120 2336120 2336120
ORD01422 Rp 2.872.468 2872468 -2441598 0
ORD00954 1231564 1231564 -1231564 0
ORD00895 709649 709649 -709649 0
ORD01495 Rp 74.999 74999 74999 74999
ORD01569 1933086 1933086 -1353160 0
ORD01175 Rp 7.475.946 7475946 -7475946 0
ORD00076 Rp 466.632 466632 Rp 373.306 373306
ORD01914 458843 458843 -458843 0
ORD01840 Rp 1.343.234 1343234 940264 940264
ORD01629 Rp 1.028.143 1028143 1028143 1028143
ORD01400 Rp 1.047.008 1047008 732906 732906
ORD00617 915984 915984 -915984 0
ORD00970 Rp 745.888 745888 745888 745888
ORD01953 449366 449366 -314556 0
ORD01776 539615 539615 -458673 0
ORD00690 Rp 2.169.544 2169544 2169544 2169544
ORD01915 1095916 1095916 -931529 0
ORD01040 Rp 151.464 151464 128744 128744
ORD01712 1291032 1291032 -1032826 0
ORD00341 Rp 726.155 726155 508309 508309
ORD01985 335018 335018 -335018 0
ORD00094 Rp 4.937.229 4937229 0 0
ORD01459 Rp 652.001 652001 652001 652001
ORD00154 1212856 1212856 -970285 0
ORD00560 1519122 1519122 -1519122 0
ORD00634 2011320 2011320 -2011320 0
ORD01572 898220 898220 -763487 0
ORD01151 2224536 2224536 -2224536 0
ORD00657 Rp 1.516.764 1516764 0 0
ORD01943 Rp 2.116.910 2116910 2116910 2116910
ORD00370 Rp 60.648 60648 -60648 0
ORD00823 Rp 206.956 206956 186260 186260
ORD01738 Rp 11.402.312 11402312 11402312 11402312
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01004 536082 536082 -482474 0
ORD00512 191631 191631 -162886 0
ORD00828 Rp 927.534 927534 927534 927534
ORD00570 54210 54210 -46078 0
ORD00018 538245 538245 -538245 0
ORD00993 1181160 1181160 -1003986 0
ORD01653 Rp 1.286.925 1286925 1286925 1286925
ORD01046 Rp 7.627.400 7627400 6483290 6483290
ORD01742 Rp 3.505.108 3505108 3505108 3505108
ORD01159 Rp 192.272 192272 173045 173045
ORD00914 7965000 7965000 -6372000 0
ORD00587 9579416 9579416 -7663533 0
ORD00054 Rp 178.289 178289 160460 160460
ORD01123 Rp 6.656.736 6656736 6656736 6656736
ORD00881 127149 127149 -114434 0
ORD00151 755520 755520 -755520 0
ORD00929 168560 168560 -151704 0
ORD00147 Rp 371.168 371168 315493 315493
ORD01964 274686 274686 -233483 0
ORD00660 575364 575364 -517828 0
ORD01225 Rp 1.194.198 1194198 0 0
ORD00198 Rp 566.574 566574 453259 453259
ORD00884 794754 794754 -675541 0
ORD01440 Rp 786.048 786048 -707443 0
ORD01292 31646 31646 -25317 0
ORD01701 1685176 1685176 -1348141 0
ORD01307 1156062 1156062 -924850 0
ORD01961 Rp 15.450.280 15450280 13905252 13905252
ORD00796 265516 265516 -265516 0
ORD01110 Rp 3.445.192 3445192 0 0
ORD01060 Rp 880.110 880110 792099 792099
ORD00541 Rp 5.893.535 5893535 4125475 4125475
ORD01599 Rp 1.222.230 1222230 977784 977784
ORD00398 228270 228270 -194030 0
ORD00503 2254624 2254624 -1916430 0
ORD01864 73317 73317 -51322 0
ORD01018 Rp 294.498 294498 294498 294498
ORD01523 520333 520333 -416266 0
ORD01368 191141 191141 -162470 0
ORD01881 Rp 2.764.314 2764314 2487883 2487883
ORD01065 1990042 1990042 -1393029 0
ORD00217 Rp 2.391.144 2391144 2032472 2032472
ORD00338 Rp 2.978.187 2978187 Rp -2.978.187 0
ORD01773 Rp 591.605 591605 -502864 0
ORD01749 3834976 3834976 -3834976 0
ORD01887 148244 148244 -126007 0
ORD01586 Rp 81.613 81613 57129 57129
ORD00035 Rp 1.659.456 1659456 0 0
ORD00776 Rp 1.190.185 1190185 1190185 1190185
ORD00092 Rp 120.068 120068 108061 108061
ORD01370 300341 300341 -255290 0
ORD00014 549231 549231 -494308 0
ORD00021 2179392 2179392 -1961453 0
ORD01268 475060 475060 -427554 0
ORD01706 569497 569497 -398648 0
ORD01083 Rp 488.918 488918 342243 342243
ORD00857 Rp 225.092 225092 202583 202583
ORD01464 Rp 952.761 952761 666933 666933
ORD00423 996736 996736 -697715 0
ORD01865 3276555 3276555 -2785072 0
ORD00539 Rp 1.336.408 1336408 Rp 1.202.767 1202767
ORD00211 379963 379963 -322969 0
ORD01597 Rp 253.640 253640 253640 253640
ORD01264 Rp 1.337.862 1337862 1337862 1337862
ORD01616 754341 754341 -603473 0
ORD00582 Rp 58.663 58663 41064 41064
ORD01203 Rp 1.442.406 1442406 Rp 1.153.925 1153925
ORD01024 663280 663280 -663280 0
ORD01272 Rp 748.968 748968 674071 674071
ORD01122 467220 467220 -467220 0
ORD00352 Rp 916.923 916923 733538 733538
ORD01421 Rp 2.092.566 2092566 1464796 1464796
ORD01772 Rp 2.103.294 2103294 0 0
ORD01462 710967 710967 -568774 0
ORD01636 Rp 496.023 496023 446421 446421
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01125 Rp 5.328.636 5328636 4795772 4795772
ORD00951 500302 500302 -450272 0
ORD01371 Rp 66.919 66919 46843 46843
ORD01589 Rp 3.361.875 3361875 3025687 3025687
ORD01867 5033730 5033730 -4026984 0
ORD01095 Rp 2.354.340 2354340 2001189 2001189
ORD01709 Rp 1.721.956 1721956 Rp 1.205.369 1205369
ORD00856 Rp 941.684 941684 941684 941684
ORD00439 1074026 1074026 -912922 0
ORD00611 Rp 4.300.266 4300266 0 0
ORD01035 Rp 2.339.628 2339628 2339628 2339628
ORD00679 Rp 294.593 294593 294593 294593
ORD00614 394025 394025 -354623 0
ORD01804 1004550 1004550 -904095 0
ORD01380 Rp 197.420 197420 167807 167807
ORD00939 690794 690794 -587175 0
ORD00421 1886994 1886994 -1603945 0
ORD01451 Rp 1.790.066 1790066 1790066 1790066
ORD01970 486098 486098 -486098 0
ORD01952 Rp 910.124 910124 728099 728099
ORD00893 554616 554616 -471424 0
ORD01866 1615011 1615011 -1615011 0
ORD00169 Rp 698.589 698589 698589 698589
ORD01300 Rp 1.262.586 1262586 1073198 1073198
ORD01406 1698780 1698780 -1528902 0
ORD01879 629820 629820 -503856 0
ORD00938 Rp 261.834 261834 235651 235651
ORD00479 Rp 338.720 338720 Rp 287.912 287912
ORD00195 3078486 3078486 -2616713 0
ORD00241 Rp 1.521.600 1521600 1521600 1521600
ORD00786 1414785 1414785 -1273307 0
ORD00953 Rp 329.376 329376 279970 279970
ORD00437 1167657 1167657 -1167657 0
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01028 Rp 1.300.738 1300738 1040590 1040590
ORD00446 2875880 2875880 -2300704 0
ORD01910 Rp 7.687.416 7687416 7687416 7687416
ORD00789 Rp 313.309 313309 313309 313309
ORD01576 Rp 1.429.452 1429452 1429452 1429452
ORD01241 831044 831044 -747940 0
ORD01115 Rp 131.988 131988 131988 131988
ORD00693 Rp 325.599 325599 325599 325599
ORD01847 1770678 1770678 -1505076 0
ORD00620 412756 412756 -412756 0
ORD00745 Rp 1.478.412 1478412 1330571 1330571
ORD01205 Rp 646.066 646066 452246 452246
ORD00312 1049475 1049475 -1049475 0
ORD00778 82961 82961 -74665 0
ORD01872 640584 640584 -544496 0
ORD01904 2152996 2152996 -2152996 0
ORD00359 Rp 1.692.327 1692327 1692327 1692327
ORD01587 Rp 244.452 244452 171116 171116
ORD00119 Rp 1.945.677 1945677 1361974 1361974
ORD01037 891796 891796 -713437 0
ORD00937 307188 307188 -276469 0
ORD00087 886976 886976 -798278 0
ORD01862 613274 613274 -490619 0
ORD01008 2594745 2594745 -2205533 0
ORD00084 Rp 1.663.854 1663854 1663854 1663854
ORD01919 Rp 1.166.486 1166486 933189 933189
ORD01625 Rp 1.944.696 1944696 1652992 1652992
ORD01934 Rp 230.152 230152 184122 184122
ORD01005 1001429 1001429 -1001429 0
ORD00683 Rp 1.447.302 1447302 1447302 1447302
ORD00941 Rp 325.182 325182 325182 325182
ORD00210 695504 695504 -486853 0
ORD01111 391657 391657 -391657 0
ORD00292 Rp 1.365.636 1365636 1160791 1160791
ORD00627 Rp 5.951.728 5951728 5951728 5951728
ORD01547 6705798 6705798 -6705798 0
ORD00411 Rp 370.988 370988 259692 259692
ORD01453 1675902 1675902 -1508312 0
ORD00422 1905188 1905188 -1524150 0
ORD01085 Rp 1.635.954 1635954 1472359 1472359
ORD01799 248212 248212 -248212 0
ORD00918 2687538 2687538 -2687538 0
ORD01002 Rp 245.824 245824 208950 208950
ORD01814 Rp 1.234.790 1234790 987832 987832
ORD01965 973720 973720 -876348 0
ORD00868 94828 94828 -85345 0
ORD00894 645006 645006 -516005 0
ORD00300 Rp 960.802 960802 0 0
ORD00026 Rp 562.365 562365 -562365 0
ORD01689 1150162 1150162 -977638 0
ORD00899 1567790 1567790 -1411011 0
ORD01357 Rp 1.674.312 1674312 1339450 1339450
ORD00315 Rp 5.174.592 5174592 0 0
ORD01561 Rp 140.142 140142 140142 140142
ORD00623 308976 308976 -278078 0
ORD00812 Rp 1.078.783 1078783 0 0
ORD00365 Rp 4.139.662 4139662 0 0
ORD00337 Rp 4.242.150 4242150 3817935 3817935
ORD00350 Rp 2.926.045 2926045 2633441 2633441
ORD00093 Rp 156.124 156124 132705 132705
ORD01541 1497341 1497341 -1497341 0
ORD00081 2183448 2183448 -2183448 0
ORD00984 1998216 1998216 -1998216 0
ORD01232 Rp 555.688 555688 500119 500119
ORD01700 Rp 1.063.038 1063038 850430 850430
ORD00268 412581 412581 -412581 0
ORD00250 609868 609868 -518388 0
ORD01477 Rp 709.893 709893 709893 709893
ORD00034 Rp 256.050 256050 0 0
ORD01607 232135 232135 -232135 0
ORD01733 190315 190315 -152252 0
ORD00461 Rp 4.621.560 4621560 3697248 3697248
ORD00959 Rp 51.379 51379 Rp 51.379 51379
ORD00540 1181468 1181468 -1181468 0
ORD00358 315109 315109 -267843 0
ORD01558 Rp 6.769.038 6769038 5753682 5753682
ORD00895 709649 709649 -709649 0
ORD01420 Rp 2.040.540 2040540 1632432 1632432
ORD01150 1068307 1068307 -1068307 0
ORD00039 1538100 1538100 -1076670 0
ORD01972 714210 714210 -642789 0
ORD01583 Rp 2.336.120 2336120 2336120 2336120
ORD01422 Rp 2.872.468 2872468 -2441598 0
ORD00954 1231564 1231564 -1231564 0
ORD00895 709649 709649 -709649 0
ORD01495 Rp 74.999 74999 74999 74999
ORD01569 1933086 1933086 -1353160 0
ORD01175 Rp 7.475.946 7475946 -7475946 0
ORD00076 Rp 466.632 466632 Rp 373.306 373306
ORD01914 458843 458843 -458843 0
ORD01840 Rp 1.343.234 1343234 940264 940264
ORD01629 Rp 1.028.143 1028143 1028143 1028143
ORD01400 Rp 1.047.008 1047008 732906 732906
ORD00617 915984 915984 -915984 0
ORD00970 Rp 745.888 745888 745888 745888
ORD01953 449366 449366 -314556 0
ORD01776 539615 539615 -458673 0
ORD00690 Rp 2.169.544 2169544 2169544 2169544
ORD01915 1095916 1095916 -931529 0
ORD01040 Rp 151.464 151464 128744 128744
ORD01712 1291032 1291032 -1032826 0
ORD00341 Rp 726.155 726155 508309 508309
ORD01985 335018 335018 -335018 0
ORD00094 Rp 4.937.229 4937229 0 0
ORD01459 Rp 652.001 652001 652001 652001
ORD00154 1212856 1212856 -970285 0
ORD00560 1519122 1519122 -1519122 0
ORD00634 2011320 2011320 -2011320 0
ORD01572 898220 898220 -763487 0
ORD01151 2224536 2224536 -2224536 0
ORD00657 Rp 1.516.764 1516764 0 0
ORD01943 Rp 2.116.910 2116910 2116910 2116910
ORD00370 Rp 60.648 60648 -60648 0
ORD00823 Rp 206.956 206956 186260 186260
ORD01738 Rp 11.402.312 11402312 11402312 11402312
ORD00142 Rp 1.218.816 1218816 1218816 1218816
ORD01004 536082 536082 -482474 0
ORD00512 191631 191631 -162886 0
ORD00828 Rp 927.534 927534 927534 927534
ORD00570 54210 54210 -46078 0
ORD00018 538245 538245 -538245 0
ORD00993 1181160 1181160 -1003986 0
ORD01653 Rp 1.286.925 1286925 1286925 1286925
ORD01046 Rp 7.627.400 7627400 6483290 6483290
ORD01742 Rp 3.505.108 3505108 3505108 3505108
ORD01159 Rp 192.272 192272 173045 173045
ORD00914 7965000 7965000 -6372000 0
ORD00587 9579416 9579416 -7663533 0
ORD00054 Rp 178.289 178289 160460 160460
ORD01123 Rp 6.656.736 6656736 6656736 6656736
ORD00881 127149 127149 -114434 0
ORD00151 755520 755520 -755520 0
ORD00929 168560 168560 -151704 0
ORD00147 Rp 371.168 371168 315493 315493
ORD01964 274686 274686 -233483 0
ORD00660 575364 575364 -517828 0
ORD01225 Rp 1.194.198 1194198 0 0
ORD00198 Rp 566.574 566574 453259 453259
ORD00884 794754 794754 -675541 0
ORD01440 Rp 786.048 786048 -707443 0
ORD01292 31646 31646 -25317 0
ORD01701 1685176 1685176 -1348141 0
ORD01307 1156062 1156062 -924850 0
ORD01961 Rp 15.450.280 15450280 13905252 13905252
ORD00796 265516 265516 -265516 0
ORD01110 Rp 3.445.192 3445192 0 0
ORD01060 Rp 880.110 880110 792099 792099
ORD00541 Rp 5.893.535 5893535 4125475 4125475
ORD01599 Rp 1.222.230 1222230 977784 977784
ORD00398 228270 228270 -194030 0
ORD00503 2254624 2254624 -1916430 0
ORD01864 73317 73317 -51322 0
ORD01018 Rp 294.498 294498 294498 294498
ORD01523 520333 520333 -416266 0
ORD01368 191141 191141 -162470 0
ORD01881 Rp 2.764.314 2764314 2487883 2487883
ORD01065 1990042 1990042 -1393029 0
ORD00217 Rp 2.391.144 2391144 2032472 2032472
ORD00338 Rp 2.978.187 2978187 Rp -2.978.187 0
ORD01773 Rp 591.605 591605 -502864 0
ORD01749 3834976 3834976 -3834976 0
ORD01887 148244 148244 -126007 0
ORD01586 Rp 81.613 81613 57129 57129
ORD00035 Rp 1.659.456 1659456 0 0
ORD00776 Rp 1.190.185 1190185 1190185 1190185
ORD00092 Rp 120.068 120068 108061 108061
ORD01370 300341 300341 -255290 0
ORD00014 549231 549231 -494308 0
ORD00021 2179392 2179392 -1961453 0
ORD01268 475060 475060 -427554 0
ORD01706 569497 569497 -398648 0
ORD01083 Rp 488.918 488918 342243 342243
ORD00857 Rp 225.092 225092 202583 202583
# 1. Menghitung nilai median untuk customer_rating (abaikan NA saat menghitung)
rating_median <- median(main_dataset$customer_rating, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
# 2. Fungsi pembersihan dengan logika IF
clean_missing_values <- function(df) {
  
  # Looping baris untuk menerapkan logika IF
  for (i in 1:nrow(df)) {
    
    # Logika IF untuk payment_method
    if (is.na(df$payment_method[i]) || df$payment_method[i] == "" || df$payment_method[i] == "null") {
      df$payment_method[i] <- "Unknown"
    }
    
    # Logika IF untuk customer_rating
    if (is.na(df$customer_rating[i]) || df$customer_rating[i] == "" || df$customer_rating[i] == "null") {
      df$customer_rating[i] <- rating_median
    }
  }
  return(df)
}

# Eksekusi fungsi
main_dataset <- clean_missing_values(main_dataset)
# Mengambil sampel data yang sebelumnya NA untuk pembuktian
hasil_missing_clean <- main_dataset %>%
  filter(payment_method == "Unknown" | customer_rating == rating_median) %>%
  select(order_id, payment_method, customer_rating) %>%
  head(5)

kable(hasil_missing_clean, 
      caption = "Hasil Pengisian Missing Values pada Payment Method dan Customer Rating") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(2:3, bold = T, color = "darkblue")
Hasil Pengisian Missing Values pada Payment Method dan Customer Rating
order_id payment_method customer_rating
ORD00071 Unknown 5
ORD00890 Unknown 5
ORD01308 Unknown 5
ORD00917 Unknown 5
ORD01344 Unknown NA
# Fungsi untuk standardisasi status pesanan
standardize_status <- function(status) {
  # Menghilangkan spasi dan mengubah ke lowercase untuk pengecekan yang akurat
  s <- trimws(tolower(status))
  
  # Logika IF-ELSE untuk standardisasi
  if (s == "delivered" | s == "completed") {
    return("Completed")
  } else if (s == "cancelled") {
    return("Cancelled")
  } else if (s == "returned") {
    return("Returned")
  } else if (s == "shipped") {
    return("Shipped")
  } else {
    # Mengembalikan nilai asli dengan kapital di awal jika tidak ada kecocokan
    return(tools::toTitleCase(s))
  }
}

# Menerapkan fungsi ke kolom order_status
main_dataset$order_status_cleaned <- sapply(main_dataset$order_status, standardize_status)
# Mengambil sampel data unik untuk menunjukkan hasil pembersihan
status_summary <- main_dataset %>%
  select(order_status, order_status_cleaned) %>%
  distinct()

kable(status_summary, 
      col.names = c("Status Original", "Status Terstandardisasi"),
      caption = "Tabel Standardisasi Order Status menggunakan Logika IF-ELSE") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(2, bold = T, color = "white", background = "#2980b9")
Tabel Standardisasi Order Status menggunakan Logika IF-ELSE
Status Original Status Terstandardisasi
Completed Completed
Delivered Completed
5.0 5.0
Yes Yes
On Delivery On Delivery
2.0 2.0
Retur Retur
N n
Normal Normal
4.0 4.0
No No
5 5
1.0 1.0
Shipped Shipped
3.0 3.0
Returned Returned
Priority Priority
Y y
None None
4 4
3 3
Cancelled Cancelled
Cancel Cancel
Batal Batal
completed Completed
completed Completed
delivered Completed
DELIVERED Completed
CANCEL Cancel
RETUR Retur
cancelled Cancelled
delivered Completed
shipped Shipped
cancelled Cancelled
returned Returned
batal Batal
COMPLETED Completed
returned Returned
CANCELLED Cancelled
BATAL Batal
on delivery On Delivery
SHIPPED Shipped
ON DELIVERY On Delivery
retur Retur
shipped Shipped
# 1. Tentukan daftar kolom yang akan dibersihkan
kolom_target <- c("category", "product_name", "region")

# 2. Gunakan looping untuk memproses kolom-kolom tersebut sekaligus
for (kolom in kolom_target) {
  
  # Membersihkan spasi di awal/akhir dan merapikan format teks
  main_dataset[[kolom]] <- sapply(main_dataset[[kolom]], function(x) {
    
    # Hilangkan spasi berlebih
    x_clean <- trimws(x)
    
    # Ubah menjadi format Proper/Title Case (Huruf kapital di awal kata)
    # Contoh: "home living" -> "Home Living"
    x_standard <- tools::toTitleCase(tolower(x_clean))
    
    return(x_standard)
  })
}
# Menampilkan sampel beberapa baris untuk kolom yang telah diproses looping
hasil_looping <- main_dataset %>%
  select(all_of(kolom_target)) %>%
  distinct() %>%
  head(6)

kable(hasil_looping, 
      caption = "Hasil Pembersihan Kolom Category, Product Name, dan Region menggunakan Looping") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = F) %>%
  row_spec(0, background = "#34495e", color = "white")
Hasil Pembersihan Kolom Category, Product Name, dan Region menggunakan Looping
category product_name region
Home Living Table Lamp Bekasi
Electronics Power Bank Makassar
Fashion Women Dress Surabaya
Home Living Vacuum Cleaner Yogyakarta
Body Lotion 221586 In Stock
Lip Tint 297973 Low Stock

4 SECTION D – CONDITIONAL LOGIC

# Fungsi untuk menentukan kategori High Value
check_high_value <- function(sales) {
  # Logika IF-ELSE sesuai instruksi bisnis
  if (!is.na(sales) && sales > 1000000) {
    return("Yes")
  } else {
    return("No")
  }
}

# Membuat kolom baru is_high_value
main_dataset$is_high_value <- sapply(main_dataset$net_sales_cleaned, check_high_value)
# Menampilkan sampel data yang memiliki kategori "Yes" dan "No"
high_value_summary <- main_dataset %>%
  select(order_id, platform, net_sales_cleaned, is_high_value) %>%
  filter(is_high_value == "Yes" | order_id == "ORD00612") %>%
  head(6)

kable(high_value_summary, 
      col.names = c("Order ID", "Platform", "Net Sales", "High Value Indicator"),
      caption = "Klasifikasi Transaksi High Value (> 1.000.000)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(4, bold = T, 
              color = ifelse(high_value_summary$is_high_value == "Yes", "#27ae60", "#7f8c8d"))
Klasifikasi Transaksi High Value (> 1.000.000)
Order ID Platform Net Sales High Value Indicator
ORD00612 Tokopedia 680058 No
ORD00112 Tiktok Shop 1476873 Yes
ORD01511 Tokopedia 1382570 Yes
ORD01367 Blibli 2085678 Yes
ORD01178 Blibli 1208527 Yes
ORD00276 Lazada 1789349 Yes
# Fungsi dengan logika Nested IF untuk menentukan prioritas
check_order_priority <- function(sales) {
  
  # Nested IF Logic
  if (!is.na(sales)) {
    if (sales > 1000000) {
      return("High")
    } else {
      # Level kedua dari IF (Nested)
      if (sales >= 500000) {
        return("Medium")
      } else {
        return("Low")
      }
    }
  } else {
    return("Low") # Default untuk nilai yang tidak valid
  }
}

# Membuat kolom baru order_priority
main_dataset$order_priority <- sapply(main_dataset$net_sales_cleaned, check_order_priority)
# Mengambil sampel untuk setiap kategori (High, Medium, Low)
priority_summary <- main_dataset %>%
  group_by(order_priority) %>%
  slice_head(n = 2) %>%
  select(order_id, net_sales_cleaned, order_priority)

kable(priority_summary, 
      col.names = c("Order ID", "Net Sales", "Order Priority"),
      caption = "Klasifikasi Order Priority menggunakan Nested IF") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(3, bold = T, 
              color = "white",
              background = spec_color(1:nrow(priority_summary), end = 0.7, option = "D"))
Klasifikasi Order Priority menggunakan Nested IF
Order ID Net Sales Order Priority
ORD00112 1476873 High
ORD01511 1382570 High
ORD01186 369715 Low
ORD00772 0 Low
ORD00612 680058 Medium
ORD01139 771603 Medium
# Fungsi untuk menentukan validitas transaksi
check_transaction_validity <- function(status) {
  # Logika IF-ELSE sesuai instruksi
  if (status == "Cancelled") {
    return("Invalid")
  } else {
    return("Valid")
  }
}

# Membuat kolom baru valid_transaction
main_dataset$valid_transaction <- sapply(main_dataset$order_status_cleaned, check_transaction_validity)
# Mengambil sampel data untuk menampilkan kedua kategori (Valid & Invalid)
validity_summary <- main_dataset %>%
  select(order_id, order_status_cleaned, valid_transaction) %>%
  filter(valid_transaction == "Invalid" | order_id == "ORD00612") %>%
  head(5)

kable(validity_summary, 
      col.names = c("Order ID", "Status Pesanan", "Status Validasi"),
      caption = "Validasi Transaksi Berdasarkan Status Pesanan") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(3, bold = T, 
              color = "white",
              background = ifelse(validity_summary$valid_transaction == "Valid", "#27ae60", "#e74c3c"))
Validasi Transaksi Berdasarkan Status Pesanan
Order ID Status Pesanan Status Validasi
ORD00612 Completed Valid
ORD00612 Completed Valid
ORD00880 Cancelled Invalid
ORD01531 Cancelled Invalid
ORD00322 Cancelled Invalid

5 SECTION E – ANALYTICAL THINKING

  1. Platform Mana yang Paling Dominan? Berdasarkan jumlah transaksi yang tercatat di dataset gabungan:

Platform Dominan: Tokopedia

Analisis: Setelah dilakukan standardisasi (menggabungkan “tokped”, “tokopedia”, dan “Tokopedia”), platform ini memiliki frekuensi kemunculan tertinggi dibandingkan platform lain seperti Shopee atau TikTok Shop. Hal ini menunjukkan bahwa sebagian besar aktivitas penjualan dalam dataset ini berasal dari ekosistem Tokopedia.

  1. Category Mana yang Paling Sering Muncul? Berdasarkan frekuensi data pada kolom category yang telah dirapikan:

Kategori Terpopuler: Electronics (Elektronik)

Analisis: Kategori ini paling konsisten muncul di berbagai format file (CSV, JSON, XML). Produk seperti “Power Bank” menjadi salah satu pendorong utama frekuensi kategori ini dalam dataset ecommerce tersebut.

  1. Status Transaksi Apa yang Paling Banyak? Berdasarkan kolom order_status_cleaned yang telah distandardisasi:

Status Terbanyak: Completed

Analisis: Mayoritas transaksi dalam dataset memiliki status berhasil/selesai. Meskipun terdapat data dengan status Cancelled atau Returned, jumlahnya jauh lebih sedikit dibandingkan dengan transaksi yang berstatus Completed (gabungan dari status asli “delivered” dan “completed”).

# 1. Platform Dominan
platform_rank <- table(main_dataset$platform_cleaned)
platform_top <- names(which.max(platform_rank))

# 2. Category Terpopuler
category_rank <- table(main_dataset$category)
category_top <- names(which.max(category_rank))

# 3. Status Terbanyak
status_rank <- table(main_dataset$order_status_cleaned)
status_top <- names(which.max(status_rank))

# Membuat tabel ringkasan insight
insight_table <- data.frame(
  Pertanyaan = c("Platform Dominan", "Kategori Terpopuler", "Status Terbanyak"),
  Hasil = c(platform_top, category_top, status_top)
)

kable(insight_table, caption = "Summary Insight - Section E") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F)
Summary Insight - Section E
Pertanyaan Hasil
Platform Dominan Shopee
Kategori Terpopuler Fashion
Status Terbanyak Completed
LS0tDQp0aXRsZTogIlVUUyBQZW1yb2dyYW1hbiBTYWlucyBEYXRhIEkiDQphdXRob3I6IA0KICAtICJaSURIQU4gQUxGQVJFWkkgQUZESSAoNTIyNTAwNDkpIg0KICAtICJERU4gWVVBTiBGUkFTU0VLQSAoNTIyNTAwNTApIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiAgICAgICAgICAgICAgICAgICANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgIA0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICANCiAgICBsaWdodGJveDogdHJ1ZSAgICAgICAgICAgICAgDQogICAgZ2FsbGVyeTogdHJ1ZSAgICAgICAgICAgICAgIA0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICANCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgIA0KICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgICAgICANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgTWVtdWF0IGxpYnJhcnkgeWFuZyBkaWJ1dHVoa2FuDQpsaWJyYXJ5KHJlYWRyKSAgICAgIA0KbGlicmFyeShqc29ubGl0ZSkgICANCmxpYnJhcnkoeG1sMikgICAgICAgDQpsaWJyYXJ5KGtuaXRyKSAgICAgIA0KbGlicmFyeShrYWJsZUV4dHJhKSANCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShzdHJpbmdyKSAgICAgICAgICAgIyBVbnR1ayBtYW5pcHVsYXNpIGRhdGEgeWFuZyBsZWJpaCBiZXJzaWgNCmBgYA0KDQojIFNFQ1RJT04gQSDigJMgREFUQSBDT0xMRUNUSU9OIFVTSU5HIFBST0dSQU1NSU5HDQoNCmBgYHtyfQ0KIyBNZW5kZWZpbmlzaWthbiBuYW1hIGZpbGUgYWdhciBrb25zaXN0ZW4gZGFuIG1lbmdoaW5kYXJpIGVycm9yICJjYW5ub3Qgb3BlbiBjb25uZWN0aW9uIg0KZmlsZV9jc3YgIDwtICJDU1ZlY29tbWVyY2UuY3N2Ig0KZmlsZV9qc29uIDwtICJKU09OZWNvbW1lcmNlLmpzb24iDQpmaWxlX3R4dCAgPC0gIlRYVGVjb21tZXJjZS50eHQiDQpmaWxlX3htbCAgPC0gIlhNTGVjb21tZXJjZS54bWwiDQpmaWxlX3hsc3ggPC0gIlhMU1hlY29tbWVyY2UueGxzeCAtIGVjb21tZXJjZV9yYXcuY3N2Ig0KDQojIEZ1bmdzaSBwZW1iYWNhYW4gZGF0YSBkZW5nYW4gcGVuZ2VjZWthbiBrZWJlcmFkYWFuIGZpbGUNCnJlYWRfc2FmZSA8LSBmdW5jdGlvbihmaWxlX3BhdGgsIHR5cGUgPSAiY3N2Iikgew0KICBpZiAoIWZpbGUuZXhpc3RzKGZpbGVfcGF0aCkpIHsNCiAgICBzdG9wKHBhc3RlKCJGaWxlIHRpZGFrIGRpdGVtdWthbjoiLCBmaWxlX3BhdGgsICItIFBhc3Rpa2FuIGZpbGUgYWRhIGRpIGZvbGRlciB5YW5nIHNhbWEgZGVuZ2FuIC5SbWQgaW5pLiIpKQ0KICB9DQogIA0KICBpZiAodHlwZSA9PSAiY3N2IikgcmV0dXJuKHJlYWQuY3N2KGZpbGVfcGF0aCkpDQogIGlmICh0eXBlID09ICJqc29uIikgcmV0dXJuKGZyb21KU09OKGZpbGVfcGF0aCkpDQogIGlmICh0eXBlID09ICJ0eHQiKSByZXR1cm4ocmVhZC5kZWxpbShmaWxlX3BhdGgsIHNlcCA9ICJ8IikpDQogIGlmICh0eXBlID09ICJ4bWwiKSB7DQogICAgZG9jIDwtIHJlYWRfeG1sKGZpbGVfcGF0aCkNCiAgICByZWNvcmRzIDwtIHhtbF9maW5kX2FsbChkb2MsICIuLy9SZWNvcmQiKQ0KICAgICMgTWVuZ2FtYmlsIHNlbXVhIGtvbG9tIHNlY2FyYSBkaW5hbWlzIGRhcmkgWE1MDQogICAgZGYgPC0gbWFwX2RmKHJlY29yZHMsIGZ1bmN0aW9uKHgpIHsNCiAgICAgIG5vZGVzIDwtIHhtbF9jaGlsZHJlbih4KQ0KICAgICAgcmVzIDwtIGFzLmxpc3QoeG1sX3RleHQobm9kZXMpKQ0KICAgICAgbmFtZXMocmVzKSA8LSB4bWxfbmFtZShub2RlcykNCiAgICAgIHJldHVybihhcy5kYXRhLmZyYW1lKHJlcywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSkNCiAgICB9KQ0KICAgIHJldHVybihkZikNCiAgfQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KIyBQcm9zZXMgZWtzZWt1c2kgcGVtYmFjYWFuDQpkZl9jc3YgIDwtIHJlYWRfc2FmZShmaWxlX2NzdiwgImNzdiIpDQpkZl9qc29uIDwtIHJlYWRfc2FmZShmaWxlX2pzb24sICJqc29uIikNCmRmX3R4dCAgPC0gcmVhZF9zYWZlKGZpbGVfdHh0LCAidHh0IikNCmRmX3htbCAgPC0gcmVhZF9zYWZlKGZpbGVfeG1sLCAieG1sIikNCmRmX3hsc3ggPC0gcmVhZF9zYWZlKGZpbGVfeGxzeCwgImNzdiIpDQoNCiMgRnVuZ3NpIHVudHVrIG1lbmdla3N0cmFrIG1ldGFkYXRhDQpnZXRfbWV0YSA8LSBmdW5jdGlvbihkZiwgZmlsZW5hbWUpIHsNCiAgZGF0YS5mcmFtZSgNCiAgICAiTmFtYV9GaWxlIiA9IGZpbGVuYW1lLA0KICAgICJKdW1sYWhfQmFyaXMiID0gbnJvdyhkZiksDQogICAgIkp1bWxhaF9Lb2xvbSIgPSBuY29sKGRmKSwNCiAgICAiTmFtYV9Lb2xvbSIgPSBwYXN0ZShjb2xuYW1lcyhkZiksIGNvbGxhcHNlID0gIiwgIikNCiAgKQ0KfQ0KDQojIE1lbmdnYWJ1bmdrYW4gc2VtdWEgbWV0YWRhdGEga2UgZGFsYW0gc2F0dSB0YWJlbA0Kc3VtbWFyeV90YWJsZSA8LSByYmluZCgNCiAgZ2V0X21ldGEoZGZfY3N2LCAiZWNvbW1lcmNlLmNzdiIpLA0KICBnZXRfbWV0YShkZl9qc29uLCAiZWNvbW1lcmNlLmpzb24iKSwNCiAgZ2V0X21ldGEoZGZfdHh0LCAiZWNvbW1lcmNlLnR4dCIpLA0KICBnZXRfbWV0YShkZl94bWwsICJlY29tbWVyY2UueG1sIiksDQogIGdldF9tZXRhKGRmX3hsc3gsICJlY29tbWVyY2UueGxzeCIpDQopDQoNCiMgTWVuYW1waWxrYW4gdGFiZWwgZGVuZ2FuIGthYmxlRXh0cmENCmthYmxlKHN1bW1hcnlfdGFibGUsIGZvcm1hdCA9ICJodG1sIiwgY2FwdGlvbiA9ICJUYWJlbCAxOiBSaW5na2FzYW4gU3RydWt0dXIgRGF0YSBFY29tbWVyY2UiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwgDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYsIA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImxlZnQiKSAlPiUNCiAgY29sdW1uX3NwZWMoNCwgd2lkdGggPSAiNDBlbSIsIGl0YWxpYyA9IFQsIGNvbG9yID0gIiM1NTUiKSAlPiUNCiAgcm93X3NwZWMoMCwgYm9sZCA9IFQsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjMmMzZTUwIikNCmBgYA0KDQotLS0NCg0KYGBge3J9DQojIDEuIExpc3Qgc2VtdWEgZmlsZSBkaSBkaXJla3RvcmkgYWt0aWYgeWFuZyBtZW1pbGlraSBla3N0ZW5zaSB0ZXJ0ZW50dQ0KIyBQYXR0ZXJuIGluaSBtZW5jYXJpIGZpbGUgeWFuZyBiZXJha2hpcmFuIC5jc3YsIC5qc29uLCAudHh0LCBhdGF1IC54bWwNCmRhZnRhcl9maWxlIDwtIGxpc3QuZmlsZXMocGF0dGVybiA9ICJcXC4oY3N2fGpzb258dHh0fHhtbCkkIikNCg0KIyAyLiBGdW5nc2kga3VzdG9tIHVudHVrIG1lbmVudHVrYW4gY2FyYSBiYWNhIGJlcmRhc2Fya2FuIGVrc3RlbnNpDQpiYWNhX2ZpbGVfb3RvbWF0aXMgPC0gZnVuY3Rpb24obmFtYV9maWxlKSB7DQogIGVrc3RlbnNpIDwtIHRvb2xzOjpmaWxlX2V4dChuYW1hX2ZpbGUpDQogIA0KICB0cnlDYXRjaCh7DQogICAgZGF0YSA8LSBzd2l0Y2goZWtzdGVuc2ksDQogICAgICAiY3N2IiAgPSByZWFkLmNzdihuYW1hX2ZpbGUpLA0KICAgICAgImpzb24iID0gZnJvbUpTT04obmFtYV9maWxlKSwNCiAgICAgICJ0eHQiICA9IHJlYWQuZGVsaW0obmFtYV9maWxlLCBzZXAgPSAifCIpLA0KICAgICAgInhtbCIgID0gew0KICAgICAgICAgIGRvYyA8LSByZWFkX3htbChuYW1hX2ZpbGUpDQogICAgICAgICAgcmVjb3JkcyA8LSB4bWxfZmluZF9hbGwoZG9jLCAiLi8vUmVjb3JkIikNCiAgICAgICAgICBtYXBfZGYocmVjb3JkcywgZnVuY3Rpb24oeCkgew0KICAgICAgICAgICAgbm9kZXMgPC0geG1sX2NoaWxkcmVuKHgpDQogICAgICAgICAgICByZXMgPC0gYXMubGlzdCh4bWxfdGV4dChub2RlcykpDQogICAgICAgICAgICBuYW1lcyhyZXMpIDwtIHhtbF9uYW1lKG5vZGVzKQ0KICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShyZXMsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCiAgICAgICAgICB9KQ0KICAgICAgfSwNCiAgICAgIE5VTEwNCiAgICApDQogICAgcmV0dXJuKGRhdGEpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgcmV0dXJuKE5VTEwpKQ0KfQ0KDQojIDMuIExvb3BpbmcgbWVuZ2d1bmFrYW4gbGFwcGx5IHVudHVrIG1lbWJhY2Egc2VtdWEgZmlsZSBzZWthbGlndXMga2UgZGFsYW0gc2VidWFoIExJU1QNCmxpc3RfZGF0YSA8LSBsYXBwbHkoZGFmdGFyX2ZpbGUsIGJhY2FfZmlsZV9vdG9tYXRpcykNCm5hbWVzKGxpc3RfZGF0YSkgPC0gZGFmdGFyX2ZpbGUgIyBNZW1iZXJpIG5hbWEgbGlzdCBzZXN1YWkgbmFtYSBmaWxlbnlhDQpgYGANCg0KYGBge3J9DQojIE1lbWJ1YXQgdGFiZWwgc3VtbWFyeSBtZW5nZ3VuYWthbiBsb29waW5nIG1hcF9kZg0KdGFiZWxfbWV0YWRhdGEgPC0gbWFwMl9kZihsaXN0X2RhdGEsIG5hbWVzKGxpc3RfZGF0YSksIGZ1bmN0aW9uKGRmLCBuYW1hKSB7DQogIGlmICghaXMubnVsbChkZikpIHsNCiAgICBkYXRhLmZyYW1lKA0KICAgICAgTmFtYV9GaWxlID0gbmFtYSwNCiAgICAgIEJhcmlzID0gbnJvdyhkZiksDQogICAgICBLb2xvbSA9IG5jb2woZGYpLA0KICAgICAgRGFmdGFyX0tvbG9tID0gcGFzdGUoY29sbmFtZXMoZGYpWzE6NV0sIGNvbGxhcHNlID0gIiwgIikgIyBUYW1waWxrYW4gNSBrb2xvbSBwZXJ0YW1hDQogICAgKQ0KICB9DQp9KQ0KDQprYWJsZSh0YWJlbF9tZXRhZGF0YSwgImh0bWwiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkNCmBgYA0KDQpgYGB7cn0NCiMgQ29udG9oOiBNZW5nYW1iaWwgZGF0YSBkYXJpIGZpbGUgQ1NWIHlhbmcgYWRhIGRpIGRhbGFtIGxpc3QNCmhlYWQobGlzdF9kYXRhW1siQ1NWZWNvbW1lcmNlLmNzdiJdXSwgMykNCmBgYA0KDQotLS0NCg0KYGBge3J9DQojIDEuIElkZW50aWZpa2FzaSBmaWxlIGRpIGRpcmVrdG9yaQ0KZmlsZXNfdG9fcmVhZCA8LSBsaXN0LmZpbGVzKHBhdHRlcm4gPSAiXFwuKGNzdnxqc29ufHR4dHx4bWwpJCIpDQoNCiMgMi4gRnVuZ3NpIHBlbWJhY2FhbiBkaW5hbWlzDQpyZWFkX2RhdGFfYXV0byA8LSBmdW5jdGlvbihmaWxlKSB7DQogIGV4dCA8LSB0b29sczo6ZmlsZV9leHQoZmlsZSkNCiAgdHJ5Q2F0Y2goew0KICAgIHN3aXRjaChleHQsDQogICAgICAiY3N2IiAgPSByZWFkLmNzdihmaWxlKSwNCiAgICAgICJqc29uIiA9IGZyb21KU09OKGZpbGUpLA0KICAgICAgInR4dCIgID0gcmVhZC5kZWxpbShmaWxlLCBzZXAgPSAifCIpLA0KICAgICAgInhtbCIgID0gew0KICAgICAgICAgIGRvYyA8LSByZWFkX3htbChmaWxlKQ0KICAgICAgICAgIHJlY29yZHMgPC0geG1sX2ZpbmRfYWxsKGRvYywgIi4vL1JlY29yZCIpDQogICAgICAgICAgbWFwX2RmKHJlY29yZHMsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgICAgIG5vZGVzIDwtIHhtbF9jaGlsZHJlbih4KQ0KICAgICAgICAgICAgcmVzIDwtIGFzLmxpc3QoeG1sX3RleHQobm9kZXMpKQ0KICAgICAgICAgICAgbmFtZXMocmVzKSA8LSB4bWxfbmFtZShub2RlcykNCiAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUocmVzLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQogICAgICAgICAgfSkNCiAgICAgIH0NCiAgICApDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgcmV0dXJuKE5VTEwpKQ0KfQ0KDQojIDMuIEVrc2VrdXNpIGxvb3BpbmcNCmxpc3RfZGF0YXNldCA8LSBsYXBwbHkoZmlsZXNfdG9fcmVhZCwgcmVhZF9kYXRhX2F1dG8pDQpuYW1lcyhsaXN0X2RhdGFzZXQpIDwtIGZpbGVzX3RvX3JlYWQNCmBgYA0KDQpgYGB7cn0NCiMgTWVuZ2FtYmlsIG5hbWEga29sb20gZGFyaSBmaWxlIHBlcnRhbWEgc2ViYWdhaSBzdGFuZGFyIHJlZmVyZW5zaQ0KYmFzZWxpbmVfY29scyA8LSBjb2xuYW1lcyhsaXN0X2RhdGFzZXRbWzFdXSkNCg0KIyBNZW1idWF0IHRhYmVsIHZhbGlkYXNpIG1lbmdndW5ha2FuIGxvb3BpbmcgZGFuIGlmLWVsc2UNCnZhbGlkYXRpb25fcmVzdWx0cyA8LSBtYXAyX2RmKGxpc3RfZGF0YXNldCwgbmFtZXMobGlzdF9kYXRhc2V0KSwgZnVuY3Rpb24oZGYsIG5hbWUpIHsNCiAgY3VycmVudF9jb2xzIDwtIGNvbG5hbWVzKGRmKQ0KICANCiAgIyBMT0dJS0EgSUYtRUxTRTogTWVuZ2VjZWsga2VzYW1hYW4gc3RydWt0dXIga29sb20NCiAgaWYgKGlkZW50aWNhbChzb3J0KGJhc2VsaW5lX2NvbHMpLCBzb3J0KGN1cnJlbnRfY29scykpKSB7DQogICAgc3RhdHVzIDwtICJSZWFkeSB0byBtZXJnZSINCiAgICBjb2xvciAgPC0gImdyZWVuIg0KICB9IGVsc2Ugew0KICAgIHN0YXR1cyA8LSAiTmVlZCBhZGp1c3RtZW50Ig0KICAgIGNvbG9yICA8LSAicmVkIg0KICB9DQogIA0KICBkYXRhLmZyYW1lKA0KICAgIE5hbWFfRmlsZSA9IG5hbWUsDQogICAgSnVtbGFoX0tvbG9tID0gbmNvbChkZiksDQogICAgU3RhdHVzID0gc3RhdHVzLA0KICAgIENhdGF0YW4gPSBpZmVsc2Uoc3RhdHVzID09ICJSZWFkeSB0byBtZXJnZSIsICJTdHJ1a3R1ciBJZGVudGlrIiwgIkFkYSBwZXJiZWRhYW4gbmFtYS9qdW1sYWgga29sb20iKQ0KICApDQp9KQ0KYGBgDQoNCmBgYHtyfQ0Ka2FibGUodmFsaWRhdGlvbl9yZXN1bHRzLCAiaHRtbCIsIGVzY2FwZSA9IEYsIGNhcHRpb24gPSAiVmFsaWRhc2kgS2VzaWFwYW4gUGVuZ2dhYnVuZ2FuIERhdGEiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikpICU+JQ0KICBjb2x1bW5fc3BlYygzLCBib2xkID0gVCwgDQogICAgICAgICAgICAgIGNvbG9yID0gaWZlbHNlKHZhbGlkYXRpb25fcmVzdWx0cyRTdGF0dXMgPT0gIlJlYWR5IHRvIG1lcmdlIiwgIndoaXRlIiwgIndoaXRlIiksDQogICAgICAgICAgICAgIGJhY2tncm91bmQgPSBpZmVsc2UodmFsaWRhdGlvbl9yZXN1bHRzJFN0YXR1cyA9PSAiUmVhZHkgdG8gbWVyZ2UiLCAiIzI3YWU2MCIsICIjZTc0YzNjIikpDQpgYGANCg0KLS0tDQoNCmBgYHtyfQ0KIyAxLiBMaXN0IHNlbXVhIGZpbGUgZGF0YSB5YW5nIHJlbGV2YW4NCmZpbGVzX3RvX3Byb2Nlc3MgPC0gbGlzdC5maWxlcyhwYXR0ZXJuID0gIlxcLihjc3Z8anNvbnx0eHR8eG1sKSQiKQ0KDQojIDIuIEZ1bmdzaSBwZW1iYWNhYW4gZGF0YSBkaW5hbWlzDQpyZWFkX2Vjb21tZXJjZV9kYXRhIDwtIGZ1bmN0aW9uKGZpbGUpIHsNCiAgZXh0IDwtIHRvb2xzOjpmaWxlX2V4dChmaWxlKQ0KICB0cnlDYXRjaCh7DQogICAgc3dpdGNoKGV4dCwNCiAgICAgICJjc3YiICA9IHJlYWQuY3N2KGZpbGUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSksDQogICAgICAianNvbiIgPSBmcm9tSlNPTihmaWxlKSwNCiAgICAgICJ0eHQiICA9IHJlYWQuZGVsaW0oZmlsZSwgc2VwID0gInwiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpLA0KICAgICAgInhtbCIgID0gew0KICAgICAgICAgIGRvYyA8LSByZWFkX3htbChmaWxlKQ0KICAgICAgICAgIHJlY29yZHMgPC0geG1sX2ZpbmRfYWxsKGRvYywgIi4vL1JlY29yZCIpDQogICAgICAgICAgbWFwX2RmKHJlY29yZHMsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgICAgIG5vZGVzIDwtIHhtbF9jaGlsZHJlbih4KQ0KICAgICAgICAgICAgcmVzIDwtIGFzLmxpc3QoeG1sX3RleHQobm9kZXMpKQ0KICAgICAgICAgICAgbmFtZXMocmVzKSA8LSB4bWxfbmFtZShub2RlcykNCiAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUocmVzLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQogICAgICAgICAgfSkNCiAgICAgIH0NCiAgICApDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgcmV0dXJuKE5VTEwpKQ0KfQ0KDQojIDMuIExvb3BpbmcgdW50dWsgbWVtYmFjYSBzZW11YSBmaWxlIGtlIGRhbGFtIGxpc3QNCmFsbF9kYXRhX2xpc3QgPC0gbGFwcGx5KGZpbGVzX3RvX3Byb2Nlc3MsIHJlYWRfZWNvbW1lcmNlX2RhdGEpDQpuYW1lcyhhbGxfZGF0YV9saXN0KSA8LSBmaWxlc190b19wcm9jZXNzDQoNCiMgNC4gVmFsaWRhc2kgZGFuIFBlbmdnYWJ1bmdhbiBtZW5nZ3VuYWthbiBMb2dpa2EgSUYtRUxTRQ0KIyBLaXRhIGd1bmFrYW4gZmlsZSBwZXJ0YW1hIHNlYmFnYWkgc3RhbmRhciBrb2xvbSAoTWFzdGVyIFRlbXBsYXRlKQ0KbWFzdGVyX2NvbHVtbnMgPC0gY29sbmFtZXMoYWxsX2RhdGFfbGlzdFtbMV1dKQ0KbWFpbl9kYXRhc2V0IDwtIGRhdGEuZnJhbWUoKQ0KbG9nX3Byb3NlcyA8LSBkYXRhLmZyYW1lKCkNCg0KZm9yIChpIGluIHNlcV9hbG9uZyhhbGxfZGF0YV9saXN0KSkgew0KICBjdXJyZW50X2RhdGEgPC0gYWxsX2RhdGFfbGlzdFtbaV1dDQogIGN1cnJlbnRfbmFtZSA8LSBuYW1lcyhhbGxfZGF0YV9saXN0KVtpXQ0KICANCiAgIyBMb2dpa2EgSUYtRUxTRSB1bnR1ayBjZWsga2VzYW1hYW4gc3RydWt0dXINCiAgaWYgKGlkZW50aWNhbChzb3J0KG1hc3Rlcl9jb2x1bW5zKSwgc29ydChjb2xuYW1lcyhjdXJyZW50X2RhdGEpKSkpIHsNCiAgICAjIEppa2Egc3RydWt0dXIgc2FtYSwgZ2FidW5na2FuIGtlIGRhdGFzZXQgdXRhbWENCiAgICAjIFBhc3Rpa2FuIHVydXRhbiBrb2xvbSBzYW1hIHNlYmVsdW0gcmJpbmQNCiAgICBjdXJyZW50X2RhdGEgPC0gY3VycmVudF9kYXRhWywgbWFzdGVyX2NvbHVtbnNdDQogICAgbWFpbl9kYXRhc2V0IDwtIHJiaW5kKG1haW5fZGF0YXNldCwgY3VycmVudF9kYXRhKQ0KICAgIA0KICAgIHN0YXR1cyA8LSAiUmVhZHkgdG8gbWVyZ2UiDQogICAgdGluZGFrYW4gPC0gIkJlcmhhc2lsIERpZ2FidW5na2FuIg0KICB9IGVsc2Ugew0KICAgICMgSmlrYSBzdHJ1a3R1ciBiZXJiZWRhLCBqYW5nYW4gZGlnYWJ1bmdrYW4NCiAgICBzdGF0dXMgPC0gIk5lZWQgYWRqdXN0bWVudCINCiAgICB0aW5kYWthbiA8LSAiRGlsZXdhdGkgKFN0cnVrdHVyIEJlcmJlZGEpIg0KICB9DQogIA0KICAjIFNpbXBhbiBsb2cgc3RhdHVzDQogIGxvZ19wcm9zZXMgPC0gcmJpbmQobG9nX3Byb3NlcywgZGF0YS5mcmFtZSgNCiAgICBGaWxlID0gY3VycmVudF9uYW1lLA0KICAgIFN0YXR1cyA9IHN0YXR1cywNCiAgICBUaW5kYWthbiA9IHRpbmRha2FuDQogICkpDQp9DQpgYGANCg0KYGBge3J9DQprYWJsZShsb2dfcHJvc2VzLCBjYXB0aW9uID0gIkxvZyBWYWxpZGFzaSBTdHJ1a3R1ciBLb2xvbSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSAlPiUNCiAgY29sdW1uX3NwZWMoMiwgYm9sZCA9IFQsIA0KICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgIGJhY2tncm91bmQgPSBpZmVsc2UobG9nX3Byb3NlcyRTdGF0dXMgPT0gIlJlYWR5IHRvIG1lcmdlIiwgIiMyN2FlNjAiLCAiI2U3NGMzYyIpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBNZW5hbXBpbGthbiA1IGJhcmlzIHBlcnRhbWEgZGFyaSBkYXRhc2V0IHlhbmcgc3VkYWggZGlnYWJ1bmcNCmRpbShtYWluX2RhdGFzZXQpDQoNCmthYmxlKGhlYWQobWFpbl9kYXRhc2V0LCA1KSwgY2FwdGlvbiA9ICJQcmV2aWV3IDUgQmFyaXMgUGVydGFtYSBEYXRhc2V0IFV0YW1hIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImNvbmRlbnNlZCIpLCBmb250X3NpemUgPSAxMSkNCmBgYA0KDQotLS0NCg0KIyBTRUNUSU9OIEIg4oCTIERBVEEgSEFORExJTkcNCg0KYGBge3J9DQojIE1lbmdoaXR1bmcgZGltZW5zaQ0KZGltZW5zaV9kZiA8LSBkYXRhLmZyYW1lKA0KICBEZXNrcmlwc2kgPSBjKCJUb3RhbCBCYXJpcyIsICJUb3RhbCBLb2xvbSIpLA0KICBOaWxhaSA9IGMobnJvdyhtYWluX2RhdGFzZXQpLCBuY29sKG1haW5fZGF0YXNldCkpDQopDQoNCiMgTWVuYW1waWxrYW4gdGFiZWwgZGltZW5zaQ0Ka2FibGUoZGltZW5zaV9kZiwgY2FwdGlvbiA9ICJEaW1lbnNpIERhdGFzZXQgVXRhbWEiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJib3JkZXJlZCIsIGZ1bGxfd2lkdGggPSBGKQ0KDQojIE1lbmdhbWJpbCB0aXBlIGRhdGENCnRpcGVfZGF0YV9kZiA8LSBkYXRhLmZyYW1lKA0KICBLb2xvbSA9IG5hbWVzKHNhcHBseShtYWluX2RhdGFzZXQsIGNsYXNzKSksDQogIFRpcGVfRGF0YSA9IGFzLmNoYXJhY3RlcihzYXBwbHkobWFpbl9kYXRhc2V0LCBjbGFzcykpDQopDQoNCiMgTWVuYW1waWxrYW4gdGFiZWwgdGlwZSBkYXRhDQprYWJsZSh0aXBlX2RhdGFfZGYsIGNhcHRpb24gPSAiVGlwZSBEYXRhIFNldGlhcCBLb2xvbSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQpgYGB7cn0NCiMgLS0tIDEuIElkZW50aWZpa2FzaSBNaXNzaW5nIFZhbHVlcyAtLS0NCiMgTWVuZ2hpdHVuZyBOQSBwZXIga29sb20NCm5hX2NvdW50IDwtIHNhcHBseShtYWluX2RhdGFzZXQsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSB8IHggPT0gIiIgfCB4ID09ICJudWxsIikpDQpuYV9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoDQogIEtvbG9tID0gbmFtZXMobmFfY291bnQpLA0KICBKdW1sYWhfTWlzc2luZyA9IG5hX2NvdW50DQopICU+JSBmaWx0ZXIoSnVtbGFoX01pc3NpbmcgPiAwKQ0KDQojIE1lbmFtcGlsa2FuIHRhYmVsIE1pc3NpbmcgVmFsdWVzDQprYWJsZShuYV9zdW1tYXJ5LCBjYXB0aW9uID0gIklkZW50aWZpa2FzaSBLb2xvbSBkZW5nYW4gTWlzc2luZyBWYWx1ZXMiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiZGFuZ2VyIiksIGZ1bGxfd2lkdGggPSBGKQ0KDQojIC0tLSAyLiBJZGVudGlmaWthc2kgRHVwbGlrYXQgLS0tDQojIE1lbmdoaXR1bmcganVtbGFoIGJhcmlzIHlhbmcgbWVydXBha2FuIGR1cGxpa2F0DQp0b3RhbF9kdXBsaWthdCA8LSBzdW0oZHVwbGljYXRlZChtYWluX2RhdGFzZXQpKQ0KDQojIE1lbmFtcGlsa2FuIGhhc2lsIGR1cGxpa2F0IGRhbGFtIGJlbnR1ayB0ZWtzIGF0YXUgYm94DQppZih0b3RhbF9kdXBsaWthdCA+IDApIHsNCiAgcHJpbnQocGFzdGUoIkRpdGVtdWthbiIsIHRvdGFsX2R1cGxpa2F0LCAiYmFyaXMgZHVwbGlrYXQgZGFsYW0gZGF0YXNldC4iKSkNCiAgIyBNZW5hbXBpbGthbiBiYXJpcyB5YW5nIGR1cGxpa2F0IHVudHVrIGRpcGVyaWtzYQ0KICBkdXBsaWthdF9kYXRhIDwtIG1haW5fZGF0YXNldFtkdXBsaWNhdGVkKG1haW5fZGF0YXNldCksIF0NCn0gZWxzZSB7DQogIHByaW50KCJUaWRhayBhZGEgYmFyaXMgZHVwbGlrYXQgeWFuZyB0ZXJkZXRla3NpLiIpDQp9DQpgYGANCg0KMS4gSW5jb25zaXN0ZW5jeSAoSW5rb25zaXN0ZW5zaSBEYXRhKQ0KVGVyZGFwYXQgcGVyYmVkYWFuIGZvcm1hdCBkYW4gcGVudWxpc2FuIHRla3MgdW50dWsgaW5mb3JtYXNpIHlhbmcgc2VoYXJ1c255YSBzYW1hLiBIYWwgaW5pIGFrYW4gbWVueXVsaXRrYW4gcHJvc2VzIHBlbmdlbG9tcG9rYW4gKGdyb3VwaW5nKSBkYXRhLg0KDQpGb3JtYXQgVGFuZ2dhbDogQWRhIGtvbG9tIHRhbmdnYWwgeWFuZyBtZW5nZ3VuYWthbiBmb3JtYXQgWVlZWS1NTS1ERCwgREQvTU0vWVlZWSwgZGFuIE1NLURELVlZWVkuIENvbnRvaDogMjAyNC0wNC0xOSwgMjIvMDUvMjAyNCwgZGFuIDEwLTI4LTIwMjQuDQoNClBlbnVsaXNhbiBUZWtzIChDYXNlIFNlbnNpdGl2aXR5KTogTmFtYSBwbGF0Zm9ybSBhdGF1IGthdGVnb3JpIGRpdHVsaXMgZGVuZ2FuIGNhcmEgYmVyYmVkYS1iZWRhLCBzZXBlcnRpIFRva29wZWRpYSwgdG9rb3BlZGlhLCBUaWtUb2sgU2hvcCwgZGFuIFRpa3RvayBTaG9wLg0KDQpTaW1ib2wgTWF0YSBVYW5nOiBQYWRhIGJlYmVyYXBhIGZpbGUgKHRlcnV0YW1hIC50eHQpLCBrb2xvbSBudW1lcmlrIHNlcGVydGkgZ3Jvc3Nfc2FsZXMgbWVuZ2FuZHVuZyB0ZWtzIHRhbWJhaGFuIHNlcGVydGkgIlJwIDQ4OC45MTgiLCBzZWRhbmdrYW4gZGkgZmlsZSBsYWluIGhhbnlhIGJlcnVwYSBhbmdrYS4NCg0KMi4gTWlzc2luZyBWYWx1ZXMgKERhdGEgSGlsYW5nKQ0KRGl0ZW11a2FuIGJhbnlhayBkYXRhIHlhbmcga29zb25nIGF0YXUgdGlkYWsgdGVyaXNpIGRpIGJlYmVyYXBhIGtvbG9tIHBlbnRpbmcuDQoNCktvbG9tIGN1c3RvbWVyX3JhdGluZzogQmFueWFrIGJhcmlzIHlhbmcgbWVtaWxpa2kgbmlsYWkgbnVsbCBhdGF1IGtvc29uZy4NCg0KS29sb20gdm91Y2hlcl9jb2RlOiBCYW55YWsgdHJhbnNha3NpIHlhbmcgdGlkYWsgbWVtaWxpa2kga29kZSB2b3VjaGVyIG5hbXVuIHRpZGFrIGRpYmVyaWthbiBuaWxhaSBzdGFuZGFyIChzZXBlcnRpICJOb25lIikuDQoNCktvbG9tIHByaW9yaXR5X2ZsYWc6IERpdGVtdWthbiBuaWxhaSBrb3NvbmcgKGVtcHR5IHN0cmluZykgZGkgYmViZXJhcGEgcmVjb3JkIGRhcmkgZmlsZSBYTUwgZGFuIEpTT04uDQoNCjMuIER1cGxpY2F0ZSBEYXRhIChEdXBsaWthc2kpDQpUZXJkYXBhdCBiYXJpcyBkYXRhIHlhbmcgaWRlbnRpayBhdGF1IG1lbWlsaWtpIE9yZGVyIElEIHlhbmcgc2FtYSB5YW5nIG11bmN1bCBiZXJ1bGFuZyBrYWxpIGRpIGJlcmJhZ2FpIGZvcm1hdCBmaWxlLg0KDQpLYXJlbmEgZmlsZSBiZXJhc2FsIGRhcmkgZm9ybWF0IHlhbmcgYmVyYmVkYSAoQ1NWLCBKU09OLCBYTUwpIG5hbXVuIGJlcmlzaSBkYXRhIHRyYW5zYWtzaSB5YW5nIHNhbWEsIHNhYXQgZGlnYWJ1bmdrYW4gbXVuY3VsIGJhcmlzIGR1cGxpa2F0LiBDb250b2hueWEsIHRyYW5zYWtzaSBkZW5nYW4gSUQgT1JEMDA2MTIgbXVuY3VsIGRpIGhhbXBpciBzZW11YSBmaWxlIGRlbmdhbiBpbmZvcm1hc2kgeWFuZyBzYW1hIHBlcnNpcy4NCg0KNC4gRGF0YSBPdXQgb2YgUmFuZ2UgLyBJbnZhbGlkIChOaWxhaSBUaWRhayBMb2dpcykNCkRpdGVtdWthbiBuaWxhaSBudW1lcmlrIHlhbmcgdGlkYWsgbWFzdWsgYWthbCBqaWthIGRpdGluamF1IGRhcmkgbG9naWthIGJpc25pcy4NCg0KTmV0IFNhbGVzIE5lZ2F0aWY6IFBhZGEgcmVjb3JkIE9SRDAxNzA2LCBkaXRlbXVrYW4gbmlsYWkgbmV0X3NhbGVzIHNlYmVzYXIgLTM5ODY0OC4wLiBTZWNhcmEgbG9naWthLCBuaWxhaSBwZW5qdWFsYW4gYmVyc2loIHRpZGFrIG11bmdraW4gbmVnYXRpZiBrZWN1YWxpIGppa2Egc2lzdGVtIHJldHVyIHRpZGFrIGRpa2Vsb2xhIGRlbmdhbiBiZW5hciBkYWxhbSBkYXRhIHRlcnNlYnV0Lg0KDQotLS0NCg0KIyBTRUNUSU9OIEMg4oCTIERBVEEgQ0xFQU5JTkcNCg0KYGBge3J9DQojIEZ1bmdzaSBzdGFuZGFyZGlzYXNpIG1lbmdndW5ha2FuIGxvZ2lrYSBJRg0Kc3RhbmRhcmRpemVfcGxhdGZvcm0gPC0gZnVuY3Rpb24ocCkgew0KICAjIE1lbmdoaWxhbmdrYW4gc3Bhc2kgZGkgYXdhbC9ha2hpciBkYW4gbWVuZ3ViYWgga2UgbG93ZXJjYXNlIHVudHVrIG1lbXBlcm11ZGFoIHBlbmdlY2VrYW4NCiAgcF9jbGVhbiA8LSB0cmltd3ModG9sb3dlcihwKSkNCiAgDQogIGlmIChwX2NsZWFuID09ICJzaG9wZWUiIHwgcF9jbGVhbiA9PSAiIHNob3BlZSAiKSB7DQogICAgcmV0dXJuKCJTaG9wZWUiKQ0KICB9IGVsc2UgaWYgKHBfY2xlYW4gPT0gInRva3BlZCIgfCBwX2NsZWFuID09ICJ0b2tvcGVkaWEiKSB7DQogICAgcmV0dXJuKCJUb2tvcGVkaWEiKQ0KICB9IGVsc2UgaWYgKHBfY2xlYW4gPT0gInRpa3RvayBzaG9wIiB8IHBfY2xlYW4gPT0gInRpa3Rva3Nob3AiKSB7DQogICAgcmV0dXJuKCJUaWtUb2sgU2hvcCIpDQogIH0gZWxzZSBpZiAocF9jbGVhbiA9PSAibGF6YWRhIikgew0KICAgIHJldHVybigiTGF6YWRhIikNCiAgfSBlbHNlIGlmIChwX2NsZWFuID09ICJibGlibGkiKSB7DQogICAgcmV0dXJuKCJCbGlibGkiKQ0KICB9IGVsc2Ugew0KICAgICMgTWVuZ2VtYmFsaWthbiB0ZWtzIGFzbGkgZGVuZ2FuIGh1cnVmIGthcGl0YWwgZGkgYXdhbCBqaWthIHRpZGFrIGFkYSBrZWNvY29rYW4ga2h1c3VzDQogICAgcmV0dXJuKHRvb2xzOjp0b1RpdGxlQ2FzZShwX2NsZWFuKSkNCiAgfQ0KfQ0KDQojIE1lbmVyYXBrYW4gZnVuZ3NpIGtlIGtvbG9tIHBsYXRmb3JtIGRpIGRhdGFzZXQgdXRhbWENCm1haW5fZGF0YXNldCRwbGF0Zm9ybV9jbGVhbmVkIDwtIHNhcHBseShtYWluX2RhdGFzZXQkcGxhdGZvcm0sIHN0YW5kYXJkaXplX3BsYXRmb3JtKQ0KYGBgDQoNCmBgYHtyIGNsZWFuaW5nX3BsYXRmb3JtfQ0KIyBNZW5nYW1iaWwgc2FtcGVsIGRhdGEgc2ViZWx1bSBkYW4gc2VzdWRhaCB1bnR1ayBwZW1idWt0aWFuDQpwbGF0Zm9ybV9jb21wYXJpc29uIDwtIG1haW5fZGF0YXNldCAlPiUNCiAgc2VsZWN0KHBsYXRmb3JtLCBwbGF0Zm9ybV9jbGVhbmVkKSAlPiUNCiAgZGlzdGluY3QoKSAlPiUNCiAgaGVhZCgxMCkNCg0Ka2FibGUocGxhdGZvcm1fY29tcGFyaXNvbiwgDQogICAgICBjb2wubmFtZXMgPSBjKCJQbGF0Zm9ybSBBc2xpIiwgIlBsYXRmb3JtIFRlcnN0YW5kYXJkaXNhc2kiKSwNCiAgICAgIGNhcHRpb24gPSAiSGFzaWwgU3RhbmRhcmRpc2FzaSBOYW1hIFBsYXRmb3JtIG1lbmdndW5ha2FuIExvZ2lrYSBJRiIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwgDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYsIA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIpICU+JQ0KICBjb2x1bW5fc3BlYygyLCBib2xkID0gVCwgY29sb3IgPSAiIzJjM2U1MCIpDQpgYGANCg0KYGBge3J9DQojIEZ1bmdzaSB1bnR1ayBtZW1iZXJzaWhrYW4gbmlsYWkgaGFyZ2Evc2FsZXMNCmNsZWFuX2N1cnJlbmN5IDwtIGZ1bmN0aW9uKHgpIHsNCiAgIyAxLiBDZWsgamlrYSBpbnB1dCBhZGFsYWgga2FyYWt0ZXIgZGFuIG1lbmdhbmR1bmcgIlJwIg0KICBpZiAoaXMuY2hhcmFjdGVyKHgpKSB7DQogICAgIyBIYXB1cyAiUnAiLCBzcGFzaSwgZGFuIHRpdGlrIHJpYnVhbg0KICAgIHggPC0gZ3N1YigiUnAiLCAiIiwgeCkNCiAgICB4IDwtIGdzdWIoIlxcLiIsICIiLCB4KQ0KICAgIHggPC0gZ3N1YigiLCIsICIiLCB4KSAjIEphZ2EtamFnYSBqaWthIGFkYSBrb21hDQogICAgeCA8LSBhcy5udW1lcmljKHRyaW13cyh4KSkNCiAgfQ0KICANCiAgIyAyLiBMb2dpa2EgSUYgdW50dWsgbWVuYW5nYW5pIG5pbGFpIG5lZ2F0aWYNCiAgaWYgKCFpcy5uYSh4KSAmJiB4IDwgMCkgew0KICAgIHJldHVybigwKQ0KICB9IGVsc2Ugew0KICAgIHJldHVybih4KQ0KICB9DQp9DQoNCiMgTWVuZXJhcGthbiBmdW5nc2kga2Uga29sb20gZ3Jvc3Nfc2FsZXMgZGFuIG5ldF9zYWxlcw0KbWFpbl9kYXRhc2V0JGdyb3NzX3NhbGVzX2NsZWFuZWQgPC0gc2FwcGx5KG1haW5fZGF0YXNldCRncm9zc19zYWxlcywgY2xlYW5fY3VycmVuY3kpDQptYWluX2RhdGFzZXQkbmV0X3NhbGVzX2NsZWFuZWQgPC0gc2FwcGx5KG1haW5fZGF0YXNldCRuZXRfc2FsZXMsIGNsZWFuX2N1cnJlbmN5KQ0KYGBgDQoNCmBgYHtyIGNsZWFuaW5nX3NhbGVzfQ0KIyBNZW5hbXBpbGthbiBiYXJpcyB5YW5nIHNlYmVsdW1ueWEgbWVtaWxpa2kgbWFzYWxhaCAoTmVnYXRpZiBhdGF1IGZvcm1hdCBScCkNCnNhbGVzX2NoZWNrIDwtIG1haW5fZGF0YXNldCAlPiUNCiAgc2VsZWN0KG9yZGVyX2lkLCBncm9zc19zYWxlcywgZ3Jvc3Nfc2FsZXNfY2xlYW5lZCwgbmV0X3NhbGVzLCBuZXRfc2FsZXNfY2xlYW5lZCkgJT4lDQogIGZpbHRlcihncmVwbCgiUnAiLCBncm9zc19zYWxlcykgfCBuZXRfc2FsZXMgPCAwKQ0KDQprYWJsZShzYWxlc19jaGVjaywgDQogICAgICBjb2wubmFtZXMgPSBjKCJPcmRlciBJRCIsICJHcm9zcyAoTGFtYSkiLCAiR3Jvc3MgKEJhcnUpIiwgIk5ldCAoTGFtYSkiLCAiTmV0IChCYXJ1KSIpLA0KICAgICAgY2FwdGlvbiA9ICJIYXNpbCBQZW1iZXJzaWhhbiBOaWxhaSBTYWxlcyAoU3RhbmRhcmRpc2FzaSBScCBkYW4gSGFuZGxpbmcgTmlsYWkgTmVnYXRpZikiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwgZnVsbF93aWR0aCA9IEYpICU+JQ0KICBjb2x1bW5fc3BlYyhjKDMsIDUpLCBib2xkID0gVCwgY29sb3IgPSAiZGFya2dyZWVuIikNCmBgYA0KDQpgYGB7cn0NCiMgMS4gTWVuZ2hpdHVuZyBuaWxhaSBtZWRpYW4gdW50dWsgY3VzdG9tZXJfcmF0aW5nIChhYmFpa2FuIE5BIHNhYXQgbWVuZ2hpdHVuZykNCnJhdGluZ19tZWRpYW4gPC0gbWVkaWFuKG1haW5fZGF0YXNldCRjdXN0b21lcl9yYXRpbmcsIG5hLnJtID0gVFJVRSkNCg0KIyAyLiBGdW5nc2kgcGVtYmVyc2loYW4gZGVuZ2FuIGxvZ2lrYSBJRg0KY2xlYW5fbWlzc2luZ192YWx1ZXMgPC0gZnVuY3Rpb24oZGYpIHsNCiAgDQogICMgTG9vcGluZyBiYXJpcyB1bnR1ayBtZW5lcmFwa2FuIGxvZ2lrYSBJRg0KICBmb3IgKGkgaW4gMTpucm93KGRmKSkgew0KICAgIA0KICAgICMgTG9naWthIElGIHVudHVrIHBheW1lbnRfbWV0aG9kDQogICAgaWYgKGlzLm5hKGRmJHBheW1lbnRfbWV0aG9kW2ldKSB8fCBkZiRwYXltZW50X21ldGhvZFtpXSA9PSAiIiB8fCBkZiRwYXltZW50X21ldGhvZFtpXSA9PSAibnVsbCIpIHsNCiAgICAgIGRmJHBheW1lbnRfbWV0aG9kW2ldIDwtICJVbmtub3duIg0KICAgIH0NCiAgICANCiAgICAjIExvZ2lrYSBJRiB1bnR1ayBjdXN0b21lcl9yYXRpbmcNCiAgICBpZiAoaXMubmEoZGYkY3VzdG9tZXJfcmF0aW5nW2ldKSB8fCBkZiRjdXN0b21lcl9yYXRpbmdbaV0gPT0gIiIgfHwgZGYkY3VzdG9tZXJfcmF0aW5nW2ldID09ICJudWxsIikgew0KICAgICAgZGYkY3VzdG9tZXJfcmF0aW5nW2ldIDwtIHJhdGluZ19tZWRpYW4NCiAgICB9DQogIH0NCiAgcmV0dXJuKGRmKQ0KfQ0KDQojIEVrc2VrdXNpIGZ1bmdzaQ0KbWFpbl9kYXRhc2V0IDwtIGNsZWFuX21pc3NpbmdfdmFsdWVzKG1haW5fZGF0YXNldCkNCmBgYA0KDQpgYGB7ciBkaXNwbGF5X21pc3NpbmdfY2xlYW5pbmd9DQojIE1lbmdhbWJpbCBzYW1wZWwgZGF0YSB5YW5nIHNlYmVsdW1ueWEgTkEgdW50dWsgcGVtYnVrdGlhbg0KaGFzaWxfbWlzc2luZ19jbGVhbiA8LSBtYWluX2RhdGFzZXQgJT4lDQogIGZpbHRlcihwYXltZW50X21ldGhvZCA9PSAiVW5rbm93biIgfCBjdXN0b21lcl9yYXRpbmcgPT0gcmF0aW5nX21lZGlhbikgJT4lDQogIHNlbGVjdChvcmRlcl9pZCwgcGF5bWVudF9tZXRob2QsIGN1c3RvbWVyX3JhdGluZykgJT4lDQogIGhlYWQoNSkNCg0Ka2FibGUoaGFzaWxfbWlzc2luZ19jbGVhbiwgDQogICAgICBjYXB0aW9uID0gIkhhc2lsIFBlbmdpc2lhbiBNaXNzaW5nIFZhbHVlcyBwYWRhIFBheW1lbnQgTWV0aG9kIGRhbiBDdXN0b21lciBSYXRpbmciKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwgZnVsbF93aWR0aCA9IEYpICU+JQ0KICBjb2x1bW5fc3BlYygyOjMsIGJvbGQgPSBULCBjb2xvciA9ICJkYXJrYmx1ZSIpDQpgYGANCg0KYGBge3J9DQojIEZ1bmdzaSB1bnR1ayBzdGFuZGFyZGlzYXNpIHN0YXR1cyBwZXNhbmFuDQpzdGFuZGFyZGl6ZV9zdGF0dXMgPC0gZnVuY3Rpb24oc3RhdHVzKSB7DQogICMgTWVuZ2hpbGFuZ2thbiBzcGFzaSBkYW4gbWVuZ3ViYWgga2UgbG93ZXJjYXNlIHVudHVrIHBlbmdlY2VrYW4geWFuZyBha3VyYXQNCiAgcyA8LSB0cmltd3ModG9sb3dlcihzdGF0dXMpKQ0KICANCiAgIyBMb2dpa2EgSUYtRUxTRSB1bnR1ayBzdGFuZGFyZGlzYXNpDQogIGlmIChzID09ICJkZWxpdmVyZWQiIHwgcyA9PSAiY29tcGxldGVkIikgew0KICAgIHJldHVybigiQ29tcGxldGVkIikNCiAgfSBlbHNlIGlmIChzID09ICJjYW5jZWxsZWQiKSB7DQogICAgcmV0dXJuKCJDYW5jZWxsZWQiKQ0KICB9IGVsc2UgaWYgKHMgPT0gInJldHVybmVkIikgew0KICAgIHJldHVybigiUmV0dXJuZWQiKQ0KICB9IGVsc2UgaWYgKHMgPT0gInNoaXBwZWQiKSB7DQogICAgcmV0dXJuKCJTaGlwcGVkIikNCiAgfSBlbHNlIHsNCiAgICAjIE1lbmdlbWJhbGlrYW4gbmlsYWkgYXNsaSBkZW5nYW4ga2FwaXRhbCBkaSBhd2FsIGppa2EgdGlkYWsgYWRhIGtlY29jb2thbg0KICAgIHJldHVybih0b29sczo6dG9UaXRsZUNhc2UocykpDQogIH0NCn0NCg0KIyBNZW5lcmFwa2FuIGZ1bmdzaSBrZSBrb2xvbSBvcmRlcl9zdGF0dXMNCm1haW5fZGF0YXNldCRvcmRlcl9zdGF0dXNfY2xlYW5lZCA8LSBzYXBwbHkobWFpbl9kYXRhc2V0JG9yZGVyX3N0YXR1cywgc3RhbmRhcmRpemVfc3RhdHVzKQ0KYGBgDQoNCmBgYHtyIGNsZWFuaW5nX3N0YXR1c30NCiMgTWVuZ2FtYmlsIHNhbXBlbCBkYXRhIHVuaWsgdW50dWsgbWVudW5qdWtrYW4gaGFzaWwgcGVtYmVyc2loYW4NCnN0YXR1c19zdW1tYXJ5IDwtIG1haW5fZGF0YXNldCAlPiUNCiAgc2VsZWN0KG9yZGVyX3N0YXR1cywgb3JkZXJfc3RhdHVzX2NsZWFuZWQpICU+JQ0KICBkaXN0aW5jdCgpDQoNCmthYmxlKHN0YXR1c19zdW1tYXJ5LCANCiAgICAgIGNvbC5uYW1lcyA9IGMoIlN0YXR1cyBPcmlnaW5hbCIsICJTdGF0dXMgVGVyc3RhbmRhcmRpc2FzaSIpLA0KICAgICAgY2FwdGlvbiA9ICJUYWJlbCBTdGFuZGFyZGlzYXNpIE9yZGVyIFN0YXR1cyBtZW5nZ3VuYWthbiBMb2dpa2EgSUYtRUxTRSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBmdWxsX3dpZHRoID0gRikgJT4lDQogIGNvbHVtbl9zcGVjKDIsIGJvbGQgPSBULCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzI5ODBiOSIpDQpgYGANCg0KYGBge3J9DQojIDEuIFRlbnR1a2FuIGRhZnRhciBrb2xvbSB5YW5nIGFrYW4gZGliZXJzaWhrYW4NCmtvbG9tX3RhcmdldCA8LSBjKCJjYXRlZ29yeSIsICJwcm9kdWN0X25hbWUiLCAicmVnaW9uIikNCg0KIyAyLiBHdW5ha2FuIGxvb3BpbmcgdW50dWsgbWVtcHJvc2VzIGtvbG9tLWtvbG9tIHRlcnNlYnV0IHNla2FsaWd1cw0KZm9yIChrb2xvbSBpbiBrb2xvbV90YXJnZXQpIHsNCiAgDQogICMgTWVtYmVyc2loa2FuIHNwYXNpIGRpIGF3YWwvYWtoaXIgZGFuIG1lcmFwaWthbiBmb3JtYXQgdGVrcw0KICBtYWluX2RhdGFzZXRbW2tvbG9tXV0gPC0gc2FwcGx5KG1haW5fZGF0YXNldFtba29sb21dXSwgZnVuY3Rpb24oeCkgew0KICAgIA0KICAgICMgSGlsYW5na2FuIHNwYXNpIGJlcmxlYmloDQogICAgeF9jbGVhbiA8LSB0cmltd3MoeCkNCiAgICANCiAgICAjIFViYWggbWVuamFkaSBmb3JtYXQgUHJvcGVyL1RpdGxlIENhc2UgKEh1cnVmIGthcGl0YWwgZGkgYXdhbCBrYXRhKQ0KICAgICMgQ29udG9oOiAiaG9tZSBsaXZpbmciIC0+ICJIb21lIExpdmluZyINCiAgICB4X3N0YW5kYXJkIDwtIHRvb2xzOjp0b1RpdGxlQ2FzZSh0b2xvd2VyKHhfY2xlYW4pKQ0KICAgIA0KICAgIHJldHVybih4X3N0YW5kYXJkKQ0KICB9KQ0KfQ0KYGBgDQoNCmBgYHtyIGNsZWFuaW5nX2xvb3B9DQojIE1lbmFtcGlsa2FuIHNhbXBlbCBiZWJlcmFwYSBiYXJpcyB1bnR1ayBrb2xvbSB5YW5nIHRlbGFoIGRpcHJvc2VzIGxvb3BpbmcNCmhhc2lsX2xvb3BpbmcgPC0gbWFpbl9kYXRhc2V0ICU+JQ0KICBzZWxlY3QoYWxsX29mKGtvbG9tX3RhcmdldCkpICU+JQ0KICBkaXN0aW5jdCgpICU+JQ0KICBoZWFkKDYpDQoNCmthYmxlKGhhc2lsX2xvb3BpbmcsIA0KICAgICAgY2FwdGlvbiA9ICJIYXNpbCBQZW1iZXJzaWhhbiBLb2xvbSBDYXRlZ29yeSwgUHJvZHVjdCBOYW1lLCBkYW4gUmVnaW9uIG1lbmdndW5ha2FuIExvb3BpbmciKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIA0KICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGKSAlPiUNCiAgcm93X3NwZWMoMCwgYmFja2dyb3VuZCA9ICIjMzQ0OTVlIiwgY29sb3IgPSAid2hpdGUiKQ0KYGBgDQoNCi0tLQ0KDQojIFNFQ1RJT04gRCDigJMgQ09ORElUSU9OQUwgTE9HSUMNCg0KYGBge3J9DQojIEZ1bmdzaSB1bnR1ayBtZW5lbnR1a2FuIGthdGVnb3JpIEhpZ2ggVmFsdWUNCmNoZWNrX2hpZ2hfdmFsdWUgPC0gZnVuY3Rpb24oc2FsZXMpIHsNCiAgIyBMb2dpa2EgSUYtRUxTRSBzZXN1YWkgaW5zdHJ1a3NpIGJpc25pcw0KICBpZiAoIWlzLm5hKHNhbGVzKSAmJiBzYWxlcyA+IDEwMDAwMDApIHsNCiAgICByZXR1cm4oIlllcyIpDQogIH0gZWxzZSB7DQogICAgcmV0dXJuKCJObyIpDQogIH0NCn0NCg0KIyBNZW1idWF0IGtvbG9tIGJhcnUgaXNfaGlnaF92YWx1ZQ0KbWFpbl9kYXRhc2V0JGlzX2hpZ2hfdmFsdWUgPC0gc2FwcGx5KG1haW5fZGF0YXNldCRuZXRfc2FsZXNfY2xlYW5lZCwgY2hlY2tfaGlnaF92YWx1ZSkNCmBgYA0KDQpgYGB7ciBoaWdoX3ZhbHVlX2FuYWx5c2lzfQ0KIyBNZW5hbXBpbGthbiBzYW1wZWwgZGF0YSB5YW5nIG1lbWlsaWtpIGthdGVnb3JpICJZZXMiIGRhbiAiTm8iDQpoaWdoX3ZhbHVlX3N1bW1hcnkgPC0gbWFpbl9kYXRhc2V0ICU+JQ0KICBzZWxlY3Qob3JkZXJfaWQsIHBsYXRmb3JtLCBuZXRfc2FsZXNfY2xlYW5lZCwgaXNfaGlnaF92YWx1ZSkgJT4lDQogIGZpbHRlcihpc19oaWdoX3ZhbHVlID09ICJZZXMiIHwgb3JkZXJfaWQgPT0gIk9SRDAwNjEyIikgJT4lDQogIGhlYWQoNikNCg0Ka2FibGUoaGlnaF92YWx1ZV9zdW1tYXJ5LCANCiAgICAgIGNvbC5uYW1lcyA9IGMoIk9yZGVyIElEIiwgIlBsYXRmb3JtIiwgIk5ldCBTYWxlcyIsICJIaWdoIFZhbHVlIEluZGljYXRvciIpLA0KICAgICAgY2FwdGlvbiA9ICJLbGFzaWZpa2FzaSBUcmFuc2Frc2kgSGlnaCBWYWx1ZSAoPiAxLjAwMC4wMDApIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksIGZ1bGxfd2lkdGggPSBGKSAlPiUNCiAgY29sdW1uX3NwZWMoNCwgYm9sZCA9IFQsIA0KICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShoaWdoX3ZhbHVlX3N1bW1hcnkkaXNfaGlnaF92YWx1ZSA9PSAiWWVzIiwgIiMyN2FlNjAiLCAiIzdmOGM4ZCIpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBGdW5nc2kgZGVuZ2FuIGxvZ2lrYSBOZXN0ZWQgSUYgdW50dWsgbWVuZW50dWthbiBwcmlvcml0YXMNCmNoZWNrX29yZGVyX3ByaW9yaXR5IDwtIGZ1bmN0aW9uKHNhbGVzKSB7DQogIA0KICAjIE5lc3RlZCBJRiBMb2dpYw0KICBpZiAoIWlzLm5hKHNhbGVzKSkgew0KICAgIGlmIChzYWxlcyA+IDEwMDAwMDApIHsNCiAgICAgIHJldHVybigiSGlnaCIpDQogICAgfSBlbHNlIHsNCiAgICAgICMgTGV2ZWwga2VkdWEgZGFyaSBJRiAoTmVzdGVkKQ0KICAgICAgaWYgKHNhbGVzID49IDUwMDAwMCkgew0KICAgICAgICByZXR1cm4oIk1lZGl1bSIpDQogICAgICB9IGVsc2Ugew0KICAgICAgICByZXR1cm4oIkxvdyIpDQogICAgICB9DQogICAgfQ0KICB9IGVsc2Ugew0KICAgIHJldHVybigiTG93IikgIyBEZWZhdWx0IHVudHVrIG5pbGFpIHlhbmcgdGlkYWsgdmFsaWQNCiAgfQ0KfQ0KDQojIE1lbWJ1YXQga29sb20gYmFydSBvcmRlcl9wcmlvcml0eQ0KbWFpbl9kYXRhc2V0JG9yZGVyX3ByaW9yaXR5IDwtIHNhcHBseShtYWluX2RhdGFzZXQkbmV0X3NhbGVzX2NsZWFuZWQsIGNoZWNrX29yZGVyX3ByaW9yaXR5KQ0KYGBgDQoNCmBgYHtyIHByaW9yaXR5X2FuYWx5c2lzfQ0KIyBNZW5nYW1iaWwgc2FtcGVsIHVudHVrIHNldGlhcCBrYXRlZ29yaSAoSGlnaCwgTWVkaXVtLCBMb3cpDQpwcmlvcml0eV9zdW1tYXJ5IDwtIG1haW5fZGF0YXNldCAlPiUNCiAgZ3JvdXBfYnkob3JkZXJfcHJpb3JpdHkpICU+JQ0KICBzbGljZV9oZWFkKG4gPSAyKSAlPiUNCiAgc2VsZWN0KG9yZGVyX2lkLCBuZXRfc2FsZXNfY2xlYW5lZCwgb3JkZXJfcHJpb3JpdHkpDQoNCmthYmxlKHByaW9yaXR5X3N1bW1hcnksIA0KICAgICAgY29sLm5hbWVzID0gYygiT3JkZXIgSUQiLCAiTmV0IFNhbGVzIiwgIk9yZGVyIFByaW9yaXR5IiksDQogICAgICBjYXB0aW9uID0gIktsYXNpZmlrYXNpIE9yZGVyIFByaW9yaXR5IG1lbmdndW5ha2FuIE5lc3RlZCBJRiIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBmdWxsX3dpZHRoID0gRikgJT4lDQogIGNvbHVtbl9zcGVjKDMsIGJvbGQgPSBULCANCiAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICAgICBiYWNrZ3JvdW5kID0gc3BlY19jb2xvcigxOm5yb3cocHJpb3JpdHlfc3VtbWFyeSksIGVuZCA9IDAuNywgb3B0aW9uID0gIkQiKSkNCmBgYA0KDQpgYGB7cn0NCiMgRnVuZ3NpIHVudHVrIG1lbmVudHVrYW4gdmFsaWRpdGFzIHRyYW5zYWtzaQ0KY2hlY2tfdHJhbnNhY3Rpb25fdmFsaWRpdHkgPC0gZnVuY3Rpb24oc3RhdHVzKSB7DQogICMgTG9naWthIElGLUVMU0Ugc2VzdWFpIGluc3RydWtzaQ0KICBpZiAoc3RhdHVzID09ICJDYW5jZWxsZWQiKSB7DQogICAgcmV0dXJuKCJJbnZhbGlkIikNCiAgfSBlbHNlIHsNCiAgICByZXR1cm4oIlZhbGlkIikNCiAgfQ0KfQ0KDQojIE1lbWJ1YXQga29sb20gYmFydSB2YWxpZF90cmFuc2FjdGlvbg0KbWFpbl9kYXRhc2V0JHZhbGlkX3RyYW5zYWN0aW9uIDwtIHNhcHBseShtYWluX2RhdGFzZXQkb3JkZXJfc3RhdHVzX2NsZWFuZWQsIGNoZWNrX3RyYW5zYWN0aW9uX3ZhbGlkaXR5KQ0KYGBgDQoNCmBgYHtyIHRyYW5zYWN0aW9uX3ZhbGlkaXR5X3JlcG9ydH0NCiMgTWVuZ2FtYmlsIHNhbXBlbCBkYXRhIHVudHVrIG1lbmFtcGlsa2FuIGtlZHVhIGthdGVnb3JpIChWYWxpZCAmIEludmFsaWQpDQp2YWxpZGl0eV9zdW1tYXJ5IDwtIG1haW5fZGF0YXNldCAlPiUNCiAgc2VsZWN0KG9yZGVyX2lkLCBvcmRlcl9zdGF0dXNfY2xlYW5lZCwgdmFsaWRfdHJhbnNhY3Rpb24pICU+JQ0KICBmaWx0ZXIodmFsaWRfdHJhbnNhY3Rpb24gPT0gIkludmFsaWQiIHwgb3JkZXJfaWQgPT0gIk9SRDAwNjEyIikgJT4lDQogIGhlYWQoNSkNCg0Ka2FibGUodmFsaWRpdHlfc3VtbWFyeSwgDQogICAgICBjb2wubmFtZXMgPSBjKCJPcmRlciBJRCIsICJTdGF0dXMgUGVzYW5hbiIsICJTdGF0dXMgVmFsaWRhc2kiKSwNCiAgICAgIGNhcHRpb24gPSAiVmFsaWRhc2kgVHJhbnNha3NpIEJlcmRhc2Fya2FuIFN0YXR1cyBQZXNhbmFuIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksIGZ1bGxfd2lkdGggPSBGKSAlPiUNCiAgY29sdW1uX3NwZWMoMywgYm9sZCA9IFQsIA0KICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgIGJhY2tncm91bmQgPSBpZmVsc2UodmFsaWRpdHlfc3VtbWFyeSR2YWxpZF90cmFuc2FjdGlvbiA9PSAiVmFsaWQiLCAiIzI3YWU2MCIsICIjZTc0YzNjIikpDQpgYGANCg0KLS0tDQoNCiMgU0VDVElPTiBFIOKAkyBBTkFMWVRJQ0FMIFRISU5LSU5HDQoNCjEuIFBsYXRmb3JtIE1hbmEgeWFuZyBQYWxpbmcgRG9taW5hbj8NCkJlcmRhc2Fya2FuIGp1bWxhaCB0cmFuc2Frc2kgeWFuZyB0ZXJjYXRhdCBkaSBkYXRhc2V0IGdhYnVuZ2FuOg0KDQpQbGF0Zm9ybSBEb21pbmFuOiBUb2tvcGVkaWENCg0KQW5hbGlzaXM6IFNldGVsYWggZGlsYWt1a2FuIHN0YW5kYXJkaXNhc2kgKG1lbmdnYWJ1bmdrYW4gInRva3BlZCIsICJ0b2tvcGVkaWEiLCBkYW4gIlRva29wZWRpYSIpLCBwbGF0Zm9ybSBpbmkgbWVtaWxpa2kgZnJla3VlbnNpIGtlbXVuY3VsYW4gdGVydGluZ2dpIGRpYmFuZGluZ2thbiBwbGF0Zm9ybSBsYWluIHNlcGVydGkgU2hvcGVlIGF0YXUgVGlrVG9rIFNob3AuIEhhbCBpbmkgbWVudW5qdWtrYW4gYmFod2Egc2ViYWdpYW4gYmVzYXIgYWt0aXZpdGFzIHBlbmp1YWxhbiBkYWxhbSBkYXRhc2V0IGluaSBiZXJhc2FsIGRhcmkgZWtvc2lzdGVtIFRva29wZWRpYS4NCg0KMi4gQ2F0ZWdvcnkgTWFuYSB5YW5nIFBhbGluZyBTZXJpbmcgTXVuY3VsPw0KQmVyZGFzYXJrYW4gZnJla3VlbnNpIGRhdGEgcGFkYSBrb2xvbSBjYXRlZ29yeSB5YW5nIHRlbGFoIGRpcmFwaWthbjoNCg0KS2F0ZWdvcmkgVGVycG9wdWxlcjogRWxlY3Ryb25pY3MgKEVsZWt0cm9uaWspDQoNCkFuYWxpc2lzOiBLYXRlZ29yaSBpbmkgcGFsaW5nIGtvbnNpc3RlbiBtdW5jdWwgZGkgYmVyYmFnYWkgZm9ybWF0IGZpbGUgKENTViwgSlNPTiwgWE1MKS4gUHJvZHVrIHNlcGVydGkgIlBvd2VyIEJhbmsiIG1lbmphZGkgc2FsYWggc2F0dSBwZW5kb3JvbmcgdXRhbWEgZnJla3VlbnNpIGthdGVnb3JpIGluaSBkYWxhbSBkYXRhc2V0IGVjb21tZXJjZSB0ZXJzZWJ1dC4NCg0KMy4gU3RhdHVzIFRyYW5zYWtzaSBBcGEgeWFuZyBQYWxpbmcgQmFueWFrPw0KQmVyZGFzYXJrYW4ga29sb20gb3JkZXJfc3RhdHVzX2NsZWFuZWQgeWFuZyB0ZWxhaCBkaXN0YW5kYXJkaXNhc2k6DQoNClN0YXR1cyBUZXJiYW55YWs6IENvbXBsZXRlZA0KDQpBbmFsaXNpczogTWF5b3JpdGFzIHRyYW5zYWtzaSBkYWxhbSBkYXRhc2V0IG1lbWlsaWtpIHN0YXR1cyBiZXJoYXNpbC9zZWxlc2FpLiBNZXNraXB1biB0ZXJkYXBhdCBkYXRhIGRlbmdhbiBzdGF0dXMgQ2FuY2VsbGVkIGF0YXUgUmV0dXJuZWQsIGp1bWxhaG55YSBqYXVoIGxlYmloIHNlZGlraXQgZGliYW5kaW5na2FuIGRlbmdhbiB0cmFuc2Frc2kgeWFuZyBiZXJzdGF0dXMgQ29tcGxldGVkIChnYWJ1bmdhbiBkYXJpIHN0YXR1cyBhc2xpICJkZWxpdmVyZWQiIGRhbiAiY29tcGxldGVkIikuDQoNCmBgYHtyfQ0KIyAxLiBQbGF0Zm9ybSBEb21pbmFuDQpwbGF0Zm9ybV9yYW5rIDwtIHRhYmxlKG1haW5fZGF0YXNldCRwbGF0Zm9ybV9jbGVhbmVkKQ0KcGxhdGZvcm1fdG9wIDwtIG5hbWVzKHdoaWNoLm1heChwbGF0Zm9ybV9yYW5rKSkNCg0KIyAyLiBDYXRlZ29yeSBUZXJwb3B1bGVyDQpjYXRlZ29yeV9yYW5rIDwtIHRhYmxlKG1haW5fZGF0YXNldCRjYXRlZ29yeSkNCmNhdGVnb3J5X3RvcCA8LSBuYW1lcyh3aGljaC5tYXgoY2F0ZWdvcnlfcmFuaykpDQoNCiMgMy4gU3RhdHVzIFRlcmJhbnlhaw0Kc3RhdHVzX3JhbmsgPC0gdGFibGUobWFpbl9kYXRhc2V0JG9yZGVyX3N0YXR1c19jbGVhbmVkKQ0Kc3RhdHVzX3RvcCA8LSBuYW1lcyh3aGljaC5tYXgoc3RhdHVzX3JhbmspKQ0KDQojIE1lbWJ1YXQgdGFiZWwgcmluZ2thc2FuIGluc2lnaHQNCmluc2lnaHRfdGFibGUgPC0gZGF0YS5mcmFtZSgNCiAgUGVydGFueWFhbiA9IGMoIlBsYXRmb3JtIERvbWluYW4iLCAiS2F0ZWdvcmkgVGVycG9wdWxlciIsICJTdGF0dXMgVGVyYmFueWFrIiksDQogIEhhc2lsID0gYyhwbGF0Zm9ybV90b3AsIGNhdGVnb3J5X3RvcCwgc3RhdHVzX3RvcCkNCikNCg0Ka2FibGUoaW5zaWdodF90YWJsZSwgY2FwdGlvbiA9ICJTdW1tYXJ5IEluc2lnaHQgLSBTZWN0aW9uIEUiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwgZnVsbF93aWR0aCA9IEYpDQpgYGA=