Central Tendency

Statistik Deskriptif Menggunakan R

1 Impor Data

# --- 1. Install dan load library ---
#install.packages("readr")
#install.packages("DT")

library(readr)
library(DT)

# --- 2. Baca file CSV dari lokasi device ---
data_customer <- read.csv("data hahahahaha.csv")

# --- 3. Tampilkan tabel interaktif ---
datatable(
  data_customer,
  options = list(pageLength = 10),  # tampil 10 baris per halaman
  caption = "Tabel Interaktif Data CSV"
)

2 Menentukan Mean, Median, Modus

# --- 1. Baca file CSV dari lokasi device ---
data_customer <- read.csv("data hahahahaha.csv")

# --- 2. Cek struktur data ---
head(data_customer)
summary(data_customer)
##        X            CustomerID          Age           Gender         
##  Min.   :  1.00   Min.   :  1.00   Min.   :18.00   Length:200        
##  1st Qu.: 50.75   1st Qu.: 50.75   1st Qu.:31.00   Class :character  
##  Median :100.50   Median :100.50   Median :39.00   Mode  :character  
##  Mean   :100.50   Mean   :100.50   Mean   :39.99                     
##  3rd Qu.:150.25   3rd Qu.:150.25   3rd Qu.:48.25                     
##  Max.   :200.00   Max.   :200.00   Max.   :70.00                     
##  StoreLocation      ProductCategory    TotalPurchase    NumberOfVisits  
##  Length:200         Length:200         Min.   :  11.0   Min.   : 1.000  
##  Class :character   Class :character   1st Qu.:  68.0   1st Qu.: 4.000  
##  Mode  :character   Mode  :character   Median : 108.5   Median : 5.000  
##                                        Mean   : 211.8   Mean   : 5.165  
##                                        3rd Qu.: 381.2   3rd Qu.: 7.000  
##                                        Max.   :1128.0   Max.   :11.000  
##  FeedbackScore
##  Min.   :1.0  
##  1st Qu.:1.0  
##  Median :3.0  
##  Mean   :2.8  
##  3rd Qu.:4.0  
##  Max.   :5.0
# --- 3. Hitung mean, median, modus ---

# Data Usia (Age)

mean_val <- mean(data_customer$Age, na.rm = TRUE)
median_val <- median(data_customer$Age, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$Age), decreasing = TRUE)[1]))

# Data Total Pembelian (TotalPurchase)

mean_val <- mean(data_customer$TotalPurchase, na.rm = TRUE)
median_val <- median(data_customer$TotalPurchase, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$TotalPurchase), decreasing = TRUE)[1]))

# Data Jumlah Pengunjung (NumberOfVisits)

mean_val <- mean(data_customer$NumberOfVisits, na.rm = TRUE)
median_val <- median(data_customer$NumberOfVisits, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$NumberOfVisits), decreasing = TRUE)[1]))

# Data Umpan Balik (FeedbackScore)

mean_val <- mean(data_customer$FeedbackScore, na.rm = TRUE)
median_val <- median(data_customer$FeedbackScore, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$FeedbackScore), decreasing = TRUE)[1]))

# Data Jenis Kelamin Pembeli (Gender)

mean_val <- mean(data_customer$Gender, na.rm = TRUE)
## Warning in mean.default(data_customer$Gender, na.rm = TRUE): argument is not
## numeric or logical: returning NA
median_val <- median(data_customer$Gender, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$Gender), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion
# Data Kategori Produk (ProductCategory)

mean_val <- mean(data_customer$ProductCategory, na.rm = TRUE)
## Warning in mean.default(data_customer$ProductCategory, na.rm = TRUE): argument
## is not numeric or logical: returning NA
median_val <- median(data_customer$ProductCategory, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$ProductCategory), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion
# Data Lokasi Toko

mean_val <- mean(data_customer$StoreLocation, na.rm = TRUE)
## Warning in mean.default(data_customer$StoreLocation, na.rm = TRUE): argument is
## not numeric or logical: returning NA
median_val <- median(data_customer$StoreLocation, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$StoreLocation), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion

3 Visualisasi Data

# --- 1. Import library yang dibutuhkan ---
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# --- 2. Visualisasi dengan ggplot2 ---

# Data Usia (Age)

mean_val <- mean(data_customer$Age, na.rm = TRUE)
median_val <- median(data_customer$Age, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$Age), decreasing = TRUE)[1]))

ggplot(data_customer, aes(x = Age)) +
  geom_histogram(aes(y = after_stat(density)), 
                 binwidth = 2, 
                 fill = "#5ab4ac", 
                 color = "white", 
                 alpha = 0.8) +
  geom_density(color = "#2b8cbe", linewidth = 1.3, alpha = 0.9) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 1.2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 1.2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 1.2, linetype = "dotdash") +
  labs(
    title = "Distribusi Data Usia Pelanggan",
    subtitle = "Menampilkan Mean, Median dan Modus",
    x = "Usia Pelanggan (Age)",
    y = "Kerapatan (Density)",
    color = "Measure"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "bottom"
  )

3.1 Interpretasi Visualisasi Data Usia Pelanggan

  1. Bentuk Distribusi:

Grafik menunjukkan distribusi usia yang agak miring ke kanan atau right-skewed. Artinya, sebagian besar pelanggan berada pada usia menengah sekitar 35–45 tahun, sedangkan ada beberapa pelanggan yang lebih tua hingga 70 tahun.

  1. Nilai Tendensi Sentral:

Mean atau rata-rata berada sedikit di kanan median, menunjukkan bahwa ada beberapa nilai usia tinggi yang menarik rata-rata ke kanan. Median berada di tengah kumpulan data, mewakili usia tipikal pelanggan. Mode atau modus berada di sebelah kiri sekitar usia belasan atau awal 20-an, menunjukkan bahwa kelompok usia muda paling sering muncul, meskipun bukan kelompok dominan dalam jumlah besar.

# Data Total Pembelian (TotalPurchase)

mean_val <- mean(data_customer$TotalPurchase, na.rm = TRUE)
median_val <- median(data_customer$TotalPurchase, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$TotalPurchase), decreasing = TRUE)[1]))

ggplot(data_customer, aes(x = TotalPurchase)) +
  geom_histogram(aes(y = after_stat(density)), 
                 bins = 30, fill = "#5ab4ac", color = "white", alpha = 0.8) +
  geom_density(color = "#2b8cbe", linewidth = 1.3, alpha = 0.9) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 1.2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 1.2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 1.2, linetype = "dotdash") +
  labs(title = "Distribusi Total Pembelian Pelanggan",
       subtitle = "Menampilkan Mean, Median dan Modus",
       x = "Total Pembelian (Total Purchase)", 
       y = "Kerapatan (Density)",
       color = "Measure") +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "bottom"
  )

