1. Introduction
The Economist adalah majalah
mingguan yang berfokus pada berita dan analisis tentang ekonomi,
politik, bisnis, teknologi, dan budaya. Didirikan pada tahun 1843,
majalah ini dikenal dengan sudut pandangnya yang global dan analisis
yang mendalam terhadap isu-isu terkini. Hal menarik dari majalah ini
yaitu adanya visualisasi berupa grafik/plot yang ditampilkan dengan
menarik. Pada artikel ini, kami akan mencoba mereplikasi plot dari The
Economist menggunakan library ggplot.
📌 Objektif:
Proyek ini menjelaskan bagaimana cara membuat replika visualisasi
dari majalah The Economist. Hal ini dilakukan untuk membuktikan bahwa
visualisasi tersebut dapat kita buat dan replika menggunakan bahasa
pemrograman R menggunakan library ggplot.
✨ Manfaat:
Setelah Anda membaca artikel ini, diharapkan Anda:
- Mengerti dasar-dasar pemrograman R.
- Mengerti cara membuat visualisasi menggunakan library
ggplot.
- Mengerti jenis plot yang sesuai berdasarkan data yang ada dan dapat
menggunakan jenis plot tersebut untuk kasus yang berbeda dikemudian
hari.
💡 Target Pembaca:
Artikel ini cocok bagi siapa saja yang ingin memulai belajar bahasa
pemrograman R. Selain itu, artikel ini juga bermanfaat bagi seorang data
analis agar menjadi rujukan dalam membuat visualisasi dalam berbagai
kasus utamanya jika menggunakan library ggplot. Artikel
ini bermanfaat untuk orang-orang yang tertarik dengan visualisasi data
dan ingin mempelajari cara mereplikasi grafik-grafik yang terkenal dan
kompleks. Dalam artikel ini dijelaskan flow dari pembersihan data,
menyiapkan data untuk pembuatan plot, pembuatan plot itu sendiri, dan
menggabungkan beberapa plot menjadi 1. Hal ini bisa dijadikan contoh
jika ada pembaca yang akan melakukan hal yang sama.
📊 Jenis Plot:
Artikel ini akan membuat sebuah visualisasi yang terdiri dari
kombinasi 3 plot sebagai berikut:
- Bubble Chart \(\rightarrow\) menampilkan jumlah individu
yang diadili. Bubble chart memiliki bentuk berupa lingkaran. Semakin
luas lingkaran, maka nilainya semakin tinggi.
- Stacked Bar Chart \(\rightarrow\) menampilkan jumlah individu
yang diadili baik mendapat hukuman mati (executed) atau tidak dihukum
mati (accused) pada suatu negara. Stacked bar chart atau diagram batang
bertumpuk seperti namanya diagram tersebut berbentuk diagram batang yang
terdiri dari 2 kategori (executed dan accused) yang disusun secara
bertumpuk.
- Line Chart \(\rightarrow\) menampilkan grafik garis yang
menunjukan track record dari individu yang diadili tiap tahun dalam
rentang tahun 1300 s.d. 1850. Line chart berbentuk garis yang dapat
menjelaskan tentang suatu data berdasarkan urutan waktu.
Setelah kita tahu tujuan, manfaat, dan hal yang akan kita lakukan,
mari kita melangkah lebih lanjut untuk mempersiapkan pengerjaan
project.
4. Create a Visualization
4.1 Bubble Chart
Untuk membuat Bubble Chart, hanya membutuhkan kolom
persons_tried_per_million. Terlihat pada gambar referensi
bahwa nilai pada bubble chart menggunakan nilai hasil formula
persons_tried_per_million dibagi 10 lalu dibulatkan.
Berikut langkah-langkah yang perlu dilakukan:
- Mempersiapkan data
persons_tried_per_million dari
dataset history.
- Membagi data
persons_tried_per_million dengan nilai 10
lalu dibulatkan menggunakan fungsi round().
- Membuat bubble chart.
# Mengambil data persons_tried_per_million
bubble_data <- history %>% select(persons_tried_per_million)
head(bubble_data)
Berdasarkan gambar referensi, nilai pada
kolompersons_tried_per_million bukanlah nilai aslinya
tetapi sudah dibagi menjadi 10.
# Membagi data dengan 10 lalu dibulatkan
bubble_data <- round(bubble_data / 10, 0)
# Proses membalik data dari yang teratas menjadi terbawah
bubble_data <- bubble_data %>%
mutate(value_reserved = rev(persons_tried_per_million)) %>%
select(-persons_tried_per_million) %>%
rename(persons_tried_per_million = value_reserved)
# Menampilkan data
head(bubble_data)
Setelah data dipersiapkan, selanjutnya adalah proses untuk membuat
Bubble Chart menggunakan fungsi
ggplot().
Berikut langkah-langkah untuk membuat Bubble
Chart.
Mempersiapkan Data: Pertama, kita membuat sebuah tibble (struktur
data dari package dplyr) yang akan menyimpan informasi untuk bubble
chart. Di dalam tibble ini, kita menentukan nilai dari 3 parameter
yaitu: x, y, dan size.
- Parameter
x \(\rightarrow\) diisi dengan nilai tetap 1
agar semua bubble terletak pada posisi yang sama secara horizontal.
- Parameter
y \(\rightarrow\) diisi dengan urutan dari 1
hingga banyaknya baris pada data, yang akan menjadi posisi vertikal dari
setiap bubble.
- Parameter
size \(\rightarrow\) diisi data
persons_tried_per_million.
Membuat Bubble Chart: Selanjutnya, kita menggunakan fungsi
ggplot() untuk membuat bubble chart. Di sini, kita
mengatur mapping aesthetic (aes) untuk x, y, dan size dari data yang
telah kita buat.
Menambahkan Bubble: Dengan menggunakan fungsi
geom_point(), kita menambahkan titik-titik (bubble) ke
plot. Kita mengatur warna bubble menjadi coral, dengan transparansi
(alpha) 0.7 dan ketebalan outline (stroke) sebesar 1.
Menambahkan Label: Kita juga menambahkan label menggunakan fungsi
geom_text(). Label ini akan menampilkan teks yang berada
dekat dengan bubble, dengan posisi horizontal sedikit di sebelah kiri (x
= 0.9) dan ukuran teks diatur menjadi 4 pt.
Mengatur Rentang Ukuran Bubble: Untuk memastikan bahwa ukuran
bubble terlihat proporsional, kita mengaturnya menggunakan fungsi
scale_size_continuous() untuk mengatur rentang ukuran
bubble antara 1 dan 18.
Menerapkan Tema Minimalis: Dengan menggunakan
theme_minimal(), kita mengubah tampilan plot menjadi lebih
sederhana dan bersih.
Mengatur Elemen Tampilan Plot: Kita melakukan beberapa
penyesuaian pada elemen-elemen di plot menggunakan fungsi
theme:
- Menghapus judul sumbu x dan y, serta menghilangkan teks dan tanda
pada sumbu menggunakan fungsi
element_blank pada parameter
axis.title.x, axis.text, dan
axis.ticks.
- Menghapus legend untuk membuat plot lebih bersih menggunaka niali
none pada parameter legend.position.
- Menghilangkan garis grid pada plot dengan cara menggunakan fungsi
element_blank() pada parameter
panel.grid.major, panel.grid.minor, dan
panel.border.
- Mengatur margin plot menjadi nol untuk memaksimalkan penggunaan
ruang pada parameter
plot.margin. Berisi 4 buah nilai yang
memiliki urutan top, right, bottom, left.
Menghapus Label/teks pada Sumbu X dan Y: Kita menambahkan labs()
dengan nilai NULL untuk memastikan bahwa label pada sumbu x
dan y tidak ditampilkan.
Mengatur Rentang Sumbu X: Menggunakan xlim(), kita
membatasi tampilan sumbu x antara 0 dan 1.5, untuk memastikan bubble
terlihat jelas.
Melakukan Cropping pada Plot: Terakhir, kita menggunakan
coord_cartesian() untuk mengatur cropping sehingga hanya
akan berfokus pada Bubble Chart saja.
Mari kita implementasikan ke dalam kode menggunakan bahasa R sebagai
berikut:.
# Menentukan X, Y, dan Size untuk menentukan ukuran bubble
data <- tibble(
x = 1,
y = 1:nrow(bubble_data),
size = c(bubble_data$persons_tried_per_million)
)
# Membuat bubble chart
bubble_chart <- ggplot(data, aes(x = x, y = y, size = size)) +
# Menentukan warna, transparansi (aplha), dan lebar outline (stroke) bubble
geom_point(color = "coral", alpha = 0.7, stroke = 1) +
#Mengatur letak dan ukuran label
geom_text(aes(x = 0.9, label = size), size = 4) +
# Mengatur rentang ukuran bubble
scale_size_continuous(range = c(1, 18)) +
# Mengatur agar tampilan plot minimalis
theme_minimal() +
# Mengatur beberapa element pada plot
theme(
# Menghapus judul, sumbu x, dan sumbu y
axis.title.x = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
# Menghapus legend
legend.position = "none",
# Menghapus garis (grid)
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
# Mengatur margin plot (top, right, bottom, left)
plot.margin = margin(0, 0, 0, 0)
) +
# Menghapus label pada sumbu X dan Y
labs(
x = NULL,
y = NULL
) +
# Mengatur range dari sumbu X
xlim(0, 1.5) +
# Melakukan cropping
coord_cartesian(xlim = c(0.9, 2))
# Menampilkan plot
bubble_chart

Setelah pembuatan bubble chart berhasil, saatnya untuk menyimpan plot
tersebut untuk dikombinasikan dengan plot yang lain.
ggsave(filename = "../asset/bubble_chart.png", plot = bubble_chart, width = 6, height = 5, dpi = 300)
4.2 Stacked Bar Chart
Untuk membuat Stacked Bar Chart pada kasus ini hanya
membutuhkan 4 data yaitu country,
persons_tried, deaths, dan
accused. Kolom accused berisi data orang yang
diadili tetapi tidak dihukum mati. Kolom ini perlu kita buat sendiri
dengan mengurangkan data pada kolom persons_tried dengan
deaths.
Berikut langkah-langkah yang perlu dilakukan:
- Mempersiapkan data
country, persons_tried,
dan deaths dari dataset history.
- Membuat kolom
accused dengan formula
persons_tried - deaths.
- Mengubah data ke long format menggunakan fungsi
pivot_longer.
- Membuat plot Stacked Bar Chart.
# Memilih data yang digunakan
data_plot = history %>% select(country, persons_tried, deaths)
# Membuat kolom accused
data_plot$accused = data_plot$persons_tried - data_plot$deaths
# Menampilkan data
data_plot
Agar data kita bisa digunakan untuk visualisasi, perlu kita ubah
formatnya dari wide format menjadi long format dengan
fungsi pivot_longer.
# ubah format data dengan pivot_longer()
data_plot <- data_plot %>%
pivot_longer(cols = c("accused", "deaths"),
names_to = "status",
values_to = "value")
# tampilkan data hasil format
print(data_plot)
Selanjutnya perlu kita ubah tipe data status menjadi
kategorikal dengan menggunakan fungsi factor().
# Ubah tipe data ke factor dan mengubah urutan dari kolom status
data_plot <- data_plot %>%
mutate(status = factor(status, levels = c("deaths", "accused")))
Setelah data dipersiapkan, selanjutnya adalah proses untuk membuat
Stacked Bar Chart menggunakan fungsi
ggplot().
Berikut langkah-langkah untuk membuat Stacked Bar
Chart.
Membuat Warna Kustom: Menentukan warna untuk membedakan antara
kategori deaths dan accused.
Membuat Stacked Bar Chart: Selanjutnya, kita mulai membuat
diagram. Namun plot ini disajikan dalam bentuk horizontal sehingga
seolah-olah sumbu x berada di sumbu y dan sebaliknya.
- Sumbu X \(\rightarrow\) nama
negara.
- Sumbu Y \(\rightarrow\) jumlah
individu yang diadili.
- Warna batang akan mencerminkan kategori yang berbeda
executed dan accused.
Mengatur Lebar Batang: Kita mengatur lebar batang agar terlihat
proporsional dan tidak terlalu lebar, sehingga memberikan sedikit ruang
antara batang-batang yang berdekatan. Lebar batang ditentukan
menggunakan parameter width.
Mengimplementasikan Warna Kustom: Warna yang telah ditentukan
sebelumnya diterapkan pada plot, sehingga memudahkan pemahaman visual
mengenai kategori yang ada. Parameter yang diatur yaitu
scale_fill_manual.
Menebalkan Garis Horizontal: Sebuah garis horizontal ditambahkan
pada sumbu Y di titik nol menggunakan parameter geom_hline.
Paramter yintercept diisi dengan nilai sumbu X di mana
garis akan ditempatkan. Sedangkan lwd untuk mengatur tebal
garis.
Menghapus Label pada sumbu X dan Y: Untuk mendapatkan tampilan
yang lebih bersih dan minimalis, label pada sumbu X dan Y dihapus
menggunakan parameter labs.
Mengubah Orientasi Plot: Orientasi plot diubah dari vertikal
menjadi horizontal menggunakan parameter
coord_flip.
Mengatur Elemen Plot: Menggunakan parameter theme,
berikut beberapa elemen yang diatur yaitu:
- Menghapus grid di dalam plot menggunakan
element_blank
pada parameter panel.grid.
- Mengatur posisi dan ukuran dari legend accused dan
executed.
- Mengatur batas tepi (margin) di mulai dari top, right, bottom, left
dalam satuan centimeter (cm).
Mengatur teks Sumbu Y: Diatur agar memiliki range antara 0 sampai
17.500 dengan jarak 2.500 menggunakan parameter breaks pada
bagian scale_y_continuos. Selain itu, terapkan pemisah
ribuan menggunakan parameter labels yang diisi dengan nilai
scales::comma.
Mengatur Legenda: Terakhir, legend diatur agar ditampilkan dalam
satu baris, menjadikannya lebih rapi dan mudah dibaca.
Mari kita implementasikan ke dalam kode menggunakan bahasa R sebagai
berikut:.
# Membuat warna kustom
custom_colors <- c("deaths" = "#0098a0", "accused" = "#70cbc4")
# Membuat stacked bar
stacked_bar_chart <- ggplot(data_plot, aes(x = reorder(country, value), y = value, fill = status)) +
# Mengatur lebar bar
geom_bar(stat = "identity", width = 0.8) +
# Implementasi warna kustom ke bar
scale_fill_manual(values = custom_colors, labels=c('Executed', 'Accused')) +
# Membuat horizontal line pada sumbu Y pada titik 0 dengan lebar 0.25
geom_hline(yintercept = 0,
lwd = 0.25) +
# Menghapus label pada sumbu X dan Y
labs(x = "", y = "") +
# Menghubah orientasi plot dari vertical ke horizontal
coord_flip() +
# Mengatur agar tampilan plot minimalis
theme_minimal() +
# Mengatur beberapa element pada plot
theme(
# Mengatur warna teks pada sumbu X dan Y
axis.text.x = element_text(color = "black"), # Align labels to the lef
axis.text.y = element_text(hjust = 0, color = "black"), # Align labels to the left
# Mengatur garis yang akan ditampilkan di tengah-tengah plot
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(size = 0.75, color = "#cbccce"),
# Mengatur posisi dan ukuran dari legend
legend.title = element_blank(),
legend.position = c(0.3, 1.1),
legend.margin = margin(0, 0, 15, 0),
legend.key.height = unit(0.3, "cm"),
legend.key.width = unit(0.7, "cm"),
legend.key.spacing.x = unit(0.9, "cm"),
# Mengatur margin dari plot secara umum
plot.margin = margin(0.7, 4, 0.5, 0, "cm")
) +
# Mengatur teks pada sumbu Y
scale_y_continuous(
# Mengatur nilai dimulai dari 0 sampai 17.500 dengan jarak 2.500
breaks = seq(0, 17500, by = 2500),
# Mengatur batas/limit teks yang ditampilkan pada sumbu Y
limits = c(0, 17500),
# Mengurangi ruang kosong pada kanan kiri atas bawah plot
expand = expansion(mult = c(0, 0)),
# Menambah pemisah ribuan pada sumbu Y
labels = scales::comma,
# Mengatur posisi sumbu Y
position = "right"
) +
# Menatur agar legend horizontal
guides(fill = guide_legend(nrow = 1, byrow = TRUE, reverse = TRUE))
# Menampilkan plot
stacked_bar_chart

