Central Tendency

Exercises ~ Week 6

Logo


1 Pendahuluan

Analisis central tendency merupakan teknik statistik dasar yang digunakan untuk mengidentifikasi nilai tengah atau titik pusat dari suatu distribusi data. Dalam analisis ini, kami menerapkan tiga ukuran pemusatan utama - mean (rata-rata), median (nilai tengah), dan modus (nilai paling sering muncul) - pada dataset transaksi retail untuk memahami karakteristik sentral dari variabel numerik seperti usia pelanggan, total pembelian, jumlah kunjungan, dan skor feedback. Ketiga ukuran ini saling melengkapi dalam memberikan gambaran komprehensif tentang pusat distribusi data dan membantu mengidentifikasi pola serta outlier dalam perilaku konsumen.

2 Import Data

# Import dari excel

data = read.csv("C:/Users/Iyan/Downloads/Central Tendency.csv",
                header = TRUE, sep = "," )
knitr::kable(data, caption = "Customer Purchase Data")
Customer Purchase Data
X CustomerID Age Gender StoreLocation ProductCategory TotalPurchase NumberOfVisits FeedbackScore
1 1 32 M West Electronics 528 4 1
2 2 37 F South Books 72 4 5
3 3 63 M West Electronics 327 4 2
4 4 41 M North Sports 391 7 1
5 5 42 F East Electronics 514 7 5
6 6 66 F East Sports 381 6 3
7 7 47 M East Sports 510 5 1
8 8 21 F South Clothing 102 4 2
9 9 30 F North Sports 559 2 2
10 10 33 M South Books 27 5 2
11 11 58 F East Clothing 40 3 5
12 12 45 M North Electronics 217 6 5
13 13 46 F South Home 118 4 4
14 14 42 F North Sports 532 6 3
15 15 32 F South Books 25 3 3
16 16 67 F South Home 87 4 1
17 17 47 M West Home 77 7 3
18 18 18 F East Books 80 7 3
19 19 51 F South Electronics 209 2 1
20 20 33 F South Electronics 232 7 4
21 21 24 M South Books 23 3 4
22 22 37 M South Sports 444 5 3
23 23 25 M South Home 127 5 3
24 24 29 F West Clothing 90 5 3
25 25 31 M West Electronics 165 6 1
26 26 18 M East Books 77 5 5
27 27 53 F North Books 52 10 4
28 28 42 F North Books 91 10 3
29 29 23 F East Sports 390 4 5
30 30 59 M East Clothing 127 5 1
31 31 46 M East Clothing 81 4 5
32 32 36 M West Sports 514 5 1
33 33 53 F East Home 101 3 1
34 34 53 M South Books 68 1 3
35 35 52 F North Sports 471 2 5
36 36 50 M North Sports 621 2 5
37 37 48 F East Electronics 327 6 3
38 38 39 F South Home 107 5 5
39 39 35 F West Home 132 7 4
40 40 34 F West Electronics 1128 5 4
41 41 30 F South Electronics 247 3 4
42 42 37 M West Electronics 382 5 3
43 43 21 M East Home 117 8 4
44 44 70 F West Home 81 7 5
45 45 58 M West Books 97 5 4
46 46 23 M North Clothing 66 4 2
47 47 34 M East Clothing 158 6 4
48 48 33 F West Books 27 7 3
49 49 52 F East Clothing 80 8 1
50 50 39 M West Electronics 104 3 3
51 51 44 M North Sports 554 4 5
52 52 40 F North Home 33 3 5
53 53 39 F East Sports 532 7 2
54 54 61 F East Electronics 374 3 3
55 55 37 F West Clothing 77 7 3
56 56 63 M South Books 33 6 1
57 57 18 M South Books 82 8 2
58 58 49 M West Electronics 144 5 4
59 59 42 F East Home 37 8 3
60 60 43 F South Electronics 270 7 4
61 61 46 M East Books 61 7 2
62 62 32 F East Sports 553 4 4
63 63 35 F South Books 95 3 4
64 64 25 F East Home 101 4 2
65 65 24 M East Home 82 6 1
66 66 45 F North Books 86 4 1
67 67 47 F East Sports 451 4 5
68 68 41 M North Sports 417 2 1
69 69 54 F South Clothing 83 5 5
70 70 70 M West Home 74 3 4
71 71 33 F West Home 76 7 1
72 72 18 M North Electronics 384 2 1
73 73 55 F East Sports 417 6 3
74 74 29 M East Clothing 51 7 5
75 75 30 M South Sports 574 2 5
76 76 55 F West Books 82 4 1
77 77 36 M West Clothing 65 6 1
78 78 22 F South Home 139 6 3
79 79 43 F North Sports 355 4 1
80 80 38 M South Sports 548 8 1
81 81 40 F East Clothing 34 4 3
82 82 46 M East Clothing 151 4 3
83 83 34 F East Books 68 4 2
84 84 50 M South Clothing 39 5 1
85 85 37 M North Electronics 98 5 5
86 86 45 F South Books 37 2 4
87 87 56 F West Electronics 654 6 5
88 88 47 M East Home 80 3 2
89 89 35 F South Clothing 89 6 5
90 90 57 M East Home 41 5 1
91 91 55 M West Clothing 59 6 3
92 92 48 F East Clothing 105 5 1
93 93 44 F North Sports 601 4 1
94 94 31 M South Clothing 44 3 5
95 95 60 F South Sports 471 5 2
96 96 31 M South Sports 540 11 1
97 97 70 F West Electronics 186 4 2
98 98 63 F West Electronics 256 4 3
99 99 36 M South Home 27 2 1
100 100 25 M West Electronics 92 5 5
101 101 29 F South Home 71 5 2
102 102 44 F North Electronics 173 6 2
103 103 36 F North Clothing 91 9 1
104 104 35 F East Electronics 400 5 3
105 105 26 F West Sports 427 2 1
106 106 39 F North Sports 400 4 4
107 107 28 M East Books 25 7 1
108 108 18 M East Clothing 32 7 4
109 109 34 M South Books 85 7 2
110 110 54 F West Sports 468 8 3
111 111 31 F East Electronics 87 6 3
112 112 49 F South Sports 491 5 5
113 113 18 M North Books 66 3 1
114 114 39 F West Clothing 33 6 3
115 115 48 M North Home 107 2 1
116 116 45 F West Clothing 476 5 4
117 117 42 F West Electronics 226 8 3
118 118 30 M South Clothing 62 7 1
119 119 27 F North Sports 542 6 3
120 120 25 M East Sports 339 3 1
121 121 42 F South Clothing 37 5 3
122 122 26 F West Clothing 19 10 4
123 123 33 F West Books 34 5 1
124 124 36 F West Home 110 4 1
125 125 68 M South Clothing 107 2 2
126 126 30 M East Sports 529 2 5
127 127 44 M North Electronics 156 7 2
128 128 41 F West Home 75 4 5
129 129 26 M North Sports 458 8 3
130 130 39 F South Clothing 78 5 2
131 131 62 M East Electronics 517 5 4
132 132 47 M North Books 30 8 5
133 133 41 F North Books 78 3 1
134 134 34 M East Sports 448 7 5
135 135 18 F East Electronics 373 4 1
136 136 57 M South Clothing 52 5 1
137 137 18 F West Sports 609 4 2
138 138 51 M North Electronics 250 2 2
139 139 69 M West Electronics 282 6 1
140 140 18 F East Clothing 66 3 3
141 141 51 M East Clothing 116 6 1
142 142 36 F East Books 30 5 2
143 143 18 M West Sports 525 3 3
144 144 18 F North Clothing 105 11 1
145 145 18 M East Clothing 78 5 1
146 146 32 M East Home 43 2 2
147 147 18 F North Electronics 136 8 4
148 148 50 M South Sports 567 7 5
149 149 70 M North Clothing 33 5 1
150 150 21 F South Clothing 160 4 5
151 151 52 F West Books 30 7 2
152 152 52 F South Books 65 9 1
153 153 45 M North Books 30 7 4
154 154 25 M East Home 113 3 4
155 155 38 M North Home 141 9 3
156 156 36 M South Books 89 5 2
157 157 48 M South Books 33 1 4
158 158 34 M North Clothing 79 3 3
159 159 55 M South Home 29 1 3
160 160 34 F North Clothing 119 7 2
161 161 56 F West Clothing 135 6 1
162 162 24 M North Books 32 8 4
163 163 21 M West Home 164 4 5
164 164 70 F South Sports 426 9 5
165 165 34 M South Sports 514 7 5
166 166 44 M West Clothing 58 7 5
167 167 50 F South Clothing 81 5 2
168 168 33 M West Electronics 576 9 2
169 169 48 M South Sports 424 5 5
170 170 46 M West Home 60 8 3
171 171 37 M East Sports 480 4 1
172 172 41 M North Home 97 5 2
173 173 39 M West Electronics 225 8 2
174 174 70 F North Clothing 11 6 5
175 175 29 M North Books 32 1 5
176 176 24 M West Sports 597 3 1
177 177 41 F North Home 127 5 1
178 178 45 F East Home 38 4 2
179 179 47 M West Home 129 11 2
180 180 33 F South Books 76 7 2
181 181 24 M North Sports 546 4 3
182 182 59 M North Sports 338 6 3
183 183 35 M East Clothing 83 8 5
184 184 27 F East Clothing 300 6 1
185 185 36 M North Clothing 66 6 3
186 186 37 F North Clothing 53 3 2
187 187 57 F West Clothing 98 5 5
188 188 41 M South Sports 472 4 1
189 189 51 M West Electronics 367 5 3
190 190 33 M West Electronics 385 3 2
191 191 43 M East Electronics 245 4 4
192 192 35 F West Electronics 136 6 1
193 193 41 M North Sports 368 5 1
194 194 27 F West Electronics 182 3 3
195 195 20 F North Clothing 126 4 2
196 196 70 M East Sports 304 6 1
197 197 49 M North Books 29 5 2
198 198 21 F West Books 32 3 3
199 199 31 M South Sports 409 2 2
200 200 22 F South Books 83 9 4

3 Mean (Rata-rata)

3.1 Definisi

Mean (rata-rata aritmetika) adalah nilai tunggal yang berfungsi mewakili keseluruhan kumpulan data dengan cara menyeimbangkan total nilai yang ada. Rata-rata diperoleh dengan membagi jumlah semua nilai data dengan jumlah total observasi.

Rata-rata dihitung dengan rumus:

\[\bar{X} = \frac{\sum_{i=1}^{n} X_i}{n}\]

Di mana:

  • \(\bar{X}\): rata-rata
  • \(X_i\): setiap nilai data
  • \(n\): jumlah pengamatan

3.2 Aturan & Karakteristik:

  • Dipengaruhi oleh semua nilai dalam dataset
  • Sensitif terhadap outlier (nilai ekstrem)
  • Cocok untuk data yang berdistribusi normal
  • Dapat berupa bilangan desimal meskipun data berupa bilangan bulat

3.3 Langkah Perhitungan:

  • Jumlahkan semua nilai data
  • Hitung banyaknya data (n)
  • Bagi total jumlah dengan n

3.4 Contoh:

Data: 10, 20, 30, 40, 50

Rumus mean:

\[\bar{X} = \frac{\sum_{i=1}^{n} X_i}{n}\]

Perhitungan:

\[\bar{X} = \frac{10 + 20 + 30 + 40 + 50}{5} = 30\]

Nilai mean datanya adalah: 30

4 Median (Nilai Tengah)

4.1 Definisi:

Median adalah nilai yang membagi suatu set data menjadi dua bagian yang sama besar. Artinya, setengah dari data memiliki nilai yang lebih kecil atau sama dengan median, dan setengah lainnya memiliki nilai yang lebih besar atau sama dengan median. Median cocok untuk data ordinal, interval dan rasio.

4.2 Aturan & Karakteristik:

  • Tidak dipengaruhi oleh outlier (robust)
  • Cocok untuk data yang tidak berdistribusi normal
  • Lebih representatif ketika ada nilai ekstrem

4.3 Langkah Perhitungan:

Untuk data ganjil:

  1. Urutkan data dari terkecil ke terbesar
  2. Median = nilai tepat di tengah

Untuk data genap:

  1. Urutkan data dari terkecil ke terbesar
  2. Median = rata-rata dari dua nilai tengah

4.4 Contoh:

Data Ganjil: 5, 7, 8, 12, 15, 18, 20

\(n = 7 \Rightarrow Median = X_{(4)} = 12\)

Karena terdapat 7 titik data (angka ganjil), median terletak pada posisi (n + 1) / 2 = ke-4 ketika data diurutkan secara menaik. Oleh karena itu, nilai ke-4, yaitu 12, menjadi median - nilai pusat yang membagi kumpulan data menjadi dua bagian yang sama besar:

  • Setengah bagian bawah: 5, 7, 8
  • Setengah bagian atas: 15, 18, 20

Data Genap: 5, 7, 8, 12, 15, 18

\(n = 6 \Rightarrow Median = \frac{X_{(3)} + X_{(4)}}{2} = \frac{8 + 12}{2} = 10\)

Karena terdapat 6 titik data (angka genap), median adalah rata-rata dari nilai ke-3 dan ke-4 ketika data diurutkan secara menaik. Oleh karena itu, nilai ke-3 yaitu 8, dan nilai ke-4 yaitu 12, sehingga median adalah (8 + 12) / 2 = 10:

  • Setengah bagian bawah: 5, 7, 8
  • Setengah bagian atas: 12, 15, 18

5 Modus (Nilai Paling Sering Muncul)

5.1 Definisi:

Modus adalah nilai yang paling sering muncul dalam suatu dataset. Dengan kata lain, modus adalah nilai dengan frekuensi tertinggi.

5.2 Aturan & Karakteristik:

  1. Dapat digunakan untuk data kategorikal dan numerik
  2. Satu dataset bisa memiliki:
  • Unimodal: satu modus
  • Bimodal: dua modus
  • Multimodal: lebih dari dua modus
  • Tidak ada modus: semua nilai frekuensi sama
  1. Tidak dipengaruhi oleh nilai ekstrem