3.2 Interpretasi Visualisasi Data Total Pembelian

  1. Bentuk Distribusi:

Distribusi total pembelian pelanggan terlihat sangat miring ke kanan (right-skewed). Hal ini menunjukkan bahwa sebagian besar pelanggan memiliki total pembelian rendah, namun terdapat beberapa pelanggan dengan pembelian sangat tinggi (outlier).

  1. Nilai Tendensi Sentral: Mean (rata-rata) berada lebih jauh di kanan median, menandakan adanya nilai ekstrem yang besar. Median berada di tengah sebagian besar data, merepresentasikan nilai pembelian tipikal pelanggan. Mode (modus) berada di area pembelian rendah, menunjukkan bahwa jumlah pelanggan dengan pembelian kecil paling sering muncul.
# Data Jumlah Pengunjung (NumberOfVisits)

mean_val <- mean(data_customer$NumberOfVisits, na.rm = TRUE)
median_val <- median(data_customer$NumberOfVisits, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$NumberOfVisits), decreasing = TRUE)[1]))

ggplot(data_customer, aes(x = NumberOfVisits)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 10,
                 fill = "#5ab4ac",
                 color = "white",
                 alpha = 0.8) +
  geom_density(color = "#2b8cbe", linewidth = 1.3, alpha = 0.9) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 1.2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 1.2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 1.2, linetype = "dotdash") +
  labs(title = "Distribusi Jumlah Pengunjung",
       subtitle = "Menampilkan Mean, Median, dan Modus",
       x = "Jumlah Pengunjung (Number of Visits)",
       y = "Kerapatan (Density)",
       color = "Measure") +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "bottom"
  )

3.3 Interpretasi Visualisasi Data Jumlah Pengunjung

  1. Bentuk Distribusi:

Distribusi jumlah pengunjung terlihat mendekati simetris (hampir normal). Kurva menunjukkan bentuk menyerupai lonceng (bell-shaped) dengan puncak di tengah, menandakan persebaran data yang seimbang antara sisi kiri dan kanan.

  1. Nilai Tendensi Sentral:

Mean, median, dan mode berada pada posisi yang hampir berdekatan, menandakan distribusi data yang seimbang tanpa outlier signifikan. Nilai ketiganya berpusat di sekitar angka 5–6 kali kunjungan, yang menjadi indikasi frekuensi kunjungan tipikal pelanggan.

# Data Umpan Balik (FeedbackScore)

mean_val <- mean(data_customer$FeedbackScore, na.rm = TRUE)
median_val <- median(data_customer$FeedbackScore, na.rm = TRUE)
mode_val <- as.numeric(names(sort(table(data_customer$FeedbackScore), decreasing = TRUE)[1]))

ggplot(data_customer, aes(x = FeedbackScore)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 5,
                 fill = "#5ab4ac",
                 color = "white",
                 alpha = 0.8) +
  geom_density(color = "#2b8cbe", linewidth = 1.3, alpha = 0.9) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 1.2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 1.2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 1.2, linetype = "dotdash") +
  labs(title = "Distribusi Skor Umpan Balik Pelanggan",
       subtitle = "Menampilkan Mean, Median, dan Modus",
       x = "Skor Umpan Balik (FeedbackScore)",
       y = "Kerapatan (Density)",
       color = "Measure") +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "bottom"
  )

3.4 Interpretasi Visualisasi Data Skor Umpan Balik

  1. Bentuk Distribusi:

Distribusi terlihat tidak simetris (sedikit miring ke kanan / right-skewed). Terlihat bahwa nilai modus (1) berada di sisi kiri grafik, menunjukkan sebagian pelanggan memberikan skor rendah, sementara skor tinggi (4–5) juga cukup sering muncul.

  1. Nilai Tendensi Sentral:

Mean (garis merah) berada di sekitar skor 2–3, Median (garis hijau) sedikit lebih tinggi dari mean, yaitu sekitar 3, Mode (garis biru) berada di skor 1, yaitu nilai yang paling sering muncul. Urutannya: Mode < Mean < Median, yang menandakan distribusi condong ke kanan.

# Data Jenis Kelamin Pembeli (Gender)

mean_val <- mean(data_customer$Gender, na.rm = TRUE)
## Warning in mean.default(data_customer$Gender, na.rm = TRUE): argument is not
## numeric or logical: returning NA
median_val <- median(data_customer$Gender, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$Gender), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion
gender_mode <- data_customer %>%
  count(Gender) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(Gender)
ggplot(data_customer, aes(x = Gender, fill = Gender)) +
  geom_bar(width = 0.6, alpha = 0.8) +
  geom_text(stat = "count", aes(label = after_stat(count)), 
            vjust = -0.3, size = 4) +
  labs(
    title = "Distribusi Gender Pembeli",
    subtitle = paste("Modus (Jenis Gender yang paling sering muncul):", gender_mode),
    x = "Jenis Kelamin (Gender)",
    y = "Jumlah Pengunjung (Number of Visits)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "none"
  )

3.5 Interpretasi Visualisasi Data Jenis Kelamin Pembeli

  1. Jenis Data:

Data Gender (Jenis Kelamin) bersifat kategori (nominal) — tidak memiliki urutan atau nilai numerik. Karena itu, ukuran tendensi sentral yang paling relevan adalah modus (mode), yaitu kategori yang paling sering muncul.

  1. Hasil Pengamatan:

Jumlah pelanggan laki-laki (M): 101 orang Jumlah pelanggan perempuan (F): 99 orang Selisihnya kecil (hanya 2 orang), sehingga distribusi antara laki-laki dan perempuan hampir seimbang.

  1. Nilai Tendensi Sentral:

Modus = “M” (Male) Artinya, jenis kelamin yang paling sering muncul dalam data pelanggan adalah laki-laki.

# Data Kategori Produk (ProductCategory)

mean_val <- mean(data_customer$ProductCategory, na.rm = TRUE)
## Warning in mean.default(data_customer$ProductCategory, na.rm = TRUE): argument
## is not numeric or logical: returning NA
median_val <- median(data_customer$ProductCategory, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$ProductCategory), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion
productcategory_mode <- data_customer %>%
  count(ProductCategory) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(ProductCategory)
ggplot(data_customer, aes(x = ProductCategory, fill = ProductCategory)) +
  geom_bar(width = 0.6, alpha = 0.8) +
  geom_text(stat = "count", aes(label = after_stat(count)), 
            vjust = -0.3, size = 4) +
  labs(
    title = "Distribusi Kategori Produk",
    subtitle = paste("Modus (Jenis Kategori Produk yang paling sering muncul):", productcategory_mode),
    x = "Kategori Produk (Product Category)",
    y = "Total Pembelian (Total Purchase)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "none"
  )