Setelah pembuatan stacked chart berhasil, saatnya untuk menyimpan
plot tersebut untuk dikombinasikan dengan plot yang lain.
ggsave(filename = "../asset/stacked_bar_chart.png", plot = stacked_bar_chart, width = 6, height = 4, dpi = 300)
4.3 Line Chart
Untuk membuat Line Chart, akan digunakan dataset
witch trails. Sama seperti 2 plot sebelumnya, untuk membuat Line
Chart juga akan memanfaatkan library dari ggplot.
Namun sebelum itu, kita perlu mempersiapkan datanya terlebih dahulu
untuk menjumlahkan total individu yang diadili tiap dekade.
Berikut langkah-langkah yang perlu dilakukan:
- Mempersiapkan data
decade, deaths, dan
tried dari dataset witch_trials.
- Lakukan proses grouping dengan fungsi
group_by untuk
menjumlahkan total individu yang dihukum mati dan tidak menggunakan
fungsi summarise.
- Membuat plot Line Chart.
# Proses groupBy untuk menjumlahkan deaths dan tried untuk tiap dekade
data_line_chart <- witch_trials %>%
group_by(decade) %>%
summarise(
deaths = sum(deaths),
tried = sum(tried)
)
# Menampilkan data
data_line_chart
Setelah data sudah berhasil dijumlahkan untuk setiap dekade,
selanjutnya yaitu pembuatan line plot menggunakan fungsi
ggplot.
Berikut langkah-langkah untuk membuat Stacked Bar
Chart.
Membuat fungsi custom_labels yang digunakan untuk
menampilkan teks pada sumbu X. Akan menampilkan tahun secara lengkap
jika tahun tersebut tidak diakhiri dengan angka 50. Tapi jika diakhiri
angka 50, hanya akan ditampilkan angka 50. Misalnya: Tahun 1800 akan
ditampilkan 1800. Tahun 1850 akan ditampilkan 50.
Membuat Line Plot: Dengan menggunakan fungsi
geom_line, akan dibuat 2 garis yaitu garis untuk data
deaths yang akan diberi label executed dan
garis untuk data tried yang diberi label
accused.
Menghapus Label pada sumbu X dan Y: Untuk mendapatkan tampilan
yang lebih bersih dan minimalis, label pada sumbu X dan Y dihapus
menggunakan parameter labs.
Mengatur Sumbu X: Pada sumbu X dengan fungsi
scale_x_continuos, kita mengatur beberapa hal sebagai
berikut:
- Membuat major breaks pada sumbu X dengan range 1300 sampai 1850 yang
dipisahkan setiap 50 satuan.
- Membuat minor breaks pada sumbu X dengan range 1300 sampai 1850 yang
dipisahkan setiap 10 satuan.
- Menuliskan teks label pada sumbu X dengan memanggil fungsi
custom_labels yang sudah dibuat di atas.
- Menampilkan garis kecil sepanjang sumbu X dengan menggunakan fungsi
guide_axis.
Mengatur Sumbu Y: Pada sumbu Y dengan fungsi
scale_y_continuos, kita mengatur beberapa hal sebagai
berikut:
- Membuat major breaks pada sumbu Y dengan range 0 sampai 6000 yang
dipisahkan setiap 1000 satuan.
- Mengatur ruang kosong di sekitar plot menggunakan fungsi
expansion.
- Menuliskan teks label pada sumbu Y yang dipisahkan dengan koma
menggunakan parameter
scales::comma.
- Mengatur agar posisi sumbu Y berada pada sisi kanan menggunakan
fungsi
position.
Mengatur Elemen Plot: Menggunakan parameter theme,
berikut beberapa elemen yang diatur yaitu:
- Menghapus grid di dalam plot menggunakan
element_blank
pada parameter panel.grid.
- Mengatur tebal dan panjang (mayor ticks dan minor ticks) menggunakan
fungsi
axis.ticks.
- Mengatur agar warna background foto dengan warna putih menggunakan
fungsi
plot.background.
Menambahkan Highlight: Kita menyoroti rentang tahun antara 1555
hingga 1648 dengan menambahkan persegi panjang berwarna coral
transparan. Hal ini membantu menarik perhatian pada periode tertentu
yang relevan dengan data. Untuk melakukan hal ini, digunakan parameter
geom pada fungsi annotate.
xmin \(\rightarrow\)
nilai pada sumbu X untuk memulai highlight.
xmax \(\rightarrow\)
nilai pada sumbu X untuk mengakhiri highlight.
ymin \(\rightarrow\)
nilai pada sumbu Y untuk menentukan titik awal tinggi highlight.
ymax \(\rightarrow\)
nilai pada sumbu Y untuk menentukan titik akhir tinggi highlight.
fill \(\rightarrow\)
menentukan warna.
alpha \(\rightarrow\)
menentukan tingkat transparansi. Semakin kecil semakin transparan.
Menambahkan teks yang lain: Menggunakan parameter
text pada fungsi annotate untuk menuliskan
teks executed, accused,
protestant reformation, dan
catholic counter-reformation.
Menambahkan garis titik titik pada teks protestant
reformation menggunakan fungsi geom_segment.
Menambahkan teks pada sisi kiri atas menggunakan fungsi
geom_label.
Mari kita implementasikan ke dalam kode menggunakan bahasa R sebagai
berikut:.
# Fungsi untuk membuat label custom
custom_labels <- function(x) {
# Membuat temporary variable
labels <- ""
# Looping untuk cek data dekade. Jika mengandung 50, hanya ditulis angka 50. Jika tidak, akan ditulis lengkap.
for (i in seq_along(x)) {
if (grepl("50$", as.character(x[i]))) {
labels[i] <- "50"
} else {
labels[i] <- as.character(x[i])
}
}
# Mengembalikan nilai dekade
return(labels)
}
# Membuat line plot
line_chart <- ggplot(data_line_chart, aes(x = decade)) +
# Membuat line untuk kolom deaths
geom_line(aes(y = deaths), color = "#0098a0", size = 2) +
# Membuat line untuk kolom tried
geom_line(aes(y = tried), color = "#70cbc4", size = 2) +
# Menghapus label pada sumbu X dan Y
labs(x = "", y = "") +
# Mengatur agar tampilan plot minimalis
theme_minimal() +
scale_x_continuous(
breaks = seq(1300, 1850, by = 50), # Tentukan titik utama
minor_breaks = seq(1300, 1850, by = 10), # Tentukan titik minor
# labels = seq(1300, 1850, by = 50),
labels = custom_labels,
guide = guide_axis(minor.ticks = TRUE),
) +
# Mengatur teks pada sumbu Y
scale_y_continuous(
# Mengatur nilai dimulai dari 0 sampai 6.000 dengan jarak 1.000
breaks = seq(0, 6000, by = 1000),
# Mengurangi ruang kosong pada kanan kiri atas bawah plot
expand = expansion(mult = c(0, 0)),
# Menambah pemisah ribuan pada sumbu Y
labels = scales::comma,
# Mengatur posisi sumbu Y
position = "right"
) +
# Mengatur beberapa element pada plot
theme(
# Mengatur warna teks pada sumbu X dan Y
axis.text.x = element_text(color = "black"), # Align labels to the lef
axis.text.y = element_text(hjust = 0, color = "black"), # Align labels to the left
# Mengatur garis yang akan ditampilkan di tengah-tengah plot
panel.grid.minor.x = element_blank(),
panel.grid.minor.y = element_blank(),
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_line(size = 0.75, color = "#cbccce"),
# Mengatur ketebalan ticks
axis.ticks.x = element_line(size = 0.6),
#axis.minor.ticks.x.bottom = element_line(size = 0.3),
# Mengatur panjang ticks
axis.ticks.length = unit(0.2, "cm"),
axis.minor.ticks.length = unit(0.1, "cm"),
# Mengatur tebal garis sumbu X
axis.line.x = element_line(size = 0.6),
# Mengatur margin dari plot secara umum
plot.margin = margin(1.5, 0, 0, 1, "cm") ,
plot.background = element_rect(fill = "white", colour = NA)
) +
# Membuat highlight pada rentang tahun 1560 s.d. 1650
annotate(geom = "rect", xmin = 1555, xmax = 1648, ymin = 0, ymax = Inf,
fill = "coral", alpha = 0.2) +
annotate("text", x = 1585, y = 250, label = "Executed", size = 4.2, hjust = 0) +
annotate("text", x = 1710, y = 850, label = "Accused", size = 4.2, hjust = 0) +
annotate("text", x = 1515, y = 2720, label = "PROTESTANT", size = 4.2, hjust = 1) +
annotate("text", x = 1515, y = 2320, label = "REFORMATION", size = 4.2, hjust = 1) +
annotate("text", x = 1650, y = 5720, label = "CATHOLIC", size = 4.2, hjust = 0) +
annotate("text", x = 1650, y = 5320, label = "COUNTER-REFORMATION", size = 4.2, hjust = 0) +
geom_segment(aes(x = 1515, xend = 1515, y = 0, yend = 2200),
linetype = "dotted", color = "coral", size = 1.3) +
geom_label(aes(x = -Inf, y = Inf, label = "By decade"),
hjust = 0, vjust = 0.8, size = 5, label.size = 0)
# Menampilkan plot
line_chart

Setelah pembuatan line chart berhasil, saatnya untuk menyimpan plot
tersebut untuk dikombinasikan dengan plot yang lain.
ggsave(filename = "../asset/line_chart.png", plot = line_chart, width = 6.6, height = 4.3, dpi = 300)
5. Final Result
Langkah terakhir yaitu menggabungkan semua plot menjadi satu kesatuan
plot. Beberapa langkah yang harus dilakukan yaitu:
- Siapkan
bubble_chart.png,
stacked_bar_chart.png, dan
line_chart.png.
- Memotong bagian plot yang diperlukan saja (cropping).
- Menggabungkan semua chart menjadi sebuah chart.
- Menambah header garis merah sebagai ciri khas The Economist.
- Tambahkan teks lain yang diperlukan.
Pertama yaitu menyiapkan gambar dari bubble chart yang sudah
disimpan. Dalam hal ini, kita hanya membutuhkan bagian angka dan
visualisasinya saja. Oleh karena itu, perlu kita buang sisi lain yang
tidak digunakan.
# Membaca gambar bubble chart
bubble_chart_img <- image_read("../asset/bubble_chart.png")
# Menyimpan lebar dan tinggi plot
img_width <- image_info(bubble_chart_img)$width
img_height <- image_info(bubble_chart_img)$height
# Menambah white space di atas plot
blank_space <- image_blank(width = img_width, height = 200, color = "white")
# Melakukan proses stacking (menambah) blank space ke bubble chart
bubble_chart_img <- image_append(c(blank_space, bubble_chart_img), stack = TRUE)
# proses cropping dengan ukuran yang dibutuhkan
cropped_bubble_chart_img <- image_crop(bubble_chart_img, "330x1700+0+0")
# Menyimpan gambar hasil crop
image_write(cropped_bubble_chart_img, "../asset/cropped_bubble_chart.png")
Proses selanjutnya yaitu menggabungkan bubble chart
yang sudah di crop dengan stacked bar chart.
# Menyimpan hasil kombinasi
png("../asset/bubble_bar_combined.png", width = 10, height = 7, units = "in", res = 300)
# Membaca plot bubble chart
img1 <- rasterGrob(as.raster(readPNG("../asset/cropped_bubble_chart.png")), interpolate = TRUE)
# Membaca plot stacked bar chart
img2 <- rasterGrob(as.raster(readPNG("../asset/stacked_bar_chart.png")), interpolate = TRUE)
# Proses menggabungkan plot
grid.arrange(img1, img2, ncol = 2, widths = c(0.4, 3.35))
Selanjutnya yaitu menggabungkan bubble chart dan
stacked bar chart yang sudah digabungkan sebelumnya
dengan line chart dan disimpan dengan nama
all_chart_combined.png.
# Menyimpan gambar hasil kombinasi 3 plot
png("../asset/all_chart_combined.png", width = 7.28, height = 4.3, units = "in", res = 500)
# Membaca gambar kombinasi bubble chart dan stacked bar chart dengan line chart
bubble_bar_combined <- rasterGrob(as.raster(readPNG("../asset/bubble_bar_combined.png")), interpolate = TRUE)
line_chart <- rasterGrob(as.raster(readPNG("../asset/line_chart.png")), interpolate = TRUE)
# Menyiapkan halaman baru untuk meletakan smua plot
grid.newpage()
# Mengatur posisi dan ukuran gambar dari bubble_bar_combined
pushViewport(viewport(x = 0.02, y = 0.49, width = 0.75, just = "left"))
# Meletakan gambar bubble_bar_combined ke tempat yang sudah disediakan
grid.draw(bubble_bar_combined)
upViewport()
# Mengatur posisi dan ukuran gambar dari line chart
pushViewport(viewport(x = 0.43, y = 0.335, width = 0.37))
# Meletakan gambar line chart ke tempat yang sudah disediakan
grid.draw(line_chart)
upViewport()
Menambah header garis merah sebagai ciri khas The Economist dan
menambahkan teks lain yang diperlukan seperti footnote yang menjelaskan
sumber data yang digunakan. Berikut langkah-langkah yang dilakukan:
Menambahkan garis merah tipis sepanjang plot menggunakan fungsi
grid.react.
Menambahkan kotak garis merah di sebelah kiri atas. Setelah garis
tipis menggunakan fungsi grid.react.
Menambahkan judul utama dan sub judul pada plot menggunakan
fungsi grid.text.
- Nilai
x merupakan posisi teks secara horizontal.
Semakin besar maka posisi semakin ke kanan.
- Nilai
y merupakan posisi teks secara vertikal. Semakin
besar maka semakin ke atas.
- Fungsi
gpar untuk mengatur ukuran huruf.
Menambahkan footnote di bawah plot yang menjelaskan sumber data
yang dirujuk dalam pembuatan plot. Untuk membuat footnote digunakan
fungsi grid.text,
Membuat kotak persegi panjang di atas bubble chart menggunakan
fungsi grid.react.
- Nilai
x merupakan posisi teks secara horizontal.
Semakin besar maka posisi semakin ke kanan.
- Nilai
y merupakan posisi teks secara vertikal. Semakin
besar maka semakin ke atas.
- Fungsi
width untuk mengatur lebar box.
- Fungsi
height untuk mengatur tinggi box.
- Fungsi
gpar untuk menentukan warna dan tingkat
transparansi warna.
Menambahkan teks di dalam kotak persegi panjang menggunakan
fungsi grid.text.
Membuat segitiga terbalik berukuran kecil di bawah kotak
menggunakan fungsi grid.polygon.
Mari kita implementasikan ke dalam kode menggunakan bahasa R sebagai
berikut:.
# Menambah header garis merah sebagai ciri khas The Economist
grid.rect(x = 1, y = 0.997,
hjust = 1, vjust = 0,
gp = gpar(fill='#E5001C',lwd=0))
grid.rect(x = 0.013, y = 0.94,
hjust = 1, vjust = 0,
gp = gpar(fill='#E5001C',lwd=0))
# Menambah judul pada plot
grid.text("Double, double toil and trouble",
x = 0.330, y = 0.935,
hjust = 1, vjust = 0,
gp = gpar(fontsize=11, fontface="bold"))
grid.text("European witchcraft, 1300-1850",
x = 0.235, y = 0.9,
hjust = 1, vjust = 0,
gp = gpar(fontsize=7.8))
# Menambah footnote
grid.text('Source: "Witch Trials", by Peter Leeson and Jacob Russ,',
x = 0.308, y = 0.12,
hjust = 1, vjust = 0,
gp = gpar(fontsize=5.67))
grid.text("Economic Journal,",
x = 0.403, y = 0.12,
hjust = 1, vjust = 0,
gp = gpar(fontface = "italic", fontsize=5.67))
grid.text('August, 2017',
x = 0.47, y = 0.12,
hjust = 1, vjust = 0,
gp = gpar(fontsize=5.67))
grid.text('Economist.com',
x = 0.08, y = 0.09,
hjust = 1, vjust = 0,
gp = gpar(fontsize=5.67, col = "#C0C0C0"))
# Membuat orange box di atas bubble chart
grid.rect(x = 0.095, y = 0.805,
width = 0.135, height = 0.074,
gp = gpar(fill = "coral", alpha = 0.7, col = NA))
# Menambahkan teks di dalam orange box
grid.text('Witchcraft trials',
x = 0.143, y = 0.815,
hjust = 1, vjust = 0,
gp = gpar(fontsize=7))
grid.text('per 100,000 people',
x = 0.153, y = 0.785,
hjust = 1, vjust = 0,
gp = gpar(fontsize=7))
# Membuat segitiga terbalik yang ada di ornage box
x <- c(0.0785, 0.0725, 0.0845)
y <- c(0.761, 0.768, 0.768)
grid.polygon(x = x, y = y, gp = gpar(fill = "coral", alpha = 0.7, col = NA))
Terkahir yaitu melakukan cropping untuk menyeleksi bagian yang
penting saja. White space yang berlebih akan dihapus (crop). Lalu hasil
crop akan disimpan dengan nama final.png dan merupakan
hasil akhir dari proyek ini.
# Membaca plot yang berisi 3 chart
final_image <- image_read("../asset/all_chart_combined.png")
# proses cropping dengan ukuran yang dibutuhkan
cropped_final_image <- image_crop(final_image, "2300x1980+0+0")
# Menyimpan gambar hasil crop
image_write(cropped_final_image, "../asset/final.png")