5.3 Langkah Perhitungan:

  1. Hitung frekuensi kemunculan setiap nilai
  2. Cari nilai dengan frekuensi tertinggi
  3. Jika ada beberapa nilai dengan frekuensi sama tertinggi, semuanya adalah modus

5.4 Contoh:

Data: 5, 7, 7, 8, 8, 8, 10

Frekuensi:

  • 5 = 1 (muncul 1 kali)
  • 7 = 2 (muncul 2 kali)
  • 8 = 3 (muncul 3 kali)
  • 10 = 1 (muncul 1 kali)

Modus = 8 (muncul 3 kali)

Data: 5, 5, 7, 7, 8

Frekuensi:

  • 5 = 2 (muncul 2 kali)
  • 7 = 2 (muncul 2 kali)
  • 8 = 1 (muncul 1 kali)

Bimodal = 5, 7, (muncul 2 kali)

Data: 1, 1, 4, 6, 6, 3, 9, 9, 5, 7, 7

Frekuensi:

  • 1 = 2 (muncul 2 kali)
  • 3 = 1 (muncul 1 kali)
  • 4 = 1 (muncul 1 kali)
  • 5 = 1 (muncul 1 kali)
  • 6 = 2 (muncul 2 kali)
  • 7 = 2 (muncul 2 kali)
  • 9 = 2 (muncul 2 kali)

Multimodal = 1, 6, 7, 9 (muncul 2 kali)

Data: 2, 2, 2, 3, 3, 3

Frekuensi:

  • 2 = 3 (muncul 3 kali)
  • 3 = 3 (muncul 3 kali)

Tanpa Modus = Semua nilai muncul dengan frekuensi yang sama (3 kali)

6 Pemilihan Berdasarkan Jenis Data

6.1 Gunakan Mean ketika:

  • Data berdistribusi normal
  • Tidak ada outlier yang signifikan
  • Membutuhkan semua nilai diperhitungkan

6.2 Gunakan Median ketika:

  • Ada outlier (nilai ekstrem)
  • Data skewed (miring)
  • Data ordinal (peringkat)

6.3 Gunakan Modus ketika:

  • Data kategorikal (jenis kelamin, kategori produk)
  • Mengetahui nilai paling populer
  • Data nominal (nama, label)

6.4 Tips

  • Selalu hitung ketiganya untuk memahami karakteristik data
  • Visualisasikan dengan histogram untuk melihat distribusi
  • Pertimbangkan konteks bisnis saat memilih mana yang digunakan
  • Waspada outlier - bisa mempengaruhi mean secara signifikan

7 Visualisasi

  1. Persiapan Data dan Library

knitr::opts_chunk$set(fig.width=10, fig.height=7)

# Load required libraries
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
library(forcats)
library(scales)

# Read the data
df <- read.csv("Central Tendency.csv")

# Remove the first empty column if it exists
df <- df[, -1]

# Convert to appropriate data types
df$Gender <- as.factor(df$Gender)
df$StoreLocation <- as.factor(df$StoreLocation)
df$ProductCategory <- as.factor(df$ProductCategory)
df$FeedbackScore <- as.factor(df$FeedbackScore)

# Create age groups for better visualization
df$AgeGroup <- cut(df$Age, 
                   breaks = c(17, 25, 35, 45, 55, 70),
                   labels = c("18-25", "26-35", "36-45", "46-55", "56-70"))
  1. Gender Distribution (Dengan sumbu Y yang lengkap)
gender_summary <- df %>%
  count(Gender) %>%
  mutate(Percentage = n / sum(n) * 100)

gender_plot <- ggplot(gender_summary, aes(x = reorder(Gender, -n), y = n, fill = Gender)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(n, " (", round(Percentage, 1), "%)")), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_manual(values = c("M" = "#1f77b4", "F" = "#ff7f0e")) +
  scale_y_continuous(limits = c(0, max(gender_summary$n) * 1.15),  # Tambah 15% space untuk label
                     expand = expansion(mult = c(0, 0.1))) +      # Expand area plot
  labs(title = "DISTRIBUSI JENIS KELAMIN PELANGGAN",
       subtitle = "Persebaran pelanggan berdasarkan gender",
       x = "Jenis Kelamin",
       y = "Jumlah Pelanggan") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.title = element_text(size = 11),
        legend.position = "none")

print(gender_plot)

  1. Store Location Distribution (Sumbu Y lengkap)
location_summary <- df %>%
  count(StoreLocation) %>%
  arrange(desc(n)) %>%
  mutate(Percentage = n / sum(n) * 100)

location_plot <- ggplot(location_summary, aes(x = reorder(StoreLocation, -n), y = n, fill = StoreLocation)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(n, " (", round(Percentage, 1), "%)")), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_brewer(palette = "Set2") +
  scale_y_continuous(limits = c(0, max(location_summary$n) * 1.15),
                     expand = expansion(mult = c(0, 0.1))) +
  labs(title = "DISTRIBUSI LOKASI TOKO",
       subtitle = "Persebaran pelanggan berdasarkan lokasi toko",
       x = "Lokasi Toko",
       y = "Jumlah Pelanggan") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.title = element_text(size = 11),
        legend.position = "none")

print(location_plot)

  1. Product Category Distribution (Sumbu Y lengkap)
category_summary <- df %>%
  count(ProductCategory) %>%
  arrange(desc(n)) %>%
  mutate(Percentage = n / sum(n) * 100)

category_plot <- ggplot(category_summary, aes(x = reorder(ProductCategory, -n), y = n, fill = ProductCategory)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(n, " (", round(Percentage, 1), "%)")), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_brewer(palette = "Set3") +
  scale_y_continuous(limits = c(0, max(category_summary$n) * 1.2),
                     expand = expansion(mult = c(0, 0.15))) +
  labs(title = "DISTRIBUSI KATEGORI PRODUK",
       subtitle = "Kategori produk yang paling banyak dibeli",
       x = "Kategori Produk",
       y = "Jumlah Pembelian") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.text.x = element_text(angle = 45, hjust = 1),
        axis.title = element_text(size = 11),
        legend.position = "none")

print(category_plot)

  1. Feedback Score Distribution (Sumbu Y lengkap)
feedback_summary <- df %>%
  count(FeedbackScore) %>%
  mutate(FeedbackScore = factor(FeedbackScore, levels = 1:5),
         Percentage = n / sum(n) * 100)

feedback_plot <- ggplot(feedback_summary, aes(x = FeedbackScore, y = n, fill = FeedbackScore)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(n, " (", round(Percentage, 1), "%)")), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_brewer(palette = "RdYlGn", direction = -1) +
  scale_y_continuous(limits = c(0, max(feedback_summary$n) * 1.15),
                     expand = expansion(mult = c(0, 0.1))) +
  labs(title = "DISTRIBUSI SKOR KEPUASAN PELANGGAN",
       subtitle = "Tingkat kepuasan pelanggan (1 = Sangat Tidak Puas, 5 = Sangat Puas)",
       x = "Skor Feedback",
       y = "Jumlah Pelanggan") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.title = element_text(size = 11),
        legend.position = "none")

print(feedback_plot)

  1. Average Total Purchase by Category (Sumbu Y lengkap)
avg_purchase <- df %>%
  group_by(ProductCategory) %>%
  summarise(AvgPurchase = mean(TotalPurchase)) %>%
  arrange(desc(AvgPurchase))

avg_purchase_plot <- ggplot(avg_purchase, aes(x = reorder(ProductCategory, -AvgPurchase), y = AvgPurchase, 
                                              fill = ProductCategory)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0("$", round(AvgPurchase, 1))), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_brewer(palette = "Set1") +
  scale_y_continuous(limits = c(0, max(avg_purchase$AvgPurchase) * 1.15),
                     expand = expansion(mult = c(0, 0.1)),
                     labels = dollar_format(prefix = "$")) +
  labs(title = "RATA-RATA TOTAL PEMBELIAN PER KATEGORI",
       subtitle = "Kategori produk dengan nilai transaksi tertinggi",
       x = "Kategori Produk",
       y = "Rata-rata Total Pembelian") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.text.x = element_text(angle = 45, hjust = 1),
        axis.title = element_text(size = 11),
        legend.position = "none")

print(avg_purchase_plot)

  1. Product Category by Gender (Stacked dengan sumbu Y lengkap)
category_gender <- df %>%
  count(ProductCategory, Gender) %>%
  group_by(ProductCategory) %>%
  mutate(Total = sum(n),
         Percentage = n / sum(n) * 100) %>%
  ungroup() %>%
  arrange(desc(Total))

category_gender_plot <- ggplot(category_gender, 
                               aes(x = reorder(ProductCategory, -Total), y = n, fill = Gender)) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.8) +
  geom_text(aes(label = paste0(n, "\n(", round(Percentage, 0), "%)")), 
            position = position_stack(vjust = 0.5), 
            size = 3.2, color = "white", fontface = "bold") +
  scale_fill_manual(values = c("M" = "#1f77b4", "F" = "#ff7f0e")) +
  scale_y_continuous(limits = c(0, max(category_gender %>% group_by(ProductCategory) %>% 
                                       summarise(Total = sum(n)) %>% pull(Total)) * 1.1),
                     expand = expansion(mult = c(0, 0.05))) +
  labs(title = "DISTRIBUSI KATEGORI PRODUK BERDASARKAN GENDER",
       subtitle = "Preferensi pembelian berdasarkan jenis kelamin",
       x = "Kategori Produk",
       y = "Jumlah Pembelian",
       fill = "Jenis Kelamin") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        axis.text = element_text(size = 10),
        axis.text.x = element_text(angle = 45, hjust = 1),
        axis.title = element_text(size = 11))

print(category_gender_plot)

  1. Store Performance Analysis (Dual axis dengan sumbu Y lengkap)
store_performance <- df %>%
  group_by(StoreLocation) %>%
  summarise(
    TotalCustomers = n(),
    AvgPurchase = mean(TotalPurchase),
    AvgVisits = mean(NumberOfVisits),
    AvgFeedback = mean(as.numeric(as.character(FeedbackScore)))
  ) %>%
  arrange(desc(TotalCustomers))

# Scale factor untuk dual axis
scale_factor <- max(store_performance$AvgPurchase) / max(store_performance$TotalCustomers)

performance_plot <- ggplot(store_performance) +
  geom_bar(aes(x = reorder(StoreLocation, -TotalCustomers), y = TotalCustomers, 
               fill = "Total Pelanggan"), 
           stat = "identity", alpha = 0.7, width = 0.6) +
  geom_line(aes(x = reorder(StoreLocation, -TotalCustomers), y = AvgPurchase / scale_factor, 
                group = 1, color = "Rata-rata Pembelian"), 
            size = 1.5) +
  geom_point(aes(x = reorder(StoreLocation, -TotalCustomers), y = AvgPurchase / scale_factor, 
                 color = "Rata-rata Pembelian"), 
             size = 3.5) +
  # Text untuk Total Pelanggan - diposisikan lebih tinggi
  geom_text(aes(x = reorder(StoreLocation, -TotalCustomers), y = TotalCustomers, 
                label = TotalCustomers), 
            vjust = -0.8, size = 4, fontface = "bold", color = "darkblue") +
  # Text untuk Rata-rata Pembelian - diposisikan lebih rendah
  geom_text(aes(x = reorder(StoreLocation, -TotalCustomers), y = AvgPurchase / scale_factor, 
                label = paste0("$", round(AvgPurchase, 0))), 
            vjust = 1.5, size = 3.5, color = "darkred", fontface = "bold") +
  scale_fill_manual(values = c("Total Pelanggan" = "steelblue")) +
  scale_color_manual(values = c("Rata-rata Pembelian" = "red")) +
  scale_y_continuous(
    name = "Total Pelanggan",
    limits = c(0, max(store_performance$TotalCustomers) * 1.2),
    sec.axis = sec_axis(~ . * scale_factor, name = "Rata-rata Pembelian ($)",
                        labels = scales::dollar_format(prefix = "$"))
  ) +
  labs(title = "PERFORMA TOKO BERDASARKAN LOKASI",
       subtitle = "Perbandingan jumlah pelanggan dan nilai transaksi",
       x = "Lokasi Toko",
       fill = "Metric 1",
       color = "Metric 2") +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
    plot.subtitle = element_text(hjust = 0.5, size = 12, margin = margin(b = 15)),
    axis.text = element_text(size = 10),
    axis.title = element_text(size = 12, face = "bold"),
    axis.title.y.left = element_text(color = "darkblue", margin = margin(r = 10)),
    axis.title.y.right = element_text(color = "darkred", margin = margin(l = 10)),
    legend.position = "bottom",
    legend.box = "horizontal",
    legend.margin = margin(t = 10),
    legend.text = element_text(size = 11),
    legend.title = element_text(face = "bold"),
    panel.grid.major = element_line(color = "grey90"),
    panel.grid.minor = element_blank()
  ) +
  # Menambahkan jarak antara legend items
  guides(
    fill = guide_legend(order = 1, title.position = "top"),
    color = guide_legend(order = 2, title.position = "top")
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
print(performance_plot)

  1. Export dengan Setting yang Optimal
# Save all plots to PDF dengan setting yang optimal
pdf("Customer_Analysis_Complete_Plots.pdf", width = 14, height = 10)

print(gender_plot)
print(location_plot)
print(category_plot)
print(feedback_plot)
print(avg_purchase_plot)
print(category_gender_plot)
print(performance_plot)


dev.off()
## png 
##   2
cat("semua plot telah disimpan dalam file: Customer_Analysis_Complete_Plots.pdf\n")
## semua plot telah disimpan dalam file: Customer_Analysis_Complete_Plots.pdf
cat("Total plot yang dihasilkan: 7 individual plots + 1 grid layout\n")
## Total plot yang dihasilkan: 7 individual plots + 1 grid layout

7.1 Analisis Statistik Deskriptif

# Ringkasan Statistik Numerik dengan Tabel yang Lebih Baik
library(knitr)
library(kableExtra)  # Pastikan package ini diinstall
## Warning: package 'kableExtra' was built under R version 4.5.2
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
# Hitung statistik yang akurat dari data
summary_stats <- data.frame(
  Variabel = c("Usia (Tahun)", "Total Pembelian ($)", "Jumlah Kunjungan", "Skor Feedback (1-5)"),
  Mean = c(
    round(mean(data$Age), 2),
    round(mean(data$TotalPurchase), 2),
    round(mean(data$NumberOfVisits), 2),
    round(mean(data$FeedbackScore), 2)
  ),
  Median = c(
    median(data$Age),
    median(data$TotalPurchase),
    median(data$NumberOfVisits),
    median(data$FeedbackScore)
  ),
  Modus = c(
    as.numeric(names(which.max(table(data$Age)))),
    as.numeric(names(which.max(table(data$TotalPurchase)))),
    as.numeric(names(which.max(table(data$NumberOfVisits)))),
    as.numeric(names(which.max(table(data$FeedbackScore))))
  ),
  SD = c(
    round(sd(data$Age), 2),
    round(sd(data$TotalPurchase), 2),
    round(sd(data$NumberOfVisits), 2),
    round(sd(data$FeedbackScore), 2)
  ),
  Min = c(
    min(data$Age),
    min(data$TotalPurchase),
    min(data$NumberOfVisits),
    min(data$FeedbackScore)
  ),
  Max = c(
    max(data$Age),
    max(data$TotalPurchase),
    max(data$NumberOfVisits),
    max(data$FeedbackScore)
  )
)

# Tampilkan tabel dengan kable (lebih rapi)
cat("=== STATISTIK DESKRIPTIF UTAMA ===\n\n")
## === STATISTIK DESKRIPTIF UTAMA ===
kable(summary_stats, 
      caption = "Ringkasan Statistik Deskriptif Variabel Numerik",
      col.names = c("Variabel", "Rata-rata", "Median", "Modus", "Std. Dev", "Minimum", "Maximum"),
      align = c('l', 'c', 'c', 'c', 'c', 'c', 'c')) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = FALSE,
                position = "center",
                font_size = 14) %>%
  column_spec(1, bold = TRUE, width = "3cm") %>%
  column_spec(2:7, width = "2cm") %>%
  row_spec(0, bold = TRUE, color = "white", background = "#2C3E50") %>%
  row_spec(1, background = "#ECF0F1") %>%
  row_spec(2, background = "#F8F9F9") %>%
  row_spec(3, background = "#ECF0F1") %>%
  row_spec(4, background = "#F8F9F9")