3.6 Interpretasi Visualisasi Data Kategori Produk

  1. Jenis Data:

Data kategori produk (Product Category) bersifat kategorikal nominal, karena hanya menunjukkan jenis tanpa urutan (Books, Clothing, Electronics, Home, Sports). Maka ukuran tendensi sentral yang paling tepat adalah modus (mode).

  1. Hasil Pengamatan:

Books: 37 pembelian Clothing: 47 pembelian Electronics: 38 pembelian Home: 33 pembelian Sports: 45 pembelian

  1. Nilai Tendensi Sentral:

Modus = “Clothing” (47 pembelian) Artinya, kategori produk yang paling sering dibeli pelanggan adalah produk pakaian (Clothing).

# Data Lokasi Toko (StoreLocation)

mean_val <- mean(data_customer$StoreLocation, na.rm = TRUE)
## Warning in mean.default(data_customer$StoreLocation, na.rm = TRUE): argument is
## not numeric or logical: returning NA
median_val <- median(data_customer$StoreLocation, na.rm = TRUE)
## Warning in mean.default(sort(x, partial = half + 0L:1L)[half + 0L:1L]):
## argument is not numeric or logical: returning NA
mode_val <- as.numeric(names(sort(table(data_customer$StoreLocation), decreasing = TRUE)[1]))
## Warning: NAs introduced by coercion
storelocation_mode <- data_customer %>%
  count(StoreLocation) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(StoreLocation)
ggplot(data_customer, aes(x = StoreLocation, fill = StoreLocation)) +
  geom_bar(width = 0.6, alpha = 0.8) +
  geom_text(stat = "count", aes(label = after_stat(count)), 
            vjust = -0.3, size = 4) +
  labs(
    title = "Distribusi Lokasi Toko",
    subtitle = "Modus Jenis Wilayah Toko yang paling sering muncul",
    x = "Lokasi Toko (Store Location)",
    y = "Jumlah Pengunjung (Number of Visits)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    legend.position = "none"
  )

3.7 Interpretasi Visualisasi Data Lokasi Toko

  1. Jenis Data:

Store Location bersifat data kategorikal nominal, maka ukuran tendensi sentral yang cocok adalah modus (mode) — yaitu kategori yang paling sering muncul.

  1. Hasil Pengamatan:

East: 51 North: 47 South: 51 West: 51 Terdapat tiga lokasi dengan frekuensi sama tertinggi, yaitu East, South, dan West.

  1. Nilai Tendensi Sentral:

Modus menunjukkan bahwa wilayah East, South, dan West memiliki jumlah pengunjung paling banyak dan seimbang. North sedikit lebih rendah, menandakan bahwa wilayah ini mungkin memiliki lebih sedikit aktivitas pelanggan. Distribusi yang hampir merata menandakan jaringan toko tersebar cukup seimbang antar wilayah, tanpa satu lokasi yang mendominasi signifikan.

4 Kesimpulan

  1. Sebagian besar pelanggan berada pada usia menengah.

  2. Total pembelian menunjukkan sebaran tidak merata dengan sedikit pelanggan yang berbelanja sangat banyak.

  3. Jumlah kunjungan dan skor umpan balik cenderung merata antar pelanggan.

  4. Pelanggan didominasi oleh laki-laki.

  5. Kategori produk yang paling sering dibeli adalah Clothing (pakaian).

  6. Lokasi toko dengan pengunjung terbanyak berada di wilayah East, South, dan West.