LS0tDQp0aXRsZTogIlJlcGxpY2F0ZSBFdXJvcGVhbiBXaXRjaGNyYWZ0IFBsb3QiDQphdXRob3I6IEFkaSBaYWVudWwgTXVzdGFxaW0NCmRhdGU6IDEyIFNlcHRlbWJlciAyMDI0DQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDINCi0tLQ0KDQo8c3R5bGU+DQpib2R5IHsNCnRleHQtYWxpZ246IGp1c3RpZnkNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNsZWFyLXVwIHRoZSBlbnZpcm9ubWVudA0Kcm0obGlzdCA9IGxzKCkpDQoNCiMgY2h1bmsgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBtZXNzYWdlID0gRkFMU0UsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgZmlnLmFsaWduID0gImNlbnRlciINCikNCmBgYA0KDQoNCiMgMS4gSW50cm9kdWN0aW9uDQpbVGhlIEVjb25vbWlzdF0oaHR0cHM6Ly93d3cuZWNvbm9taXN0LmNvbS8pIGFkYWxhaCBtYWphbGFoIG1pbmdndWFuIHlhbmcgYmVyZm9rdXMgcGFkYSBiZXJpdGEgZGFuIGFuYWxpc2lzIHRlbnRhbmcgZWtvbm9taSwgcG9saXRpaywgYmlzbmlzLCB0ZWtub2xvZ2ksIGRhbiBidWRheWEuIERpZGlyaWthbiBwYWRhIHRhaHVuIDE4NDMsIG1hamFsYWggaW5pIGRpa2VuYWwgZGVuZ2FuIHN1ZHV0IHBhbmRhbmdueWEgeWFuZyBnbG9iYWwgZGFuIGFuYWxpc2lzIHlhbmcgbWVuZGFsYW0gdGVyaGFkYXAgaXN1LWlzdSB0ZXJraW5pLiBIYWwgbWVuYXJpayBkYXJpIG1hamFsYWggaW5pIHlhaXR1IGFkYW55YSB2aXN1YWxpc2FzaSBiZXJ1cGEgZ3JhZmlrL3Bsb3QgeWFuZyBkaXRhbXBpbGthbiBkZW5nYW4gbWVuYXJpay4gUGFkYSBhcnRpa2VsIGluaSwga2FtaSBha2FuIG1lbmNvYmEgbWVyZXBsaWthc2kgcGxvdCBkYXJpIFRoZSBFY29ub21pc3QgbWVuZ2d1bmFrYW4gbGlicmFyeSAqKmdncGxvdCoqLg0KDQrwn5OMICoqT2JqZWt0aWY6KioNCg0KUHJveWVrIGluaSBtZW5qZWxhc2thbiBiYWdhaW1hbmEgY2FyYSBtZW1idWF0IHJlcGxpa2EgdmlzdWFsaXNhc2kgZGFyaSBtYWphbGFoIFRoZSBFY29ub21pc3QuIEhhbCBpbmkgZGlsYWt1a2FuIHVudHVrIG1lbWJ1a3Rpa2FuIGJhaHdhIHZpc3VhbGlzYXNpIHRlcnNlYnV0IGRhcGF0IGtpdGEgYnVhdCBkYW4gcmVwbGlrYSBtZW5nZ3VuYWthbiBiYWhhc2EgcGVtcm9ncmFtYW4gUiBtZW5nZ3VuYWthbiBsaWJyYXJ5ICoqZ2dwbG90KiouDQoNCuKcqCAqKk1hbmZhYXQ6KioNCg0KU2V0ZWxhaCBBbmRhIG1lbWJhY2EgYXJ0aWtlbCBpbmksIGRpaGFyYXBrYW4gQW5kYToNCg0KMS4gTWVuZ2VydGkgZGFzYXItZGFzYXIgcGVtcm9ncmFtYW4gUi4NCjIuIE1lbmdlcnRpIGNhcmEgbWVtYnVhdCB2aXN1YWxpc2FzaSBtZW5nZ3VuYWthbiBsaWJyYXJ5ICoqZ2dwbG90KiouDQozLiBNZW5nZXJ0aSBqZW5pcyBwbG90IHlhbmcgc2VzdWFpIGJlcmRhc2Fya2FuIGRhdGEgeWFuZyBhZGEgZGFuIGRhcGF0IG1lbmdndW5ha2FuIGplbmlzIHBsb3QgdGVyc2VidXQgdW50dWsga2FzdXMgeWFuZyBiZXJiZWRhIGRpa2VtdWRpYW4gaGFyaS4NCg0K8J+SoSAqKlRhcmdldCBQZW1iYWNhOioqDQoNCkFydGlrZWwgaW5pIGNvY29rIGJhZ2kgc2lhcGEgc2FqYSB5YW5nIGluZ2luIG1lbXVsYWkgYmVsYWphciBiYWhhc2EgcGVtcm9ncmFtYW4gUi4gU2VsYWluIGl0dSwgYXJ0aWtlbCBpbmkganVnYSBiZXJtYW5mYWF0IGJhZ2kgc2VvcmFuZyBkYXRhIGFuYWxpcyBhZ2FyIG1lbmphZGkgcnVqdWthbiBkYWxhbSBtZW1idWF0IHZpc3VhbGlzYXNpIGRhbGFtIGJlcmJhZ2FpIGthc3VzIHV0YW1hbnlhIGppa2EgbWVuZ2d1bmFrYW4gbGlicmFyeSAqKmdncGxvdCoqLiBBcnRpa2VsIGluaSBiZXJtYW5mYWF0IHVudHVrIG9yYW5nLW9yYW5nIHlhbmcgdGVydGFyaWsgZGVuZ2FuIHZpc3VhbGlzYXNpIGRhdGEgZGFuIGluZ2luIG1lbXBlbGFqYXJpIGNhcmEgbWVyZXBsaWthc2kgZ3JhZmlrLWdyYWZpayB5YW5nIHRlcmtlbmFsIGRhbiBrb21wbGVrcy4gRGFsYW0gYXJ0aWtlbCBpbmkgZGlqZWxhc2thbiBmbG93IGRhcmkgcGVtYmVyc2loYW4gZGF0YSwgbWVueWlhcGthbiBkYXRhIHVudHVrIHBlbWJ1YXRhbiBwbG90LCBwZW1idWF0YW4gcGxvdCBpdHUgc2VuZGlyaSwgZGFuIG1lbmdnYWJ1bmdrYW4gYmViZXJhcGEgcGxvdCBtZW5qYWRpIDEuIEhhbCBpbmkgYmlzYSBkaWphZGlrYW4gY29udG9oIGppa2EgYWRhIHBlbWJhY2EgeWFuZyBha2FuIG1lbGFrdWthbiBoYWwgeWFuZyBzYW1hLg0KDQrwn5OKICoqSmVuaXMgUGxvdDoqKg0KDQpBcnRpa2VsIGluaSBha2FuIG1lbWJ1YXQgc2VidWFoIHZpc3VhbGlzYXNpIHlhbmcgdGVyZGlyaSBkYXJpIGtvbWJpbmFzaSAzIHBsb3Qgc2ViYWdhaSBiZXJpa3V0Og0KDQoxLiAqKkJ1YmJsZSBDaGFydCoqICRccmlnaHRhcnJvdyQgbWVuYW1waWxrYW4ganVtbGFoIGluZGl2aWR1IHlhbmcgZGlhZGlsaS4gQnViYmxlIGNoYXJ0IG1lbWlsaWtpIGJlbnR1ayBiZXJ1cGEgbGluZ2thcmFuLiBTZW1ha2luIGx1YXMgbGluZ2thcmFuLCBtYWthIG5pbGFpbnlhIHNlbWFraW4gdGluZ2dpLg0KMi4gKipTdGFja2VkIEJhciBDaGFydCoqICRccmlnaHRhcnJvdyQgbWVuYW1waWxrYW4ganVtbGFoIGluZGl2aWR1IHlhbmcgZGlhZGlsaSBiYWlrIG1lbmRhcGF0IGh1a3VtYW4gbWF0aSAoZXhlY3V0ZWQpIGF0YXUgdGlkYWsgZGlodWt1bSBtYXRpIChhY2N1c2VkKSBwYWRhIHN1YXR1IG5lZ2FyYS4gU3RhY2tlZCBiYXIgY2hhcnQgYXRhdSBkaWFncmFtIGJhdGFuZyBiZXJ0dW1wdWsgc2VwZXJ0aSBuYW1hbnlhIGRpYWdyYW0gdGVyc2VidXQgYmVyYmVudHVrIGRpYWdyYW0gYmF0YW5nIHlhbmcgdGVyZGlyaSBkYXJpIDIga2F0ZWdvcmkgKGV4ZWN1dGVkIGRhbiBhY2N1c2VkKSB5YW5nIGRpc3VzdW4gc2VjYXJhIGJlcnR1bXB1ay4NCjMuICoqTGluZSBDaGFydCoqICRccmlnaHRhcnJvdyQgbWVuYW1waWxrYW4gZ3JhZmlrIGdhcmlzIHlhbmcgbWVudW5qdWthbiB0cmFjayByZWNvcmQgZGFyaSBpbmRpdmlkdSB5YW5nIGRpYWRpbGkgdGlhcCB0YWh1biBkYWxhbSByZW50YW5nIHRhaHVuIDEzMDAgcy5kLiAxODUwLiBMaW5lIGNoYXJ0IGJlcmJlbnR1ayBnYXJpcyB5YW5nIGRhcGF0IG1lbmplbGFza2FuIHRlbnRhbmcgc3VhdHUgZGF0YSBiZXJkYXNhcmthbiB1cnV0YW4gd2FrdHUuDQoNCg0KU2V0ZWxhaCBraXRhIHRhaHUgdHVqdWFuLCBtYW5mYWF0LCBkYW4gaGFsIHlhbmcgYWthbiBraXRhIGxha3VrYW4sIG1hcmkga2l0YSBtZWxhbmdrYWggbGViaWggbGFuanV0IHVudHVrIG1lbXBlcnNpYXBrYW4gcGVuZ2VyamFhbiBwcm9qZWN0Lg0KDQojIDIuIEJhY2tncm91bmQgey50YWJzZXR9DQojIyAyLjEgQXJ0aWNsZQ0KUGFkYSB0YWh1biAxMzAwIC0gMTg1MCBhbiwgcHJha3RpayBwZW51ZHVoYW4gc2VzZW9yYW5nIG1lbWlsaWtpIGlsbXUgc2loaXIgZGkgRXJvcGEgbGF6aW0gdGVyamFkaS4gVHVkdWhhbiBpbmkgc2VyaW5nIGRpZ3VuYWthbiBvbGVoIHBlbmd1YXNhIHVudHVrIG1lbmdlbmRhbGlrYW4gbWFzeWFyYWthdCBkYW4gbWVuZ2FsaWhrYW4gcGVyaGF0aWFuIGRhcmkgbWFzYWxhaCB5YW5nIGxlYmloIGJlc2FyIChzZWJhZ2FpIHBlbmdhbGloYW4gaXN1KS4gRGFsYW0gYXJ0aWtlbCB5YW5nIGJlcmp1ZHVsIFtUaGUgcG9saXRpY2FsIGVjb25vbXkgb2Ygd2l0Y2hjcmFmdF0oaHR0cHM6Ly93d3cuZWNvbm9taXN0LmNvbS9ncmFwaGljLWRldGFpbC8yMDE3LzEwLzMxL3RoZS1wb2xpdGljYWwtZWNvbm9teS1vZi13aXRjaGNyYWZ0KSBpbmkgZGlzYWppa2FuIHN0YXRpc3RpayBqdW1sYWggb3JhbmcgeWFuZyBkaXR1ZHVoIG1lbWlsaWtpIGlsbXUgc2loaXIgZGFuIGp1bWxhaCBvcmFuZyB5YW5nIGRpZWtzZWt1c2kgbWF0aSBha2liYXQgdHVkdWhhbiB0ZXJzZWJ1dC4gQmVyaWt1dCBhZGFsYWggdGFtcGlsYW4gdmlzdWFsaXNhc2kgeWFuZyBha2FuIGRpLXJlcGxpY2F0ZS4NCg0KIVtdKC4uL2Fzc2V0L0dyYXBoLmpwZykNCg0KIyMgMi4yIEltcG9ydCBMaWJyYXJ5DQpJbXBvcnQgYmViZXJhcGEgbGlicmFyeSB5YW5nIGRpYnV0dWhrYW4gdW50dWsgcGVtYnVhdGFuIHJlcGxpa2EgdmlzdWFsaXNhc2kuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBkYXRhIHdyYW5nbGluZw0KbGlicmFyeShnZ3Bsb3QyKSAjIGRhdGEgdmlzdWFsaXphdGlvbg0KbGlicmFyeShkcGx5cikgIyBkYXRhIHdyYW5nbGluZw0KbGlicmFyeShncmlkKSAjIGNyZWF0ZSBncmlkDQpsaWJyYXJ5KGdyaWRFeHRyYSkgIyBtZXJnZSBncmlkDQpsaWJyYXJ5KHBuZykgIyBpbXBvcnQgcGxvdCB0byBpbWFnZQ0KbGlicmFyeShtYWdpY2spICMgY29tYmluZSBwbG90DQpgYGANCg0KDQojIDMuIERhdGEgUHJlcHJvY2Vzc2luZyB7LnRhYnNldH0NCg0KU2ViZWx1bSBtZW1idWF0IHZpc3VhbGlzYXNpLCBkaXBlcmx1a2FuIHByb3NlcyBEYXRhIFByZXByb2Nlc3NpbmcgdW50dWsgbWVuZ29sYWggZGF0YSB0ZXJsZWJpaCBkYWh1bHUgdW50dWsgbWVueWlhcGthbiBkYXRhIHlhbmcgYmlzYSBkaWd1bmFrYW4gdW50dWsgdmlzdWFsaXNhc2kgc2VwZXJ0aSBtZW5ndWJhaCB0aXBlIGRhdGEga2UgYmVudHVrIHlhbmcgc2VzdWFpLCBtZW5naGlsYW5na2FuIHNpbWJvbCwgZGFuIGxhaW4gc2ViYWdhaW55YS4NCg0KIyMgMy4xIExvYWQgRGF0YQ0KDQpQYWRhIGthc3VzIGluaSBha2FuIGRpZ3VuYWthbiAyIGRhdGEuIA0KDQoqICoqRGF0YXNldCBIaXN0b3J5KiogZGlhbWJpbCBkYXJpIGFydGlrZWwgWypXaXRjaCB0cmlhbHMqXShodHRwczovL29ubGluZWxpYnJhcnkud2lsZXkuY29tL2RvaS9hYnMvMTAuMTExMS9lY29qLjEyNDk4KSBrYXJ5YSBQZXRlciBULiBMZWVzb24gZGFuIEphY29iIFcuIFJ1c3MgeWFuZyBkaXRlcmJpdGthbiBwYWRhICoqVGhlIEVjb25vbWljIEpvdXJuYWwqKiAoKlRhYmxlIDEgV2l0Y2gtdHJpYWxzIEFjdGl2aXR5IEFjcm9zcyBDb3VudHJpZXMqLCAxMzAw4oCTMTg1MCkgeWFuZyBiZXJpc2kgZGF0YSBuZWdhcmEgZGkgRXJvcGEgeWFuZyBtZW5qYWxhbmthbiBwcm9zZXMgcGVuZ2FkaWxhbiB1bnR1ayBvcmFuZy1vcmFuZyB5YW5nIGRpdHVkdWggbWVtaWxpa2kgaWxtdSBzaWhpci4NCiogKipEYXRhc2V0IFdpdGNoIHRyaWFscyoqICBkaWFtYmlsIGRhcmkgWypLYWdnbGUqXShodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL21pY2hhZWxicnlhbnRkcy93aXRjaC10cmlhbHMpIHlhbmcgYmVyaXNpIGRhdGEgc3Blc2lmaWsganVtbGFoIG9yYW5nIHlhbmcgZGlhZGlsaSBwYWRhIHJlbnRhbmcgdGFodW4gMTMwMCAtIDE4NTAuDQoNCkRhdGFzZXQgaGlzdG9yeSBha2FuIGRpZ3VuYWthbiB1bnR1ayBtZW1idWF0ICoqQnViYmxlIENoYXJ0KiogZGFuICoqU3RhY2tlZCBCYXIgQ2hhcnQqKi4gU2VkYW5na2FuIGRhdGFzZXQgd2l0Y2ggdHJpYWxzIGRpZ3VuYWthbiB1bnR1ayBtZW1idWF0ICoqTGluZSBDaGFydCoqLiBNYXJpIGtpdGEgbGFrdWthbiB0YWhhcCBwcmVwcm9jZXNzaW5nIHVudHVrIGtlZHVhIGRhdGFzZXQgdGVyc2VidXQuDQoNCiMjIyBBLiBEYXRhc2V0IEhpc3RvcnkNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmhpc3RvcnkgPC0gcmVhZC50YWJsZSgiLi4vZGF0YV9pbnB1dC9oaXN0b3J5LmNzdiIsIHNlcCA9ICIgIiwgaGVhZGVyID0gVFJVRSkNCmhpc3RvcnkNCmBgYA0KKipQZW5qZWxhc2FuIERhdGE6KioNCg0KQmVyZGFzYXJrYW4gdGFiZWwgZGkgYXRhcyBkYXBhdCBkaWtldGFodWkgYmFod2EgZGF0YXN0ZSBoaXN0b3J5IG1lbWlsaWtpIDE1IGRhdGEgeWFuZyB0ZXJkaXJpIGRhcmkgOCBrb2xvbS4gUGVuamVsYXNhbiBkYXJpIGtvbG9tLWtvbG9tIHRlcnNlYnV0IGFkYWxhaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNCiogKipjb3VudHJ5KiogPSBuYW1hIG5lZ2FyYSBhdGF1IHdpbGF5YWggdGVtcGF0IHBlbmdhZGlsYW4gcGVueWloaXIgYmVybGFuZ3N1bmcuDQoqICoqcG9wdWxhdGlvbioqID0ganVtbGFoIHBvcHVsYXNpIHBlbmR1ZHVrIG5lZ2FyYSB0ZXJzZWJ1dC4NCiogKipwZXJzb25zX3RyaWVkKiogPSBqdW1sYWggdG90YWwgaW5kaXZpZHUgeWFuZyBkaWFkaWxpIGJhaWsgeWFuZyBkaWh1a3VtIG1hdGkgYXRhdXB1biB0aWRhay4NCiogKipwZXJfY2VudF9vZl90b3RhbF90cmllZCoqID0gcGVyc2VudGFzZSBqdW1sYWggcGVuZ2FkaWxhbiBwYWRhIG5lZ2FyYSB0ZXJzZWJ1dCBkYXJpIHRvdGFsIGp1bWxhaCBwZW5nYWRpbGFuIGRpIHNlbHVydWggbmVnYXJhLg0KKiAqKnBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb24qKiA9IGp1bWxhaCBpbmRpdmlkdSB5YW5nIGRpYWRpbGkgcGVyIHNhdHUganV0YSBvcmFuZyBkYWxhbSBwb3B1bGFzaSBuZWdhcmEgdGVyc2VidXQuDQoqICoqZGVhdGhzKiogPSBqdW1sYWggaW5kaXZpZHUgeWFuZyBkaWh1a3VtIG1hdGkuDQoqICoqcGVyX2NlbnRfb2ZfdG90YWxfZGVhdGhzKiogPSBwZXJzZW50YXNlIGp1bWxhaCBla3Nla3VzaSBwYWRhIG5lZ2FyYSB0ZXJzZWJ1dCBkYXJpIHRvdGFsIGp1bWxhaCBla3Nla3VzaSB5YW5nIHRlcmphZGkgZGkgc2VsdXJ1aCBuZWdhcmEuDQoqICoqZGVhdGhzX3Blcl9taWxsaW9uKiogPSBqdW1sYWggZWtzZWt1c2kgcGVyIHNhdHUganV0YSBvcmFuZyBkYWxhbSBwb3B1bGFzaSBuZWdhcmEuDQoNCiMjIyBCLiBEYXRhc2V0IFdpdGNoIHRyaWFscw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0Kd2l0Y2hfdHJpYWxzIDwtIHJlYWQuY3N2KCIuLi9kYXRhX2lucHV0L3dpdGNoX3RyaWFscy5jc3YiKQ0Kd2l0Y2hfdHJpYWxzDQpgYGANCioqUGVuamVsYXNhbiBEYXRhOioqDQoNCkJlcmRhc2Fya2FuIHRhYmVsIGRpIGF0YXMgZGFwYXQgZGlrZXRhaHVpIGJhaHdhIGRhdGFzdGUgd2l0Y2ggdHJpYWxzIG1lbWlsaWtpIDEwLjk0MCBkYXRhIHlhbmcgdGVyZGlyaSBkYXJpIDEyIGtvbG9tLiBQZW5qZWxhc2FuIGRhcmkga29sb20ta29sb20gdGVyc2VidXQgYWRhbGFoIHNlYmFnYWkgYmVyaWt1dDoNCg0KKiAqKnllYXIqKiA9IHRhaHVuLg0KKiAqKmRlY2FkZSoqID0gZGVrYWRlICh0aWFwIDEwIHRhaHVuKS4NCiogKipjZW50dXJ5KiogPSBhYmFkLg0KKiAqKnRyaWVkKiogPSBqdW1sYWggdG90YWwgaW5kaXZpZHUgeWFuZyBkaWFkaWxpIGJhaWsgeWFuZyBkaWh1a3VtIG1hdGkgYXRhdXB1biB0aWRhay4NCiogKipkZWF0aHMqKiA9IGp1bWxhaCBpbmRpdmlkdSB5YW5nIGRpaHVrdW0gbWF0aS4NCiogKipjaXR5KiogPSBuYW1hIGtvdGEuDQoqICoqZ2FkbS5hZG0yKiogPSBpbmZvcm1hc2kgZ2VvZ3JhZmkgMS4NCiogKipnYWRtLmFkbTEqKiA9IGluZm9ybWFzaSBnZW9ncmFmaSAyLg0KKiAqKmdhZG0uYWRtMCoqID0gaW5mb3JtYXNpIGdlb2dyYWZpIDAgKG5hbWEgbmVnYXJhKS4NCiogKipsb24qKiA9IGxvbmdpdHVkZS4NCiogKipsYXQqKiA9IGxhdGl0dWRlLg0KKiAqKnJlY29yZC5zb3VyY2UqKiA9IHN1bWJlciBkYXRhLg0KDQojIyAzLjIgU3Vic2V0dGluZw0KVGlkYWsgc2VtdWEga29sb20gYWthbiBkaWd1bmFrYW4gdW50dWsgcHJvc2VzIHZpc3VhbGlzYXNpLiBPbGVoIGthcmVuYSBpdHUsIHVudHVrIG1lbXVkYWhrYW4gcGVuZ29sYWhhbiBkYXRhLCBrb2xvbS1rb2xvbSB5YW5nIHRpZGFrIGRpZ3VuYWthbiBha2FuIGRpaGlsYW5na2FuLg0KDQojIyMgQS4gRGF0YXNldCBIaXN0b3J5DQpQYWRhIGRhdGFzZXQgaGlzdG9yeSwga29sb20geWFuZyBha2FuIGRpZ3VuYWthbiB5YWl0dSBgY291bnRyeWAsIGBwZXJzb25zX3RyaWVkYCwgYHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb25gLCBkYW4gYGRlYXRoc2AuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpoaXN0b3J5IDwtIGhpc3RvcnkgJT4lIHNlbGVjdChjb3VudHJ5LCBwZXJzb25zX3RyaWVkLCBwZXJzb25zX3RyaWVkX3Blcl9taWxsaW9uLCBkZWF0aHMpDQpoaXN0b3J5DQpgYGANCg0KIyMjIEIuIERhdGFzZXQgV2l0Y2ggdHJpYWxzDQpQYWRhIGRhdGFzZXQgd2l0Y2ggdHJpYWxzLCBrb2xvbSB5YW5nIGFrYW4gZGlndW5ha2FuIHlhaXR1IGBkZWNhZGVgLCBgdHJpZWRgLCBkYW4gYGRlYXRoc2AuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQp3aXRjaF90cmlhbHMgPC0gd2l0Y2hfdHJpYWxzICU+JSBzZWxlY3QoZGVjYWRlLCB0cmllZCwgZGVhdGhzKQ0Kd2l0Y2hfdHJpYWxzDQpgYGANCg0KDQojIyAzLjMgSGFwdXMgU2ltYm9sDQojIyMgQS4gRGF0YXNldCBIaXN0b3J5DQoNClRlcmxpaGF0IHBhZGEgdGFiZWwgZGF0YXNldCBoaXN0b3J5LCBiYWh3YSB0ZXJkYXBhdCBwZW1pc2FoIHJpYnVhbiBkZW5nYW4gc2ltYm9sIGtvbWEgKCwpLiBIYWwgaW5pIHBlcmx1IGRpaGlsYW5na2FuIHRlcmxlYmloIGRhaHVsdSBhZ2FyIGRhcGF0IGRpa29udmVyc2kgbWVuamFkaSBiZW50dWsgbnVtZXJpay4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmhpc3RvcnkkcGVyc29uc190cmllZCA8LSBnc3ViKCIsIiwgIiIsIGhpc3RvcnkkcGVyc29uc190cmllZCkNCmhpc3RvcnkkcGVyc29uc190cmllZF9wZXJfbWlsbGlvbiA8LSBnc3ViKCIsIiwgIiIsIGhpc3RvcnkkcGVyc29uc190cmllZF9wZXJfbWlsbGlvbikNCmhpc3RvcnkkZGVhdGhzIDwtIGdzdWIoIiwiLCAiIiwgaGlzdG9yeSRkZWF0aHMpDQpgYGANCg0KU2V0ZWxhaCBkaWxha3VrYW4gcHJvc2VzIHBlbWJlcnNpaGFuIHBlbWlzYWggcmlidWFuLCBtYWthIGRhdGEgYGhpc3RvcnlgIGFrYW4gdGFtcGlsIHNlYmFnYWkgYmVyaWt1dDoNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmhpc3RvcnkNCmBgYA0KDQojIyMgQi4gRGF0YXNldCBXaXRjaCB0cmlhbHMNClRpZGFrIGFkYSBwcm9zZXMgcGVuZ2hhcHVzYW4gc2ltYm9sIHBhZGEgZGF0YXNldCB3aXRjaCB0cmlhbHMuDQoNCiMjIDMuNCBUaXBlIERhdGENCg0KVGlwZSBkYXRhIHNldGlhcCBrb2xvbSBwZXJsdSBkaWNlayB1bnR1ayBtZW1hc3Rpa2FuIGJhaHdhIGRhdGEtZGF0YSB5YW5nIGFkYSBtZW1pbGlraSB0aXBlIGRhdGEgeWFuZyB0ZXBhdCBzZWhpbmdnYSBkYXBhdCBkaWxha3VrYW4gcHJvc2VzIHZpc3VhbGlzYXNpIHlhbmcgc2VzdWFpIGRhbiBkYXRhIHlhbmcgdGVyc2FqaSBtZW5qYWRpIGluZm9ybWF0aWYuDQoNCiMjIyBBLiBEYXRhc2V0IEhpc3RvcnkNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnN0cihoaXN0b3J5KQ0KYGBgDQoqKkluc2lnaHQqKg0KDQpEYXJpIHN0cnVrdHVyIGRpIGF0YXMsIGRhcGF0IGRpa2V0YWh1aSBiYWh3YSBiZWJlcmFwYSBrb2xvbSBiZWx1bSBtZW1pbGlraSB0aXBlIGRhdGEgeWFuZyBzZXN1YWkuIFNlcGVydGkga29sb20gYHBlcnNvbnNfdHJpZWRgLCBgcGVyc29uc190cmllZF9wZXJfbWlsbGlvbmAsIGRhbiBgZGVhdGhzYCB5YW5nIG1hc2loIG1lbWlsaWtpIHRpcGUgZGF0YSBjaHIgeWFuZyBzZWhhcnVzbnlhIGFkYWxhaCBudW1lcmlrIChudW0pIGRhbiBrb2xvbSBgY291bnRyeWAgeWFuZyBoYXJ1c255YSBhZGFsYWggRmFjdG9yLiBVbnR1ayBpdHUgcGVybHUgZGlsYWt1a2FuIHByb3NlcyBrb252ZXJzaSB0aXBlIGRhdGEgeWFuZyBzZXN1YWkuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpoaXN0b3J5JGNvdW50cnkgPC0gZmFjdG9yKGhpc3RvcnkkY291bnRyeSkNCmhpc3RvcnkkcGVyc29uc190cmllZCA8LSBhcy5udW1lcmljKGhpc3RvcnkkcGVyc29uc190cmllZCkNCmhpc3RvcnkkcGVyc29uc190cmllZF9wZXJfbWlsbGlvbiA8LSBhcy5udW1lcmljKGhpc3RvcnkkcGVyc29uc190cmllZF9wZXJfbWlsbGlvbikNCmhpc3RvcnkkZGVhdGhzIDwtIGFzLm51bWVyaWMoaGlzdG9yeSRkZWF0aHMpDQpgYGANCg0KU2V0ZWxhaCBwcm9zZXMga29udmVyc2kgdGlwZSBkYXRhLCBrZW11ZGlhbiBjZWsgdGlwZSBkYXRhIHVudHVrIHRpYXAga29sb20ga2VtYmFsaSB1bnR1ayBtZW1hc3Rpa2FuIGJhaHdhIGtvbG9tLWtvbG9tIHRlcnNlYnV0IHN1ZGFoIG1lbWlsaWtpIHRpcGUgZGF0YSB5YW5nIHRlcGF0Lg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0Kc3RyKGhpc3RvcnkpDQpgYGANCioqSW5zaWdodCoqDQoNCkRpbGloYXQgcGFkYSBzdHJ1a3R1ciBkaSBhdGFzIGRhcGF0IGRpc2ltcHVsa2FuIGJhaHdhIHRpYXAga29sb20gc3VkYWggbWVtaWxpa2kgdGlwZSBkYXRhIHlhbmcgc2VzdWFpIGRhbiBzaWFwIGRpbGFrdWthbiBwcm9zZXMgc2VsYW5qdXRueWEuDQoNCiMjIyBCLiBEYXRhc2V0IFdpdGNoIHRyaWFscw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0Kc3RyKHdpdGNoX3RyaWFscykNCmBgYA0KKipJbnNpZ2h0KioNCg0KRGlsaWhhdCBwYWRhIHN0cnVrdHVyIGRpIGF0YXMgZGFwYXQgZGlzaW1wdWxrYW4gYmFod2Ega29sb20gcGFkYSBkYXRhc2V0IHdpdGNoIHRyaWFscyBzdWRhaCBtZW1pbGlraSB0aXBlIGRhdGEgeWFuZyBzZXN1YWkgZGFuIHNpYXAgZGlsYWt1a2FuIHByb3NlcyBzZWxhbmp1dG55YS4NCg0KDQojIyAzLjUgTWlzc2luZyBWYWx1ZQ0KTmlsYWkga29zb25nIC8gKm1pc3NpbmcgdmFsdWUqIHBlcmx1IGRpdGFuZ2FuaSBhZ2FyIGRhdGEgbGVuZ2thcCBkYW4gYmlzYSBkaWd1bmFrYW4gdW50dWsgcHJvc2VzIHZpc3VhbGlzYXNpLg0KDQojIyMgQS4gRGF0YXNldCBIaXN0b3J5DQpDZWsgYXBha2FoIGRhdGFzZXQgdGVyZGFwYXQgbWlzc2luZyB2YWx1ZSBhdGF1IHRpZGFrIGRlbmdhbiBtZW5nZ3VuYWthbiBmdW5nc2kgYGlzLm5hKClgLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0Kc3VtKGlzLm5hKGhpc3RvcnkpKQ0KYGBgDQoqKkluc2lnaHQqKg0KDQpTZXRlbGFoIGRpY2VrLCBkYXBhdCBkaWtldGFodWkgYmFod2Egc2VtdWEgZGF0YSB0ZWxhaCBsZW5na2FwIGRhbiB0aWRhayBwZXJsdSBkaWxha3VrYW4gcGVuZ2lzaWFuIGRhdGEga29zb25nLg0KDQojIyMgQi4gRGF0YXNldCBXaXRjaCBUcmlhbHMNCg0KQ2VrIGFwYWthaCBkYXRhc2V0IHRlcmRhcGF0IG1pc3NpbmcgdmFsdWUgYXRhdSB0aWRhayBkZW5nYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGBpcy5uYSgpYC4NCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpzdW0oaXMubmEod2l0Y2hfdHJpYWxzKSkNCmBgYA0KKipJbnNpZ2h0KioNCg0KU2V0ZWxhaCBkaWNlaywgdGVybnlhdGEgdGVyZGFwYXQgMy44MjYgZGF0YSB5YW5nIGtvc29uZy4gVW50dWsgbWVuYW5nYW5pIGluaSwgbWlzc2luZyB2YWx1ZSBha2FuIGRpaXNpIGRlbmdhbiBuaWxhaSAwIHlhbmcgYXJ0aW55YSBwYWRhIHRhaHVuIHRlcnNlYnV0IHRpZGFrIGFkYSBpbmRpdmlkdSB5YW5nIGRpYWRpbGkuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIElzaSBtaXNzaW5nIHZhbHVlIGRlbmdhbiAwDQp3aXRjaF90cmlhbHNbaXMubmEod2l0Y2hfdHJpYWxzKV0gPC0gMA0KDQojIENlayBhcGFrYWggbWFzaWggYWRhIG1pc3NpbmcgdmFsdWUgYXRhdSB0aWRhaw0Kc3VtKGlzLm5hKHdpdGNoX3RyaWFscykpDQpgYGANCg0KKipJbnNpZ2h0KioNCg0KU2V0ZWxhaCBkaWxha3VrYW4gcHJvc2VzIHBlbmdpc2lhbiBuaWxhaSBOQSBkZW5nYW4gMCwgZGFwYXQgZGlrZXRhaHVpIGJhaHdhIGRhdGFzZXQgd2l0Y2ggdHJpYWxzIHN1ZGFoIGxlbmdrYXAgZGFuIHRpZGFrIGFkYSBuaWxhaSAwLg0KDQojIyAzLjYgRmluYWwgRGF0YQ0KDQpCZXJpa3V0IHRhbXBpbGFuIGRhdGEgc2V0ZWxhaCBwcm9zZXMgcHJlLXByb2Nlc3NpbmcgZGFuIHNpYXAgZGlndW5ha2FuIHVudHVrIHByb3NlcyB2aXN1YWxpc2FzaS4NCg0KIyMjIEEuIERhdGFzZXQgSGlzdG9yeQ0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmhpc3RvcnkNCmBgYA0KDQojIyMgQi4gRGF0YXNldCBXaXRjaCBUcmlhbHMNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCndpdGNoX3RyaWFscw0KYGBgDQoNCg0KIyA0LiBDcmVhdGUgYSBWaXN1YWxpemF0aW9uIHsudGFic2V0fQ0KIyMgNC4xIEJ1YmJsZSBDaGFydA0KDQpVbnR1ayBtZW1idWF0ICoqQnViYmxlIENoYXJ0KiosIGhhbnlhIG1lbWJ1dHVoa2FuIGtvbG9tIGBwZXJzb25zX3RyaWVkX3Blcl9taWxsaW9uYC4gVGVybGloYXQgcGFkYSBnYW1iYXIgcmVmZXJlbnNpIGJhaHdhIG5pbGFpIHBhZGEgYnViYmxlIGNoYXJ0IG1lbmdndW5ha2FuIG5pbGFpIGhhc2lsIGZvcm11bGEgYHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb25gIGRpYmFnaSAxMCBsYWx1IGRpYnVsYXRrYW4uDQoNCkJlcmlrdXQgbGFuZ2thaC1sYW5na2FoIHlhbmcgcGVybHUgZGlsYWt1a2FuOg0KDQoxLiBNZW1wZXJzaWFwa2FuIGRhdGEgYHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb25gIGRhcmkgZGF0YXNldCBoaXN0b3J5Lg0KMi4gTWVtYmFnaSBkYXRhIGBwZXJzb25zX3RyaWVkX3Blcl9taWxsaW9uYCBkZW5nYW4gbmlsYWkgMTAgbGFsdSBkaWJ1bGF0a2FuIG1lbmdndW5ha2FuIGZ1bmdzaSBgcm91bmQoKWAuDQozLiBNZW1idWF0IGJ1YmJsZSBjaGFydC4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgTWVuZ2FtYmlsIGRhdGEgcGVyc29uc190cmllZF9wZXJfbWlsbGlvbg0KYnViYmxlX2RhdGEgPC0gaGlzdG9yeSAlPiUgc2VsZWN0KHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb24pDQoNCiMgTWVuYW1waWxrYW4gZGF0YQ0KaGVhZChidWJibGVfZGF0YSkNCmBgYA0KDQpCZXJkYXNhcmthbiBnYW1iYXIgcmVmZXJlbnNpLCBuaWxhaSBwYWRhIGtvbG9tYHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb25gIGJ1a2FubGFoIG5pbGFpIGFzbGlueWEgdGV0YXBpIHN1ZGFoIGRpYmFnaSBtZW5qYWRpIDEwLg0KDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1lbWJhZ2kgZGF0YSBkZW5nYW4gMTAgbGFsdSBkaWJ1bGF0a2FuDQpidWJibGVfZGF0YSA8LSByb3VuZChidWJibGVfZGF0YSAvIDEwLCAwKQ0KDQojIFByb3NlcyBtZW1iYWxpayBkYXRhIGRhcmkgeWFuZyB0ZXJhdGFzIG1lbmphZGkgdGVyYmF3YWgNCmJ1YmJsZV9kYXRhIDwtIGJ1YmJsZV9kYXRhICU+JQ0KICBtdXRhdGUodmFsdWVfcmVzZXJ2ZWQgPSByZXYocGVyc29uc190cmllZF9wZXJfbWlsbGlvbikpICU+JQ0KICBzZWxlY3QoLXBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb24pICU+JQ0KICByZW5hbWUocGVyc29uc190cmllZF9wZXJfbWlsbGlvbiA9IHZhbHVlX3Jlc2VydmVkKQ0KDQojIE1lbmFtcGlsa2FuIGRhdGENCmhlYWQoYnViYmxlX2RhdGEpDQpgYGANClNldGVsYWggZGF0YSBkaXBlcnNpYXBrYW4sIHNlbGFuanV0bnlhIGFkYWxhaCBwcm9zZXMgdW50dWsgbWVtYnVhdCAqKkJ1YmJsZSBDaGFydCoqIG1lbmdndW5ha2FuIGZ1bmdzaSBgZ2dwbG90KClgLiANCg0KPGhyIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCBibGFjazsiPg0KDQpCZXJpa3V0IGxhbmdrYWgtbGFuZ2thaCB1bnR1ayBtZW1idWF0ICoqQnViYmxlIENoYXJ0KiouDQoNCjEuIE1lbXBlcnNpYXBrYW4gRGF0YTogUGVydGFtYSwga2l0YSBtZW1idWF0IHNlYnVhaCB0aWJibGUgKHN0cnVrdHVyIGRhdGEgZGFyaSBwYWNrYWdlIGRwbHlyKSB5YW5nIGFrYW4gbWVueWltcGFuIGluZm9ybWFzaSB1bnR1ayBidWJibGUgY2hhcnQuIERpIGRhbGFtIHRpYmJsZSBpbmksIGtpdGEgbWVuZW50dWthbiBuaWxhaSBkYXJpIDMgcGFyYW1ldGVyIHlhaXR1OiB4LCB5LCBkYW4gc2l6ZS4NCg0KICAgIC0gUGFyYW1ldGVyIGB4YCAkXHJpZ2h0YXJyb3ckIGRpaXNpIGRlbmdhbiBuaWxhaSB0ZXRhcCAxIGFnYXIgc2VtdWEgYnViYmxlIHRlcmxldGFrIHBhZGEgcG9zaXNpIHlhbmcgc2FtYSBzZWNhcmEgaG9yaXpvbnRhbC4NCiAgICAtIFBhcmFtZXRlciBgeWAgJFxyaWdodGFycm93JCBkaWlzaSBkZW5nYW4gdXJ1dGFuIGRhcmkgMSBoaW5nZ2EgYmFueWFrbnlhIGJhcmlzIHBhZGEgZGF0YSwgeWFuZyBha2FuIG1lbmphZGkgcG9zaXNpIHZlcnRpa2FsIGRhcmkgc2V0aWFwIGJ1YmJsZS4NCiAgICAtIFBhcmFtZXRlciBgc2l6ZWAgJFxyaWdodGFycm93JCBkaWlzaSBkYXRhIGBwZXJzb25zX3RyaWVkX3Blcl9taWxsaW9uYC4NCiAgICANCg0KMi4gTWVtYnVhdCBCdWJibGUgQ2hhcnQ6IFNlbGFuanV0bnlhLCBraXRhIG1lbmdndW5ha2FuIGZ1bmdzaSAqKmdncGxvdCgpKiogdW50dWsgbWVtYnVhdCBidWJibGUgY2hhcnQuIERpIHNpbmksIGtpdGEgbWVuZ2F0dXIgbWFwcGluZyBhZXN0aGV0aWMgKGFlcykgdW50dWsgeCwgeSwgZGFuIHNpemUgZGFyaSBkYXRhIHlhbmcgdGVsYWgga2l0YSBidWF0Lg0KDQozLiBNZW5hbWJhaGthbiBCdWJibGU6IERlbmdhbiBtZW5nZ3VuYWthbiBmdW5nc2kgYGdlb21fcG9pbnQoKWAsIGtpdGEgbWVuYW1iYWhrYW4gdGl0aWstdGl0aWsgKGJ1YmJsZSkga2UgcGxvdC4gS2l0YSBtZW5nYXR1ciB3YXJuYSBidWJibGUgbWVuamFkaSBjb3JhbCwgZGVuZ2FuIHRyYW5zcGFyYW5zaSAoYWxwaGEpIDAuNyBkYW4ga2V0ZWJhbGFuIG91dGxpbmUgKHN0cm9rZSkgc2ViZXNhciAxLg0KDQo0LiBNZW5hbWJhaGthbiBMYWJlbDogS2l0YSBqdWdhIG1lbmFtYmFoa2FuIGxhYmVsIG1lbmdndW5ha2FuIGZ1bmdzaSBgZ2VvbV90ZXh0KClgLiBMYWJlbCBpbmkgYWthbiBtZW5hbXBpbGthbiB0ZWtzIHlhbmcgYmVyYWRhIGRla2F0IGRlbmdhbiBidWJibGUsIGRlbmdhbiBwb3Npc2kgaG9yaXpvbnRhbCBzZWRpa2l0IGRpIHNlYmVsYWgga2lyaSAoeCA9IDAuOSkgZGFuIHVrdXJhbiB0ZWtzIGRpYXR1ciBtZW5qYWRpIDQgcHQuDQoNCjUuIE1lbmdhdHVyIFJlbnRhbmcgVWt1cmFuIEJ1YmJsZTogVW50dWsgbWVtYXN0aWthbiBiYWh3YSB1a3VyYW4gYnViYmxlIHRlcmxpaGF0IHByb3BvcnNpb25hbCwga2l0YSBtZW5nYXR1cm55YSBtZW5nZ3VuYWthbiBmdW5nc2kgYHNjYWxlX3NpemVfY29udGludW91cygpYCB1bnR1ayBtZW5nYXR1ciByZW50YW5nIHVrdXJhbiBidWJibGUgYW50YXJhIDEgZGFuIDE4Lg0KDQo2LiBNZW5lcmFwa2FuIFRlbWEgTWluaW1hbGlzOiBEZW5nYW4gbWVuZ2d1bmFrYW4gYHRoZW1lX21pbmltYWwoKWAsIGtpdGEgbWVuZ3ViYWggdGFtcGlsYW4gcGxvdCBtZW5qYWRpIGxlYmloIHNlZGVyaGFuYSBkYW4gYmVyc2loLg0KDQo3LiBNZW5nYXR1ciBFbGVtZW4gVGFtcGlsYW4gUGxvdDogS2l0YSBtZWxha3VrYW4gYmViZXJhcGEgcGVueWVzdWFpYW4gcGFkYSBlbGVtZW4tZWxlbWVuIGRpIHBsb3QgbWVuZ2d1bmFrYW4gZnVuZ3NpIGB0aGVtZWA6DQoNCiAgICAtIE1lbmdoYXB1cyBqdWR1bCBzdW1idSB4IGRhbiB5LCBzZXJ0YSBtZW5naGlsYW5na2FuIHRla3MgZGFuIHRhbmRhIHBhZGEgc3VtYnUgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBlbGVtZW50X2JsYW5rYCBwYWRhIHBhcmFtZXRlciBgYXhpcy50aXRsZS54YCwgYGF4aXMudGV4dGAsIGRhbiBgYXhpcy50aWNrc2AuDQogICAgLSBNZW5naGFwdXMgbGVnZW5kIHVudHVrIG1lbWJ1YXQgcGxvdCBsZWJpaCBiZXJzaWggbWVuZ2d1bmFrYSBuaWFsaSBgbm9uZWAgcGFkYSBwYXJhbWV0ZXIgYGxlZ2VuZC5wb3NpdGlvbmAuDQogICAgLSBNZW5naGlsYW5na2FuIGdhcmlzIGdyaWQgcGFkYSBwbG90IGRlbmdhbiBjYXJhIG1lbmdndW5ha2FuIGZ1bmdzaSBgZWxlbWVudF9ibGFuaygpYCBwYWRhIHBhcmFtZXRlciBgcGFuZWwuZ3JpZC5tYWpvcmAsIGBwYW5lbC5ncmlkLm1pbm9yYCwgZGFuIGBwYW5lbC5ib3JkZXJgLg0KICAgIC0gTWVuZ2F0dXIgbWFyZ2luIHBsb3QgbWVuamFkaSBub2wgdW50dWsgbWVtYWtzaW1hbGthbiBwZW5nZ3VuYWFuIHJ1YW5nIHBhZGEgcGFyYW1ldGVyIGBwbG90Lm1hcmdpbmAuIEJlcmlzaSA0IGJ1YWggbmlsYWkgeWFuZyBtZW1pbGlraSB1cnV0YW4gdG9wLCByaWdodCwgYm90dG9tLCBsZWZ0Lg0KICAgIA0KDQo4LiBNZW5naGFwdXMgTGFiZWwvdGVrcyBwYWRhIFN1bWJ1IFggZGFuIFk6IEtpdGEgbWVuYW1iYWhrYW4gbGFicygpIGRlbmdhbiBuaWxhaSBgTlVMTGAgdW50dWsgbWVtYXN0aWthbiBiYWh3YSBsYWJlbCBwYWRhIHN1bWJ1IHggZGFuIHkgdGlkYWsgZGl0YW1waWxrYW4uDQoNCjkuIE1lbmdhdHVyIFJlbnRhbmcgU3VtYnUgWDogTWVuZ2d1bmFrYW4gYHhsaW0oKWAsIGtpdGEgbWVtYmF0YXNpIHRhbXBpbGFuIHN1bWJ1IHggYW50YXJhIDAgZGFuIDEuNSwgdW50dWsgbWVtYXN0aWthbiBidWJibGUgdGVybGloYXQgamVsYXMuDQoNCjEwLiBNZWxha3VrYW4gQ3JvcHBpbmcgcGFkYSBQbG90OiBUZXJha2hpciwga2l0YSBtZW5nZ3VuYWthbiBgY29vcmRfY2FydGVzaWFuKClgIHVudHVrIG1lbmdhdHVyIGNyb3BwaW5nIHNlaGluZ2dhIGhhbnlhIGFrYW4gYmVyZm9rdXMgcGFkYSBCdWJibGUgQ2hhcnQgc2FqYS4NCg0KPGhyIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCBibGFjazsiPg0KDQpNYXJpIGtpdGEgaW1wbGVtZW50YXNpa2FuIGtlIGRhbGFtIGtvZGUgbWVuZ2d1bmFrYW4gYmFoYXNhIFIgc2ViYWdhaSBiZXJpa3V0Oi4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgTWVuZW50dWthbiBYLCBZLCBkYW4gU2l6ZSB1bnR1ayBtZW5lbnR1a2FuIHVrdXJhbiBidWJibGUNCmRhdGEgPC0gdGliYmxlKA0KICB4ID0gMSwNCiAgeSA9IDE6bnJvdyhidWJibGVfZGF0YSksDQogIHNpemUgPSBjKGJ1YmJsZV9kYXRhJHBlcnNvbnNfdHJpZWRfcGVyX21pbGxpb24pDQopDQoNCiMgTWVtYnVhdCBidWJibGUgY2hhcnQNCmJ1YmJsZV9jaGFydCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSB4LCB5ID0geSwgc2l6ZSA9IHNpemUpKSArDQogICMgTWVuZW50dWthbiB3YXJuYSwgdHJhbnNwYXJhbnNpIChhcGxoYSksIGRhbiBsZWJhciBvdXRsaW5lIChzdHJva2UpIGJ1YmJsZQ0KICBnZW9tX3BvaW50KGNvbG9yID0gImNvcmFsIiwgYWxwaGEgPSAwLjcsIHN0cm9rZSA9IDEpICsNCg0KICAjIE1lbmdhdHVyIGxldGFrIGRhbiB1a3VyYW4gbGFiZWwNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gMC45LCBsYWJlbCA9IHNpemUpLCBzaXplID0gNCkgKw0KICAgIA0KICAjIE1lbmdhdHVyIHJlbnRhbmcgdWt1cmFuIGJ1YmJsZQ0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDEsIDE4KSkgKyANCiAgICANCiAgIyBNZW5nYXR1ciBhZ2FyIHRhbXBpbGFuIHBsb3QgbWluaW1hbGlzDQogIHRoZW1lX21pbmltYWwoKSArDQogICAgDQogICMgTWVuZ2F0dXIgYmViZXJhcGEgZWxlbWVudCBwYWRhIHBsb3QNCiAgdGhlbWUoDQogICAgIyBNZW5naGFwdXMganVkdWwsIHN1bWJ1IHgsIGRhbiBzdW1idSB5DQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIA0KICAgICMgTWVuZ2hhcHVzIGxlZ2VuZA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICANCiAgICAjIE1lbmdoYXB1cyBnYXJpcyAoZ3JpZCkNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgIA0KICAgICMgTWVuZ2F0dXIgbWFyZ2luIHBsb3QgKHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCkNCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQ0KICApICsNCiAgICANCiAgIyBNZW5naGFwdXMgbGFiZWwgcGFkYSBzdW1idSBYIGRhbiBZDQogIGxhYnMoDQogICAgeCA9IE5VTEwsDQogICAgeSA9IE5VTEwNCiAgKSArDQogICAgDQogICMgTWVuZ2F0dXIgcmFuZ2UgZGFyaSBzdW1idSBYDQogIHhsaW0oMCwgMS41KSArIA0KICAgIA0KICAjIE1lbGFrdWthbiBjcm9wcGluZw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMC45LCAyKSkNCg0KIyBNZW5hbXBpbGthbiBwbG90DQpidWJibGVfY2hhcnQNCmBgYA0KU2V0ZWxhaCBwZW1idWF0YW4gYnViYmxlIGNoYXJ0IGJlcmhhc2lsLCBzYWF0bnlhIHVudHVrIG1lbnlpbXBhbiBwbG90IHRlcnNlYnV0IHVudHVrIGRpa29tYmluYXNpa2FuIGRlbmdhbiBwbG90IHlhbmcgbGFpbi4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmdnc2F2ZShmaWxlbmFtZSA9ICIuLi9hc3NldC9idWJibGVfY2hhcnQucG5nIiwgcGxvdCA9IGJ1YmJsZV9jaGFydCwgd2lkdGggPSA2LCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApDQpgYGANCg0KDQojIyA0LjIgU3RhY2tlZCBCYXIgQ2hhcnQNCg0KVW50dWsgbWVtYnVhdCAqKlN0YWNrZWQgQmFyIENoYXJ0KiogcGFkYSBrYXN1cyBpbmkgaGFueWEgbWVtYnV0dWhrYW4gNCBkYXRhIHlhaXR1IGBjb3VudHJ5YCwgYHBlcnNvbnNfdHJpZWRgLCBgZGVhdGhzYCwgZGFuIGBhY2N1c2VkYC4gS29sb20gYGFjY3VzZWRgIGJlcmlzaSBkYXRhIG9yYW5nIHlhbmcgZGlhZGlsaSB0ZXRhcGkgdGlkYWsgZGlodWt1bSBtYXRpLiBLb2xvbSBpbmkgcGVybHUga2l0YSBidWF0IHNlbmRpcmkgZGVuZ2FuIG1lbmd1cmFuZ2thbiBkYXRhIHBhZGEga29sb20gYHBlcnNvbnNfdHJpZWRgIGRlbmdhbiBgZGVhdGhzYC4NCg0KQmVyaWt1dCBsYW5na2FoLWxhbmdrYWggeWFuZyBwZXJsdSBkaWxha3VrYW46DQoNCjEuIE1lbXBlcnNpYXBrYW4gZGF0YSBgY291bnRyeWAsIGBwZXJzb25zX3RyaWVkYCwgZGFuIGBkZWF0aHNgIGRhcmkgZGF0YXNldCBoaXN0b3J5Lg0KMi4gTWVtYnVhdCBrb2xvbSBgYWNjdXNlZGAgZGVuZ2FuIGZvcm11bGEgYHBlcnNvbnNfdHJpZWRgIC0gYGRlYXRoc2AuDQozLiBNZW5ndWJhaCBkYXRhIGtlIGxvbmcgZm9ybWF0IG1lbmdndW5ha2FuIGZ1bmdzaSBgcGl2b3RfbG9uZ2VyYC4NCjQuIE1lbWJ1YXQgcGxvdCAqKlN0YWNrZWQgQmFyIENoYXJ0KiouDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1lbWlsaWggZGF0YSB5YW5nIGRpZ3VuYWthbg0KZGF0YV9wbG90IDwtIGhpc3RvcnkgJT4lIHNlbGVjdChjb3VudHJ5LCBwZXJzb25zX3RyaWVkLCBkZWF0aHMpDQoNCiMgTWVtYnVhdCBrb2xvbSBhY2N1c2VkDQpkYXRhX3Bsb3QkYWNjdXNlZCA8LSBkYXRhX3Bsb3QkcGVyc29uc190cmllZCAtIGRhdGFfcGxvdCRkZWF0aHMNCg0KIyBNZW5hbXBpbGthbiBkYXRhDQpkYXRhX3Bsb3QNCmBgYA0KDQpBZ2FyIGRhdGEga2l0YSBiaXNhIGRpZ3VuYWthbiB1bnR1ayB2aXN1YWxpc2FzaSwgcGVybHUga2l0YSB1YmFoIGZvcm1hdG55YSBkYXJpICp3aWRlIGZvcm1hdCogbWVuamFkaSAqbG9uZyBmb3JtYXQqIGRlbmdhbiBmdW5nc2kgYHBpdm90X2xvbmdlcmAuDQoNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgdWJhaCBmb3JtYXQgZGF0YSBkZW5nYW4gcGl2b3RfbG9uZ2VyKCkNCmRhdGFfcGxvdCA8LSBkYXRhX3Bsb3QgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYygiYWNjdXNlZCIsICJkZWF0aHMiKSwgDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJzdGF0dXMiLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSIpDQoNCiMgdGFtcGlsa2FuIGRhdGEgaGFzaWwgZm9ybWF0DQpwcmludChkYXRhX3Bsb3QpDQpgYGANCg0KU2VsYW5qdXRueWEgcGVybHUga2l0YSB1YmFoIHRpcGUgZGF0YSBgc3RhdHVzYCBtZW5qYWRpIGthdGVnb3Jpa2FsIGRlbmdhbiBtZW5nZ3VuYWthbiBmdW5nc2kgYGZhY3RvcigpYC4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgVWJhaCB0aXBlIGRhdGEga2UgZmFjdG9yIGRhbiBtZW5ndWJhaCB1cnV0YW4gZGFyaSBrb2xvbSBzdGF0dXMNCmRhdGFfcGxvdCA8LSBkYXRhX3Bsb3QgJT4lDQogIG11dGF0ZShzdGF0dXMgPSBmYWN0b3Ioc3RhdHVzLCBsZXZlbHMgPSBjKCJkZWF0aHMiLCAiYWNjdXNlZCIpKSkNCmBgYA0KDQpTZXRlbGFoIGRhdGEgZGlwZXJzaWFwa2FuLCBzZWxhbmp1dG55YSBhZGFsYWggcHJvc2VzIHVudHVrIG1lbWJ1YXQgKipTdGFja2VkIEJhciBDaGFydCoqIG1lbmdndW5ha2FuIGZ1bmdzaSBgZ2dwbG90KClgLg0KDQo8aHIgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOyI+DQoNCkJlcmlrdXQgbGFuZ2thaC1sYW5na2FoIHVudHVrIG1lbWJ1YXQgKipTdGFja2VkIEJhciBDaGFydCoqLg0KDQoxLiBNZW1idWF0IFdhcm5hIEt1c3RvbTogTWVuZW50dWthbiB3YXJuYSB1bnR1ayBtZW1iZWRha2FuIGFudGFyYSBrYXRlZ29yaSAqKmRlYXRocyoqIGRhbiAqKmFjY3VzZWQqKi4NCg0KMi4gTWVtYnVhdCBTdGFja2VkIEJhciBDaGFydDogU2VsYW5qdXRueWEsIGtpdGEgbXVsYWkgbWVtYnVhdCBkaWFncmFtLiBOYW11biBwbG90IGluaSBkaXNhamlrYW4gZGFsYW0gYmVudHVrIGhvcml6b250YWwgc2VoaW5nZ2Egc2VvbGFoLW9sYWggc3VtYnUgeCBiZXJhZGEgZGkgc3VtYnUgeSBkYW4gc2ViYWxpa255YS4NCg0KICAgIC0gU3VtYnUgWCAkXHJpZ2h0YXJyb3ckIG5hbWEgbmVnYXJhLg0KICAgIC0gU3VtYnUgWSAkXHJpZ2h0YXJyb3ckIGp1bWxhaCBpbmRpdmlkdSB5YW5nIGRpYWRpbGkuIA0KICAgIC0gV2FybmEgYmF0YW5nIGFrYW4gbWVuY2VybWlua2FuIGthdGVnb3JpIHlhbmcgYmVyYmVkYSAqKmV4ZWN1dGVkKiogZGFuICoqYWNjdXNlZCoqLiANCiAgDQoNCjMuIE1lbmdhdHVyIExlYmFyIEJhdGFuZzogS2l0YSBtZW5nYXR1ciBsZWJhciBiYXRhbmcgYWdhciB0ZXJsaWhhdCBwcm9wb3JzaW9uYWwgZGFuIHRpZGFrIHRlcmxhbHUgbGViYXIsIHNlaGluZ2dhIG1lbWJlcmlrYW4gc2VkaWtpdCBydWFuZyBhbnRhcmEgYmF0YW5nLWJhdGFuZyB5YW5nIGJlcmRla2F0YW4uIExlYmFyIGJhdGFuZyBkaXRlbnR1a2FuIG1lbmdndW5ha2FuIHBhcmFtZXRlciBgd2lkdGhgLg0KDQo0LiBNZW5naW1wbGVtZW50YXNpa2FuIFdhcm5hIEt1c3RvbTogV2FybmEgeWFuZyB0ZWxhaCBkaXRlbnR1a2FuIHNlYmVsdW1ueWEgZGl0ZXJhcGthbiBwYWRhIHBsb3QsIHNlaGluZ2dhIG1lbXVkYWhrYW4gcGVtYWhhbWFuIHZpc3VhbCBtZW5nZW5haSBrYXRlZ29yaSB5YW5nIGFkYS4gUGFyYW1ldGVyIHlhbmcgZGlhdHVyIHlhaXR1IGBzY2FsZV9maWxsX21hbnVhbGAuDQoNCjUuIE1lbmViYWxrYW4gR2FyaXMgSG9yaXpvbnRhbDogU2VidWFoIGdhcmlzIGhvcml6b250YWwgZGl0YW1iYWhrYW4gcGFkYSBzdW1idSBZIGRpIHRpdGlrIG5vbCBtZW5nZ3VuYWthbiBwYXJhbWV0ZXIgYGdlb21faGxpbmVgLiBQYXJhbXRlciBgeWludGVyY2VwdGAgZGlpc2kgZGVuZ2FuIG5pbGFpIHN1bWJ1IFggZGkgbWFuYSBnYXJpcyBha2FuIGRpdGVtcGF0a2FuLiBTZWRhbmdrYW4gYGx3ZGAgdW50dWsgbWVuZ2F0dXIgdGViYWwgZ2FyaXMuDQoNCjYuIE1lbmdoYXB1cyBMYWJlbCBwYWRhIHN1bWJ1IFggZGFuIFk6IFVudHVrIG1lbmRhcGF0a2FuIHRhbXBpbGFuIHlhbmcgbGViaWggYmVyc2loIGRhbiBtaW5pbWFsaXMsIGxhYmVsIHBhZGEgc3VtYnUgWCBkYW4gWSBkaWhhcHVzIG1lbmdndW5ha2FuIHBhcmFtZXRlciBgbGFic2AuDQoNCjcuIE1lbmd1YmFoIE9yaWVudGFzaSBQbG90OiBPcmllbnRhc2kgcGxvdCBkaXViYWggZGFyaSB2ZXJ0aWthbCBtZW5qYWRpIGhvcml6b250YWwgbWVuZ2d1bmFrYW4gcGFyYW1ldGVyIGBjb29yZF9mbGlwYC4NCg0KOC4gTWVuZ2F0dXIgRWxlbWVuIFBsb3Q6IE1lbmdndW5ha2FuIHBhcmFtZXRlciBgdGhlbWVgLCBiZXJpa3V0IGJlYmVyYXBhIGVsZW1lbiB5YW5nIGRpYXR1ciB5YWl0dToNCg0KICAgIC0gTWVuZ2hhcHVzIGdyaWQgZGkgZGFsYW0gcGxvdCBtZW5nZ3VuYWthbiBgZWxlbWVudF9ibGFua2AgcGFkYSBwYXJhbWV0ZXIgYHBhbmVsLmdyaWRgLg0KICAgIC0gTWVuZ2F0dXIgcG9zaXNpIGRhbiB1a3VyYW4gZGFyaSBsZWdlbmQgKiphY2N1c2VkKiogZGFuICoqZXhlY3V0ZWQqKi4NCiAgICAtIE1lbmdhdHVyIGJhdGFzIHRlcGkgKG1hcmdpbikgZGkgbXVsYWkgZGFyaSB0b3AsIHJpZ2h0LCBib3R0b20sIGxlZnQgZGFsYW0gc2F0dWFuIGNlbnRpbWV0ZXIgKGNtKS4NCg0KOS4gTWVuZ2F0dXIgdGVrcyBTdW1idSBZOiBEaWF0dXIgYWdhciBtZW1pbGlraSByYW5nZSBhbnRhcmEgMCBzYW1wYWkgMTcuNTAwIGRlbmdhbiBqYXJhayAyLjUwMCBtZW5nZ3VuYWthbiBwYXJhbWV0ZXIgYGJyZWFrc2AgcGFkYSBiYWdpYW4gYHNjYWxlX3lfY29udGludW9zYC4gU2VsYWluIGl0dSwgdGVyYXBrYW4gcGVtaXNhaCByaWJ1YW4gbWVuZ2d1bmFrYW4gcGFyYW1ldGVyIGBsYWJlbHNgIHlhbmcgZGlpc2kgZGVuZ2FuIG5pbGFpIGBzY2FsZXM6OmNvbW1hYC4NCg0KMTAuIE1lbmdhdHVyIExlZ2VuZGE6IFRlcmFraGlyLCBsZWdlbmQgZGlhdHVyIGFnYXIgZGl0YW1waWxrYW4gZGFsYW0gc2F0dSBiYXJpcywgbWVuamFkaWthbm55YSBsZWJpaCByYXBpIGRhbiBtdWRhaCBkaWJhY2EuIA0KDQo8aHIgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOyI+DQoNCk1hcmkga2l0YSBpbXBsZW1lbnRhc2lrYW4ga2UgZGFsYW0ga29kZSBtZW5nZ3VuYWthbiBiYWhhc2EgUiBzZWJhZ2FpIGJlcmlrdXQ6Lg0KDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0NCiMgTWVtYnVhdCB3YXJuYSBrdXN0b20NCmN1c3RvbV9jb2xvcnMgPC0gYygiZGVhdGhzIiA9ICIjMDA5OGEwIiwgImFjY3VzZWQiID0gIiM3MGNiYzQiKQ0KDQojIE1lbWJ1YXQgc3RhY2tlZCBiYXINCnN0YWNrZWRfYmFyX2NoYXJ0IDwtIGdncGxvdChkYXRhX3Bsb3QsIGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCB2YWx1ZSksIHkgPSB2YWx1ZSwgZmlsbCA9IHN0YXR1cykpICsNCiAgDQogICMgTWVuZ2F0dXIgbGViYXIgYmFyDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOCkgKw0KICANCiAgIyBJbXBsZW1lbnRhc2kgd2FybmEga3VzdG9tIGtlIGJhcg0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fY29sb3JzLCBsYWJlbHM9YygnRXhlY3V0ZWQnLCAnQWNjdXNlZCcpKSArDQogIA0KICAjIE1lbWJ1YXQgaG9yaXpvbnRhbCBsaW5lIHBhZGEgc3VtYnUgWSBwYWRhIHRpdGlrIDAgZGVuZ2FuIGxlYmFyIDAuMjUNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwNCiAgICAgICAgICAgICBsd2QgPSAwLjI1KSArDQogIA0KICAjIE1lbmdoYXB1cyBsYWJlbCBwYWRhIHN1bWJ1IFggZGFuIFkNCiAgbGFicyh4ID0gIiIsIHkgPSAiIikgKyANCiAgDQogICMgTWVuZ2h1YmFoIG9yaWVudGFzaSBwbG90IGRhcmkgdmVydGljYWwga2UgaG9yaXpvbnRhbA0KICBjb29yZF9mbGlwKCkgKw0KICANCiAgIyBNZW5nYXR1ciBhZ2FyIHRhbXBpbGFuIHBsb3QgbWluaW1hbGlzDQogIHRoZW1lX21pbmltYWwoKSArIA0KICANCiAgIyBNZW5nYXR1ciBiZWJlcmFwYSBlbGVtZW50IHBhZGEgcGxvdA0KICB0aGVtZSgNCiAgICAjIE1lbmdhdHVyIHdhcm5hIHRla3MgcGFkYSBzdW1idSBYIGRhbiBZDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwgICMgQWxpZ24gbGFiZWxzIHRvIHRoZSBsZWYNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAsIGNvbG9yID0gImJsYWNrIiksICAjIEFsaWduIGxhYmVscyB0byB0aGUgbGVmdA0KICAgIA0KICAgICMgTWVuZ2F0dXIgZ2FyaXMgeWFuZyBha2FuIGRpdGFtcGlsa2FuIGRpIHRlbmdhaC10ZW5nYWggcGxvdA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShzaXplID0gMC43NSwgY29sb3IgPSAiI2NiY2NjZSIpLA0KICAgIA0KICAgICMgTWVuZ2F0dXIgcG9zaXNpIGRhbiB1a3VyYW4gZGFyaSBsZWdlbmQNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjMsIDEuMSksDQogICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigwLCAwLCAxNSwgMCksDQogICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMywgImNtIiksDQogICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC43LCAiY20iKSwNCiAgICBsZWdlbmQua2V5LnNwYWNpbmcueCA9IHVuaXQoMC45LCAiY20iKSwNCiAgICANCiAgICAjIE1lbmdhdHVyIG1hcmdpbiBkYXJpIHBsb3Qgc2VjYXJhIHVtdW0NCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjcsIDQsIDAuNSwgMCwgImNtIikgDQogICkgKyANCiAgDQogICMgTWVuZ2F0dXIgdGVrcyBwYWRhIHN1bWJ1IFkNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgICMgTWVuZ2F0dXIgbmlsYWkgZGltdWxhaSBkYXJpIDAgc2FtcGFpIDE3LjUwMCBkZW5nYW4gamFyYWsgMi41MDANCiAgICBicmVha3MgPSBzZXEoMCwgMTc1MDAsIGJ5ID0gMjUwMCksDQogICAgDQogICAgIyBNZW5nYXR1ciBiYXRhcy9saW1pdCB0ZWtzIHlhbmcgZGl0YW1waWxrYW4gcGFkYSBzdW1idSBZDQogICAgbGltaXRzID0gYygwLCAxNzUwMCksIA0KICAgIA0KICAgICMgTWVuZ3VyYW5naSBydWFuZyBrb3NvbmcgcGFkYSBrYW5hbiBraXJpIGF0YXMgYmF3YWggcGxvdA0KICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwKSksDQogICAgDQogICAgIyBNZW5hbWJhaCBwZW1pc2FoIHJpYnVhbiBwYWRhIHN1bWJ1IFkNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hLA0KICAgIA0KICAgICMgTWVuZ2F0dXIgcG9zaXNpIHN1bWJ1IFkNCiAgICBwb3NpdGlvbiA9ICJyaWdodCINCiAgKSArDQogIA0KICAjIE1lbmF0dXIgYWdhciBsZWdlbmQgaG9yaXpvbnRhbA0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgYnlyb3cgPSBUUlVFLCByZXZlcnNlID0gVFJVRSkpDQogIA0KIyBNZW5hbXBpbGthbiBwbG90DQpzdGFja2VkX2Jhcl9jaGFydA0KYGBgDQoNClNldGVsYWggcGVtYnVhdGFuIHN0YWNrZWQgY2hhcnQgYmVyaGFzaWwsIHNhYXRueWEgdW50dWsgbWVueWltcGFuIHBsb3QgdGVyc2VidXQgdW50dWsgZGlrb21iaW5hc2lrYW4gZGVuZ2FuIHBsb3QgeWFuZyBsYWluLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KZ2dzYXZlKGZpbGVuYW1lID0gIi4uL2Fzc2V0L3N0YWNrZWRfYmFyX2NoYXJ0LnBuZyIsIHBsb3QgPSBzdGFja2VkX2Jhcl9jaGFydCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApDQpgYGANCg0KDQojIyA0LjMgTGluZSBDaGFydA0KDQpVbnR1ayBtZW1idWF0ICoqTGluZSBDaGFydCoqLCBha2FuIGRpZ3VuYWthbiBkYXRhc2V0IHdpdGNoIHRyYWlscy4gU2FtYSBzZXBlcnRpIDIgcGxvdCBzZWJlbHVtbnlhLCB1bnR1ayBtZW1idWF0ICoqTGluZSBDaGFydCoqIGp1Z2EgYWthbiBtZW1hbmZhYXRrYW4gbGlicmFyeSBkYXJpIGBnZ3Bsb3RgLiBOYW11biBzZWJlbHVtIGl0dSwga2l0YSBwZXJsdSBtZW1wZXJzaWFwa2FuIGRhdGFueWEgdGVybGViaWggZGFodWx1IHVudHVrIG1lbmp1bWxhaGthbiB0b3RhbCBpbmRpdmlkdSB5YW5nIGRpYWRpbGkgdGlhcCBkZWthZGUuDQoNCkJlcmlrdXQgbGFuZ2thaC1sYW5na2FoIHlhbmcgcGVybHUgZGlsYWt1a2FuOg0KDQoxLiBNZW1wZXJzaWFwa2FuIGRhdGEgYGRlY2FkZWAsIGBkZWF0aHNgLCBkYW4gYHRyaWVkYCBkYXJpIGRhdGFzZXQgd2l0Y2hfdHJpYWxzLg0KMi4gTGFrdWthbiBwcm9zZXMgZ3JvdXBpbmcgZGVuZ2FuIGZ1bmdzaSBgZ3JvdXBfYnlgIHVudHVrIG1lbmp1bWxhaGthbiB0b3RhbCBpbmRpdmlkdSB5YW5nIGRpaHVrdW0gbWF0aSBkYW4gdGlkYWsgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBzdW1tYXJpc2VgLg0KNC4gTWVtYnVhdCBwbG90ICoqTGluZSBDaGFydCoqLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBQcm9zZXMgZ3JvdXBCeSB1bnR1ayBtZW5qdW1sYWhrYW4gZGVhdGhzIGRhbiB0cmllZCB1bnR1ayB0aWFwIGRla2FkZQ0KZGF0YV9saW5lX2NoYXJ0IDwtIHdpdGNoX3RyaWFscyAlPiUNCiAgZ3JvdXBfYnkoZGVjYWRlKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGRlYXRocyA9IHN1bShkZWF0aHMpLA0KICAgIHRyaWVkID0gc3VtKHRyaWVkKQ0KICApDQoNCiMgTWVuYW1waWxrYW4gZGF0YQ0KZGF0YV9saW5lX2NoYXJ0DQpgYGANCg0KU2V0ZWxhaCBkYXRhIHN1ZGFoIGJlcmhhc2lsIGRpanVtbGFoa2FuIHVudHVrIHNldGlhcCBkZWthZGUsIHNlbGFuanV0bnlhIHlhaXR1IHBlbWJ1YXRhbiBsaW5lIHBsb3QgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBnZ3Bsb3RgLg0KDQo8aHIgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOyI+DQoNCkJlcmlrdXQgbGFuZ2thaC1sYW5na2FoIHVudHVrIG1lbWJ1YXQgKipTdGFja2VkIEJhciBDaGFydCoqLg0KDQoxLiBNZW1idWF0IGZ1bmdzaSBgY3VzdG9tX2xhYmVsc2AgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuYW1waWxrYW4gdGVrcyBwYWRhIHN1bWJ1IFguIEFrYW4gbWVuYW1waWxrYW4gdGFodW4gc2VjYXJhIGxlbmdrYXAgamlrYSB0YWh1biB0ZXJzZWJ1dCB0aWRhayBkaWFraGlyaSBkZW5nYW4gYW5na2EgNTAuIFRhcGkgamlrYSBkaWFraGlyaSBhbmdrYSA1MCwgaGFueWEgYWthbiBkaXRhbXBpbGthbiBhbmdrYSA1MC4gTWlzYWxueWE6IFRhaHVuIDE4MDAgYWthbiBkaXRhbXBpbGthbiAxODAwLiBUYWh1biAxODUwIGFrYW4gZGl0YW1waWxrYW4gNTAuDQoNCjIuIE1lbWJ1YXQgTGluZSBQbG90OiBEZW5nYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGBnZW9tX2xpbmVgLCBha2FuIGRpYnVhdCAyIGdhcmlzIHlhaXR1IGdhcmlzIHVudHVrIGRhdGEgYGRlYXRoc2AgeWFuZyBha2FuIGRpYmVyaSBsYWJlbCAqKmV4ZWN1dGVkKiogZGFuIGdhcmlzIHVudHVrIGRhdGEgYHRyaWVkYCB5YW5nIGRpYmVyaSBsYWJlbCAqKmFjY3VzZWQqKi4NCg0KMy4gTWVuZ2hhcHVzIExhYmVsIHBhZGEgc3VtYnUgWCBkYW4gWTogVW50dWsgbWVuZGFwYXRrYW4gdGFtcGlsYW4geWFuZyBsZWJpaCBiZXJzaWggZGFuIG1pbmltYWxpcywgbGFiZWwgcGFkYSBzdW1idSBYIGRhbiBZIGRpaGFwdXMgbWVuZ2d1bmFrYW4gcGFyYW1ldGVyIGBsYWJzYC4NCg0KNC4gTWVuZ2F0dXIgU3VtYnUgWDogUGFkYSBzdW1idSBYIGRlbmdhbiBmdW5nc2kgYHNjYWxlX3hfY29udGludW9zYCwga2l0YSBtZW5nYXR1ciBiZWJlcmFwYSBoYWwgc2ViYWdhaSBiZXJpa3V0Og0KICAgICAgDQogICAgLSBNZW1idWF0IG1ham9yIGJyZWFrcyBwYWRhIHN1bWJ1IFggZGVuZ2FuIHJhbmdlIDEzMDAgc2FtcGFpIDE4NTAgeWFuZyBkaXBpc2Foa2FuIHNldGlhcCA1MCBzYXR1YW4uIA0KICAgIC0gTWVtYnVhdCBtaW5vciBicmVha3MgcGFkYSBzdW1idSBYIGRlbmdhbiByYW5nZSAxMzAwIHNhbXBhaSAxODUwIHlhbmcgZGlwaXNhaGthbiBzZXRpYXAgMTAgc2F0dWFuLg0KICAgIC0gTWVudWxpc2thbiB0ZWtzIGxhYmVsIHBhZGEgc3VtYnUgWCBkZW5nYW4gbWVtYW5nZ2lsIGZ1bmdzaSBgY3VzdG9tX2xhYmVsc2AgeWFuZyBzdWRhaCBkaWJ1YXQgZGkgYXRhcy4NCiAgICAtIE1lbmFtcGlsa2FuIGdhcmlzIGtlY2lsIHNlcGFuamFuZyBzdW1idSBYIGRlbmdhbiBtZW5nZ3VuYWthbiBmdW5nc2kgYGd1aWRlX2F4aXNgLg0KDQo1LiBNZW5nYXR1ciBTdW1idSBZOiBQYWRhIHN1bWJ1IFkgZGVuZ2FuIGZ1bmdzaSBgc2NhbGVfeV9jb250aW51b3NgLCBraXRhIG1lbmdhdHVyIGJlYmVyYXBhIGhhbCBzZWJhZ2FpIGJlcmlrdXQ6DQogICAgICANCiAgICAtIE1lbWJ1YXQgbWFqb3IgYnJlYWtzIHBhZGEgc3VtYnUgWSBkZW5nYW4gcmFuZ2UgMCBzYW1wYWkgNjAwMCB5YW5nIGRpcGlzYWhrYW4gc2V0aWFwIDEwMDAgc2F0dWFuLiANCiAgICAtIE1lbmdhdHVyIHJ1YW5nIGtvc29uZyBkaSBzZWtpdGFyIHBsb3QgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBleHBhbnNpb25gLg0KICAgIC0gTWVudWxpc2thbiB0ZWtzIGxhYmVsIHBhZGEgc3VtYnUgWSB5YW5nIGRpcGlzYWhrYW4gZGVuZ2FuIGtvbWEgbWVuZ2d1bmFrYW4gcGFyYW1ldGVyIGBzY2FsZXM6OmNvbW1hYC4NCiAgICAtIE1lbmdhdHVyIGFnYXIgcG9zaXNpIHN1bWJ1IFkgYmVyYWRhIHBhZGEgc2lzaSBrYW5hbiBtZW5nZ3VuYWthbiBmdW5nc2kgYHBvc2l0aW9uYC4NCg0KNi4gTWVuZ2F0dXIgRWxlbWVuIFBsb3Q6IE1lbmdndW5ha2FuIHBhcmFtZXRlciBgdGhlbWVgLCBiZXJpa3V0IGJlYmVyYXBhIGVsZW1lbiB5YW5nIGRpYXR1ciB5YWl0dToNCg0KICAgIC0gTWVuZ2hhcHVzIGdyaWQgZGkgZGFsYW0gcGxvdCBtZW5nZ3VuYWthbiBgZWxlbWVudF9ibGFua2AgcGFkYSBwYXJhbWV0ZXIgYHBhbmVsLmdyaWRgLg0KICAgIC0gTWVuZ2F0dXIgdGViYWwgZGFuIHBhbmphbmcgKG1heW9yIHRpY2tzIGRhbiBtaW5vciB0aWNrcykgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBheGlzLnRpY2tzYC4NCiAgICAtIE1lbmdhdHVyIGFnYXIgd2FybmEgYmFja2dyb3VuZCBmb3RvIGRlbmdhbiB3YXJuYSBwdXRpaCBtZW5nZ3VuYWthbiBmdW5nc2kgYHBsb3QuYmFja2dyb3VuZGAuDQoNCjcuIE1lbmFtYmFoa2FuIEhpZ2hsaWdodDogS2l0YSBtZW55b3JvdGkgcmVudGFuZyB0YWh1biBhbnRhcmEgMTU1NSBoaW5nZ2EgMTY0OCBkZW5nYW4gbWVuYW1iYWhrYW4gcGVyc2VnaSBwYW5qYW5nIGJlcndhcm5hIGNvcmFsIHRyYW5zcGFyYW4uIEhhbCBpbmkgbWVtYmFudHUgbWVuYXJpayBwZXJoYXRpYW4gcGFkYSBwZXJpb2RlIHRlcnRlbnR1IHlhbmcgcmVsZXZhbiBkZW5nYW4gZGF0YS4gVW50dWsgbWVsYWt1a2FuIGhhbCBpbmksIGRpZ3VuYWthbiBwYXJhbWV0ZXIgYGdlb21gIHBhZGEgZnVuZ3NpIGBhbm5vdGF0ZWAuDQoNCiAgICAtIGB4bWluYCAkXHJpZ2h0YXJyb3ckIG5pbGFpIHBhZGEgc3VtYnUgWCB1bnR1ayBtZW11bGFpIGhpZ2hsaWdodC4NCiAgICAtIGB4bWF4YCAkXHJpZ2h0YXJyb3ckIG5pbGFpIHBhZGEgc3VtYnUgWCB1bnR1ayBtZW5nYWtoaXJpIGhpZ2hsaWdodC4NCiAgICAtIGB5bWluYCAkXHJpZ2h0YXJyb3ckIG5pbGFpIHBhZGEgc3VtYnUgWSB1bnR1ayBtZW5lbnR1a2FuIHRpdGlrIGF3YWwgdGluZ2dpIGhpZ2hsaWdodC4NCiAgICAtIGB5bWF4YCAkXHJpZ2h0YXJyb3ckIG5pbGFpIHBhZGEgc3VtYnUgWSB1bnR1ayBtZW5lbnR1a2FuIHRpdGlrIGFraGlyIHRpbmdnaSBoaWdobGlnaHQuDQogICAgLSBgZmlsbGAgJFxyaWdodGFycm93JCBtZW5lbnR1a2FuIHdhcm5hLg0KICAgIC0gYGFscGhhYCAkXHJpZ2h0YXJyb3ckIG1lbmVudHVrYW4gdGluZ2thdCB0cmFuc3BhcmFuc2kuIFNlbWFraW4ga2VjaWwgc2VtYWtpbiB0cmFuc3BhcmFuLg0KICAgIA0KOC4gTWVuYW1iYWhrYW4gdGVrcyB5YW5nIGxhaW46IE1lbmdndW5ha2FuIHBhcmFtZXRlciBgdGV4dGAgcGFkYSBmdW5nc2kgYGFubm90YXRlYCB1bnR1ayBtZW51bGlza2FuIHRla3MgYGV4ZWN1dGVkYCwgYGFjY3VzZWRgLCBgcHJvdGVzdGFudCByZWZvcm1hdGlvbmAsIGRhbiBgY2F0aG9saWMgY291bnRlci1yZWZvcm1hdGlvbmAuDQoNCjkuIE1lbmFtYmFoa2FuIGdhcmlzIHRpdGlrIHRpdGlrIHBhZGEgdGVrcyAqcHJvdGVzdGFudCByZWZvcm1hdGlvbiogbWVuZ2d1bmFrYW4gZnVuZ3NpIGBnZW9tX3NlZ21lbnRgLg0KDQoxMC4gTWVuYW1iYWhrYW4gdGVrcyBwYWRhIHNpc2kga2lyaSBhdGFzIG1lbmdndW5ha2FuIGZ1bmdzaSBgZ2VvbV9sYWJlbGAuDQoNCg0KPGhyIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCBibGFjazsiPg0KDQpNYXJpIGtpdGEgaW1wbGVtZW50YXNpa2FuIGtlIGRhbGFtIGtvZGUgbWVuZ2d1bmFrYW4gYmFoYXNhIFIgc2ViYWdhaSBiZXJpa3V0Oi4NCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KDQojIEZ1bmdzaSB1bnR1ayBtZW1idWF0IGxhYmVsIGN1c3RvbQ0KY3VzdG9tX2xhYmVscyA8LSBmdW5jdGlvbih4KSB7DQogICMgTWVtYnVhdCB0ZW1wb3JhcnkgdmFyaWFibGUNCiAgbGFiZWxzIDwtICIiDQogIA0KICAjIExvb3BpbmcgdW50dWsgY2VrIGRhdGEgZGVrYWRlLiBKaWthIG1lbmdhbmR1bmcgNTAsIGhhbnlhIGRpdHVsaXMgYW5na2EgNTAuIEppa2EgdGlkYWssIGFrYW4gZGl0dWxpcyBsZW5na2FwLg0KICBmb3IgKGkgaW4gc2VxX2Fsb25nKHgpKSB7DQogICAgaWYgKGdyZXBsKCI1MCQiLCBhcy5jaGFyYWN0ZXIoeFtpXSkpKSB7DQogICAgICBsYWJlbHNbaV0gPC0gIjUwIg0KICAgIH0gZWxzZSB7DQogICAgICBsYWJlbHNbaV0gPC0gYXMuY2hhcmFjdGVyKHhbaV0pDQogICAgfQ0KICB9DQogIA0KICAjIE1lbmdlbWJhbGlrYW4gbmlsYWkgZGVrYWRlDQogIHJldHVybihsYWJlbHMpDQp9DQoNCiMgTWVtYnVhdCBsaW5lIHBsb3QNCmxpbmVfY2hhcnQgPC0gZ2dwbG90KGRhdGFfbGluZV9jaGFydCwgYWVzKHggPSBkZWNhZGUpKSArDQogICMgTWVtYnVhdCBsaW5lIHVudHVrIGtvbG9tIGRlYXRocw0KICBnZW9tX2xpbmUoYWVzKHkgPSBkZWF0aHMpLCBjb2xvciA9ICIjMDA5OGEwIiwgc2l6ZSA9IDIpICsNCiAgDQogICMgTWVtYnVhdCBsaW5lIHVudHVrIGtvbG9tIHRyaWVkDQogIGdlb21fbGluZShhZXMoeSA9IHRyaWVkKSwgY29sb3IgPSAiIzcwY2JjNCIsIHNpemUgPSAyKSArDQogIA0KICAjIE1lbmdoYXB1cyBsYWJlbCBwYWRhIHN1bWJ1IFggZGFuIFkNCiAgbGFicyh4ID0gIiIsIHkgPSAiIikgKyANCiAgDQogICMgTWVuZ2F0dXIgYWdhciB0YW1waWxhbiBwbG90IG1pbmltYWxpcw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICANCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgxMzAwLCAxODUwLCBieSA9IDUwKSwgIyBUZW50dWthbiB0aXRpayB1dGFtYQ0KICAgIG1pbm9yX2JyZWFrcyA9IHNlcSgxMzAwLCAxODUwLCBieSA9IDEwKSwgIyBUZW50dWthbiB0aXRpayBtaW5vcg0KICAgIGxhYmVscyA9IGN1c3RvbV9sYWJlbHMsDQogICAgZ3VpZGUgPSBndWlkZV9heGlzKG1pbm9yLnRpY2tzID0gVFJVRSksDQogICkgKw0KICANCiAgIyBNZW5nYXR1ciB0ZWtzIHBhZGEgc3VtYnUgWQ0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgIyBNZW5nYXR1ciBuaWxhaSBkaW11bGFpIGRhcmkgMCBzYW1wYWkgNi4wMDAgZGVuZ2FuIGphcmFrIDEuMDAwDQogICAgYnJlYWtzID0gc2VxKDAsIDYwMDAsIGJ5ID0gMTAwMCksDQogICAgDQogICAgIyBNZW5ndXJhbmdpIHJ1YW5nIGtvc29uZyBwYWRhIGthbmFuIGtpcmkgYXRhcyBiYXdhaCBwbG90DQogICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDApKSwNCiAgICANCiAgICAjIE1lbmFtYmFoIHBlbWlzYWggcmlidWFuIHBhZGEgc3VtYnUgWQ0KICAgIGxhYmVscyA9IHNjYWxlczo6Y29tbWEsDQogICAgDQogICAgIyBNZW5nYXR1ciBwb3Npc2kgc3VtYnUgWQ0KICAgIHBvc2l0aW9uID0gInJpZ2h0Ig0KICApICsNCiAgDQogICMgTWVuZ2F0dXIgYmViZXJhcGEgZWxlbWVudCBwYWRhIHBsb3QNCiAgdGhlbWUoDQogICAgIyBNZW5nYXR1ciB3YXJuYSB0ZWtzIHBhZGEgc3VtYnUgWCBkYW4gWQ0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksICAjIEFsaWduIGxhYmVscyB0byB0aGUgbGVmDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBjb2xvciA9ICJibGFjayIpLCAgIyBBbGlnbiBsYWJlbHMgdG8gdGhlIGxlZnQNCiAgICANCiAgICAjIE1lbmdhdHVyIGdhcmlzIHlhbmcgYWthbiBkaXRhbXBpbGthbiBkaSB0ZW5nYWgtdGVuZ2FoIHBsb3QNCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNzUsIGNvbG9yID0gIiNjYmNjY2UiKSwNCiAgICANCiAgICAjIE1lbmdhdHVyIGtldGViYWxhbiB0aWNrcw0KICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfbGluZShzaXplID0gMC42KSwNCiAgICANCiAgICAjIE1lbmdhdHVyIHBhbmphbmcgdGlja3MNCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSwNCiAgICBheGlzLm1pbm9yLnRpY2tzLmxlbmd0aCA9IHVuaXQoMC4xLCAiY20iKSwNCiAgICANCiAgICAjIE1lbmdhdHVyIHRlYmFsIGdhcmlzIHN1bWJ1IFgNCiAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfbGluZShzaXplID0gMC42KSwNCiAgICANCiAgICAjIE1lbmdhdHVyIG1hcmdpbiBkYXJpIHBsb3Qgc2VjYXJhIHVtdW0NCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxLjUsIDAsIDAsIDEsICJjbSIpICwNCiAgICANCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9IE5BKQ0KICApICsgDQogIA0KICAjIE1lbWJ1YXQgaGlnaGxpZ2h0IHBhZGEgcmVudGFuZyB0YWh1biAxNTU1IHMuZC4gMTY0OA0KICBhbm5vdGF0ZShnZW9tID0gInJlY3QiLCB4bWluID0gMTU1NSwgeG1heCA9IDE2NDgsIHltaW4gPSAwLCB5bWF4ID0gSW5mLA0KICAgICAgICAgICBmaWxsID0gImNvcmFsIiwgYWxwaGEgPSAwLjIpICsNCiAgDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE1ODUsIHkgPSAyNTAsIGxhYmVsID0gIkV4ZWN1dGVkIiwgc2l6ZSA9IDQuMiwgaGp1c3QgPSAwKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxNzEwLCB5ID0gODUwLCBsYWJlbCA9ICJBY2N1c2VkIiwgc2l6ZSA9IDQuMiwgaGp1c3QgPSAwKSArDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE1MTUsIHkgPSAyNzIwLCBsYWJlbCA9ICJQUk9URVNUQU5UIiwgc2l6ZSA9IDQuMiwgaGp1c3QgPSAxKSArDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE1MTUsIHkgPSAyMzIwLCBsYWJlbCA9ICJSRUZPUk1BVElPTiIsIHNpemUgPSA0LjIsIGhqdXN0ID0gMSkgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxNjUwLCB5ID0gNTcyMCwgbGFiZWwgPSAiQ0FUSE9MSUMiLCBzaXplID0gNC4yLCBoanVzdCA9IDApICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMTY1MCwgeSA9IDUzMjAsIGxhYmVsID0gIkNPVU5URVItUkVGT1JNQVRJT04iLCBzaXplID0gNC4yLCBoanVzdCA9IDApICsNCiAgDQogIGdlb21fc2VnbWVudChhZXMoeCA9IDE1MTUsIHhlbmQgPSAxNTE1LCB5ID0gMCwgeWVuZCA9IDIyMDApLCANCiAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRvdHRlZCIsIGNvbG9yID0gImNvcmFsIiwgc2l6ZSA9IDEuMykgKw0KICANCiAgZ2VvbV9sYWJlbChhZXMoeCA9IC1JbmYsIHkgPSBJbmYsIGxhYmVsID0gIkJ5IGRlY2FkZSIpLCANCiAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC44LCBzaXplID0gNSwgbGFiZWwuc2l6ZSA9IDApIA0KDQojIE1lbmFtcGlsa2FuIHBsb3QNCmxpbmVfY2hhcnQNCmBgYA0KDQpTZXRlbGFoIHBlbWJ1YXRhbiBsaW5lIGNoYXJ0IGJlcmhhc2lsLCBzYWF0bnlhIHVudHVrIG1lbnlpbXBhbiBwbG90IHRlcnNlYnV0IHVudHVrIGRpa29tYmluYXNpa2FuIGRlbmdhbiBwbG90IHlhbmcgbGFpbi4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmdnc2F2ZShmaWxlbmFtZSA9ICIuLi9hc3NldC9saW5lX2NoYXJ0LnBuZyIsIHBsb3QgPSBsaW5lX2NoYXJ0LCB3aWR0aCA9IDYuNiwgaGVpZ2h0ID0gNC4zLCBkcGkgPSAzMDApDQpgYGANCg0KDQojIDUuIEZpbmFsIFJlc3VsdA0KDQpMYW5na2FoIHRlcmFraGlyIHlhaXR1IG1lbmdnYWJ1bmdrYW4gc2VtdWEgcGxvdCBtZW5qYWRpIHNhdHUga2VzYXR1YW4gcGxvdC4gQmViZXJhcGEgbGFuZ2thaCB5YW5nIGhhcnVzIGRpbGFrdWthbiB5YWl0dToNCg0KMS4gU2lhcGthbiBgYnViYmxlX2NoYXJ0LnBuZ2AsIGBzdGFja2VkX2Jhcl9jaGFydC5wbmdgLCBkYW4gYGxpbmVfY2hhcnQucG5nYC4NCjIuIE1lbW90b25nIGJhZ2lhbiBwbG90IHlhbmcgZGlwZXJsdWthbiBzYWphIChjcm9wcGluZykuDQozLiBNZW5nZ2FidW5na2FuIHNlbXVhIGNoYXJ0IG1lbmphZGkgc2VidWFoIGNoYXJ0Lg0KNC4gTWVuYW1iYWggaGVhZGVyIGdhcmlzIG1lcmFoIHNlYmFnYWkgY2lyaSBraGFzIFRoZSBFY29ub21pc3QuDQo1LiBUYW1iYWhrYW4gdGVrcyBsYWluIHlhbmcgZGlwZXJsdWthbi4NCg0KUGVydGFtYSB5YWl0dSBtZW55aWFwa2FuIGdhbWJhciBkYXJpIGJ1YmJsZSBjaGFydCB5YW5nIHN1ZGFoIGRpc2ltcGFuLiBEYWxhbSBoYWwgaW5pLCBraXRhIGhhbnlhIG1lbWJ1dHVoa2FuIGJhZ2lhbiBhbmdrYSBkYW4gdmlzdWFsaXNhc2lueWEgc2FqYS4gT2xlaCBrYXJlbmEgaXR1LCBwZXJsdSBraXRhIGJ1YW5nIHNpc2kgbGFpbiB5YW5nIHRpZGFrIGRpZ3VuYWthbi4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgTWVtYmFjYSBnYW1iYXIgYnViYmxlIGNoYXJ0DQpidWJibGVfY2hhcnRfaW1nIDwtIGltYWdlX3JlYWQoIi4uL2Fzc2V0L2J1YmJsZV9jaGFydC5wbmciKQ0KDQojIE1lbnlpbXBhbiBsZWJhciBkYW4gdGluZ2dpIHBsb3QNCmltZ193aWR0aCA8LSBpbWFnZV9pbmZvKGJ1YmJsZV9jaGFydF9pbWcpJHdpZHRoDQppbWdfaGVpZ2h0IDwtIGltYWdlX2luZm8oYnViYmxlX2NoYXJ0X2ltZykkaGVpZ2h0DQoNCiMgTWVuYW1iYWggd2hpdGUgc3BhY2UgZGkgYXRhcyBwbG90DQpibGFua19zcGFjZSA8LSBpbWFnZV9ibGFuayh3aWR0aCA9IGltZ193aWR0aCwgaGVpZ2h0ID0gMjAwLCBjb2xvciA9ICJ3aGl0ZSIpDQoNCiMgTWVsYWt1a2FuIHByb3NlcyBzdGFja2luZyAobWVuYW1iYWgpIGJsYW5rIHNwYWNlIGtlIGJ1YmJsZSBjaGFydA0KYnViYmxlX2NoYXJ0X2ltZyA8LSBpbWFnZV9hcHBlbmQoYyhibGFua19zcGFjZSwgYnViYmxlX2NoYXJ0X2ltZyksIHN0YWNrID0gVFJVRSkNCg0KIyBwcm9zZXMgY3JvcHBpbmcgZGVuZ2FuIHVrdXJhbiB5YW5nIGRpYnV0dWhrYW4NCmNyb3BwZWRfYnViYmxlX2NoYXJ0X2ltZyA8LSBpbWFnZV9jcm9wKGJ1YmJsZV9jaGFydF9pbWcsICIzMzB4MTcwMCswKzAiKQ0KDQojIE1lbnlpbXBhbiBnYW1iYXIgaGFzaWwgY3JvcA0KaW1hZ2Vfd3JpdGUoY3JvcHBlZF9idWJibGVfY2hhcnRfaW1nLCAiLi4vYXNzZXQvY3JvcHBlZF9idWJibGVfY2hhcnQucG5nIikNCg0KYGBgDQoNClByb3NlcyBzZWxhbmp1dG55YSB5YWl0dSBtZW5nZ2FidW5na2FuICoqYnViYmxlIGNoYXJ0KiogIHlhbmcgc3VkYWggZGkgY3JvcCBkZW5nYW4gKipzdGFja2VkIGJhciBjaGFydCoqLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBNZW55aW1wYW4gaGFzaWwga29tYmluYXNpDQpwbmcoIi4uL2Fzc2V0L2J1YmJsZV9iYXJfY29tYmluZWQucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNywgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDApDQoNCiMgTWVtYmFjYSBwbG90IGJ1YmJsZSBjaGFydA0KaW1nMSA8LSByYXN0ZXJHcm9iKGFzLnJhc3RlcihyZWFkUE5HKCIuLi9hc3NldC9jcm9wcGVkX2J1YmJsZV9jaGFydC5wbmciKSksIGludGVycG9sYXRlID0gVFJVRSkNCg0KIyBNZW1iYWNhIHBsb3Qgc3RhY2tlZCBiYXIgY2hhcnQNCmltZzIgPC0gcmFzdGVyR3JvYihhcy5yYXN0ZXIocmVhZFBORygiLi4vYXNzZXQvc3RhY2tlZF9iYXJfY2hhcnQucG5nIikpLCBpbnRlcnBvbGF0ZSA9IFRSVUUpDQoNCiMgUHJvc2VzIG1lbmdnYWJ1bmdrYW4gcGxvdA0KZ3JpZC5hcnJhbmdlKGltZzEsIGltZzIsIG5jb2wgPSAyLCB3aWR0aHMgPSBjKDAuNCwgMy4zNSkpDQoNCmBgYA0KDQpTZWxhbmp1dG55YSB5YWl0dSBtZW5nZ2FidW5na2FuICoqYnViYmxlIGNoYXJ0KiogZGFuICoqc3RhY2tlZCBiYXIgY2hhcnQqKiB5YW5nIHN1ZGFoIGRpZ2FidW5na2FuIHNlYmVsdW1ueWEgZGVuZ2FuICoqbGluZSBjaGFydCoqIGRhbiBkaXNpbXBhbiBkZW5nYW4gbmFtYSBgYWxsX2NoYXJ0X2NvbWJpbmVkLnBuZ2AuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1lbnlpbXBhbiBnYW1iYXIgaGFzaWwga29tYmluYXNpIDMgcGxvdA0KcG5nKCIuLi9hc3NldC9hbGxfY2hhcnRfY29tYmluZWQucG5nIiwgd2lkdGggPSA3LjI4LCBoZWlnaHQgPSA0LjMsIHVuaXRzID0gImluIiwgcmVzID0gNTAwKQ0KDQojIE1lbWJhY2EgZ2FtYmFyIGtvbWJpbmFzaSBidWJibGUgY2hhcnQgZGFuIHN0YWNrZWQgYmFyIGNoYXJ0IGRlbmdhbiBsaW5lIGNoYXJ0DQpidWJibGVfYmFyX2NvbWJpbmVkIDwtIHJhc3Rlckdyb2IoYXMucmFzdGVyKHJlYWRQTkcoIi4uL2Fzc2V0L2J1YmJsZV9iYXJfY29tYmluZWQucG5nIikpLCBpbnRlcnBvbGF0ZSA9IFRSVUUpDQpsaW5lX2NoYXJ0IDwtIHJhc3Rlckdyb2IoYXMucmFzdGVyKHJlYWRQTkcoIi4uL2Fzc2V0L2xpbmVfY2hhcnQucG5nIikpLCBpbnRlcnBvbGF0ZSA9IFRSVUUpDQoNCiMgTWVueWlhcGthbiBoYWxhbWFuIGJhcnUgdW50dWsgbWVsZXRha2FuIHNtdWEgcGxvdA0KZ3JpZC5uZXdwYWdlKCkNCg0KIyBNZW5nYXR1ciBwb3Npc2kgZGFuIHVrdXJhbiBnYW1iYXIgZGFyaSBidWJibGVfYmFyX2NvbWJpbmVkDQpwdXNoVmlld3BvcnQodmlld3BvcnQoeCA9IDAuMDIsIHkgPSAwLjQ5LCB3aWR0aCA9IDAuNzUsIGp1c3QgPSAibGVmdCIpKQ0KDQojIE1lbGV0YWthbiBnYW1iYXIgYnViYmxlX2Jhcl9jb21iaW5lZCBrZSB0ZW1wYXQgeWFuZyBzdWRhaCBkaXNlZGlha2FuDQpncmlkLmRyYXcoYnViYmxlX2Jhcl9jb21iaW5lZCkNCnVwVmlld3BvcnQoKQ0KDQojIE1lbmdhdHVyIHBvc2lzaSBkYW4gdWt1cmFuIGdhbWJhciBkYXJpIGxpbmUgY2hhcnQNCnB1c2hWaWV3cG9ydCh2aWV3cG9ydCh4ID0gMC40MywgeSA9IDAuMzM1LCB3aWR0aCA9IDAuMzcpKQ0KDQojIE1lbGV0YWthbiBnYW1iYXIgbGluZSBjaGFydCBrZSB0ZW1wYXQgeWFuZyBzdWRhaCBkaXNlZGlha2FuDQpncmlkLmRyYXcobGluZV9jaGFydCkNCnVwVmlld3BvcnQoKQ0KYGBgDQoNCk1lbmFtYmFoIGhlYWRlciBnYXJpcyBtZXJhaCBzZWJhZ2FpIGNpcmkga2hhcyBUaGUgRWNvbm9taXN0IGRhbiBtZW5hbWJhaGthbiB0ZWtzIGxhaW4geWFuZyBkaXBlcmx1a2FuIHNlcGVydGkgZm9vdG5vdGUgeWFuZyBtZW5qZWxhc2thbiBzdW1iZXIgZGF0YSB5YW5nIGRpZ3VuYWthbi4gQmVyaWt1dCBsYW5na2FoLWxhbmdrYWggeWFuZyBkaWxha3VrYW46DQoNCjEuIE1lbmFtYmFoa2FuIGdhcmlzIG1lcmFoIHRpcGlzIHNlcGFuamFuZyBwbG90IG1lbmdndW5ha2FuIGZ1bmdzaSBgZ3JpZC5yZWFjdGAuDQoyLiBNZW5hbWJhaGthbiBrb3RhayBnYXJpcyBtZXJhaCBkaSBzZWJlbGFoIGtpcmkgYXRhcy4gU2V0ZWxhaCBnYXJpcyB0aXBpcyBtZW5nZ3VuYWthbiBmdW5nc2kgYGdyaWQucmVhY3RgLg0KMy4gTWVuYW1iYWhrYW4ganVkdWwgdXRhbWEgZGFuIHN1YiBqdWR1bCBwYWRhIHBsb3QgbWVuZ2d1bmFrYW4gZnVuZ3NpIGBncmlkLnRleHRgLiANCg0KICAgIC0gTmlsYWkgYHhgIG1lcnVwYWthbiBwb3Npc2kgdGVrcyBzZWNhcmEgaG9yaXpvbnRhbC4gU2VtYWtpbiBiZXNhciBtYWthIHBvc2lzaSBzZW1ha2luIGtlIGthbmFuLiANCiAgICAtIE5pbGFpIGB5YCBtZXJ1cGFrYW4gcG9zaXNpIHRla3Mgc2VjYXJhIHZlcnRpa2FsLiBTZW1ha2luIGJlc2FyIG1ha2Egc2VtYWtpbiBrZSBhdGFzLg0KICAgIC0gRnVuZ3NpIGBncGFyYCB1bnR1ayBtZW5nYXR1ciB1a3VyYW4gaHVydWYuDQogICAgDQo0LiBNZW5hbWJhaGthbiBmb290bm90ZSBkaSBiYXdhaCBwbG90IHlhbmcgbWVuamVsYXNrYW4gc3VtYmVyIGRhdGEgeWFuZyBkaXJ1anVrIGRhbGFtIHBlbWJ1YXRhbiBwbG90LiBVbnR1ayBtZW1idWF0IGZvb3Rub3RlIGRpZ3VuYWthbiBmdW5nc2kgYGdyaWQudGV4dGAsDQo1LiBNZW1idWF0IGtvdGFrIHBlcnNlZ2kgcGFuamFuZyBkaSBhdGFzIGJ1YmJsZSBjaGFydCBtZW5nZ3VuYWthbiBmdW5nc2kgYGdyaWQucmVhY3RgLg0KDQogICAgLSBOaWxhaSBgeGAgbWVydXBha2FuIHBvc2lzaSB0ZWtzIHNlY2FyYSBob3Jpem9udGFsLiBTZW1ha2luIGJlc2FyIG1ha2EgcG9zaXNpIHNlbWFraW4ga2Uga2FuYW4uIA0KICAgIC0gTmlsYWkgYHlgIG1lcnVwYWthbiBwb3Npc2kgdGVrcyBzZWNhcmEgdmVydGlrYWwuIFNlbWFraW4gYmVzYXIgbWFrYSBzZW1ha2luIGtlIGF0YXMuDQogICAgLSBGdW5nc2kgYHdpZHRoYCB1bnR1ayBtZW5nYXR1ciBsZWJhciBib3guDQogICAgLSBGdW5nc2kgYGhlaWdodGAgdW50dWsgbWVuZ2F0dXIgdGluZ2dpIGJveC4NCiAgICAtIEZ1bmdzaSBgZ3BhcmAgdW50dWsgbWVuZW50dWthbiB3YXJuYSBkYW4gdGluZ2thdCB0cmFuc3BhcmFuc2kgd2FybmEuDQogICAgDQo2LiBNZW5hbWJhaGthbiB0ZWtzIGRpIGRhbGFtIGtvdGFrIHBlcnNlZ2kgcGFuamFuZyBtZW5nZ3VuYWthbiBmdW5nc2kgYGdyaWQudGV4dGAuDQo3LiBNZW1idWF0IHNlZ2l0aWdhIHRlcmJhbGlrIGJlcnVrdXJhbiBrZWNpbCBkaSBiYXdhaCBrb3RhayBtZW5nZ3VuYWthbiBmdW5nc2kgYGdyaWQucG9seWdvbmAuDQoNCjxociBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgYmxhY2s7Ij4NCg0KTWFyaSBraXRhIGltcGxlbWVudGFzaWthbiBrZSBkYWxhbSBrb2RlIG1lbmdndW5ha2FuIGJhaGFzYSBSIHNlYmFnYWkgYmVyaWt1dDouDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1lbmFtYmFoIGhlYWRlciBnYXJpcyBtZXJhaCBzZWJhZ2FpIGNpcmkga2hhcyBUaGUgRWNvbm9taXN0DQpncmlkLnJlY3QoeCA9IDEsIHkgPSAwLjk5NywNCiAgICAgICAgICBoanVzdCA9IDEsIHZqdXN0ID0gMCwNCiAgICAgICAgICBncCA9IGdwYXIoZmlsbD0nI0U1MDAxQycsbHdkPTApKQ0KDQpncmlkLnJlY3QoeCA9IDAuMDEzLCB5ID0gMC45NCwNCiAgICAgICAgICBoanVzdCA9IDEsIHZqdXN0ID0gMCwNCiAgICAgICAgICBncCA9IGdwYXIoZmlsbD0nI0U1MDAxQycsbHdkPTApKQ0KDQojIE1lbmFtYmFoIGp1ZHVsIHBhZGEgcGxvdA0KZ3JpZC50ZXh0KCJEb3VibGUsIGRvdWJsZSB0b2lsIGFuZCB0cm91YmxlIiwNCiAgICAgICAgICB4ID0gMC4zMzAsIHkgPSAwLjkzNSwNCiAgICAgICAgICBoanVzdCA9IDEsIHZqdXN0ID0gMCwNCiAgICAgICAgICBncCA9IGdwYXIoZm9udHNpemU9MTEsIGZvbnRmYWNlPSJib2xkIikpDQoNCmdyaWQudGV4dCgiRXVyb3BlYW4gd2l0Y2hjcmFmdCwgMTMwMC0xODUwIiwNCiAgICAgICAgICB4ID0gMC4yMzUsIHkgPSAwLjksDQogICAgICAgICAgaGp1c3QgPSAxLCB2anVzdCA9IDAsDQogICAgICAgICAgZ3AgPSBncGFyKGZvbnRzaXplPTcuOCkpDQoNCiMgTWVuYW1iYWggZm9vdG5vdGUgDQpncmlkLnRleHQoJ1NvdXJjZTogIldpdGNoIFRyaWFscyIsIGJ5IFBldGVyIExlZXNvbiBhbmQgSmFjb2IgUnVzcywnLA0KICAgICAgICAgIHggPSAwLjMwOCwgeSA9IDAuMTIsDQogICAgICAgICAgaGp1c3QgPSAxLCB2anVzdCA9IDAsDQogICAgICAgICAgZ3AgPSBncGFyKGZvbnRzaXplPTUuNjcpKQ0KDQpncmlkLnRleHQoIkVjb25vbWljIEpvdXJuYWwsIiwNCiAgICAgICAgICB4ID0gMC40MDMsIHkgPSAwLjEyLA0KICAgICAgICAgIGhqdXN0ID0gMSwgdmp1c3QgPSAwLA0KICAgICAgICAgIGdwID0gZ3Bhcihmb250ZmFjZSA9ICJpdGFsaWMiLCBmb250c2l6ZT01LjY3KSkNCg0KZ3JpZC50ZXh0KCdBdWd1c3QsIDIwMTcnLA0KICAgICAgICAgIHggPSAwLjQ3LCB5ID0gMC4xMiwNCiAgICAgICAgICBoanVzdCA9IDEsIHZqdXN0ID0gMCwNCiAgICAgICAgICBncCA9IGdwYXIoZm9udHNpemU9NS42NykpDQoNCmdyaWQudGV4dCgnRWNvbm9taXN0LmNvbScsDQogICAgICAgICAgeCA9IDAuMDgsIHkgPSAwLjA5LA0KICAgICAgICAgIGhqdXN0ID0gMSwgdmp1c3QgPSAwLA0KICAgICAgICAgIGdwID0gZ3Bhcihmb250c2l6ZT01LjY3LCBjb2wgPSAiI0MwQzBDMCIpKQ0KDQojIE1lbWJ1YXQgb3JhbmdlIGJveCBkaSBhdGFzIGJ1YmJsZSBjaGFydA0KZ3JpZC5yZWN0KHggPSAwLjA5NSwgeSA9IDAuODA1LA0KICAgICAgICAgIHdpZHRoID0gMC4xMzUsIGhlaWdodCA9IDAuMDc0LA0KICAgICAgICAgIGdwID0gZ3BhcihmaWxsID0gImNvcmFsIiwgYWxwaGEgPSAwLjcsIGNvbCA9IE5BKSkNCg0KIyBNZW5hbWJhaGthbiB0ZWtzIGRpIGRhbGFtIG9yYW5nZSBib3gNCmdyaWQudGV4dCgnV2l0Y2hjcmFmdCB0cmlhbHMnLA0KICAgICAgICAgIHggPSAwLjE0MywgeSA9IDAuODE1LA0KICAgICAgICAgIGhqdXN0ID0gMSwgdmp1c3QgPSAwLA0KICAgICAgICAgIGdwID0gZ3Bhcihmb250c2l6ZT03KSkNCg0KZ3JpZC50ZXh0KCdwZXIgMTAwLDAwMCBwZW9wbGUnLA0KICAgICAgICAgIHggPSAwLjE1MywgeSA9IDAuNzg1LA0KICAgICAgICAgIGhqdXN0ID0gMSwgdmp1c3QgPSAwLA0KICAgICAgICAgIGdwID0gZ3Bhcihmb250c2l6ZT03KSkNCg0KIyBNZW1idWF0IHNlZ2l0aWdhIHRlcmJhbGlrIHlhbmcgYWRhIGRpIG9ybmFnZSBib3gNCnggPC0gYygwLjA3ODUsIDAuMDcyNSwgMC4wODQ1KSANCnkgPC0gYygwLjc2MSwgMC43NjgsIDAuNzY4KQ0KDQpncmlkLnBvbHlnb24oeCA9IHgsIHkgPSB5LCBncCA9IGdwYXIoZmlsbCA9ICJjb3JhbCIsIGFscGhhID0gMC43LCBjb2wgPSBOQSkpDQoNCmBgYA0KDQpUZXJrYWhpciB5YWl0dSBtZWxha3VrYW4gY3JvcHBpbmcgdW50dWsgbWVueWVsZWtzaSBiYWdpYW4geWFuZyBwZW50aW5nIHNhamEuIFdoaXRlIHNwYWNlIHlhbmcgYmVybGViaWggYWthbiBkaWhhcHVzIChjcm9wKS4gTGFsdSBoYXNpbCBjcm9wIGFrYW4gZGlzaW1wYW4gZGVuZ2FuIG5hbWEgYGZpbmFsLnBuZ2AgZGFuIG1lcnVwYWthbiBoYXNpbCBha2hpciBkYXJpIHByb3llayBpbmkuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1lbWJhY2EgcGxvdCB5YW5nIGJlcmlzaSAzIGNoYXJ0DQpmaW5hbF9pbWFnZSA8LSBpbWFnZV9yZWFkKCIuLi9hc3NldC9hbGxfY2hhcnRfY29tYmluZWQucG5nIikNCg0KIyBwcm9zZXMgY3JvcHBpbmcgZGVuZ2FuIHVrdXJhbiB5YW5nIGRpYnV0dWhrYW4NCmNyb3BwZWRfZmluYWxfaW1hZ2UgPC0gaW1hZ2VfY3JvcChmaW5hbF9pbWFnZSwgIjIzMDB4MTk4MCswKzAiKQ0KDQojIE1lbnlpbXBhbiBnYW1iYXIgaGFzaWwgY3JvcA0KaW1hZ2Vfd3JpdGUoY3JvcHBlZF9maW5hbF9pbWFnZSwgIi4uL2Fzc2V0L2ZpbmFsLnBuZyIpDQpgYGANCg0KIVtdKC4uL2Fzc2V0L2ZpbmFsLnBuZykNCg0KIyBDb25jbHVzaW9uDQoNClByb2plY3QgcmVwbGlrYSB2aXN1YWxpc2FzaSBkYXJpIG1hamFsYWggVGhlIEVjb25vbWlzdCBtZW5nZ3VuYWthbiBsaWJyYXJ5IGBnZ3Bsb3RgIG1lcnVwYWthbiBzYWxhaCBzYXR1IGNhcmEgY2VwYXQgYmFnaSBBbmRhIHlhbmcgaW5naW4gYmVsYWphciBiYWhhc2EgcGVtcm9ncmFtYW4gUi4gS2FyZW5hIGRlbmdhbiBtZW5nZXJqYWthbiBwcm9qZWN0IGluaSwgQW5kYSBha2FuIG1lbmdndW5ha2FuIGJlcmJhZ2FpIGZ1bmdzaSB5YW5nIGFkYSBkaSBSLiBTZWxhaW4gaXR1LCBkZW5nYW4gbWVtcGVsYWphcmkgdmlzdWFsaXNhc2kgeWFuZyBhZGEgZGkgbWFqYWxhaCBUaGUgRWNvbm9taXN0LCBraXRhIGJpc2EgYmVsYWphciBiYWdhaW1hbmEgY2FyYSBtZW1idWF0IHZpc3VhbGlzYXNpIHlhbmcgdGVwYXQsIG1lbmFyaWssIGRhbiBpbnNpZ2h0ZnVsIHlhbmcgYmlzYSBtZW5qZWxhc2thbiBzdWF0dSBkYXRhIGRlbmdhbiBiYWlrIGRhbGFtIGJlbnR1ayB2aXN1YWwuDQoNCg0KU2V0ZWxhaCBiZXJoYXNpbCBtZWxha3VrYW4gcmVwbGlrYSB2aXN1YWxpc2FzaSBkYXJpIG1hamFsYWggVGhlIEVjb25vbWlzdCwgZGlkYXBhdCBiYWh3YSBoYXNpbCB2aXN1YWxpc2FzaSB0aWRhayAxMDAlIG1pcmlwIGRlbmdhbiB2aXN1YWxpc2FzaSB5YW5nIG1lbmphZGkgc3VtYmVyIHJ1anVrYW4uIEhhbCBpbmkgZGlrYXJlbmFrYW4gYmViZXJhcGEgZmFrdG9yIHNlcGVydGkga2V0aWRha3RhaHVhbiBwZW51bGlzIHRlbnRhbmcgamVuaXMgZm9udCB5YW5nIGRpZ3VuYWthbiBkYW4gbGFpbm55YS4gVW50dWsgaXR1LCBpbXByb3ZlbWVudCB5YW5nIGJpc2EgZGlsYWt1a2FuIHlhaXR1IG1lbmdndW5ha2FuIGplbmlzIGZvbnQgeWFuZyBzYW1hIHNlcGVydGkgcGFkYSBzdW1iZXIgcnVqdWthbiBhZ2FyIGhhc2lsIHJlcGxpa2Egc2VtYWtpbiBtaXJpcCAoYmlsYSBtZW11bmdraW5rYW4pLg0KDQoNCiMgUmVmZXJlbmNlcw0KDQoxLiAqKltUaGUgUG9saXRpY2FsIEVjb25vbXkgb2YgV2l0Y2hjcmFmdF0qKiAtIGh0dHBzOi8vd3d3LmVjb25vbWlzdC5jb20vZ3JhcGhpYy1kZXRhaWwvMjAxNy8xMC8zMS90aGUtcG9saXRpY2FsLWVjb25vbXktb2Ytd2l0Y2hjcmFmdA0KMi4gKipbV2l0Y2ggVHJpYWxzIFBhcGVyXSoqIC0gaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvYWJzLzEwLjExMTEvZWNvai4xMjQ5OA0KDQo8ZGl2IGNsYXNzPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIGRhdGEtdW5pcXVlPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIHN0eWxlPSJoZWlnaHQ6IDAiPjwvZGl2Pg==