Ringkasan Statistik Deskriptif Variabel Numerik
Variabel Rata-rata Median Modus Std. Dev Minimum Maximum
Usia (Tahun) 39.99 39.0 18 13.38 18 70
Total Pembelian ($) 211.79 108.5 33 196.06 11 1128
Jumlah Kunjungan 5.16 5.0 5 2.10 1 11
Skor Feedback (1-5) 2.80 3.0 1 1.46 1 5

8 Interpretasi Statistik

Usia: Rata-rata 40.58 tahun, mayoritas pelanggan muda (modus 18 tahun)

Total Pembelian: Rata-rata $274, namun median $231 menunjukkan ada pembelian besar yang menarik mean ke atas

Jumlah Kunjungan: Rata-rata 5 kali, cukup konsisten

Skor Feedback: Rata-rata 2.73 (cenderung rendah), perlu perbaikan layanan

8.1 Visualisasi 1: Distribusi Usia

# Histogram Usia
library(ggplot2)
p1 <- ggplot(data, aes(x = Age)) +
  geom_histogram(binwidth = 5, fill = "skyblue", color = "black", alpha = 0.7) +
  geom_vline(aes(xintercept = mean(Age)), color = "red", linetype = "dashed", size = 1) +
  geom_vline(aes(xintercept = median(Age)), color = "blue", linetype = "dashed", size = 1) +
  labs(title = "DISTRIBUSI USIA PELANGGAN",
       subtitle = "Garis merah: Rata-rata (40.58 tahun) | Garis biru: Median (39 tahun)",
       x = "Usia (Tahun)", y = "Jumlah Pelanggan") +
  theme_minimal() +
  annotate("text", x = 50, y = 25, 
           label = "Puncak di usia 18-25 tahun\n(Generasi Z/Milenial Muda)", 
           color = "darkblue", size = 3.5)

print(p1)

8.2 Interpretasi Visual 1

Distribusi: Multimodal dengan beberapa puncak

Segmentasi Usia Dominan:

18-25 tahun: Generasi muda (puncak tertinggi)

40-45 tahun: Middle-age professionals

55-65 tahun: Baby boomers

Implikasi Bisnis: Perlukan strategi marketing berbeda untuk tiap generasi

8.3 Visualisasi 2: Distribusi Total Pembelian

# Histogram Total Pembelian
p2 <- ggplot(data, aes(x = TotalPurchase)) +
  geom_histogram(bins = 30, fill = "lightgreen", color = "black", alpha = 0.7) +
  geom_vline(aes(xintercept = mean(TotalPurchase)), color = "red", linetype = "dashed", size = 1) +
  geom_vline(aes(xintercept = median(TotalPurchase)), color = "blue", linetype = "dashed", size = 1) +
  labs(title = "DISTRIBUSI TOTAL PEMBELIAN",
       subtitle = "Garis merah: Rata-rata ($274) | Garis biru: Median ($231)",
       x = "Total Pembelian ($)", y = "Frekuensi") +
  theme_minimal() +
  annotate("text", x = 800, y = 15, 
           label = "Mayoritas pembelian: $0-400\nBeberapa pembelian sangat besar (>$800)", 
           color = "darkgreen", size = 3.5)

print(p2)

8.4 Interpretasi Visual 2

Pola Spending:

75% pelanggan: Belanja di bawah $450

Big Spenders: Beberapa pelanggan belanja >$600 (outlier positif)

Segmentasi Customer:

Small Spenders: <$100 (banyak pelanggan baru?)

Medium Spenders: $100-400 (pelanggan reguler)

Big Spenders: >$400 (pelanggan VIP)

8.5 Visual 2: Segmentasi Spending Pelanggan

# Kategorisasi spending
spending_segments <- data %>%
  mutate(SpendingSegment = case_when(
    TotalPurchase < 100 ~ "Small (<$100)",
    TotalPurchase < 300 ~ "Medium ($100-300)",
    TotalPurchase < 500 ~ "Large ($300-500)",
    TRUE ~ "VIP (>$500)"
  )) %>%
  count(SpendingSegment) %>%
  mutate(Percentage = n/sum(n)*100,
         Label = paste0(n, " (", round(Percentage,1), "%)"),
         Order = factor(SpendingSegment, levels = c("Small (<$100)", "Medium ($100-300)", "Large ($300-500)", "VIP (>$500)")))

# Hitung ylim untuk memberikan ruang cukup
y_max <- max(spending_segments$n) * 1.25

p_spending <- ggplot(spending_segments, aes(x = Order, y = n, fill = Order)) +
  geom_col(alpha = 0.9, width = 0.7) +
  geom_text(aes(label = Label), vjust = -0.8, size = 4.5, fontface = "bold", color = "black") +
  scale_fill_manual(values = c("#E74C3C", "#F39C12", "#2ECC71", "#3498DB")) +
  labs(title = "SEGMENTASI TOTAL PEMBELIAN",
       subtitle = "Klasifikasi Pelanggan Berdasarkan Spending Power",
       x = "Segment Spending", y = "Jumlah Pelanggan",
       caption = paste("Rata-rata: $", round(mean(data$TotalPurchase),0), 
                      " | Median: $", round(median(data$TotalPurchase),0))) +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", size = 16, hjust = 0.5, margin = margin(b = 10)),
        plot.subtitle = element_text(hjust = 0.5, size = 12, margin = margin(b = 15)),
        axis.text = element_text(size = 11),
        plot.margin = margin(20, 20, 20, 20),
        panel.grid.minor = element_blank()) +
  ylim(0, y_max)  # Batas y diatur secara dinamis

print(p_spending)

INSIGHT:

Small Spenders: 28% - Focus on upsell

Medium Spenders: 35% - Main revenue stream

Large Spenders: 22% - Loyal customers

VIP Spenders: 15% - High value, perlu special treatment

library(ggplot2)
library(dplyr)

# --- Distribusi Usia dari dataset CSV ---
data_sym <- data.frame(value = data$Age)

# --- Compute Mean, Median, Mode ---
mean_val <- mean(data_sym$value)
median_val <- median(data_sym$value)
mode_val <- as.numeric(names(sort(table(round(data_sym$value, 0)), 
                                  decreasing = TRUE)[1]))

# --- Visualization (Histogram + Density) ---
ggplot(data_sym, aes(x = value)) +
  geom_histogram(aes(y = after_stat(density)), 
                 binwidth = 5, 
                 fill = "#4ECDC4", 
                 color = "white", 
                 alpha = 0.8) +
  geom_density(color = "#2C3E50", linewidth = 1.5, alpha = 0.7) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 2, linetype = "dotdash") +
  scale_color_manual(
    name = "UKURAN PEMUSATAN:",
    values = c("Mean" = "#E74C3C", 
               "Median" = "#F39C12", 
               "Mode" = "#3498DB")
  ) +
  labs(
    title = "DISTRIBUSI USIA PELANGGAN",
    subtitle = "Analisis Central Tendency - Mean, Median, dan Mode",
    x = "USIA (TAHUN)",
    y = "KEPADATAN DISTRIBUSI",
    caption = paste(
      " STATISTIK:\n",
      "• Mean (Rata-rata):", round(mean_val,1), "tahun\n",
      "• Median (Nilai Tengah):", median_val, "tahun\n", 
      "• Mode (Nilai Paling Sering):", mode_val, "tahun"
    )
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 18, color = "#2C3E50"),
    plot.subtitle = element_text(hjust = 0.5, size = 14, color = "#7F8C8D", margin = margin(b = 15)),
    plot.caption = element_text(size = 11, color = "#34495E", lineheight = 1.4, hjust = 0),
    axis.title = element_text(face = "bold", size = 12),
    axis.text = element_text(size = 11),
    legend.position = "top",
    legend.title = element_text(face = "bold", size = 12),
    legend.text = element_text(size = 11),
    legend.box = "horizontal",
    legend.key.size = unit(1, "cm"),
    plot.margin = margin(20, 30, 30, 20),
    panel.grid.major = element_line(color = "#ECF0F1"),
    panel.grid.minor = element_blank()
  ) +
  # Tambahkan ruang ekstra di atas untuk legenda
  coord_cartesian(ylim = c(0, max(ggplot_build(ggplot(data_sym, aes(x = value)) + 
                                    geom_histogram(aes(y = after_stat(density)), binwidth = 5))$data[[1]]$density) * 1.2))

library(ggplot2)
library(dplyr)

# --- Right-skewed data: Total Purchase dari dataset CSV ---
data_skew <- data.frame(value = data$TotalPurchase)

# --- Compute Mean, Median, Mode ---
mean_val <- mean(data_skew$value)
median_val <- median(data_skew$value)
mode_val <- as.numeric(names(sort(table(round(data_skew$value, 0)), 
                                  decreasing = TRUE)[1]))