LS0tDQp0aXRsZTogIkNlbnRyYWwgVGVuZGVuY3kiDQpzdWJ0aXRsZTogIlN0YXRpc3RpayBEZXNrcmlwdGlmIE1lbmdndW5ha2FuIFIiDQphdXRob3I6DQotICAgIktFTE9NUE9LIDUiDQotICAgIktheWxhIEFwcmlsaWEiDQotICAgIkphbnVhcmlhIFRlcmVuc2luaGEiDQotICAgIk9jdGF2aWEgTWFpYSBSZWdvIg0KLSAgICJBZGFtIFJpY2hpZSBXaWpheWEiDQotICAgIkFuZHJlIg0KLSAgICJNb3JyaXMgQWxleGFuZHJpYSBQYW5nYXJpYnVhbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246DQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICB0aHVtYm5haWxzOiB0cnVlDQogICAgbGlnaHRib3g6IHRydWUNCiAgICBnYWxsZXJ5OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgbGliX2RpcjogbGlicw0KICAgIGRmX3ByaW50OiAicGFnZWQiDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyINCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQojICBJbXBvciBEYXRhDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyAtLS0gMS4gSW5zdGFsbCBkYW4gbG9hZCBsaWJyYXJ5IC0tLQ0KI2luc3RhbGwucGFja2FnZXMoInJlYWRyIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJEVCIpDQoNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KERUKQ0KDQojIC0tLSAyLiBCYWNhIGZpbGUgQ1NWIGRhcmkgbG9rYXNpIGRldmljZSAtLS0NCmRhdGFfY3VzdG9tZXIgPC0gcmVhZC5jc3YoImRhdGEgaGFoYWhhaGFoYS5jc3YiKQ0KDQojIC0tLSAzLiBUYW1waWxrYW4gdGFiZWwgaW50ZXJha3RpZiAtLS0NCmRhdGF0YWJsZSgNCiAgZGF0YV9jdXN0b21lciwNCiAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSwgICMgdGFtcGlsIDEwIGJhcmlzIHBlciBoYWxhbWFuDQogIGNhcHRpb24gPSAiVGFiZWwgSW50ZXJha3RpZiBEYXRhIENTViINCikNCmBgYA0KDQojICAgTWVuZW50dWthbiBNZWFuLCBNZWRpYW4sIE1vZHVzIA0KDQpgYGB7cn0NCiMgLS0tIDEuIEJhY2EgZmlsZSBDU1YgZGFyaSBsb2thc2kgZGV2aWNlIC0tLQ0KZGF0YV9jdXN0b21lciA8LSByZWFkLmNzdigiZGF0YSBoYWhhaGFoYWhhLmNzdiIpDQoNCiMgLS0tIDIuIENlayBzdHJ1a3R1ciBkYXRhIC0tLQ0KaGVhZChkYXRhX2N1c3RvbWVyKQ0Kc3VtbWFyeShkYXRhX2N1c3RvbWVyKQ0KDQojIC0tLSAzLiBIaXR1bmcgbWVhbiwgbWVkaWFuLCBtb2R1cyAtLS0NCg0KIyBEYXRhIFVzaWEgKEFnZSkNCg0KbWVhbl92YWwgPC0gbWVhbihkYXRhX2N1c3RvbWVyJEFnZSwgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciRBZ2UsIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJEFnZSksIGRlY3JlYXNpbmcgPSBUUlVFKVsxXSkpDQoNCiMgRGF0YSBUb3RhbCBQZW1iZWxpYW4gKFRvdGFsUHVyY2hhc2UpDQoNCm1lYW5fdmFsIDwtIG1lYW4oZGF0YV9jdXN0b21lciRUb3RhbFB1cmNoYXNlLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJFRvdGFsUHVyY2hhc2UsIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJFRvdGFsUHVyY2hhc2UpLCBkZWNyZWFzaW5nID0gVFJVRSlbMV0pKQ0KDQojIERhdGEgSnVtbGFoIFBlbmd1bmp1bmcgKE51bWJlck9mVmlzaXRzKQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkTnVtYmVyT2ZWaXNpdHMsIG5hLnJtID0gVFJVRSkNCm1lZGlhbl92YWwgPC0gbWVkaWFuKGRhdGFfY3VzdG9tZXIkTnVtYmVyT2ZWaXNpdHMsIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJE51bWJlck9mVmlzaXRzKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KIyBEYXRhIFVtcGFuIEJhbGlrIChGZWVkYmFja1Njb3JlKQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkRmVlZGJhY2tTY29yZSwgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciRGZWVkYmFja1Njb3JlLCBuYS5ybSA9IFRSVUUpDQptb2RlX3ZhbCA8LSBhcy5udW1lcmljKG5hbWVzKHNvcnQodGFibGUoZGF0YV9jdXN0b21lciRGZWVkYmFja1Njb3JlKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KIyBEYXRhIEplbmlzIEtlbGFtaW4gUGVtYmVsaSAoR2VuZGVyKQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkR2VuZGVyLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJEdlbmRlciwgbmEucm0gPSBUUlVFKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKGRhdGFfY3VzdG9tZXIkR2VuZGVyKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KIyBEYXRhIEthdGVnb3JpIFByb2R1ayAoUHJvZHVjdENhdGVnb3J5KQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkUHJvZHVjdENhdGVnb3J5LCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJFByb2R1Y3RDYXRlZ29yeSwgbmEucm0gPSBUUlVFKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKGRhdGFfY3VzdG9tZXIkUHJvZHVjdENhdGVnb3J5KSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KIyBEYXRhIExva2FzaSBUb2tvDQoNCm1lYW5fdmFsIDwtIG1lYW4oZGF0YV9jdXN0b21lciRTdG9yZUxvY2F0aW9uLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJFN0b3JlTG9jYXRpb24sIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJFN0b3JlTG9jYXRpb24pLCBkZWNyZWFzaW5nID0gVFJVRSlbMV0pKQ0KDQpgYGANCg0KIyAgIFZpc3VhbGlzYXNpIERhdGENCg0KYGBge3J9DQojIC0tLSAxLiBJbXBvcnQgbGlicmFyeSB5YW5nIGRpYnV0dWhrYW4gLS0tDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIC0tLSAyLiBWaXN1YWxpc2FzaSBkZW5nYW4gZ2dwbG90MiAtLS0NCg0KIyBEYXRhIFVzaWEgKEFnZSkNCg0KbWVhbl92YWwgPC0gbWVhbihkYXRhX2N1c3RvbWVyJEFnZSwgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciRBZ2UsIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJEFnZSksIGRlY3JlYXNpbmcgPSBUUlVFKVsxXSkpDQoNCmdncGxvdChkYXRhX2N1c3RvbWVyLCBhZXMoeCA9IEFnZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMiwgDQogICAgICAgICAgICAgICAgIGZpbGwgPSAiIzVhYjRhYyIsIA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsIA0KICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuOCkgKw0KICBnZW9tX2RlbnNpdHkoY29sb3IgPSAiIzJiOGNiZSIsIGxpbmV3aWR0aCA9IDEuMywgYWxwaGEgPSAwLjkpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW5fdmFsLCBjb2xvciA9ICJNZWFuIiksIGxpbmV3aWR0aCA9IDEuMikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuX3ZhbCwgY29sb3IgPSAiTWVkaWFuIiksIA0KICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbW9kZV92YWwsIGNvbG9yID0gIk1vZGUiKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMS4yLCBsaW5ldHlwZSA9ICJkb3RkYXNoIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1c2kgRGF0YSBVc2lhIFBlbGFuZ2dhbiIsDQogICAgc3VidGl0bGUgPSAiTWVuYW1waWxrYW4gTWVhbiwgTWVkaWFuIGRhbiBNb2R1cyIsDQogICAgeCA9ICJVc2lhIFBlbGFuZ2dhbiAoQWdlKSIsDQogICAgeSA9ICJLZXJhcGF0YW4gKERlbnNpdHkpIiwNCiAgICBjb2xvciA9ICJNZWFzdXJlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICApDQpgYGANCg0KIyMgSW50ZXJwcmV0YXNpIFZpc3VhbGlzYXNpIERhdGEgVXNpYSBQZWxhbmdnYW4NCg0KMS4gQmVudHVrIERpc3RyaWJ1c2k6DQoNCkdyYWZpayBtZW51bmp1a2thbiBkaXN0cmlidXNpIHVzaWEgeWFuZyBhZ2FrIG1pcmluZyBrZSBrYW5hbiBhdGF1IHJpZ2h0LXNrZXdlZC4gQXJ0aW55YSwgc2ViYWdpYW4gYmVzYXIgcGVsYW5nZ2FuIGJlcmFkYSBwYWRhIHVzaWEgbWVuZW5nYWggc2VraXRhciAzNeKAkzQ1IHRhaHVuLCBzZWRhbmdrYW4gYWRhIGJlYmVyYXBhIHBlbGFuZ2dhbiB5YW5nIGxlYmloIHR1YSBoaW5nZ2EgNzAgdGFodW4uDQoNCjIuIE5pbGFpIFRlbmRlbnNpIFNlbnRyYWw6DQoNCk1lYW4gYXRhdSByYXRhLXJhdGEgYmVyYWRhIHNlZGlraXQgZGkga2FuYW4gbWVkaWFuLCBtZW51bmp1a2thbiBiYWh3YSBhZGEgYmViZXJhcGEgbmlsYWkgdXNpYSB0aW5nZ2kgeWFuZyBtZW5hcmlrIHJhdGEtcmF0YSBrZSBrYW5hbi4gDQpNZWRpYW4gYmVyYWRhIGRpIHRlbmdhaCBrdW1wdWxhbiBkYXRhLCAgbWV3YWtpbGkgdXNpYSB0aXBpa2FsIHBlbGFuZ2dhbi4NCk1vZGUgYXRhdSBtb2R1cyBiZXJhZGEgZGkgc2ViZWxhaCBraXJpIHNla2l0YXIgdXNpYSBiZWxhc2FuIGF0YXUgYXdhbCAyMC1hbiwgbWVudW5qdWtrYW4gYmFod2Ega2Vsb21wb2sgdXNpYSBtdWRhIHBhbGluZyBzZXJpbmcgbXVuY3VsLCBtZXNraXB1biBidWthbiBrZWxvbXBvayBkb21pbmFuIGRhbGFtIGp1bWxhaCBiZXNhci4NCg0KYGBge3J9DQojIERhdGEgVG90YWwgUGVtYmVsaWFuIChUb3RhbFB1cmNoYXNlKQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkVG90YWxQdXJjaGFzZSwgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciRUb3RhbFB1cmNoYXNlLCBuYS5ybSA9IFRSVUUpDQptb2RlX3ZhbCA8LSBhcy5udW1lcmljKG5hbWVzKHNvcnQodGFibGUoZGF0YV9jdXN0b21lciRUb3RhbFB1cmNoYXNlKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KZ2dwbG90KGRhdGFfY3VzdG9tZXIsIGFlcyh4ID0gVG90YWxQdXJjaGFzZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgDQogICAgICAgICAgICAgICAgIGJpbnMgPSAzMCwgZmlsbCA9ICIjNWFiNGFjIiwgY29sb3IgPSAid2hpdGUiLCBhbHBoYSA9IDAuOCkgKw0KICBnZW9tX2RlbnNpdHkoY29sb3IgPSAiIzJiOGNiZSIsIGxpbmV3aWR0aCA9IDEuMywgYWxwaGEgPSAwLjkpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW5fdmFsLCBjb2xvciA9ICJNZWFuIiksIGxpbmV3aWR0aCA9IDEuMikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuX3ZhbCwgY29sb3IgPSAiTWVkaWFuIiksIA0KICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbW9kZV92YWwsIGNvbG9yID0gIk1vZGUiKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMS4yLCBsaW5ldHlwZSA9ICJkb3RkYXNoIikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1c2kgVG90YWwgUGVtYmVsaWFuIFBlbGFuZ2dhbiIsDQogICAgICAgc3VidGl0bGUgPSAiTWVuYW1waWxrYW4gTWVhbiwgTWVkaWFuIGRhbiBNb2R1cyIsDQogICAgICAgeCA9ICJUb3RhbCBQZW1iZWxpYW4gKFRvdGFsIFB1cmNoYXNlKSIsIA0KICAgICAgIHkgPSAiS2VyYXBhdGFuIChEZW5zaXR5KSIsDQogICAgICAgY29sb3IgPSAiTWVhc3VyZSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICApDQpgYGANCg0KIyMgSW50ZXJwcmV0YXNpIFZpc3VhbGlzYXNpIERhdGEgVG90YWwgUGVtYmVsaWFuIA0KDQoxLiBCZW50dWsgRGlzdHJpYnVzaToNCg0KRGlzdHJpYnVzaSB0b3RhbCBwZW1iZWxpYW4gcGVsYW5nZ2FuIHRlcmxpaGF0IHNhbmdhdCBtaXJpbmcga2Uga2FuYW4gKHJpZ2h0LXNrZXdlZCkuDQpIYWwgaW5pIG1lbnVuanVra2FuIGJhaHdhIHNlYmFnaWFuIGJlc2FyIHBlbGFuZ2dhbiBtZW1pbGlraSB0b3RhbCBwZW1iZWxpYW4gcmVuZGFoLCBuYW11biB0ZXJkYXBhdCBiZWJlcmFwYSBwZWxhbmdnYW4gZGVuZ2FuIHBlbWJlbGlhbiBzYW5nYXQgdGluZ2dpIChvdXRsaWVyKS4NCg0KMi4gTmlsYWkgVGVuZGVuc2kgU2VudHJhbDoNCk1lYW4gKHJhdGEtcmF0YSkgYmVyYWRhIGxlYmloIGphdWggZGkga2FuYW4gbWVkaWFuLCBtZW5hbmRha2FuIGFkYW55YSBuaWxhaSBla3N0cmVtIHlhbmcgYmVzYXIuDQpNZWRpYW4gYmVyYWRhIGRpIHRlbmdhaCBzZWJhZ2lhbiBiZXNhciBkYXRhLCBtZXJlcHJlc2VudGFzaWthbiBuaWxhaSBwZW1iZWxpYW4gdGlwaWthbCBwZWxhbmdnYW4uDQpNb2RlIChtb2R1cykgYmVyYWRhIGRpIGFyZWEgcGVtYmVsaWFuIHJlbmRhaCwgbWVudW5qdWtrYW4gYmFod2EganVtbGFoIHBlbGFuZ2dhbiBkZW5nYW4gcGVtYmVsaWFuIGtlY2lsIHBhbGluZyBzZXJpbmcgbXVuY3VsLg0KDQpgYGB7cn0NCiMgRGF0YSBKdW1sYWggUGVuZ3VuanVuZyAoTnVtYmVyT2ZWaXNpdHMpDQoNCm1lYW5fdmFsIDwtIG1lYW4oZGF0YV9jdXN0b21lciROdW1iZXJPZlZpc2l0cywgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciROdW1iZXJPZlZpc2l0cywgbmEucm0gPSBUUlVFKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKGRhdGFfY3VzdG9tZXIkTnVtYmVyT2ZWaXNpdHMpLCBkZWNyZWFzaW5nID0gVFJVRSlbMV0pKQ0KDQpnZ3Bsb3QoZGF0YV9jdXN0b21lciwgYWVzKHggPSBOdW1iZXJPZlZpc2l0cykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwNCiAgICAgICAgICAgICAgICAgYmlucyA9IDEwLA0KICAgICAgICAgICAgICAgICBmaWxsID0gIiM1YWI0YWMiLA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgIGFscGhhID0gMC44KSArDQogIGdlb21fZGVuc2l0eShjb2xvciA9ICIjMmI4Y2JlIiwgbGluZXdpZHRoID0gMS4zLCBhbHBoYSA9IDAuOSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl92YWwsIGNvbG9yID0gIk1lYW4iKSwgbGluZXdpZHRoID0gMS4yKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWRpYW5fdmFsLCBjb2xvciA9ICJNZWRpYW4iKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMS4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtb2RlX3ZhbCwgY29sb3IgPSAiTW9kZSIpLCANCiAgICAgICAgICAgICBsaW5ld2lkdGggPSAxLjIsIGxpbmV0eXBlID0gImRvdGRhc2giKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVzaSBKdW1sYWggUGVuZ3VuanVuZyIsDQogICAgICAgc3VidGl0bGUgPSAiTWVuYW1waWxrYW4gTWVhbiwgTWVkaWFuLCBkYW4gTW9kdXMiLA0KICAgICAgIHggPSAiSnVtbGFoIFBlbmd1bmp1bmcgKE51bWJlciBvZiBWaXNpdHMpIiwNCiAgICAgICB5ID0gIktlcmFwYXRhbiAoRGVuc2l0eSkiLA0KICAgICAgIGNvbG9yID0gIk1lYXN1cmUiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgKQ0KYGBgDQoNCiMjIEludGVycHJldGFzaSBWaXN1YWxpc2FzaSBEYXRhIEp1bWxhaCBQZW5ndW5qdW5nDQoNCjEuIEJlbnR1ayBEaXN0cmlidXNpOg0KDQpEaXN0cmlidXNpIGp1bWxhaCBwZW5ndW5qdW5nIHRlcmxpaGF0IG1lbmRla2F0aSBzaW1ldHJpcyAoaGFtcGlyIG5vcm1hbCkuDQpLdXJ2YSBtZW51bmp1a2thbiBiZW50dWsgbWVueWVydXBhaSBsb25jZW5nIChiZWxsLXNoYXBlZCkgZGVuZ2FuIHB1bmNhayBkaSB0ZW5nYWgsIG1lbmFuZGFrYW4gcGVyc2ViYXJhbiBkYXRhIHlhbmcgc2VpbWJhbmcgYW50YXJhIHNpc2kga2lyaSBkYW4ga2FuYW4uDQoNCjIuIE5pbGFpIFRlbmRlbnNpIFNlbnRyYWw6DQoNCk1lYW4sIG1lZGlhbiwgZGFuIG1vZGUgYmVyYWRhIHBhZGEgcG9zaXNpIHlhbmcgaGFtcGlyIGJlcmRla2F0YW4sIG1lbmFuZGFrYW4gZGlzdHJpYnVzaSBkYXRhIHlhbmcgc2VpbWJhbmcgdGFucGEgb3V0bGllciBzaWduaWZpa2FuLg0KTmlsYWkga2V0aWdhbnlhIGJlcnB1c2F0IGRpIHNla2l0YXIgYW5na2EgNeKAkzYga2FsaSBrdW5qdW5nYW4sIHlhbmcgbWVuamFkaSBpbmRpa2FzaSBmcmVrdWVuc2kga3VuanVuZ2FuIHRpcGlrYWwgcGVsYW5nZ2FuLg0KDQpgYGB7cn0NCiMgRGF0YSBVbXBhbiBCYWxpayAoRmVlZGJhY2tTY29yZSkNCg0KbWVhbl92YWwgPC0gbWVhbihkYXRhX2N1c3RvbWVyJEZlZWRiYWNrU2NvcmUsIG5hLnJtID0gVFJVRSkNCm1lZGlhbl92YWwgPC0gbWVkaWFuKGRhdGFfY3VzdG9tZXIkRmVlZGJhY2tTY29yZSwgbmEucm0gPSBUUlVFKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKGRhdGFfY3VzdG9tZXIkRmVlZGJhY2tTY29yZSksIGRlY3JlYXNpbmcgPSBUUlVFKVsxXSkpDQoNCmdncGxvdChkYXRhX2N1c3RvbWVyLCBhZXMoeCA9IEZlZWRiYWNrU2NvcmUpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksDQogICAgICAgICAgICAgICAgIGJpbnMgPSA1LA0KICAgICAgICAgICAgICAgICBmaWxsID0gIiM1YWI0YWMiLA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgIGFscGhhID0gMC44KSArDQogIGdlb21fZGVuc2l0eShjb2xvciA9ICIjMmI4Y2JlIiwgbGluZXdpZHRoID0gMS4zLCBhbHBoYSA9IDAuOSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl92YWwsIGNvbG9yID0gIk1lYW4iKSwgbGluZXdpZHRoID0gMS4yKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWRpYW5fdmFsLCBjb2xvciA9ICJNZWRpYW4iKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMS4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtb2RlX3ZhbCwgY29sb3IgPSAiTW9kZSIpLCANCiAgICAgICAgICAgICBsaW5ld2lkdGggPSAxLjIsIGxpbmV0eXBlID0gImRvdGRhc2giKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVzaSBTa29yIFVtcGFuIEJhbGlrIFBlbGFuZ2dhbiIsDQogICAgICAgc3VidGl0bGUgPSAiTWVuYW1waWxrYW4gTWVhbiwgTWVkaWFuLCBkYW4gTW9kdXMiLA0KICAgICAgIHggPSAiU2tvciBVbXBhbiBCYWxpayAoRmVlZGJhY2tTY29yZSkiLA0KICAgICAgIHkgPSAiS2VyYXBhdGFuIChEZW5zaXR5KSIsDQogICAgICAgY29sb3IgPSAiTWVhc3VyZSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICApDQpgYGANCg0KIyMgSW50ZXJwcmV0YXNpIFZpc3VhbGlzYXNpIERhdGEgU2tvciBVbXBhbiBCYWxpaw0KDQoxLiBCZW50dWsgRGlzdHJpYnVzaToNCg0KRGlzdHJpYnVzaSB0ZXJsaWhhdCB0aWRhayBzaW1ldHJpcyAoc2VkaWtpdCBtaXJpbmcga2Uga2FuYW4gLyByaWdodC1za2V3ZWQpLg0KVGVybGloYXQgYmFod2EgbmlsYWkgbW9kdXMgKDEpIGJlcmFkYSBkaSBzaXNpIGtpcmkgZ3JhZmlrLCBtZW51bmp1a2thbiBzZWJhZ2lhbiBwZWxhbmdnYW4gbWVtYmVyaWthbiBza29yIHJlbmRhaCwgc2VtZW50YXJhIHNrb3IgdGluZ2dpICg04oCTNSkganVnYSBjdWt1cCBzZXJpbmcgbXVuY3VsLg0KDQoyLiBOaWxhaSBUZW5kZW5zaSBTZW50cmFsOg0KDQpNZWFuIChnYXJpcyBtZXJhaCkgYmVyYWRhIGRpIHNla2l0YXIgc2tvciAy4oCTMywNCk1lZGlhbiAoZ2FyaXMgaGlqYXUpIHNlZGlraXQgbGViaWggdGluZ2dpIGRhcmkgbWVhbiwgeWFpdHUgc2VraXRhciAzLA0KTW9kZSAoZ2FyaXMgYmlydSkgYmVyYWRhIGRpIHNrb3IgMSwgeWFpdHUgbmlsYWkgeWFuZyBwYWxpbmcgc2VyaW5nIG11bmN1bC4NClVydXRhbm55YTogTW9kZSA8IE1lYW4gPCBNZWRpYW4sIHlhbmcgbWVuYW5kYWthbiBkaXN0cmlidXNpIGNvbmRvbmcga2Uga2FuYW4uDQoNCmBgYHtyfQ0KIyBEYXRhIEplbmlzIEtlbGFtaW4gUGVtYmVsaSAoR2VuZGVyKQ0KDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfY3VzdG9tZXIkR2VuZGVyLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJEdlbmRlciwgbmEucm0gPSBUUlVFKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKGRhdGFfY3VzdG9tZXIkR2VuZGVyKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KZ2VuZGVyX21vZGUgPC0gZGF0YV9jdXN0b21lciAlPiUNCiAgY291bnQoR2VuZGVyKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgc2xpY2UoMSkgJT4lDQogIHB1bGwoR2VuZGVyKQ0KZ2dwbG90KGRhdGFfY3VzdG9tZXIsIGFlcyh4ID0gR2VuZGVyLCBmaWxsID0gR2VuZGVyKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV90ZXh0KHN0YXQgPSAiY291bnQiLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KGNvdW50KSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMC4zLCBzaXplID0gNCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1c2kgR2VuZGVyIFBlbWJlbGkiLA0KICAgIHN1YnRpdGxlID0gcGFzdGUoIk1vZHVzIChKZW5pcyBHZW5kZXIgeWFuZyBwYWxpbmcgc2VyaW5nIG11bmN1bCk6IiwgZ2VuZGVyX21vZGUpLA0KICAgIHggPSAiSmVuaXMgS2VsYW1pbiAoR2VuZGVyKSIsDQogICAgeSA9ICJKdW1sYWggUGVuZ3VuanVuZyAoTnVtYmVyIG9mIFZpc2l0cykiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQpgYGANCg0KIyMgSW50ZXJwcmV0YXNpIFZpc3VhbGlzYXNpIERhdGEgSmVuaXMgS2VsYW1pbiBQZW1iZWxpDQoNCjEuIEplbmlzIERhdGE6DQoNCkRhdGEgR2VuZGVyIChKZW5pcyBLZWxhbWluKSBiZXJzaWZhdCBrYXRlZ29yaSAobm9taW5hbCkg4oCUIHRpZGFrIG1lbWlsaWtpIHVydXRhbiBhdGF1IG5pbGFpIG51bWVyaWsuDQpLYXJlbmEgaXR1LCB1a3VyYW4gdGVuZGVuc2kgc2VudHJhbCB5YW5nIHBhbGluZyByZWxldmFuIGFkYWxhaCBtb2R1cyAobW9kZSksIHlhaXR1IGthdGVnb3JpIHlhbmcgcGFsaW5nIHNlcmluZyBtdW5jdWwuDQoNCjIuIEhhc2lsIFBlbmdhbWF0YW46DQoNCkp1bWxhaCBwZWxhbmdnYW4gbGFraS1sYWtpIChNKTogMTAxIG9yYW5nDQpKdW1sYWggcGVsYW5nZ2FuIHBlcmVtcHVhbiAoRik6IDk5IG9yYW5nDQpTZWxpc2lobnlhIGtlY2lsIChoYW55YSAyIG9yYW5nKSwgc2VoaW5nZ2EgZGlzdHJpYnVzaSBhbnRhcmEgbGFraS1sYWtpIGRhbiBwZXJlbXB1YW4gaGFtcGlyIHNlaW1iYW5nLg0KDQozLiBOaWxhaSBUZW5kZW5zaSBTZW50cmFsOg0KDQpNb2R1cyA9ICJNIiAoTWFsZSkNCkFydGlueWEsIGplbmlzIGtlbGFtaW4geWFuZyBwYWxpbmcgc2VyaW5nIG11bmN1bCBkYWxhbSBkYXRhIHBlbGFuZ2dhbiBhZGFsYWggbGFraS1sYWtpLg0KDQpgYGB7cn0NCiMgRGF0YSBLYXRlZ29yaSBQcm9kdWsgKFByb2R1Y3RDYXRlZ29yeSkNCg0KbWVhbl92YWwgPC0gbWVhbihkYXRhX2N1c3RvbWVyJFByb2R1Y3RDYXRlZ29yeSwgbmEucm0gPSBUUlVFKQ0KbWVkaWFuX3ZhbCA8LSBtZWRpYW4oZGF0YV9jdXN0b21lciRQcm9kdWN0Q2F0ZWdvcnksIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJFByb2R1Y3RDYXRlZ29yeSksIGRlY3JlYXNpbmcgPSBUUlVFKVsxXSkpDQoNCnByb2R1Y3RjYXRlZ29yeV9tb2RlIDwtIGRhdGFfY3VzdG9tZXIgJT4lDQogIGNvdW50KFByb2R1Y3RDYXRlZ29yeSkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIHNsaWNlKDEpICU+JQ0KICBwdWxsKFByb2R1Y3RDYXRlZ29yeSkNCmdncGxvdChkYXRhX2N1c3RvbWVyLCBhZXMoeCA9IFByb2R1Y3RDYXRlZ29yeSwgZmlsbCA9IFByb2R1Y3RDYXRlZ29yeSkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAwLjYsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChzdGF0ID0gImNvdW50IiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChjb3VudCkpLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDQpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXNpIEthdGVnb3JpIFByb2R1ayIsDQogICAgc3VidGl0bGUgPSBwYXN0ZSgiTW9kdXMgKEplbmlzIEthdGVnb3JpIFByb2R1ayB5YW5nIHBhbGluZyBzZXJpbmcgbXVuY3VsKToiLCBwcm9kdWN0Y2F0ZWdvcnlfbW9kZSksDQogICAgeCA9ICJLYXRlZ29yaSBQcm9kdWsgKFByb2R1Y3QgQ2F0ZWdvcnkpIiwNCiAgICB5ID0gIlRvdGFsIFBlbWJlbGlhbiAoVG90YWwgUHVyY2hhc2UpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KYGBgDQoNCiMjIEludGVycHJldGFzaSBWaXN1YWxpc2FzaSBEYXRhIEthdGVnb3JpIFByb2R1aw0KDQoxLiBKZW5pcyBEYXRhOg0KDQpEYXRhIGthdGVnb3JpIHByb2R1ayAoUHJvZHVjdCBDYXRlZ29yeSkgYmVyc2lmYXQga2F0ZWdvcmlrYWwgbm9taW5hbCwga2FyZW5hIGhhbnlhIG1lbnVuanVra2FuIGplbmlzIHRhbnBhIHVydXRhbiAoQm9va3MsIENsb3RoaW5nLCBFbGVjdHJvbmljcywgSG9tZSwgU3BvcnRzKS4NCk1ha2EgdWt1cmFuIHRlbmRlbnNpIHNlbnRyYWwgeWFuZyBwYWxpbmcgdGVwYXQgYWRhbGFoIG1vZHVzIChtb2RlKS4NCg0KMi4gSGFzaWwgUGVuZ2FtYXRhbjoNCg0KQm9va3M6IDM3IHBlbWJlbGlhbg0KQ2xvdGhpbmc6IDQ3IHBlbWJlbGlhbg0KRWxlY3Ryb25pY3M6IDM4IHBlbWJlbGlhbg0KSG9tZTogMzMgcGVtYmVsaWFuDQpTcG9ydHM6IDQ1IHBlbWJlbGlhbg0KDQozLiBOaWxhaSBUZW5kZW5zaSBTZW50cmFsOg0KDQpNb2R1cyA9ICJDbG90aGluZyIgKDQ3IHBlbWJlbGlhbikNCkFydGlueWEsIGthdGVnb3JpIHByb2R1ayB5YW5nIHBhbGluZyBzZXJpbmcgZGliZWxpIHBlbGFuZ2dhbiBhZGFsYWggcHJvZHVrIHBha2FpYW4gKENsb3RoaW5nKS4NCg0KYGBge3J9DQojIERhdGEgTG9rYXNpIFRva28gKFN0b3JlTG9jYXRpb24pDQoNCm1lYW5fdmFsIDwtIG1lYW4oZGF0YV9jdXN0b21lciRTdG9yZUxvY2F0aW9uLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fdmFsIDwtIG1lZGlhbihkYXRhX2N1c3RvbWVyJFN0b3JlTG9jYXRpb24sIG5hLnJtID0gVFJVRSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShkYXRhX2N1c3RvbWVyJFN0b3JlTG9jYXRpb24pLCBkZWNyZWFzaW5nID0gVFJVRSlbMV0pKQ0KDQpzdG9yZWxvY2F0aW9uX21vZGUgPC0gZGF0YV9jdXN0b21lciAlPiUNCiAgY291bnQoU3RvcmVMb2NhdGlvbikgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogIHNsaWNlKDEpICU+JQ0KICBwdWxsKFN0b3JlTG9jYXRpb24pDQpnZ3Bsb3QoZGF0YV9jdXN0b21lciwgYWVzKHggPSBTdG9yZUxvY2F0aW9uLCBmaWxsID0gU3RvcmVMb2NhdGlvbikpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAwLjYsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChzdGF0ID0gImNvdW50IiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChjb3VudCkpLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDQpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXNpIExva2FzaSBUb2tvIiwNCiAgICBzdWJ0aXRsZSA9ICJNb2R1cyBKZW5pcyBXaWxheWFoIFRva28geWFuZyBwYWxpbmcgc2VyaW5nIG11bmN1bCIsDQogICAgeCA9ICJMb2thc2kgVG9rbyAoU3RvcmUgTG9jYXRpb24pIiwNCiAgICB5ID0gIkp1bWxhaCBQZW5ndW5qdW5nIChOdW1iZXIgb2YgVmlzaXRzKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCmBgYA0KDQojIyBJbnRlcnByZXRhc2kgVmlzdWFsaXNhc2kgRGF0YSBMb2thc2kgVG9rbw0KDQoxLiBKZW5pcyBEYXRhOg0KDQpTdG9yZSBMb2NhdGlvbiBiZXJzaWZhdCBkYXRhIGthdGVnb3Jpa2FsIG5vbWluYWwsIG1ha2EgdWt1cmFuIHRlbmRlbnNpIHNlbnRyYWwgeWFuZyBjb2NvayBhZGFsYWggbW9kdXMgKG1vZGUpIOKAlCB5YWl0dSBrYXRlZ29yaSB5YW5nIHBhbGluZyBzZXJpbmcgbXVuY3VsLg0KDQoyLiBIYXNpbCBQZW5nYW1hdGFuOg0KDQpFYXN0OiA1MQ0KTm9ydGg6IDQ3DQpTb3V0aDogNTENCldlc3Q6IDUxDQpUZXJkYXBhdCB0aWdhIGxva2FzaSBkZW5nYW4gZnJla3VlbnNpIHNhbWEgdGVydGluZ2dpLCB5YWl0dSBFYXN0LCBTb3V0aCwgZGFuIFdlc3QuDQoNCjMuIE5pbGFpIFRlbmRlbnNpIFNlbnRyYWw6DQoNCk1vZHVzIG1lbnVuanVra2FuIGJhaHdhIHdpbGF5YWggRWFzdCwgU291dGgsIGRhbiBXZXN0IG1lbWlsaWtpIGp1bWxhaCBwZW5ndW5qdW5nIHBhbGluZyBiYW55YWsgZGFuIHNlaW1iYW5nLg0KTm9ydGggc2VkaWtpdCBsZWJpaCByZW5kYWgsIG1lbmFuZGFrYW4gYmFod2Egd2lsYXlhaCBpbmkgbXVuZ2tpbiBtZW1pbGlraSBsZWJpaCBzZWRpa2l0IGFrdGl2aXRhcyBwZWxhbmdnYW4uDQpEaXN0cmlidXNpIHlhbmcgaGFtcGlyIG1lcmF0YSBtZW5hbmRha2FuIGphcmluZ2FuIHRva28gdGVyc2ViYXIgY3VrdXAgc2VpbWJhbmcgYW50YXIgd2lsYXlhaCwgdGFucGEgc2F0dSBsb2thc2kgeWFuZyBtZW5kb21pbmFzaSBzaWduaWZpa2FuLg0KDQoNCiMgS2VzaW1wdWxhbg0KDQoxLiBTZWJhZ2lhbiBiZXNhciBwZWxhbmdnYW4gYmVyYWRhIHBhZGEgdXNpYSBtZW5lbmdhaC4NCg0KMi4gVG90YWwgcGVtYmVsaWFuIG1lbnVuanVra2FuIHNlYmFyYW4gdGlkYWsgbWVyYXRhIGRlbmdhbiBzZWRpa2l0IHBlbGFuZ2dhbiB5YW5nIGJlcmJlbGFuamEgc2FuZ2F0IGJhbnlhay4NCg0KMy4gSnVtbGFoIGt1bmp1bmdhbiBkYW4gc2tvciB1bXBhbiBiYWxpayBjZW5kZXJ1bmcgbWVyYXRhIGFudGFyIHBlbGFuZ2dhbi4NCg0KNC4gUGVsYW5nZ2FuIGRpZG9taW5hc2kgb2xlaCBsYWtpLWxha2kuDQoNCg0KNS4gS2F0ZWdvcmkgcHJvZHVrIHlhbmcgcGFsaW5nIHNlcmluZyBkaWJlbGkgYWRhbGFoIENsb3RoaW5nIChwYWthaWFuKS4NCg0KNi4gTG9rYXNpIHRva28gZGVuZ2FuIHBlbmd1bmp1bmcgdGVyYmFueWFrIGJlcmFkYSBkaSB3aWxheWFoIEVhc3QsIFNvdXRoLCBkYW4gV2VzdC4NCg0K