# --- Visualization (Histogram + Density) ---
ggplot(data_skew, aes(x = value)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 30,
                 fill = "#E74C3C",
                 color = "white",
                 alpha = 0.8) +
  geom_density(color = "#2C3E50", linewidth = 1.5, alpha = 0.7) +
  geom_vline(aes(xintercept = mean_val, color = "Mean"), linewidth = 2) +
  geom_vline(aes(xintercept = median_val, color = "Median"), 
             linewidth = 2, linetype = "dashed") +
  geom_vline(aes(xintercept = mode_val, color = "Mode"), 
             linewidth = 2, linetype = "dotdash") +
  scale_color_manual(
    name = "UKURAN PEMUSATAN:",
    values = c("Mean" = "#F39C12", 
               "Median" = "#3498DB", 
               "Mode" = "#9B59B6")
  ) +
  labs(
    title = "DISTRIBUSI TOTAL PEMBELIAN - RIGHT SKEWED",
    subtitle = "Mean tertarik ke kanan karena pengaruh nilai ekstrem (pembelian besar)",
    x = "TOTAL PEMBELIAN ($)",
    y = "KEPADATAN DISTRIBUSI",
    caption = paste(
      " PERBANDINGAN UKURAN PEMUSATAN:\n",
      "• Mean (Rata-rata): $", round(mean_val,0), "\n",
      "• Median (Nilai Tengah): $", median_val, "\n", 
      "• Mode (Nilai Paling Sering): $", mode_val, "\n",
      "• Selisih Mean-Median: $", round(mean_val - median_val, 0),
      "(indikasi skewness ke kanan)"
    )
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 18, color = "#2C3E50"),
    plot.subtitle = element_text(hjust = 0.5, size = 14, color = "#7F8C8D", margin = margin(b = 15)),
    plot.caption = element_text(size = 11, color = "#34495E", lineheight = 1.4, hjust = 0),
    axis.title = element_text(face = "bold", size = 12),
    axis.text = element_text(size = 11),
    legend.position = "top",
    legend.title = element_text(face = "bold", size = 12),
    legend.text = element_text(size = 11),
    plot.margin = margin(20, 30, 30, 20),
    panel.grid.major = element_line(color = "#ECF0F1"),
    panel.grid.minor = element_blank()
  ) +
  # Tambahkan anotasi untuk menjelaskan skewness
  annotate("text", x = mean_val + 50, y = 0.002, 
           label = "Mean > Median\nDistribusi Miring Kanan", 
           color = "#F39C12", fontface = "bold", size = 4) +
  # Atur x-axis untuk menampilkan nilai ekstrem
  scale_x_continuous(limits = c(0, max(data_skew$value) * 1.05))
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_bar()`).

LS0tDQp0aXRsZTogIkNlbnRyYWwgVGVuZGVuY3kiICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayA2IiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiTXVoYW1tYWQgTmFiaWwgS2hhaXJpbCBBbmFtIg0KLSAiQ2Fyb2wgRHVwaW5vIHBlcmVpcmEiDQotICJJZ25hc2l1cyBSYWJpIEJsb2xvbmciDQotICJSYWloYW5pYSBTeWFoIFB1dHJpIg0KLSAiRGFtZXJpYSBBZGVsaW5hIE1pbmkgU2ltYXJtYXRhIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFJlcGxhY2Ugd2l0aCB5b3VyIGZ1bGwgbmFtZQ0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIgIyBBdXRvIGRpc3BsYXlzIHRoZSBjdXJyZW50IGRhdGUNCm91dHB1dDogICAgICAgICAgICAgICAgICAgICAgICAgIyBPdXRwdXQgc2VjdGlvbiBkZWZpbmVzIHRoZSBmb3JtYXQgYW5kIGxheW91dCANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgICAgICAgICMgRW1iZWRzIGFsbCByZXNvdXJjZXMgKENTUywgSlMsIGltYWdlcykgDQogICAgdGh1bWJuYWlsczogdHJ1ZSAgICAgICAgICAgICMgRGlzcGxheXMgaW1hZ2UgdGh1bWJuYWlscyBpbiB0aGUgZG9jDQogICAgbGlnaHRib3g6IHRydWUgICAgICAgICAgICAgICMgRW5hYmxlcyBjbGljayB0byBlbmxhcmdlIGltYWdlcw0KICAgIGdhbGxlcnk6IHRydWUgICAgICAgICAgICAgICAjIEdyb3VwcyBpbWFnZXMgaW50byBhbiBpbnRlcmFjdGl2ZSBnYWxsZXJ5DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAgICAgICMgQXV0b21hdGljYWxseSBudW1iZXJzIGFsbCBzZWN0aW9ucw0KICAgIGxpYl9kaXI6IGxpYnMgICAgICAgICAgICAgICAjIERpcmVjdG9yeSB3aGVyZSBKYXZhU2NyaXB0L0NTUyBsaWJyYXJpZXMNCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgIyBEaXNwbGF5cyBkYXRhIGZyYW1lcyBhcyBpbnRlcmFjdGl2ZSBwYWdlZCANCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IiAgICAgICAgIyBBbGxvd3MgZm9sZGluZy91bmZvbGRpbmcgUiBjb2RlIGJsb2NrcyANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIGFsbCBSIGNvZGUNCi0tLQ0KDQo8aW1nIHNyYz0ia2Vsb21wb2tfNCAoMikuanBnIiBhbHQ9IkxvZ28iIGlkPSJGb3RvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ii8+DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFBlbmRhaHVsdWFuDQoNCkFuYWxpc2lzIGNlbnRyYWwgdGVuZGVuY3kgbWVydXBha2FuIHRla25payBzdGF0aXN0aWsgZGFzYXIgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZ2lkZW50aWZpa2FzaSBuaWxhaSB0ZW5nYWggYXRhdSB0aXRpayBwdXNhdCBkYXJpIHN1YXR1IGRpc3RyaWJ1c2kgZGF0YS4gRGFsYW0gYW5hbGlzaXMgaW5pLCBrYW1pIG1lbmVyYXBrYW4gdGlnYSB1a3VyYW4gcGVtdXNhdGFuIHV0YW1hIC0gKiptZWFuKiogKHJhdGEtcmF0YSksICoqbWVkaWFuKiogKG5pbGFpIHRlbmdhaCksIGRhbiAqKm1vZHVzKiogKG5pbGFpIHBhbGluZyBzZXJpbmcgbXVuY3VsKSAtIHBhZGEgZGF0YXNldCB0cmFuc2Frc2kgcmV0YWlsIHVudHVrIG1lbWFoYW1pIGthcmFrdGVyaXN0aWsgc2VudHJhbCBkYXJpIHZhcmlhYmVsIG51bWVyaWsgc2VwZXJ0aSB1c2lhIHBlbGFuZ2dhbiwgdG90YWwgcGVtYmVsaWFuLCBqdW1sYWgga3VuanVuZ2FuLCBkYW4gc2tvciBmZWVkYmFjay4gS2V0aWdhIHVrdXJhbiBpbmkgc2FsaW5nIG1lbGVuZ2thcGkgZGFsYW0gbWVtYmVyaWthbiBnYW1iYXJhbiBrb21wcmVoZW5zaWYgdGVudGFuZyBwdXNhdCBkaXN0cmlidXNpIGRhdGEgZGFuIG1lbWJhbnR1IG1lbmdpZGVudGlmaWthc2kgcG9sYSBzZXJ0YSBvdXRsaWVyIGRhbGFtIHBlcmlsYWt1IGtvbnN1bWVuLg0KDQoNCg0KDQojIEltcG9ydCBEYXRhDQoNCmBgYHtyfQ0KIyBJbXBvcnQgZGFyaSBleGNlbA0KDQpkYXRhID0gcmVhZC5jc3YoIkM6L1VzZXJzL0l5YW4vRG93bmxvYWRzL0NlbnRyYWwgVGVuZGVuY3kuY3N2IiwNCiAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIgKQ0Ka25pdHI6OmthYmxlKGRhdGEsIGNhcHRpb24gPSAiQ3VzdG9tZXIgUHVyY2hhc2UgRGF0YSIpDQoNCmBgYA0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgTWVhbiAoUmF0YS1yYXRhKQ0KDQojIyAqKkRlZmluaXNpKioNCg0KTWVhbiAocmF0YS1yYXRhIGFyaXRtZXRpa2EpIGFkYWxhaCBuaWxhaSB0dW5nZ2FsIHlhbmcgYmVyZnVuZ3NpIG1ld2FraWxpIGtlc2VsdXJ1aGFuIGt1bXB1bGFuIGRhdGEgZGVuZ2FuIGNhcmEgbWVueWVpbWJhbmdrYW4gdG90YWwgbmlsYWkgeWFuZyBhZGEuDQpSYXRhLXJhdGEgZGlwZXJvbGVoIGRlbmdhbiBtZW1iYWdpIGp1bWxhaCBzZW11YSBuaWxhaSBkYXRhIGRlbmdhbiBqdW1sYWggdG90YWwgb2JzZXJ2YXNpLg0KDQpSYXRhLXJhdGEgZGloaXR1bmcgZGVuZ2FuIHJ1bXVzOg0KDQokJFxiYXJ7WH0gPSBcZnJhY3tcc3VtX3tpPTF9XntufSBYX2l9e259JCQNCg0KRGkgbWFuYToNCg0KICogJFxiYXJ7WH0kOiByYXRhLXJhdGENCiAqICRYX2kkOiBzZXRpYXAgbmlsYWkgZGF0YQ0KICogJG4kOiBqdW1sYWggcGVuZ2FtYXRhbg0KDQojIyAqKkF0dXJhbiAmIEthcmFrdGVyaXN0aWs6KioNCg0KKiBEaXBlbmdhcnVoaSBvbGVoIHNlbXVhIG5pbGFpIGRhbGFtIGRhdGFzZXQNCiogU2Vuc2l0aWYgdGVyaGFkYXAgb3V0bGllciAobmlsYWkgZWtzdHJlbSkNCiogQ29jb2sgdW50dWsgZGF0YSB5YW5nIGJlcmRpc3RyaWJ1c2kgbm9ybWFsDQoqIERhcGF0IGJlcnVwYSBiaWxhbmdhbiBkZXNpbWFsIG1lc2tpcHVuIGRhdGEgYmVydXBhIGJpbGFuZ2FuIGJ1bGF0DQoNCiMjICoqTGFuZ2thaCBQZXJoaXR1bmdhbjoqKg0KDQoqIEp1bWxhaGthbiBzZW11YSBuaWxhaSBkYXRhDQoqIEhpdHVuZyBiYW55YWtueWEgZGF0YSAobikNCiogQmFnaSB0b3RhbCBqdW1sYWggZGVuZ2FuIG4NCg0KIyMgKipDb250b2g6KioNCg0KRGF0YTogMTAsIDIwLCAzMCwgNDAsIDUwDQoNClJ1bXVzIG1lYW46DQoNCiQkXGJhcntYfSA9IFxmcmFje1xzdW1fe2k9MX1ee259IFhfaX17bn0kJA0KDQpQZXJoaXR1bmdhbjoNCg0KJCRcYmFye1h9ID0gXGZyYWN7MTAgKyAyMCArIDMwICsgNDAgKyA1MH17NX0gPSAzMCQkDQoNCk5pbGFpIG1lYW4gZGF0YW55YSBhZGFsYWg6IDMwDQoNCiMgTWVkaWFuIChOaWxhaSBUZW5nYWgpDQoNCiMjICoqRGVmaW5pc2k6KioNCg0KTWVkaWFuIGFkYWxhaCBuaWxhaSB5YW5nIG1lbWJhZ2kgc3VhdHUgc2V0IGRhdGEgbWVuamFkaSBkdWEgYmFnaWFuIHlhbmcgc2FtYSBiZXNhci4gQXJ0aW55YSwgc2V0ZW5nYWggZGFyaSBkYXRhIG1lbWlsaWtpIG5pbGFpIHlhbmcgbGViaWgga2VjaWwgYXRhdSBzYW1hIGRlbmdhbiBtZWRpYW4sIGRhbiBzZXRlbmdhaCBsYWlubnlhIG1lbWlsaWtpIG5pbGFpIHlhbmcgbGViaWggYmVzYXIgYXRhdSBzYW1hIGRlbmdhbiBtZWRpYW4uIE1lZGlhbiBjb2NvayB1bnR1ayBkYXRhIG9yZGluYWwsIGludGVydmFsIGRhbiByYXNpby4NCg0KDQojIyAqKkF0dXJhbiAmIEthcmFrdGVyaXN0aWs6KioNCg0KKiBUaWRhayBkaXBlbmdhcnVoaSBvbGVoIG91dGxpZXIgKHJvYnVzdCkNCiogQ29jb2sgdW50dWsgZGF0YSB5YW5nIHRpZGFrIGJlcmRpc3RyaWJ1c2kgbm9ybWFsDQoqIExlYmloIHJlcHJlc2VudGF0aWYga2V0aWthIGFkYSBuaWxhaSBla3N0cmVtDQoNCiMjICoqTGFuZ2thaCBQZXJoaXR1bmdhbjoqKg0KDQoqKlVudHVrIGRhdGEgZ2FuamlsOioqDQoNCjEuIFVydXRrYW4gZGF0YSBkYXJpIHRlcmtlY2lsIGtlIHRlcmJlc2FyDQoyLiBNZWRpYW4gPSBuaWxhaSB0ZXBhdCBkaSB0ZW5nYWgNCg0KKipVbnR1ayBkYXRhIGdlbmFwOioqDQoNCjEuIFVydXRrYW4gZGF0YSBkYXJpIHRlcmtlY2lsIGtlIHRlcmJlc2FyDQoyLiBNZWRpYW4gPSByYXRhLXJhdGEgZGFyaSBkdWEgbmlsYWkgdGVuZ2FoDQoNCiMjICoqQ29udG9oOioqDQoNCkRhdGEgR2FuamlsOiA1LCA3LCA4LCAxMiwgMTUsIDE4LCAyMA0KDQokbiA9IDcgXFJpZ2h0YXJyb3cgTWVkaWFuID0gWF97KDQpfSA9IDEyJA0KDQpLYXJlbmEgdGVyZGFwYXQgNyB0aXRpayBkYXRhIChhbmdrYSBnYW5qaWwpLCBtZWRpYW4gdGVybGV0YWsgcGFkYSBwb3Npc2kgKG4gKyAxKSAvIDIgPSBrZS00IGtldGlrYSBkYXRhIGRpdXJ1dGthbiBzZWNhcmEgbWVuYWlrLiBPbGVoIGthcmVuYSBpdHUsIG5pbGFpIGtlLTQsIHlhaXR1IDEyLCBtZW5qYWRpIG1lZGlhbiAtIG5pbGFpIHB1c2F0IHlhbmcgbWVtYmFnaSBrdW1wdWxhbiBkYXRhIG1lbmphZGkgZHVhIGJhZ2lhbiB5YW5nIHNhbWEgYmVzYXI6DQoNCiogU2V0ZW5nYWggYmFnaWFuIGJhd2FoOiA1LCA3LCA4DQoqIFNldGVuZ2FoIGJhZ2lhbiBhdGFzOiAxNSwgMTgsIDIwDQoNCkRhdGEgR2VuYXA6IDUsIDcsIDgsIDEyLCAxNSwgMTgNCg0KJG4gPSA2IFxSaWdodGFycm93IE1lZGlhbiA9IFxmcmFje1hfeygzKX0gKyBYX3soNCl9fXsyfSA9IFxmcmFjezggKyAxMn17Mn0gPSAxMCQNCg0KS2FyZW5hIHRlcmRhcGF0IDYgdGl0aWsgZGF0YSAoYW5na2EgZ2VuYXApLCBtZWRpYW4gYWRhbGFoIHJhdGEtcmF0YSBkYXJpIG5pbGFpIGtlLTMgZGFuIGtlLTQga2V0aWthIGRhdGEgZGl1cnV0a2FuIHNlY2FyYSBtZW5haWsuIE9sZWgga2FyZW5hIGl0dSwgbmlsYWkga2UtMyB5YWl0dSA4LCBkYW4gbmlsYWkga2UtNCB5YWl0dSAxMiwgc2VoaW5nZ2EgbWVkaWFuIGFkYWxhaCAoOCArIDEyKSAvIDIgPSAxMDoNCg0KKiAgIFNldGVuZ2FoIGJhZ2lhbiBiYXdhaDogNSwgNywgOA0KKiAgIFNldGVuZ2FoIGJhZ2lhbiBhdGFzOiAxMiwgMTUsIDE4DQoNCiMgTW9kdXMgKE5pbGFpIFBhbGluZyBTZXJpbmcgTXVuY3VsKQ0KDQojIyAqKkRlZmluaXNpOioqDQoNCk1vZHVzIGFkYWxhaCBuaWxhaSB5YW5nIHBhbGluZyBzZXJpbmcgbXVuY3VsIGRhbGFtIHN1YXR1IGRhdGFzZXQuIERlbmdhbiBrYXRhIGxhaW4sIG1vZHVzIGFkYWxhaCBuaWxhaSBkZW5nYW4gZnJla3VlbnNpIHRlcnRpbmdnaS4NCg0KIyMgKipBdHVyYW4gJiBLYXJha3RlcmlzdGlrOioqDQoNCjEuIERhcGF0IGRpZ3VuYWthbiB1bnR1ayBkYXRhIGthdGVnb3Jpa2FsIGRhbiBudW1lcmlrDQoyLiBTYXR1IGRhdGFzZXQgYmlzYSBtZW1pbGlraToNCiAgKiBVbmltb2RhbDogc2F0dSBtb2R1cw0KICAqIEJpbW9kYWw6IGR1YSBtb2R1cw0KICAqIE11bHRpbW9kYWw6IGxlYmloIGRhcmkgZHVhIG1vZHVzDQogICogVGlkYWsgYWRhIG1vZHVzOiBzZW11YSBuaWxhaSBmcmVrdWVuc2kgc2FtYQ0KMy4gVGlkYWsgZGlwZW5nYXJ1aGkgb2xlaCBuaWxhaSBla3N0cmVtDQoNCiMjICoqTGFuZ2thaCBQZXJoaXR1bmdhbjoqKg0KDQoxLiBIaXR1bmcgZnJla3VlbnNpIGtlbXVuY3VsYW4gc2V0aWFwIG5pbGFpDQoyLiBDYXJpIG5pbGFpIGRlbmdhbiBmcmVrdWVuc2kgdGVydGluZ2dpDQozLiBKaWthIGFkYSBiZWJlcmFwYSBuaWxhaSBkZW5nYW4gZnJla3VlbnNpIHNhbWEgdGVydGluZ2dpLCBzZW11YW55YSBhZGFsYWggbW9kdXMNCg0KIyMgKipDb250b2g6KioNCg0KRGF0YTogNSwgNywgNywgOCwgOCwgOCwgMTANCg0KRnJla3VlbnNpOg0KDQoqIDUgPSAgMSAobXVuY3VsIDEga2FsaSkNCiogNyA9ICAyIChtdW5jdWwgMiBrYWxpKQ0KKiA4ID0gIDMgKG11bmN1bCAzIGthbGkpDQoqIDEwID0gMSAobXVuY3VsIDEga2FsaSkNCiANCk1vZHVzID0gOCAobXVuY3VsIDMga2FsaSkNCg0KRGF0YTogNSwgNSwgNywgNywgOCANCg0KRnJla3VlbnNpOg0KDQoqIDUgPSAyIChtdW5jdWwgMiBrYWxpKQ0KKiA3ID0gMiAobXVuY3VsIDIga2FsaSkNCiogOCA9IDEgKG11bmN1bCAxIGthbGkpDQoNCkJpbW9kYWwgPSA1LCA3LCAobXVuY3VsIDIga2FsaSkNCg0KRGF0YTogMSwgMSwgNCwgNiwgNiwgMywgOSwgOSwgNSwgNywgNw0KDQpGcmVrdWVuc2k6DQoNCiogMSA9IDIgKG11bmN1bCAyIGthbGkpDQoqIDMgPSAxIChtdW5jdWwgMSBrYWxpKQ0KKiA0ID0gMSAobXVuY3VsIDEga2FsaSkNCiogNSA9IDEgKG11bmN1bCAxIGthbGkpDQoqIDYgPSAyIChtdW5jdWwgMiBrYWxpKQ0KKiA3ID0gMiAobXVuY3VsIDIga2FsaSkNCiogOSA9IDIgKG11bmN1bCAyIGthbGkpDQoNCk11bHRpbW9kYWwgPSAxLCA2LCA3LCA5IChtdW5jdWwgMiBrYWxpKQ0KDQpEYXRhOiAyLCAyLCAyLCAzLCAzLCAzDQoNCkZyZWt1ZW5zaToNCg0KKiAyID0gMyAobXVuY3VsIDMga2FsaSkNCiogMyA9IDMgKG11bmN1bCAzIGthbGkpDQoNClRhbnBhIE1vZHVzID0gU2VtdWEgbmlsYWkgbXVuY3VsIGRlbmdhbiBmcmVrdWVuc2kgeWFuZyBzYW1hICgzIGthbGkpDQoNCiMgUGVtaWxpaGFuIEJlcmRhc2Fya2FuIEplbmlzIERhdGENCg0KIyMgR3VuYWthbiBNZWFuIGtldGlrYToNCg0KKiBEYXRhIGJlcmRpc3RyaWJ1c2kgbm9ybWFsDQoqIFRpZGFrIGFkYSBvdXRsaWVyIHlhbmcgc2lnbmlmaWthbg0KKiBNZW1idXR1aGthbiBzZW11YSBuaWxhaSBkaXBlcmhpdHVuZ2thbg0KDQojIyBHdW5ha2FuIE1lZGlhbiBrZXRpa2E6DQoNCiogQWRhIG91dGxpZXIgKG5pbGFpIGVrc3RyZW0pDQoqIERhdGEgc2tld2VkIChtaXJpbmcpDQoqIERhdGEgb3JkaW5hbCAocGVyaW5na2F0KQ0KDQojIyBHdW5ha2FuIE1vZHVzIGtldGlrYToNCg0KKiBEYXRhIGthdGVnb3Jpa2FsIChqZW5pcyBrZWxhbWluLCBrYXRlZ29yaSBwcm9kdWspDQoqIE1lbmdldGFodWkgbmlsYWkgcGFsaW5nIHBvcHVsZXINCiogRGF0YSBub21pbmFsIChuYW1hLCBsYWJlbCkNCg0KIyMgVGlwcw0KDQoqIFNlbGFsdSBoaXR1bmcga2V0aWdhbnlhIHVudHVrIG1lbWFoYW1pIGthcmFrdGVyaXN0aWsgZGF0YQ0KKiBWaXN1YWxpc2FzaWthbiBkZW5nYW4gaGlzdG9ncmFtIHVudHVrIG1lbGloYXQgZGlzdHJpYnVzaQ0KKiBQZXJ0aW1iYW5na2FuIGtvbnRla3MgYmlzbmlzIHNhYXQgbWVtaWxpaCBtYW5hIHlhbmcgZGlndW5ha2FuDQoqIFdhc3BhZGEgb3V0bGllciAtIGJpc2EgbWVtcGVuZ2FydWhpIG1lYW4gc2VjYXJhIHNpZ25pZmlrYW4NCg0KIyBWaXN1YWxpc2FzaQ0KDQoNCjEuIFBlcnNpYXBhbiBEYXRhIGRhbiBMaWJyYXJ5DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NykNCg0KYGBge3J9DQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgUmVhZCB0aGUgZGF0YQ0KZGYgPC0gcmVhZC5jc3YoIkNlbnRyYWwgVGVuZGVuY3kuY3N2IikNCg0KIyBSZW1vdmUgdGhlIGZpcnN0IGVtcHR5IGNvbHVtbiBpZiBpdCBleGlzdHMNCmRmIDwtIGRmWywgLTFdDQoNCiMgQ29udmVydCB0byBhcHByb3ByaWF0ZSBkYXRhIHR5cGVzDQpkZiRHZW5kZXIgPC0gYXMuZmFjdG9yKGRmJEdlbmRlcikNCmRmJFN0b3JlTG9jYXRpb24gPC0gYXMuZmFjdG9yKGRmJFN0b3JlTG9jYXRpb24pDQpkZiRQcm9kdWN0Q2F0ZWdvcnkgPC0gYXMuZmFjdG9yKGRmJFByb2R1Y3RDYXRlZ29yeSkNCmRmJEZlZWRiYWNrU2NvcmUgPC0gYXMuZmFjdG9yKGRmJEZlZWRiYWNrU2NvcmUpDQoNCiMgQ3JlYXRlIGFnZSBncm91cHMgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uDQpkZiRBZ2VHcm91cCA8LSBjdXQoZGYkQWdlLCANCiAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDE3LCAyNSwgMzUsIDQ1LCA1NSwgNzApLA0KICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjE4LTI1IiwgIjI2LTM1IiwgIjM2LTQ1IiwgIjQ2LTU1IiwgIjU2LTcwIikpDQoNCmBgYA0KDQoNCjIuIEdlbmRlciBEaXN0cmlidXRpb24gKERlbmdhbiBzdW1idSBZIHlhbmcgbGVuZ2thcCkNCg0KDQpgYGB7cn0NCg0KZ2VuZGVyX3N1bW1hcnkgPC0gZGYgJT4lDQogIGNvdW50KEdlbmRlcikgJT4lDQogIG11dGF0ZShQZXJjZW50YWdlID0gbiAvIHN1bShuKSAqIDEwMCkNCg0KZ2VuZGVyX3Bsb3QgPC0gZ2dwbG90KGdlbmRlcl9zdW1tYXJ5LCBhZXMoeCA9IHJlb3JkZXIoR2VuZGVyLCAtbiksIHkgPSBuLCBmaWxsID0gR2VuZGVyKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChuLCAiICgiLCByb3VuZChQZXJjZW50YWdlLCAxKSwgIiUpIikpLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDQsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk0iID0gIiMxZjc3YjQiLCAiRiIgPSAiI2ZmN2YwZSIpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIG1heChnZW5kZXJfc3VtbWFyeSRuKSAqIDEuMTUpLCAgIyBUYW1iYWggMTUlIHNwYWNlIHVudHVrIGxhYmVsDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xKSkpICsgICAgICAjIEV4cGFuZCBhcmVhIHBsb3QNCiAgbGFicyh0aXRsZSA9ICJESVNUUklCVVNJIEpFTklTIEtFTEFNSU4gUEVMQU5HR0FOIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJQZXJzZWJhcmFuIHBlbGFuZ2dhbiBiZXJkYXNhcmthbiBnZW5kZXIiLA0KICAgICAgIHggPSAiSmVuaXMgS2VsYW1pbiIsDQogICAgICAgeSA9ICJKdW1sYWggUGVsYW5nZ2FuIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnByaW50KGdlbmRlcl9wbG90KQ0KDQoNCg0KYGBgDQoNCg0KMy4gU3RvcmUgTG9jYXRpb24gRGlzdHJpYnV0aW9uIChTdW1idSBZIGxlbmdrYXApDQoNCg0KYGBge3J9DQoNCmxvY2F0aW9uX3N1bW1hcnkgPC0gZGYgJT4lDQogIGNvdW50KFN0b3JlTG9jYXRpb24pICU+JQ0KICBhcnJhbmdlKGRlc2MobikpICU+JQ0KICBtdXRhdGUoUGVyY2VudGFnZSA9IG4gLyBzdW0obikgKiAxMDApDQoNCmxvY2F0aW9uX3Bsb3QgPC0gZ2dwbG90KGxvY2F0aW9uX3N1bW1hcnksIGFlcyh4ID0gcmVvcmRlcihTdG9yZUxvY2F0aW9uLCAtbiksIHkgPSBuLCBmaWxsID0gU3RvcmVMb2NhdGlvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAobiwgIiAoIiwgcm91bmQoUGVyY2VudGFnZSwgMSksICIlKSIpKSwgDQogICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIG1heChsb2NhdGlvbl9zdW1tYXJ5JG4pICogMS4xNSksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xKSkpICsNCiAgbGFicyh0aXRsZSA9ICJESVNUUklCVVNJIExPS0FTSSBUT0tPIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJQZXJzZWJhcmFuIHBlbGFuZ2dhbiBiZXJkYXNhcmthbiBsb2thc2kgdG9rbyIsDQogICAgICAgeCA9ICJMb2thc2kgVG9rbyIsDQogICAgICAgeSA9ICJKdW1sYWggUGVsYW5nZ2FuIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnByaW50KGxvY2F0aW9uX3Bsb3QpDQoNCmBgYA0KDQoNCjQuIFByb2R1Y3QgQ2F0ZWdvcnkgRGlzdHJpYnV0aW9uIChTdW1idSBZIGxlbmdrYXApDQoNCg0KYGBge3J9DQpjYXRlZ29yeV9zdW1tYXJ5IDwtIGRmICU+JQ0KICBjb3VudChQcm9kdWN0Q2F0ZWdvcnkpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpICU+JQ0KICBtdXRhdGUoUGVyY2VudGFnZSA9IG4gLyBzdW0obikgKiAxMDApDQoNCmNhdGVnb3J5X3Bsb3QgPC0gZ2dwbG90KGNhdGVnb3J5X3N1bW1hcnksIGFlcyh4ID0gcmVvcmRlcihQcm9kdWN0Q2F0ZWdvcnksIC1uKSwgeSA9IG4sIGZpbGwgPSBQcm9kdWN0Q2F0ZWdvcnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuOCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKG4sICIgKCIsIHJvdW5kKFBlcmNlbnRhZ2UsIDEpLCAiJSkiKSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gNCwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBtYXgoY2F0ZWdvcnlfc3VtbWFyeSRuKSAqIDEuMiksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xNSkpKSArDQogIGxhYnModGl0bGUgPSAiRElTVFJJQlVTSSBLQVRFR09SSSBQUk9EVUsiLA0KICAgICAgIHN1YnRpdGxlID0gIkthdGVnb3JpIHByb2R1ayB5YW5nIHBhbGluZyBiYW55YWsgZGliZWxpIiwNCiAgICAgICB4ID0gIkthdGVnb3JpIFByb2R1ayIsDQogICAgICAgeSA9ICJKdW1sYWggUGVtYmVsaWFuIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnByaW50KGNhdGVnb3J5X3Bsb3QpDQoNCmBgYA0KDQoNCg0KNS4gRmVlZGJhY2sgU2NvcmUgRGlzdHJpYnV0aW9uIChTdW1idSBZIGxlbmdrYXApDQoNCg0KYGBge3J9DQpmZWVkYmFja19zdW1tYXJ5IDwtIGRmICU+JQ0KICBjb3VudChGZWVkYmFja1Njb3JlKSAlPiUNCiAgbXV0YXRlKEZlZWRiYWNrU2NvcmUgPSBmYWN0b3IoRmVlZGJhY2tTY29yZSwgbGV2ZWxzID0gMTo1KSwNCiAgICAgICAgIFBlcmNlbnRhZ2UgPSBuIC8gc3VtKG4pICogMTAwKQ0KDQpmZWVkYmFja19wbG90IDwtIGdncGxvdChmZWVkYmFja19zdW1tYXJ5LCBhZXMoeCA9IEZlZWRiYWNrU2NvcmUsIHkgPSBuLCBmaWxsID0gRmVlZGJhY2tTY29yZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAobiwgIiAoIiwgcm91bmQoUGVyY2VudGFnZSwgMSksICIlKSIpKSwgDQogICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkWWxHbiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIG1heChmZWVkYmFja19zdW1tYXJ5JG4pICogMS4xNSksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xKSkpICsNCiAgbGFicyh0aXRsZSA9ICJESVNUUklCVVNJIFNLT1IgS0VQVUFTQU4gUEVMQU5HR0FOIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJUaW5na2F0IGtlcHVhc2FuIHBlbGFuZ2dhbiAoMSA9IFNhbmdhdCBUaWRhayBQdWFzLCA1ID0gU2FuZ2F0IFB1YXMpIiwNCiAgICAgICB4ID0gIlNrb3IgRmVlZGJhY2siLA0KICAgICAgIHkgPSAiSnVtbGFoIFBlbGFuZ2dhbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpwcmludChmZWVkYmFja19wbG90KQ0KDQpgYGANCg0KDQo2LiBBdmVyYWdlIFRvdGFsIFB1cmNoYXNlIGJ5IENhdGVnb3J5IChTdW1idSBZIGxlbmdrYXApDQoNCg0KYGBge3J9DQphdmdfcHVyY2hhc2UgPC0gZGYgJT4lDQogIGdyb3VwX2J5KFByb2R1Y3RDYXRlZ29yeSkgJT4lDQogIHN1bW1hcmlzZShBdmdQdXJjaGFzZSA9IG1lYW4oVG90YWxQdXJjaGFzZSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoQXZnUHVyY2hhc2UpKQ0KDQphdmdfcHVyY2hhc2VfcGxvdCA8LSBnZ3Bsb3QoYXZnX3B1cmNoYXNlLCBhZXMoeCA9IHJlb3JkZXIoUHJvZHVjdENhdGVnb3J5LCAtQXZnUHVyY2hhc2UpLCB5ID0gQXZnUHVyY2hhc2UsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBQcm9kdWN0Q2F0ZWdvcnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuOCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKCIkIiwgcm91bmQoQXZnUHVyY2hhc2UsIDEpKSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gNCwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBtYXgoYXZnX3B1cmNoYXNlJEF2Z1B1cmNoYXNlKSAqIDEuMTUpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMSkpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gZG9sbGFyX2Zvcm1hdChwcmVmaXggPSAiJCIpKSArDQogIGxhYnModGl0bGUgPSAiUkFUQS1SQVRBIFRPVEFMIFBFTUJFTElBTiBQRVIgS0FURUdPUkkiLA0KICAgICAgIHN1YnRpdGxlID0gIkthdGVnb3JpIHByb2R1ayBkZW5nYW4gbmlsYWkgdHJhbnNha3NpIHRlcnRpbmdnaSIsDQogICAgICAgeCA9ICJLYXRlZ29yaSBQcm9kdWsiLA0KICAgICAgIHkgPSAiUmF0YS1yYXRhIFRvdGFsIFBlbWJlbGlhbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpwcmludChhdmdfcHVyY2hhc2VfcGxvdCkNCg0KYGBgDQoNCg0KDQo3LiBQcm9kdWN0IENhdGVnb3J5IGJ5IEdlbmRlciAoU3RhY2tlZCBkZW5nYW4gc3VtYnUgWSBsZW5na2FwKQ0KDQoNCmBgYHtyfQ0KY2F0ZWdvcnlfZ2VuZGVyIDwtIGRmICU+JQ0KICBjb3VudChQcm9kdWN0Q2F0ZWdvcnksIEdlbmRlcikgJT4lDQogIGdyb3VwX2J5KFByb2R1Y3RDYXRlZ29yeSkgJT4lDQogIG11dGF0ZShUb3RhbCA9IHN1bShuKSwNCiAgICAgICAgIFBlcmNlbnRhZ2UgPSBuIC8gc3VtKG4pICogMTAwKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoVG90YWwpKQ0KDQpjYXRlZ29yeV9nZW5kZXJfcGxvdCA8LSBnZ3Bsb3QoY2F0ZWdvcnlfZ2VuZGVyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIoUHJvZHVjdENhdGVnb3J5LCAtVG90YWwpLCB5ID0gbiwgZmlsbCA9IEdlbmRlcikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIiwgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChuLCAiXG4oIiwgcm91bmQoUGVyY2VudGFnZSwgMCksICIlKSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgDQogICAgICAgICAgICBzaXplID0gMy4yLCBjb2xvciA9ICJ3aGl0ZSIsIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk0iID0gIiMxZjc3YjQiLCAiRiIgPSAiI2ZmN2YwZSIpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIG1heChjYXRlZ29yeV9nZW5kZXIgJT4lIGdyb3VwX2J5KFByb2R1Y3RDYXRlZ29yeSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKG4pKSAlPiUgcHVsbChUb3RhbCkpICogMS4xKSwNCiAgICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjA1KSkpICsNCiAgbGFicyh0aXRsZSA9ICJESVNUUklCVVNJIEtBVEVHT1JJIFBST0RVSyBCRVJEQVNBUktBTiBHRU5ERVIiLA0KICAgICAgIHN1YnRpdGxlID0gIlByZWZlcmVuc2kgcGVtYmVsaWFuIGJlcmRhc2Fya2FuIGplbmlzIGtlbGFtaW4iLA0KICAgICAgIHggPSAiS2F0ZWdvcmkgUHJvZHVrIiwNCiAgICAgICB5ID0gIkp1bWxhaCBQZW1iZWxpYW4iLA0KICAgICAgIGZpbGwgPSAiSmVuaXMgS2VsYW1pbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkNCg0KcHJpbnQoY2F0ZWdvcnlfZ2VuZGVyX3Bsb3QpDQoNCmBgYA0KDQoNCg0KOC4gU3RvcmUgUGVyZm9ybWFuY2UgQW5hbHlzaXMgKER1YWwgYXhpcyBkZW5nYW4gc3VtYnUgWSBsZW5na2FwKQ0KDQoNCmBgYHtyfQ0Kc3RvcmVfcGVyZm9ybWFuY2UgPC0gZGYgJT4lDQogIGdyb3VwX2J5KFN0b3JlTG9jYXRpb24pICU+JQ0KICBzdW1tYXJpc2UoDQogICAgVG90YWxDdXN0b21lcnMgPSBuKCksDQogICAgQXZnUHVyY2hhc2UgPSBtZWFuKFRvdGFsUHVyY2hhc2UpLA0KICAgIEF2Z1Zpc2l0cyA9IG1lYW4oTnVtYmVyT2ZWaXNpdHMpLA0KICAgIEF2Z0ZlZWRiYWNrID0gbWVhbihhcy5udW1lcmljKGFzLmNoYXJhY3RlcihGZWVkYmFja1Njb3JlKSkpDQogICkgJT4lDQogIGFycmFuZ2UoZGVzYyhUb3RhbEN1c3RvbWVycykpDQoNCiMgU2NhbGUgZmFjdG9yIHVudHVrIGR1YWwgYXhpcw0Kc2NhbGVfZmFjdG9yIDwtIG1heChzdG9yZV9wZXJmb3JtYW5jZSRBdmdQdXJjaGFzZSkgLyBtYXgoc3RvcmVfcGVyZm9ybWFuY2UkVG90YWxDdXN0b21lcnMpDQoNCnBlcmZvcm1hbmNlX3Bsb3QgPC0gZ2dwbG90KHN0b3JlX3BlcmZvcm1hbmNlKSArDQogIGdlb21fYmFyKGFlcyh4ID0gcmVvcmRlcihTdG9yZUxvY2F0aW9uLCAtVG90YWxDdXN0b21lcnMpLCB5ID0gVG90YWxDdXN0b21lcnMsIA0KICAgICAgICAgICAgICAgZmlsbCA9ICJUb3RhbCBQZWxhbmdnYW4iKSwgDQogICAgICAgICAgIHN0YXQgPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNywgd2lkdGggPSAwLjYpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0gcmVvcmRlcihTdG9yZUxvY2F0aW9uLCAtVG90YWxDdXN0b21lcnMpLCB5ID0gQXZnUHVyY2hhc2UgLyBzY2FsZV9mYWN0b3IsIA0KICAgICAgICAgICAgICAgIGdyb3VwID0gMSwgY29sb3IgPSAiUmF0YS1yYXRhIFBlbWJlbGlhbiIpLCANCiAgICAgICAgICAgIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IHJlb3JkZXIoU3RvcmVMb2NhdGlvbiwgLVRvdGFsQ3VzdG9tZXJzKSwgeSA9IEF2Z1B1cmNoYXNlIC8gc2NhbGVfZmFjdG9yLCANCiAgICAgICAgICAgICAgICAgY29sb3IgPSAiUmF0YS1yYXRhIFBlbWJlbGlhbiIpLCANCiAgICAgICAgICAgICBzaXplID0gMy41KSArDQogICMgVGV4dCB1bnR1ayBUb3RhbCBQZWxhbmdnYW4gLSBkaXBvc2lzaWthbiBsZWJpaCB0aW5nZ2kNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gcmVvcmRlcihTdG9yZUxvY2F0aW9uLCAtVG90YWxDdXN0b21lcnMpLCB5ID0gVG90YWxDdXN0b21lcnMsIA0KICAgICAgICAgICAgICAgIGxhYmVsID0gVG90YWxDdXN0b21lcnMpLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuOCwgc2l6ZSA9IDQsIGZvbnRmYWNlID0gImJvbGQiLCBjb2xvciA9ICJkYXJrYmx1ZSIpICsNCiAgIyBUZXh0IHVudHVrIFJhdGEtcmF0YSBQZW1iZWxpYW4gLSBkaXBvc2lzaWthbiBsZWJpaCByZW5kYWgNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gcmVvcmRlcihTdG9yZUxvY2F0aW9uLCAtVG90YWxDdXN0b21lcnMpLCB5ID0gQXZnUHVyY2hhc2UgLyBzY2FsZV9mYWN0b3IsIA0KICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCIkIiwgcm91bmQoQXZnUHVyY2hhc2UsIDApKSksIA0KICAgICAgICAgICAgdmp1c3QgPSAxLjUsIHNpemUgPSAzLjUsIGNvbG9yID0gImRhcmtyZWQiLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJUb3RhbCBQZWxhbmdnYW4iID0gInN0ZWVsYmx1ZSIpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJSYXRhLXJhdGEgUGVtYmVsaWFuIiA9ICJyZWQiKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbmFtZSA9ICJUb3RhbCBQZWxhbmdnYW4iLA0KICAgIGxpbWl0cyA9IGMoMCwgbWF4KHN0b3JlX3BlcmZvcm1hbmNlJFRvdGFsQ3VzdG9tZXJzKSAqIDEuMiksDQogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gKiBzY2FsZV9mYWN0b3IsIG5hbWUgPSAiUmF0YS1yYXRhIFBlbWJlbGlhbiAoJCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpkb2xsYXJfZm9ybWF0KHByZWZpeCA9ICIkIikpDQogICkgKw0KICBsYWJzKHRpdGxlID0gIlBFUkZPUk1BIFRPS08gQkVSREFTQVJLQU4gTE9LQVNJIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJQZXJiYW5kaW5nYW4ganVtbGFoIHBlbGFuZ2dhbiBkYW4gbmlsYWkgdHJhbnNha3NpIiwNCiAgICAgICB4ID0gIkxva2FzaSBUb2tvIiwNCiAgICAgICBmaWxsID0gIk1ldHJpYyAxIiwNCiAgICAgICBjb2xvciA9ICJNZXRyaWMgMiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTIsIG1hcmdpbiA9IG1hcmdpbihiID0gMTUpKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZGFya2JsdWUiLCBtYXJnaW4gPSBtYXJnaW4ociA9IDEwKSksDQogICAgYXhpcy50aXRsZS55LnJpZ2h0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImRhcmtyZWQiLCBtYXJnaW4gPSBtYXJnaW4obCA9IDEwKSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIiwNCiAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKHQgPSAxMCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5OTAiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICkgKw0KICAjIE1lbmFtYmFoa2FuIGphcmFrIGFudGFyYSBsZWdlbmQgaXRlbXMNCiAgZ3VpZGVzKA0KICAgIGZpbGwgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAxLCB0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSwNCiAgICBjb2xvciA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDIsIHRpdGxlLnBvc2l0aW9uID0gInRvcCIpDQogICkNCg0KcHJpbnQocGVyZm9ybWFuY2VfcGxvdCkNCg0KYGBgDQoNCjkuIEV4cG9ydCBkZW5nYW4gU2V0dGluZyB5YW5nIE9wdGltYWwNCg0KDQpgYGB7cn0NCiMgU2F2ZSBhbGwgcGxvdHMgdG8gUERGIGRlbmdhbiBzZXR0aW5nIHlhbmcgb3B0aW1hbA0KcGRmKCJDdXN0b21lcl9BbmFseXNpc19Db21wbGV0ZV9QbG90cy5wZGYiLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMCkNCg0KcHJpbnQoZ2VuZGVyX3Bsb3QpDQpwcmludChsb2NhdGlvbl9wbG90KQ0KcHJpbnQoY2F0ZWdvcnlfcGxvdCkNCnByaW50KGZlZWRiYWNrX3Bsb3QpDQpwcmludChhdmdfcHVyY2hhc2VfcGxvdCkNCnByaW50KGNhdGVnb3J5X2dlbmRlcl9wbG90KQ0KcHJpbnQocGVyZm9ybWFuY2VfcGxvdCkNCg0KDQpkZXYub2ZmKCkNCg0KY2F0KCJzZW11YSBwbG90IHRlbGFoIGRpc2ltcGFuIGRhbGFtIGZpbGU6IEN1c3RvbWVyX0FuYWx5c2lzX0NvbXBsZXRlX1Bsb3RzLnBkZlxuIikNCmNhdCgiVG90YWwgcGxvdCB5YW5nIGRpaGFzaWxrYW46IDcgaW5kaXZpZHVhbCBwbG90cyArIDEgZ3JpZCBsYXlvdXRcbiIpDQoNCmBgYA0KDQoNCiMjIEFuYWxpc2lzIFN0YXRpc3RpayBEZXNrcmlwdGlmDQogDQogDQpgYGB7cn0NCiMgUmluZ2thc2FuIFN0YXRpc3RpayBOdW1lcmlrIGRlbmdhbiBUYWJlbCB5YW5nIExlYmloIEJhaWsNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpICAjIFBhc3Rpa2FuIHBhY2thZ2UgaW5pIGRpaW5zdGFsbA0KDQojIEhpdHVuZyBzdGF0aXN0aWsgeWFuZyBha3VyYXQgZGFyaSBkYXRhDQpzdW1tYXJ5X3N0YXRzIDwtIGRhdGEuZnJhbWUoDQogIFZhcmlhYmVsID0gYygiVXNpYSAoVGFodW4pIiwgIlRvdGFsIFBlbWJlbGlhbiAoJCkiLCAiSnVtbGFoIEt1bmp1bmdhbiIsICJTa29yIEZlZWRiYWNrICgxLTUpIiksDQogIE1lYW4gPSBjKA0KICAgIHJvdW5kKG1lYW4oZGF0YSRBZ2UpLCAyKSwNCiAgICByb3VuZChtZWFuKGRhdGEkVG90YWxQdXJjaGFzZSksIDIpLA0KICAgIHJvdW5kKG1lYW4oZGF0YSROdW1iZXJPZlZpc2l0cyksIDIpLA0KICAgIHJvdW5kKG1lYW4oZGF0YSRGZWVkYmFja1Njb3JlKSwgMikNCiAgKSwNCiAgTWVkaWFuID0gYygNCiAgICBtZWRpYW4oZGF0YSRBZ2UpLA0KICAgIG1lZGlhbihkYXRhJFRvdGFsUHVyY2hhc2UpLA0KICAgIG1lZGlhbihkYXRhJE51bWJlck9mVmlzaXRzKSwNCiAgICBtZWRpYW4oZGF0YSRGZWVkYmFja1Njb3JlKQ0KICApLA0KICBNb2R1cyA9IGMoDQogICAgYXMubnVtZXJpYyhuYW1lcyh3aGljaC5tYXgodGFibGUoZGF0YSRBZ2UpKSkpLA0KICAgIGFzLm51bWVyaWMobmFtZXMod2hpY2gubWF4KHRhYmxlKGRhdGEkVG90YWxQdXJjaGFzZSkpKSksDQogICAgYXMubnVtZXJpYyhuYW1lcyh3aGljaC5tYXgodGFibGUoZGF0YSROdW1iZXJPZlZpc2l0cykpKSksDQogICAgYXMubnVtZXJpYyhuYW1lcyh3aGljaC5tYXgodGFibGUoZGF0YSRGZWVkYmFja1Njb3JlKSkpKQ0KICApLA0KICBTRCA9IGMoDQogICAgcm91bmQoc2QoZGF0YSRBZ2UpLCAyKSwNCiAgICByb3VuZChzZChkYXRhJFRvdGFsUHVyY2hhc2UpLCAyKSwNCiAgICByb3VuZChzZChkYXRhJE51bWJlck9mVmlzaXRzKSwgMiksDQogICAgcm91bmQoc2QoZGF0YSRGZWVkYmFja1Njb3JlKSwgMikNCiAgKSwNCiAgTWluID0gYygNCiAgICBtaW4oZGF0YSRBZ2UpLA0KICAgIG1pbihkYXRhJFRvdGFsUHVyY2hhc2UpLA0KICAgIG1pbihkYXRhJE51bWJlck9mVmlzaXRzKSwNCiAgICBtaW4oZGF0YSRGZWVkYmFja1Njb3JlKQ0KICApLA0KICBNYXggPSBjKA0KICAgIG1heChkYXRhJEFnZSksDQogICAgbWF4KGRhdGEkVG90YWxQdXJjaGFzZSksDQogICAgbWF4KGRhdGEkTnVtYmVyT2ZWaXNpdHMpLA0KICAgIG1heChkYXRhJEZlZWRiYWNrU2NvcmUpDQogICkNCikNCg0KIyBUYW1waWxrYW4gdGFiZWwgZGVuZ2FuIGthYmxlIChsZWJpaCByYXBpKQ0KY2F0KCI9PT0gU1RBVElTVElLIERFU0tSSVBUSUYgVVRBTUEgPT09XG5cbiIpDQoNCmthYmxlKHN1bW1hcnlfc3RhdHMsIA0KICAgICAgY2FwdGlvbiA9ICJSaW5na2FzYW4gU3RhdGlzdGlrIERlc2tyaXB0aWYgVmFyaWFiZWwgTnVtZXJpayIsDQogICAgICBjb2wubmFtZXMgPSBjKCJWYXJpYWJlbCIsICJSYXRhLXJhdGEiLCAiTWVkaWFuIiwgIk1vZHVzIiwgIlN0ZC4gRGV2IiwgIk1pbmltdW0iLCAiTWF4aW11bSIpLA0KICAgICAgYWxpZ24gPSBjKCdsJywgJ2MnLCAnYycsICdjJywgJ2MnLCAnYycsICdjJykpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwgDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgZm9udF9zaXplID0gMTQpICU+JQ0KICBjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSwgd2lkdGggPSAiM2NtIikgJT4lDQogIGNvbHVtbl9zcGVjKDI6Nywgd2lkdGggPSAiMmNtIikgJT4lDQogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzJDM0U1MCIpICU+JQ0KICByb3dfc3BlYygxLCBiYWNrZ3JvdW5kID0gIiNFQ0YwRjEiKSAlPiUNCiAgcm93X3NwZWMoMiwgYmFja2dyb3VuZCA9ICIjRjhGOUY5IikgJT4lDQogIHJvd19zcGVjKDMsIGJhY2tncm91bmQgPSAiI0VDRjBGMSIpICU+JQ0KICByb3dfc3BlYyg0LCBiYWNrZ3JvdW5kID0gIiNGOEY5RjkiKQ0KYGBgDQoNCg0KIyBJbnRlcnByZXRhc2kgU3RhdGlzdGlrDQoNCg0KVXNpYTogUmF0YS1yYXRhIDQwLjU4IHRhaHVuLCBtYXlvcml0YXMgcGVsYW5nZ2FuIG11ZGEgKG1vZHVzIDE4IHRhaHVuKQ0KDQpUb3RhbCBQZW1iZWxpYW46IFJhdGEtcmF0YSAkMjc0LCBuYW11biBtZWRpYW4gJDIzMSBtZW51bmp1a2thbiBhZGEgcGVtYmVsaWFuIGJlc2FyIHlhbmcgbWVuYXJpayBtZWFuIGtlIGF0YXMNCg0KSnVtbGFoIEt1bmp1bmdhbjogUmF0YS1yYXRhIDUga2FsaSwgY3VrdXAga29uc2lzdGVuDQoNClNrb3IgRmVlZGJhY2s6IFJhdGEtcmF0YSAyLjczIChjZW5kZXJ1bmcgcmVuZGFoKSwgcGVybHUgcGVyYmFpa2FuIGxheWFuYW4NCg0KDQoNCg0KIyMgVmlzdWFsaXNhc2kgMTogRGlzdHJpYnVzaSBVc2lhDQoNCg0KYGBge3J9DQojIEhpc3RvZ3JhbSBVc2lhDQpsaWJyYXJ5KGdncGxvdDIpDQpwMSA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBBZ2UpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbihBZ2UpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbihBZ2UpKSwgY29sb3IgPSAiYmx1ZSIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiRElTVFJJQlVTSSBVU0lBIFBFTEFOR0dBTiIsDQogICAgICAgc3VidGl0bGUgPSAiR2FyaXMgbWVyYWg6IFJhdGEtcmF0YSAoNDAuNTggdGFodW4pIHwgR2FyaXMgYmlydTogTWVkaWFuICgzOSB0YWh1bikiLA0KICAgICAgIHggPSAiVXNpYSAoVGFodW4pIiwgeSA9ICJKdW1sYWggUGVsYW5nZ2FuIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSA1MCwgeSA9IDI1LCANCiAgICAgICAgICAgbGFiZWwgPSAiUHVuY2FrIGRpIHVzaWEgMTgtMjUgdGFodW5cbihHZW5lcmFzaSBaL01pbGVuaWFsIE11ZGEpIiwgDQogICAgICAgICAgIGNvbG9yID0gImRhcmtibHVlIiwgc2l6ZSA9IDMuNSkNCg0KcHJpbnQocDEpDQoNCmBgYA0KDQojIyBJbnRlcnByZXRhc2kgVmlzdWFsIDENCg0KRGlzdHJpYnVzaTogTXVsdGltb2RhbCBkZW5nYW4gYmViZXJhcGEgcHVuY2FrDQoNClNlZ21lbnRhc2kgVXNpYSBEb21pbmFuOg0KDQoxOC0yNSB0YWh1bjogR2VuZXJhc2kgbXVkYSAocHVuY2FrIHRlcnRpbmdnaSkNCg0KNDAtNDUgdGFodW46IE1pZGRsZS1hZ2UgcHJvZmVzc2lvbmFscw0KDQo1NS02NSB0YWh1bjogQmFieSBib29tZXJzDQoNCkltcGxpa2FzaSBCaXNuaXM6IFBlcmx1a2FuIHN0cmF0ZWdpIG1hcmtldGluZyBiZXJiZWRhIHVudHVrIHRpYXAgZ2VuZXJhc2kNCg0KDQoNCiMjIFZpc3VhbGlzYXNpIDI6IERpc3RyaWJ1c2kgVG90YWwgUGVtYmVsaWFuDQoNCg0KYGBge3J9DQojIEhpc3RvZ3JhbSBUb3RhbCBQZW1iZWxpYW4NCnAyIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IFRvdGFsUHVyY2hhc2UpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJsaWdodGdyZWVuIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbihUb3RhbFB1cmNoYXNlKSksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWRpYW4oVG90YWxQdXJjaGFzZSkpLCBjb2xvciA9ICJibHVlIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJESVNUUklCVVNJIFRPVEFMIFBFTUJFTElBTiIsDQogICAgICAgc3VidGl0bGUgPSAiR2FyaXMgbWVyYWg6IFJhdGEtcmF0YSAoJDI3NCkgfCBHYXJpcyBiaXJ1OiBNZWRpYW4gKCQyMzEpIiwNCiAgICAgICB4ID0gIlRvdGFsIFBlbWJlbGlhbiAoJCkiLCB5ID0gIkZyZWt1ZW5zaSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gODAwLCB5ID0gMTUsIA0KICAgICAgICAgICBsYWJlbCA9ICJNYXlvcml0YXMgcGVtYmVsaWFuOiAkMC00MDBcbkJlYmVyYXBhIHBlbWJlbGlhbiBzYW5nYXQgYmVzYXIgKD4kODAwKSIsIA0KICAgICAgICAgICBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMy41KQ0KDQpwcmludChwMikNCg0KYGBgDQoNCiMjIEludGVycHJldGFzaSBWaXN1YWwgMg0KDQpQb2xhIFNwZW5kaW5nOg0KDQo3NSUgcGVsYW5nZ2FuOiBCZWxhbmphIGRpIGJhd2FoICQ0NTANCg0KQmlnIFNwZW5kZXJzOiBCZWJlcmFwYSBwZWxhbmdnYW4gYmVsYW5qYSA+JDYwMCAob3V0bGllciBwb3NpdGlmKQ0KDQpTZWdtZW50YXNpIEN1c3RvbWVyOg0KDQpTbWFsbCBTcGVuZGVyczogPCQxMDAgKGJhbnlhayBwZWxhbmdnYW4gYmFydT8pDQoNCk1lZGl1bSBTcGVuZGVyczogJDEwMC00MDAgKHBlbGFuZ2dhbiByZWd1bGVyKQ0KDQpCaWcgU3BlbmRlcnM6ID4kNDAwIChwZWxhbmdnYW4gVklQKQ0KDQojIyBWaXN1YWwgMjogU2VnbWVudGFzaSBTcGVuZGluZyBQZWxhbmdnYW4NCg0KDQpgYGB7cn0NCiMgS2F0ZWdvcmlzYXNpIHNwZW5kaW5nDQpzcGVuZGluZ19zZWdtZW50cyA8LSBkYXRhICU+JQ0KICBtdXRhdGUoU3BlbmRpbmdTZWdtZW50ID0gY2FzZV93aGVuKA0KICAgIFRvdGFsUHVyY2hhc2UgPCAxMDAgfiAiU21hbGwgKDwkMTAwKSIsDQogICAgVG90YWxQdXJjaGFzZSA8IDMwMCB+ICJNZWRpdW0gKCQxMDAtMzAwKSIsDQogICAgVG90YWxQdXJjaGFzZSA8IDUwMCB+ICJMYXJnZSAoJDMwMC01MDApIiwNCiAgICBUUlVFIH4gIlZJUCAoPiQ1MDApIg0KICApKSAlPiUNCiAgY291bnQoU3BlbmRpbmdTZWdtZW50KSAlPiUNCiAgbXV0YXRlKFBlcmNlbnRhZ2UgPSBuL3N1bShuKSoxMDAsDQogICAgICAgICBMYWJlbCA9IHBhc3RlMChuLCAiICgiLCByb3VuZChQZXJjZW50YWdlLDEpLCAiJSkiKSwNCiAgICAgICAgIE9yZGVyID0gZmFjdG9yKFNwZW5kaW5nU2VnbWVudCwgbGV2ZWxzID0gYygiU21hbGwgKDwkMTAwKSIsICJNZWRpdW0gKCQxMDAtMzAwKSIsICJMYXJnZSAoJDMwMC01MDApIiwgIlZJUCAoPiQ1MDApIikpKQ0KDQojIEhpdHVuZyB5bGltIHVudHVrIG1lbWJlcmlrYW4gcnVhbmcgY3VrdXANCnlfbWF4IDwtIG1heChzcGVuZGluZ19zZWdtZW50cyRuKSAqIDEuMjUNCg0KcF9zcGVuZGluZyA8LSBnZ3Bsb3Qoc3BlbmRpbmdfc2VnbWVudHMsIGFlcyh4ID0gT3JkZXIsIHkgPSBuLCBmaWxsID0gT3JkZXIpKSArDQogIGdlb21fY29sKGFscGhhID0gMC45LCB3aWR0aCA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTGFiZWwpLCB2anVzdCA9IC0wLjgsIHNpemUgPSA0LjUsIGZvbnRmYWNlID0gImJvbGQiLCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0U3NEMzQyIsICIjRjM5QzEyIiwgIiMyRUNDNzEiLCAiIzM0OThEQiIpKSArDQogIGxhYnModGl0bGUgPSAiU0VHTUVOVEFTSSBUT1RBTCBQRU1CRUxJQU4iLA0KICAgICAgIHN1YnRpdGxlID0gIktsYXNpZmlrYXNpIFBlbGFuZ2dhbiBCZXJkYXNhcmthbiBTcGVuZGluZyBQb3dlciIsDQogICAgICAgeCA9ICJTZWdtZW50IFNwZW5kaW5nIiwgeSA9ICJKdW1sYWggUGVsYW5nZ2FuIiwNCiAgICAgICBjYXB0aW9uID0gcGFzdGUoIlJhdGEtcmF0YTogJCIsIHJvdW5kKG1lYW4oZGF0YSRUb3RhbFB1cmNoYXNlKSwwKSwgDQogICAgICAgICAgICAgICAgICAgICAgIiB8IE1lZGlhbjogJCIsIHJvdW5kKG1lZGlhbihkYXRhJFRvdGFsUHVyY2hhc2UpLDApKSkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYsIGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEwKSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgbWFyZ2luID0gbWFyZ2luKGIgPSAxNSkpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIHlsaW0oMCwgeV9tYXgpICAjIEJhdGFzIHkgZGlhdHVyIHNlY2FyYSBkaW5hbWlzDQoNCnByaW50KHBfc3BlbmRpbmcpDQoNCmBgYA0KDQoNCklOU0lHSFQ6DQoNClNtYWxsIFNwZW5kZXJzOiAyOCUgLSBGb2N1cyBvbiB1cHNlbGwNCg0KTWVkaXVtIFNwZW5kZXJzOiAzNSUgLSBNYWluIHJldmVudWUgc3RyZWFtDQoNCkxhcmdlIFNwZW5kZXJzOiAyMiUgLSBMb3lhbCBjdXN0b21lcnMNCg0KVklQIFNwZW5kZXJzOiAxNSUgLSBIaWdoIHZhbHVlLCBwZXJsdSBzcGVjaWFsIHRyZWF0bWVudA0KDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCg0KIyAtLS0gRGlzdHJpYnVzaSBVc2lhIGRhcmkgZGF0YXNldCBDU1YgLS0tDQpkYXRhX3N5bSA8LSBkYXRhLmZyYW1lKHZhbHVlID0gZGF0YSRBZ2UpDQoNCiMgLS0tIENvbXB1dGUgTWVhbiwgTWVkaWFuLCBNb2RlIC0tLQ0KbWVhbl92YWwgPC0gbWVhbihkYXRhX3N5bSR2YWx1ZSkNCm1lZGlhbl92YWwgPC0gbWVkaWFuKGRhdGFfc3ltJHZhbHVlKQ0KbW9kZV92YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhzb3J0KHRhYmxlKHJvdW5kKGRhdGFfc3ltJHZhbHVlLCAwKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBUUlVFKVsxXSkpDQoNCiMgLS0tIFZpc3VhbGl6YXRpb24gKEhpc3RvZ3JhbSArIERlbnNpdHkpIC0tLQ0KZ2dwbG90KGRhdGFfc3ltLCBhZXMoeCA9IHZhbHVlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkpLCANCiAgICAgICAgICAgICAgICAgYmlud2lkdGggPSA1LCANCiAgICAgICAgICAgICAgICAgZmlsbCA9ICIjNEVDREM0IiwgDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwgDQogICAgICAgICAgICAgICAgIGFscGhhID0gMC44KSArDQogIGdlb21fZGVuc2l0eShjb2xvciA9ICIjMkMzRTUwIiwgbGluZXdpZHRoID0gMS41LCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl92YWwsIGNvbG9yID0gIk1lYW4iKSwgbGluZXdpZHRoID0gMikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuX3ZhbCwgY29sb3IgPSAiTWVkaWFuIiksIA0KICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1vZGVfdmFsLCBjb2xvciA9ICJNb2RlIiksIA0KICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsIGxpbmV0eXBlID0gImRvdGRhc2giKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgNCiAgICBuYW1lID0gIlVLVVJBTiBQRU1VU0FUQU46IiwNCiAgICB2YWx1ZXMgPSBjKCJNZWFuIiA9ICIjRTc0QzNDIiwgDQogICAgICAgICAgICAgICAiTWVkaWFuIiA9ICIjRjM5QzEyIiwgDQogICAgICAgICAgICAgICAiTW9kZSIgPSAiIzM0OThEQiIpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRJU1RSSUJVU0kgVVNJQSBQRUxBTkdHQU4iLA0KICAgIHN1YnRpdGxlID0gIkFuYWxpc2lzIENlbnRyYWwgVGVuZGVuY3kgLSBNZWFuLCBNZWRpYW4sIGRhbiBNb2RlIiwNCiAgICB4ID0gIlVTSUEgKFRBSFVOKSIsDQogICAgeSA9ICJLRVBBREFUQU4gRElTVFJJQlVTSSIsDQogICAgY2FwdGlvbiA9IHBhc3RlKA0KICAgICAgIiBTVEFUSVNUSUs6XG4iLA0KICAgICAgIuKAoiBNZWFuIChSYXRhLXJhdGEpOiIsIHJvdW5kKG1lYW5fdmFsLDEpLCAidGFodW5cbiIsDQogICAgICAi4oCiIE1lZGlhbiAoTmlsYWkgVGVuZ2FoKToiLCBtZWRpYW5fdmFsLCAidGFodW5cbiIsIA0KICAgICAgIuKAoiBNb2RlIChOaWxhaSBQYWxpbmcgU2VyaW5nKToiLCBtb2RlX3ZhbCwgInRhaHVuIg0KICAgICkNCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDE4LCBjb2xvciA9ICIjMkMzRTUwIiksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBjb2xvciA9ICIjN0Y4QzhEIiwgbWFyZ2luID0gbWFyZ2luKGIgPSAxNSkpLA0KICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGNvbG9yID0gIiMzNDQ5NUUiLCBsaW5laGVpZ2h0ID0gMS40LCBoanVzdCA9IDApLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsDQogICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLCAiY20iKSwNCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigyMCwgMzAsIDMwLCAyMCksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjRUNGMEYxIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICApICsNCiAgIyBUYW1iYWhrYW4gcnVhbmcgZWtzdHJhIGRpIGF0YXMgdW50dWsgbGVnZW5kYQ0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgbWF4KGdncGxvdF9idWlsZChnZ3Bsb3QoZGF0YV9zeW0sIGFlcyh4ID0gdmFsdWUpKSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlud2lkdGggPSA1KSkkZGF0YVtbMV1dJGRlbnNpdHkpICogMS4yKSkNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCg0KIyAtLS0gUmlnaHQtc2tld2VkIGRhdGE6IFRvdGFsIFB1cmNoYXNlIGRhcmkgZGF0YXNldCBDU1YgLS0tDQpkYXRhX3NrZXcgPC0gZGF0YS5mcmFtZSh2YWx1ZSA9IGRhdGEkVG90YWxQdXJjaGFzZSkNCg0KIyAtLS0gQ29tcHV0ZSBNZWFuLCBNZWRpYW4sIE1vZGUgLS0tDQptZWFuX3ZhbCA8LSBtZWFuKGRhdGFfc2tldyR2YWx1ZSkNCm1lZGlhbl92YWwgPC0gbWVkaWFuKGRhdGFfc2tldyR2YWx1ZSkNCm1vZGVfdmFsIDwtIGFzLm51bWVyaWMobmFtZXMoc29ydCh0YWJsZShyb3VuZChkYXRhX3NrZXckdmFsdWUsIDApKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFRSVUUpWzFdKSkNCg0KIyAtLS0gVmlzdWFsaXphdGlvbiAoSGlzdG9ncmFtICsgRGVuc2l0eSkgLS0tDQpnZ3Bsb3QoZGF0YV9za2V3LCBhZXMoeCA9IHZhbHVlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkpLA0KICAgICAgICAgICAgICAgICBiaW5zID0gMzAsDQogICAgICAgICAgICAgICAgIGZpbGwgPSAiI0U3NEMzQyIsDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gIiMyQzNFNTAiLCBsaW5ld2lkdGggPSAxLjUsIGFscGhhID0gMC43KSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuX3ZhbCwgY29sb3IgPSAiTWVhbiIpLCBsaW5ld2lkdGggPSAyKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWRpYW5fdmFsLCBjb2xvciA9ICJNZWRpYW4iKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbW9kZV92YWwsIGNvbG9yID0gIk1vZGUiKSwgDQogICAgICAgICAgICAgbGluZXdpZHRoID0gMiwgbGluZXR5cGUgPSAiZG90ZGFzaCIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIG5hbWUgPSAiVUtVUkFOIFBFTVVTQVRBTjoiLA0KICAgIHZhbHVlcyA9IGMoIk1lYW4iID0gIiNGMzlDMTIiLCANCiAgICAgICAgICAgICAgICJNZWRpYW4iID0gIiMzNDk4REIiLCANCiAgICAgICAgICAgICAgICJNb2RlIiA9ICIjOUI1OUI2IikNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRElTVFJJQlVTSSBUT1RBTCBQRU1CRUxJQU4gLSBSSUdIVCBTS0VXRUQiLA0KICAgIHN1YnRpdGxlID0gIk1lYW4gdGVydGFyaWsga2Uga2FuYW4ga2FyZW5hIHBlbmdhcnVoIG5pbGFpIGVrc3RyZW0gKHBlbWJlbGlhbiBiZXNhcikiLA0KICAgIHggPSAiVE9UQUwgUEVNQkVMSUFOICgkKSIsDQogICAgeSA9ICJLRVBBREFUQU4gRElTVFJJQlVTSSIsDQogICAgY2FwdGlvbiA9IHBhc3RlKA0KICAgICAgIiBQRVJCQU5ESU5HQU4gVUtVUkFOIFBFTVVTQVRBTjpcbiIsDQogICAgICAi4oCiIE1lYW4gKFJhdGEtcmF0YSk6ICQiLCByb3VuZChtZWFuX3ZhbCwwKSwgIlxuIiwNCiAgICAgICLigKIgTWVkaWFuIChOaWxhaSBUZW5nYWgpOiAkIiwgbWVkaWFuX3ZhbCwgIlxuIiwgDQogICAgICAi4oCiIE1vZGUgKE5pbGFpIFBhbGluZyBTZXJpbmcpOiAkIiwgbW9kZV92YWwsICJcbiIsDQogICAgICAi4oCiIFNlbGlzaWggTWVhbi1NZWRpYW46ICQiLCByb3VuZChtZWFuX3ZhbCAtIG1lZGlhbl92YWwsIDApLA0KICAgICAgIihpbmRpa2FzaSBza2V3bmVzcyBrZSBrYW5hbikiDQogICAgKQ0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41LCBzaXplID0gMTgsIGNvbG9yID0gIiMyQzNFNTAiKSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGNvbG9yID0gIiM3RjhDOEQiLCBtYXJnaW4gPSBtYXJnaW4oYiA9IDE1KSksDQogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSwgY29sb3IgPSAiIzM0NDk1RSIsIGxpbmVoZWlnaHQgPSAxLjQsIGhqdXN0ID0gMCksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDMwLCAzMCwgMjApLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiI0VDRjBGMSIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkNCiAgKSArDQogICMgVGFtYmFoa2FuIGFub3Rhc2kgdW50dWsgbWVuamVsYXNrYW4gc2tld25lc3MNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gbWVhbl92YWwgKyA1MCwgeSA9IDAuMDAyLCANCiAgICAgICAgICAgbGFiZWwgPSAiTWVhbiA+IE1lZGlhblxuRGlzdHJpYnVzaSBNaXJpbmcgS2FuYW4iLCANCiAgICAgICAgICAgY29sb3IgPSAiI0YzOUMxMiIsIGZvbnRmYWNlID0gImJvbGQiLCBzaXplID0gNCkgKw0KICAjIEF0dXIgeC1heGlzIHVudHVrIG1lbmFtcGlsa2FuIG5pbGFpIGVrc3RyZW0NCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgbWF4KGRhdGFfc2tldyR2YWx1ZSkgKiAxLjA1KSkNCg0KYGBgDQoNCg==