Install dan Load Packages
Jalankan perintah di bawah ini untuk install package (jika Anda belum pernah install) yang akan digunakan untuk dapat mengikuti tutorial ini sampai selesai.
install.packages(c("ggplot2", "dplyr", "tidyr", "nycflights13"))
# atau
install.packages(c("tidyverse", "nycflights13"))
Panggil package yang sudah Anda install dengan fungsi library().
# Panggil package yang sudah terisntall
library(ggplot2)
library(dplyr)
library(tidyr)
# # atau cukup memanggil `tidyverse` untuk memanggil package ggplot2 dan package lain di tidyverse
# library(tidyverse)
library(nycflights13)
Package ggplot2 (dan beberapa package lain yang tidak digunakan di tutorial ini) termasuk dalam bagian package tidyverse. tidyverse adalah kumpulan package yang dibuat oleh Hadley Wickham dkk untuk kebutuhan data science menggunakan R.
ggplot2 adalah salah satu package yang sangat banyak digunakan oleh pengguna R untuk kebutuhan visualisasi.
dplyr dan tidyr adalah package yang sangat berguna untuk melakukan manipulasi/transformasi data menggunakan R.
nycflights13 adalah package yang menyediakan 5 data frame dalam format tibble tentang penerbangan di NYC selama tahun 2013.
Tidyverse
tidyverse menggunakan tibble sebagai pengganti data.frame.
Tibbles are data frames, but they tweak some older behaviours to make life a little easier. R is an old language, and some things that were useful 10 or 20 years ago now get in your way. It’s difficult to change base R without breaking existing code, so most innovation occurs in packages – Grolemund & Wickham.
Operator Pipe %>%
Sebelum melangkah lebih jauh, kita harus mengeksploitasi operator pipe yang diimpor dari package magrittr oleh Stefan Bache. Ini akan mengubah kehidupan analitik data Anda. Anda tidak perlu lagi memberlakukan perintah multi-operasi dengan menyatukannya di dalam satu sama lain. Sintaks baru ini mengarah ke kode yang lebih mudah untuk ditulis dan dibaca.
Begini tampilannya: %>%. Pintasan keyboard RStudio: Ctrl + Shift + M (Windows), Cmd + Shift + M (Mac). Lebih lanjut mengenai operator %>% silahkan baca penjelasan operator pipe.
Eksplorasi dan Visualisasi Data
Kita lihat terlebih dulu data yang akan kita gunakan. Data yang akan digunakan ada 3, yaitu flights, airlines dan weather.
flights
Ada 336,776 jadwal penerbangan selama tahun 2013. Variabel dep_delay dengan nilai positif (dep_delay > 0) menunjukkan bahwa penerbangan tersebut mengalami keterlambatan dari jadwal berangkat yang seharusnya, sedangkan dep_delay negatif (dep_delay < 0) menunjukkan penerbanga dilakukan lebih awal dari yang seharusnya, dalam satuan menit. Adapun dep_delay yang NA (kosong atau missing value) menunjukkan penerbangan dibatalkan atau cancel.
airlines
Di data ini terdapat 16 perusahaan maskapai penerbangan. Variabel carrier nantinya digunakan untuk di-join dengan variabel carrier juga pada data flights.
weather
Data di atas adalah data cuaca berdasarkan bandara yang ada pada varibel origin selama tahun 2013 dengan rentang waktu setiap satu jam (lihat time_hour).
Sekarang kita lihat dulu secara sekilas seperti apa data flights yang akan kita gunakan.
str(flights)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 336776 obs. of 19 variables:
$ year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
$ month : int 1 1 1 1 1 1 1 1 1 1 ...
$ day : int 1 1 1 1 1 1 1 1 1 1 ...
$ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
$ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
$ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
$ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
$ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
$ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8 ...
$ carrier : chr "UA" "UA" "AA" "B6" ...
$ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301 ...
$ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
$ origin : chr "EWR" "LGA" "JFK" "JFK" ...
$ dest : chr "IAH" "IAH" "MIA" "BQN" ...
$ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
$ distance : num 1400 1416 1089 1576 762 ...
$ hour : num 5 5 5 5 6 5 6 6 6 6 ...
$ minute : num 15 29 40 45 0 58 0 0 0 0 ...
$ time_hour : POSIXct, format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
summary(flights)
year month day dep_time sched_dep_time
Min. :2013 Min. : 1.000 Min. : 1.00 Min. : 1 Min. : 106
1st Qu.:2013 1st Qu.: 4.000 1st Qu.: 8.00 1st Qu.: 907 1st Qu.: 906
Median :2013 Median : 7.000 Median :16.00 Median :1401 Median :1359
Mean :2013 Mean : 6.549 Mean :15.71 Mean :1349 Mean :1344
3rd Qu.:2013 3rd Qu.:10.000 3rd Qu.:23.00 3rd Qu.:1744 3rd Qu.:1729
Max. :2013 Max. :12.000 Max. :31.00 Max. :2400 Max. :2359
NA's :8255
dep_delay arr_time sched_arr_time arr_delay
Min. : -43.00 Min. : 1 Min. : 1 Min. : -86.000
1st Qu.: -5.00 1st Qu.:1104 1st Qu.:1124 1st Qu.: -17.000
Median : -2.00 Median :1535 Median :1556 Median : -5.000
Mean : 12.64 Mean :1502 Mean :1536 Mean : 6.895
3rd Qu.: 11.00 3rd Qu.:1940 3rd Qu.:1945 3rd Qu.: 14.000
Max. :1301.00 Max. :2400 Max. :2359 Max. :1272.000
NA's :8255 NA's :8713 NA's :9430
carrier flight tailnum origin
Length:336776 Min. : 1 Length:336776 Length:336776
Class :character 1st Qu.: 553 Class :character Class :character
Mode :character Median :1496 Mode :character Mode :character
Mean :1972
3rd Qu.:3465
Max. :8500
dest air_time distance hour minute
Length:336776 Min. : 20.0 Min. : 17 Min. : 1.00 Min. : 0.00
Class :character 1st Qu.: 82.0 1st Qu.: 502 1st Qu.: 9.00 1st Qu.: 8.00
Mode :character Median :129.0 Median : 872 Median :13.00 Median :29.00
Mean :150.7 Mean :1040 Mean :13.18 Mean :26.23
3rd Qu.:192.0 3rd Qu.:1389 3rd Qu.:17.00 3rd Qu.:44.00
Max. :695.0 Max. :4983 Max. :23.00 Max. :59.00
NA's :9430
time_hour
Min. :2013-01-01 05:00:00
1st Qu.:2013-04-04 13:00:00
Median :2013-07-03 10:00:00
Mean :2013-07-03 05:22:54
3rd Qu.:2013-10-01 07:00:00
Max. :2013-12-31 23:00:00
Dari hasil di atas saja sudah banyak hal yang kita dapatkan. Pertama, isi dari variabel year semuanya adalah 2013. Tidak ada nilai lain selain itu. Variabel seperti ini biasanya akan langsung dibuang karena tidak mempunyai informasi yang dapat digunakan untuk analisis. Atau digunakan untuk membuat variabel baru. Misalnya dengan menggabungkan variabel year, month dan day menjadi sebuah variabel tanggal.
Kedua, pada variabel dep_time, dep_delay, arr_time, arr_delay dan air_time terdapat beberapa data yang nilainya NA. Artinya ada data penerbangan yang tidak memiliki data-data tersebut. Perlu diketahui dulu penyebab dan konteks data tersebut NA. Misalnya, jika suatu penerbangan tidak memiliki data dep_time artinya penerbangan tersebut tidak mempunyai catatan waktu take-off. Bisa jadi penerbangan tersebut di-cancel. Jika suatu penerbangan mempunyai data dep_time tapi tidak memiliki data arr_time maka bisa jadi penerbangan tersebut mengalami kecelakaan atau hal lainnya.
Siapkan data yang akan digunakan. Kita join data flights dengan airlines untuk mendapatkan variabel nama perusahaan maskapai penerbangan (name), kemudian join lagi dengan weather untuk mendapatkan data cuaca.
flights_tbl <- flights %>%
left_join(airlines, by = "carrier") %>%
left_join(weather, suffix = c("_flight", "_weather"))
Untuk lebih mengetahui mengenai join menggunakan dplyr silahkan baca artikel ini dan ini.
str(flights_tbl)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 336776 obs. of 29 variables:
$ year : num 2013 2013 2013 2013 2013 ...
$ month : num 1 1 1 1 1 1 1 1 1 1 ...
$ day : int 1 1 1 1 1 1 1 1 1 1 ...
$ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
$ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
$ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
$ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
$ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
$ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8 ...
$ carrier : chr "UA" "UA" "AA" "B6" ...
$ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301 ...
$ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
$ origin : chr "EWR" "LGA" "JFK" "JFK" ...
$ dest : chr "IAH" "IAH" "MIA" "BQN" ...
$ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
$ distance : num 1400 1416 1089 1576 762 ...
$ hour : num 5 5 5 5 6 5 6 6 6 6 ...
$ minute : num 15 29 40 45 0 58 0 0 0 0 ...
$ time_hour : POSIXct, format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
$ name : chr "United Air Lines Inc." "United Air Lines Inc." "American Airlines Inc." "JetBlue Airways" ...
$ temp : num 39 39.9 39 39 39.9 ...
$ dewp : num 28 25 27 27 25 ...
$ humid : num 64.4 54.8 61.6 61.6 54.8 ...
$ wind_dir : num 260 250 260 260 260 260 240 260 260 260 ...
$ wind_speed : num 12.7 15 15 15 16.1 ...
$ wind_gust : num NA 21.9 NA NA 23 ...
$ precip : num 0 0 0 0 0 0 0 0 0 0 ...
$ pressure : num 1012 1011 1012 1012 1012 ...
$ visib : num 10 10 10 10 10 10 10 10 10 10 ...
Dasar-dasar ggplot2
Package ggplot2 merupakan salah satu package untuk visualisasi yang paling banyak digunakan oleh pengguna R. Package ini juga yang menjadikan salah satu keutamaan R dibanding software pemrograman dan analisis data yang lain.
ggplot2 didesain untuk bekerja secara iteratif. Kata ggplot sendiri merupaka kependekan dari grammar of graphics plot. Terdapat dua fungsi utama yang digunakan untuk visualisasi data. Fungsi qplot(), yang merupakan kependekan dari quick-plot. Penggunaan qplot() sendiri tidak terlalu banyak, bahkan pembuatnya sendiri mengatakan bahwa qplot() dibuat untuk mereka yang memang sudah sangat terbiasa menggunakan fungsi plot() pada base R.
Fungsi kedua, dan yang paling sering digunakan, adalah ggplot(). Perbedaan yang paling mencolok dari fungsi qplot() dan ggplot() adalah tipe data yang dapat digunakan. Fungsi qplot() dapat menggunakan vector atau dataframe, sedangkan ggplot()hanya menerima dataframe. Fungsi-fungsi pada ggplot2 berperan sebagai layer yang ditandai dengan +.
Berikut contoh dari penggunaan qplot().
not_cancel <- flights_tbl %>%
filter(!is.na(dep_delay))
qplot(x = name, data = not_cancel)

Tentu saja tampilan grafik seperti di atas tidak baik karena informasi yang diberikan kurang sempurna. Nama maskapai penerbangan yang saling tumpang tindih juga membuat grafik tersebut tidak menarik.
qplot(x = name, data = not_cancel) +
theme(axis.text.x = element_text(angle = 90))

Fungsi theme() akan diabhas lebih banyak di bagian berikutnya.
Visualisasi dengan ggplot()
Fungsi yang paling sering digunakan dari package ggplot2 adalah ggplot(). Secara umum visualisasi menggunakan ggplot() adalah seperti berikut.
ggplot(data = <DATA>, mapping = aes(x = <VAR>, y = <VAR>)) +
<GEOM_FUNCTION>()
Anda dapat mempelajari tentang ggplot2 dari buku ggplot2 Elegant Graphics for Data Analysis second edition.
Barplot
Yang pertama kita akan melakukan eksplorasi data dengan menggunakan diagram batang atau barplot. Grafik yang akan dihasilkan sama dengan yang dihasilkan oleh qplot() sebelumnya.
ggplot(data = not_cancel, mapping = aes(x = name)) +
geom_bar() +
theme(axis.text.x = element_text(angle = 90))

Geom geom_bar() dapat menerima data dengan format memanjang (raw) atau tabulasi.
not_cancel %>%
select(name)
Jika bentuk datanya memanjang seperti ini maka cukup menyebutkan variabelnya di argumen x = pada aes().
ggplot(data = not_cancel, mapping = aes(x = name)) +
geom_bar() +
theme(axis.text.x = element_text(angle = 90))

Jika datanya dalam bentuk tabulasi, sebutkan kategorinya di argumen x = dan nilainya di argumen y =, kemudian tambahkan stat = "identity" pada geom_bar().
not_cancel <- not_cancel %>%
count(name)
not_cancel
ggplot(data = not_cancel, mapping = aes(x = name, y = n)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90))

Secara default tampilan barplot diurutkan berdasarkan alfabet kategori pada argumen x. Jika ingin barplot diurutkan berdasarkan nilainya, gunakan fungsi reorder().
ggplot(data = not_cancel, mapping = aes(x = reorder(name, -n), y = n)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90))

Untuk mengurutkan barplot berdasarkan value
- Buat terlebih dahulu tabel frekuensi dari kategori yang diinginkan.
- gunakan fungsi reorder() pada aestethic
x dan n sbg y.
- gunakan
stat = "identity" pada geom_bar().
not_cancel <- not_cancel %>%
mutate(pct = n/sum(n))
ggplot(data = not_cancel, mapping = aes(x = reorder(name, -pct), y = pct)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90))

canceled <- flights_tbl %>%
filter(is.na(dep_delay)) %>%
count(name) %>%
mutate(pct = n/sum(n))
canceled
Dari tabel di atas kita dapat mengetahui bahwa ExpressJet Airlines Inc. yang paling banyak melakukan cancel selama tahun 2013. Sekarang mari kita tampilkan dalam visualisasi.
g <- ggplot(data = canceled, mapping = aes(x = reorder(name, -pct), y = pct)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90))
g

g +
labs(title = "Persentase Maskapai Yang Sering Melakukan Cancel",
x = "Maskapai",
y = "Persentase") +
theme(axis.title.y = element_text(angle = 0, vjust = 1))

Hasil dari ggplot dapat disimpan dalam sebuah objek di R kemudian ditambahkan layer dengan + dan geom atau komponen lain.
Kita juga dapat menentukan warna untuk masing-masing batang pada barplot. Misalnya, setiap batang berbeda warnanya berdasarkan nama kategorinya secara default.
Untuk menambahkan judul (title), mengganti judul masing-masing axis x dan y atau menambahkan subtitledapat menggunakan labs().
ggplot(data = canceled, mapping = aes(x = reorder(name, -pct), y = pct, fill = name)) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle = 90),
axis.title.y = element_text(angle = 0, vjust = 1),
legend.position = "none") +
labs(title = "Persentase Maskapai Yang Sering Melakukan Cancel",
x = "Maskapai",
y = "Persentase")

Argumen legend.position = "none" digunakan untuk menghilangkan legend dari grafik yang dibuat. Cobalah untuk menghapus argumen legend.position = "none" dan lihat hasilnya.
ggplot(data = canceled, mapping = aes(x = reorder(name, -pct), y = pct*100, fill = name)) +
geom_bar(stat = "identity") +
geom_text(aes(label = paste(round(pct*100, 2), "%")), vjust = -0.25) +
theme(axis.text.x = element_text(angle = 90),
axis.title.y = element_text(angle = 0, vjust = 1),
legend.position = "none") +
labs(title = "Persentase Maskapai Yang Sering Melakukan Cancel",
x = "Maskapai",
y = "Persentase")

Anda juga dapat melakukan operasi matematika sederhana untuk variabel yang akan digunakan. Misalnya mengubah satuan pct dengan dikalikan 100. geom_text() digunakan untuk menambahkan komponen layer teks pada grafik. Dalam kasus ini digunakan untuk menampilkan nilai di atas masing-masing batang. vjust = -0.25 agar teks berada di atas batang.
ggplot(data = canceled, mapping = aes(x = reorder(name, pct), y = pct*100, fill = name)) +
geom_bar(stat = "identity") +
geom_text(aes(label = paste(round(pct*100, 2), "%")), hjust = -0.01) +
theme(legend.position = "none") +
labs(title = "Persentase Maskapai Yang Sering Melakukan Cancel",
x = "Maskapai",
y = "Persentase") +
coord_flip()

Agar tampilan barplot dengan axis.text.x lebih menarik, gunakan coord_flip() untuk memutar grafik. Posisi axis x di posisi y dan sebaliknya.
Histogram & Density
Histogram atau Density dapat digunakan untuk memvisualisasikan sebaran dari sebuah variabel numerik.
g <- ggplot(data = flights_tbl, mapping = aes(x = air_time))
g

Karena variabel yang akan kita gunakan sama, yaitu hanya air_time maka kita simpan dahulu hasil dari ggplot ke dalam objek g sehingga kita dapat mengganti argumen pada geom_histogram() tanpa perlu memanggil lagi fungsi ggplot() dengan argumen yang sama sepertisebelumnya. Ketika kita panggil objek dari ggplot tersebut, maka hnaya menapilkan sebuah kanvas kosong karena kita belum menambahkan layer geom apa yang akan digunakan.
g +
geom_histogram()

Ketika kita tambahkan geom_histogram() maka akan ditambahkan histogram. Secara default geom_histogram() menggunakan 30 bins. bins adalah banyaknya kotak/batang, sedangkan lebar batang disebut binwidth. Jika ada NA maka secara otomatis akan dibuang.
g +
geom_histogram(bins = 50, fill = "skyblue", color = "white")

Dengan bins = 50 artinya pada histogram tersebut akan digunakan 50 batang. Argumen fill = "skyblue" untuk memberikan warna pada batang histogram. Anda juga dapat menggunakan warna lain, misalnya fill = "pink" atau fill = "lightblue" atau bahkan menggunakan kode warna Hex.
Sebagian besar lamanya penerbangan kurang dari 200 menit. Namun dari grafik di atas terlihat ada beberapa puncak yang terjadi. Mari kita lihat menggunakan geom_density()
g +
geom_histogram(aes(y = ..density..), bins = 50, fill = "skyblue", color = "white") +
geom_density(color = "darkgreen", size = 0.7)

g +
geom_density(fill = "skyblue", alpha = 0.5)

Namun jika diperhatikan, ada juga penerbangan yang lama waktu terbangnya lebih dari 600 menit atau 10 jam. Kita lihat data dengan penerbangan selama sekitar 10 jam tersebut.
flights10h <- flights_tbl %>%
filter(air_time > 500)
flights10h %>%
group_by(origin, dest) %>%
summarise(min = min(air_time), avg = mean(air_time), std = sd(air_time), max = max(air_time))
Ternyata penerbangan dari bandara EWR dan JFK menuju bandara HNL rata-rata membutuhkan waktu terbang lebih dari 600 menit atau 10 jam. Apa itu HNL?
airports %>%
filter(faa == "HNL")
Boxplot
Secara default, boxplot di ggplot2 memerlukan variabel kategorik sebagai argumen x dan variabel numerik sebagai argumen y.
ggplot(data = flights_tbl, mapping = aes(x = name, y = wind_speed)) +
geom_boxplot() +
coord_flip()

Jika hanya ingin satu boxplot untuk satu variabel tanpa dibedakan berdasarkan kategori lain maka cukup gunakan x = '' atau string lain seperti contoh berikut.
ggplot(data = flights_tbl, mapping = aes(x = "Statistics", y = temp)) +
geom_boxplot()

ggplot(data = flights_tbl, mapping = aes(x = origin, y = temp)) +
geom_boxplot() +
coord_flip()

ggplot(data = flights_tbl, mapping = aes(x = origin, y = temp)) +
geom_boxplot(color = "skyblue") +
coord_flip()

Anda dapat membaca beberapa artikel tentang geom_boxplot(), salah satunya geom_boxplot.
Scatter plot
Scatter plot adalah visualisasi data dari dua buah variabel numerik. Misalkan dari data weather kita ambil data cuaca di bandara JFK saja selama tahun 2013.
weather_jfk <- weather %>%
filter(origin == "JFK")
ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_point()

Anda dapat merubah shape dari geom_point dengan sebuah bilangan integer.
Point Shape
ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_point(shape = 1) +
labs(title = "Suhu Bandara JFK Selama Tahun 2013",
x = "waktu",
y = "Suhu")

Line plot/time series plot
ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_line()

ggplot(data = weather_jfk, mapping = aes(x = time_hour)) +
geom_line(aes(y = temp), color = "skyblue")

Ketebalan garis dapat disesuaikan dengan size =, misalnya size = 1 untuk garis yang lebih tebal dari default.
ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_line(color = "skyblue") +
geom_point(size = 0.5) +
scale_x_datetime(breaks = "1 month", date_labels = "%b %d") +
theme(axis.text.x = element_text(angle = 90))

ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_line() +
geom_point(size = 0.5) +
scale_x_datetime(breaks = "days", date_labels = "%b %d") +
theme(axis.text.x = element_text(angle = 90))

ggplot(data = weather_jfk, mapping = aes(x = time_hour, y = temp)) +
geom_line() +
geom_point(size = 0.5) +
scale_x_datetime(breaks = "1 month", date_labels = "%b %d") +
theme(axis.text.x = element_text(angle = 90)) +
labs(title = "Suhu Bandara JFK Selama Tahun 2013",
x = "Waktu",
y = "Suhu")

weather_jfk %>%
ggplot(mapping = aes(x = time_hour, y = temp)) +
geom_line() +
geom_smooth()

weather %>%
ggplot(mapping = aes(x = time_hour, y = temp, color = origin)) +
# geom_line() +
geom_smooth() +
scale_color_manual(values = c("#ea5454", "#6f45d8", "#57c158"))

Facet
flights_aug2 <- flights_tbl %>%
inner_join(airports, by = c("origin" = "faa"), suffix = c("_carrier", "_originairports")) %>%
filter(!is.na(dep_delay) & month == 8) %>%
mutate(tgl = as.Date(paste(year, month, day, sep = "-"))) %>%
group_by(name_originairports, tgl) %>%
summarise(n = n())
ggplot(data = flights_aug2, mapping = aes(x = tgl, y = n)) +
geom_line(color = "skyblue") +
geom_point() +
facet_grid(rows = vars(name_originairports)) +
scale_x_date(breaks = "days", date_labels = "%d") +
theme(axis.text.x = element_text(angle = 45)) +
labs(title = "Jumlah Penerbangan Harian Bulan Agustus 2013",
x = "Tanggal",
y = "Jumlah")

ggplot(data = flights_aug2, mapping = aes(x = tgl, y = n)) +
geom_line(color = "skyblue") +
geom_point() +
facet_grid(name_originairports ~ . ) +
scale_x_date(breaks = "days", date_labels = "%d") +
theme(axis.text.x = element_text(angle = 45)) +
labs(title = "Jumlah Penerbangan Harian Bulan Agustus 2013",
x = "Tanggal",
y = "Jumlah")

ggplot(data = flights_aug2, mapping = aes(x = tgl, y = n)) +
geom_line(color = "skyblue") +
geom_point() +
facet_grid(cols = vars(name_originairports)) +
labs(title = "Jumlah Penerbangan Harian Bulan Agustus 2013",
x = "Tanggal",
y = "Jumlah")

ggplot(data = flights_aug2, mapping = aes(x = tgl, y = n)) +
geom_line(color = "skyblue") +
geom_point() +
facet_grid( . ~ name_originairports) +
labs(title = "Jumlah Penerbangan Harian Bulan Agustus 2013",
x = "Tanggal",
y = "Jumlah")

ggplot(data = flights_aug2, mapping = aes(x = tgl, y = n)) +
geom_line(color = "skyblue") +
geom_point() +
facet_grid(rows = vars(), cols = vars(name_originairports)) +
labs(title = "Jumlah Penerbangan Harian Bulan Agustus 2013",
x = "Tanggal",
y = "Jumlah")

Setelah selesai membuat grafik yang Anda inginkan, Anda dapat menyimpan grafik tersebut dengan fungsi ggsave().
g <- flights_tbl %>%
filter(origin == "JFK") %>%
ggplot(mapping = aes(x = time_hour, y = temp)) +
geom_line() +
geom_smooth()
ggsave(filename = "plotR.jpg", plot = g, width = 10, height = 7)
Jika Anda tidak menyebutkan objek ggplot2 pada plot = maka secara otomatis plot yang terakhir dibuat yang akan dipilih.
LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiBUbyBEYXRhIFZpc3VhbGl6YXRpb24gVXNpbmcgZ2dwbG90MiINCmF1dGhvcjogIkFlcCBIaWRheWF0dWxvaCINCmRhdGU6ICJMYXN0IFVwZGF0ZTogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclWSAlYiAlZCcpYCINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICBodG1sX2RvY3VtZW50Og0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICc0Jw0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmJvZHl7IC8qIE5vcm1hbCAgKi8NCiAgICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgfQ0KdGQgeyAgLyogVGFibGUgICovDQogIGZvbnQtc2l6ZTogMTJweDsNCn0NCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAzOHB4Ow0KICBjb2xvcjogbGlnaHRibHVlOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgxIHsgLyogSGVhZGVyIDEgKi8NCiAgZm9udC1zaXplOiAyNHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpoMiB7IC8qIEhlYWRlciAyICovDQogIGZvbnQtc2l6ZTogMjBweDsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDMgeyAvKiBIZWFkZXIgMyAqLw0KICBmb250LXNpemU6IDE2cHg7DQojICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDQgeyAvKiBIZWFkZXIgNCAqLw0KICBmb250LXNpemU6IDE0cHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmNvZGUucnsgLyogQ29kZSBibG9jayAqLw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCnByZSB7IC8qIENvZGUgYmxvY2sgLSBkZXRlcm1pbmVzIGNvZGUgc3BhY2luZyBiZXR3ZWVuIGxpbmVzICovDQogICAgZm9udC1zaXplOiAxMnB4Ow0KfQ0KPC9zdHlsZT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiNrbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTMuNSwgZmlnLndpZHRoPTkuMiwgcmVzdWx0cz0naG9sZCcsIHdhcm5pbmc9RkFMU0UsIGZpZy5zaG93PSdob2xkJywgbWVzc2FnZT1GQUxTRSkgDQpvcHRpb25zKHNjaXBlbiA9IDk5KQ0KYGBgDQoNCg0KIyBPYmpla3RpZg0KDQpJbmkgYWRhbGFoIGNhdGF0YW4gdW50dWsgbWVtYW5kdSBzZWNhcmEgc2luZ2thdCBkYWxhbSBtZWxha3VrYW4gdmlzdWFsaXNhc2kgZGF0YSB1bnR1ayBrZWJ1dHVoYW4gZWtzcGxvcmFzaSBkYXRhIGF0YXUgcHVibGlrYXNpIG1lbmdndW5ha2FuIFIgZGFuIHBhY2thZ2UgYGdncGxvdDJgLiBUdWp1YW4gZGFyaSB0dXRvcmlhbCBpbmkgYWRhbGFoIGFnYXIgcGVzZXJ0YSBkYXBhdCBtZW5jb2JhIG1lbWJ1YXQgZ3JhZmlrIHlhbmcgbWVuYXJpayBkYW4gbXVkYWguIA0KDQojIENha3VwYW4gTWF0ZXJpDQpNYXRlcmkgeWFuZyBha2FuIGRpYmFoYXM6DQoNCisgRGFzYXItZGFzYXIgZ2dwbG90Mg0KKyBQZW5nZ3VuYWFuIGZ1bmdzaSBgcXBsb3QoKWANCisgQWVzdGhldGljIHBhZGEgZ2dwbG90Mg0KKyBCYXJwbG90DQorIEhpc3RvZ3JhbSAmIERlbnNpdHkNCisgQm94cGxvdA0KKyBTY2F0dGVyIHBsb3QNCisgTGluZSBwbG90DQorIE1lbmVudHVrYW4gd2FybmENCisgRmFjZXRpbmcNCisgQW5ub3RhdGlvbg0KKyBUZW1hIChgdGhlbWVgKQ0KDQojIFByYXN5YXJhdA0KDQpVbnR1ayBkYXBhdCBtZW5naWt1dGkgdHV0b3JpYWwgaW5pIGRlbmdhbiBiYWlrLCBhZGEgYmViZXJhcGEgaGFsIHlhbmcgcGVybHUgZGlwZXJzaWFwa2FuLCB5YWl0dToNCg0KMS4gS29uZWtzaSBpbnRlcm5ldCB5YW5nIGJhaWsNCg0KMi4gTWVuZ2luc3RhbGwgc29mdHdhcmUNCg0KICAgIGEuIFIgcHJvZ3JhbSA8aHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvPg0KDQogICAgYi4gUlN0dWRpbyA8aHR0cHM6Ly93d3cucnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9kb3dubG9hZC8+DQoNCjMuIERhdGEgJiBTY3JpcHQgeWFuZyBkYXBhdCBkaXBlcm9sZWggZGFyaSBbcmVwb3NpdG9yeSBpbmldKGh0dHBzOi8vZ2l0aHViLmNvbS9hZXBoaWRheWF0dWxvaC9la3NwbG9yYXNpLWRhdGEpIGRhbiBwYWRhIGRhdGFiYXNlIHlhbmcgZGlzZWRpYWthbiBwZW1iaWNhcmEuDQoNCjQuIFBhY2thZ2UgUiB5YW5nIGRpYnV0dWhrYW46IGBnZ3Bsb3QyYCwgYGRwbHlyYCAoYXRhdSBgdGlkeXZlcnNlYCkgZGFuIGBueWNmbGlnaHRzMTNgLg0KDQpDYXRhdGFuOiBEYXRhIGRpcGVyb2xlaCBkYXJpIHBhY2thZ2VzIGBueWNmbGlnaHRzMTNgIHlhbmcgZGlzaW1wYW4ga2UgZGFsYW0gZGF0YWJhc2UuIEppa2EgQW5kYSBpbmdpbiBtZW5jb2JhIGRpbHVhciBrZWdpYXRhbiBhdGF1IHRpZGFrIGRhcGF0IHRlcmh1YnVuZyBkZW5nYW4gZGF0YWJhc2UgcGVtYmljYXJhLCBBbmRhIGRhcGF0IG1lbmdpbnN0YWxsIHBhY2thZ2UgYG55Y2ZsaWdodHMxM2AgdW50dWsgbWVtcGVyb2xlaCBkYXRhIHlhbmcgZGlndW5ha2FuIHBhZGEgZGF0YWJhc2UuIER1YSBkYXRhIGxhaW4gYmVydXBhIGZpbGUgQ1NWIHVudHVrIGRpc2VzdWFpa2FuIGRlbmdhbiBrZWJ1dHVoYW4gdHV0b3JpYWwuIA0KDQpEYXRhIGluaSB0ZXJkaXJpIGRhcmkgMzM2LDc3NiBwZW5lcmJhbmdhbiBkYXJpIE5ldyBZb3JrIENpdHkgKE5ZQykgc2VsYW1hIHRhaHVuIDIwMTMuIERhdGEgYXNsaSBiZXJhc2FsIGRhcmkgVVMgQnVyZWF1IG9mIFRyYW5zcG9ydGF0aW9uIFN0YXRpc3RpY3MsIGRhbiBkYXBhdCBkaWxpaGF0IGRva3VtZW50YXNpbnlhIGRlbmdhbiBgP255Y2ZsaWdodHMxMzo6ZmxpZ2h0c2AuDQpQYXN0aWthbiBBbmRhIHN1ZGFoIGJlcmhhc2lsIGluc3RhbGwgcGFja2FnZSB0ZXJzZWJ1dC4NCg0KIyBJbnN0YWxsIGRhbiBMb2FkIFBhY2thZ2VzDQoNCkphbGFua2FuIHBlcmludGFoIGRpIGJhd2FoIGluaSB1bnR1ayBpbnN0YWxsIHBhY2thZ2UgKCoqamlrYSBBbmRhIGJlbHVtIHBlcm5haCBpbnN0YWxsKiopIHlhbmcgYWthbiBkaWd1bmFrYW4gdW50dWsgZGFwYXQgbWVuZ2lrdXRpIHR1dG9yaWFsIGluaSBzYW1wYWkgc2VsZXNhaS4NCg0KYGBge3IgZXZhbD1GQUxTRX0NCmluc3RhbGwucGFja2FnZXMoYygiZ2dwbG90MiIsICJkcGx5ciIsICJ0aWR5ciIsICJueWNmbGlnaHRzMTMiKSkNCiMgYXRhdSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmluc3RhbGwucGFja2FnZXMoYygidGlkeXZlcnNlIiwgIm55Y2ZsaWdodHMxMyIpKSAgICAgICAgICAgICAgICAgICAgICAgICANCmBgYA0KDQpQYW5nZ2lsIHBhY2thZ2UgeWFuZyBzdWRhaCBBbmRhIGluc3RhbGwgZGVuZ2FuIGZ1bmdzaSBgbGlicmFyeSgpYC4NCg0KYGBge3IgbG9hZHBrZ30NCiMgUGFuZ2dpbCBwYWNrYWdlIHlhbmcgc3VkYWggdGVyaXNudGFsbA0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQoNCiMgIyBhdGF1IGN1a3VwIG1lbWFuZ2dpbCBgdGlkeXZlcnNlYCB1bnR1ayBtZW1hbmdnaWwgcGFja2FnZSBnZ3Bsb3QyIGRhbiBwYWNrYWdlIGxhaW4gZGkgdGlkeXZlcnNlDQojIGxpYnJhcnkodGlkeXZlcnNlKQ0KDQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmBgYA0KDQpQYWNrYWdlIGBnZ3Bsb3QyYCAoZGFuIGJlYmVyYXBhIHBhY2thZ2UgbGFpbiB5YW5nIHRpZGFrIGRpZ3VuYWthbiBkaSB0dXRvcmlhbCBpbmkpIHRlcm1hc3VrIGRhbGFtIGJhZ2lhbiBwYWNrYWdlIGB0aWR5dmVyc2VgLiBgdGlkeXZlcnNlYCBhZGFsYWgga3VtcHVsYW4gcGFja2FnZSB5YW5nIGRpYnVhdCBvbGVoICoqSGFkbGV5IFdpY2toYW0qKiBka2sgdW50dWsga2VidXR1aGFuIGRhdGEgc2NpZW5jZSBtZW5nZ3VuYWthbiBSLg0KDQorIGBnZ3Bsb3QyYCBhZGFsYWggc2FsYWggc2F0dSBwYWNrYWdlIHlhbmcgc2FuZ2F0IGJhbnlhayBkaWd1bmFrYW4gb2xlaCBwZW5nZ3VuYSBSIHVudHVrIGtlYnV0dWhhbiB2aXN1YWxpc2FzaS4NCisgYGRwbHlyYCBkYW4gYHRpZHlyYCBhZGFsYWggcGFja2FnZSB5YW5nIHNhbmdhdCBiZXJndW5hIHVudHVrIG1lbGFrdWthbiBtYW5pcHVsYXNpL3RyYW5zZm9ybWFzaSBkYXRhIG1lbmdndW5ha2FuIFIuDQorIGBueWNmbGlnaHRzMTNgIGFkYWxhaCBwYWNrYWdlIHlhbmcgbWVueWVkaWFrYW4gNSBkYXRhIGZyYW1lIGRhbGFtIGZvcm1hdCBbdGliYmxlXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RpYmJsZS5odG1sKSB0ZW50YW5nIHBlbmVyYmFuZ2FuIGRpIE5ZQyBzZWxhbWEgdGFodW4gMjAxMy4NCg0KPHAgYWxpZ249ImNlbnRlciI+DQogICAgPGltZyBzcmM9InRpZHl2ZXJzZS5wbmciIGFsdD0iVGlkeXZlcnNlIj4NCiAgICA8YnIvPg0KICAgIDxici8+DQogICAgPGVtPlRpZHl2ZXJzZTwvZW0+DQo8L3A+DQoNCmB0aWR5dmVyc2VgIG1lbmdndW5ha2FuICoqdGliYmxlKiogc2ViYWdhaSBwZW5nZ2FudGkgYGRhdGEuZnJhbWVgLiANCg0KPiBUaWJibGVzIGFyZSBkYXRhIGZyYW1lcywgYnV0IHRoZXkgdHdlYWsgc29tZSBvbGRlciBiZWhhdmlvdXJzIHRvIG1ha2UgbGlmZSBhIGxpdHRsZSBlYXNpZXIuIFIgaXMgYW4gb2xkIGxhbmd1YWdlLCBhbmQgc29tZSB0aGluZ3MgdGhhdCB3ZXJlIHVzZWZ1bCAxMCBvciAyMCB5ZWFycyBhZ28gbm93IGdldCBpbiB5b3VyIHdheS4gSXTigJlzIGRpZmZpY3VsdCB0byBjaGFuZ2UgYmFzZSBSIHdpdGhvdXQgYnJlYWtpbmcgZXhpc3RpbmcgY29kZSwgc28gbW9zdCBpbm5vdmF0aW9uIG9jY3VycyBpbiBwYWNrYWdlcyAtLSBbR3JvbGVtdW5kICYgV2lja2hhbV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5ueikuIA0KDQojIyBPcGVyYXRvciBQaXBlIGAlPiVgDQoNClNlYmVsdW0gbWVsYW5na2FoIGxlYmloIGphdWgsIGtpdGEgaGFydXMgbWVuZ2Vrc3Bsb2l0YXNpIG9wZXJhdG9yIHBpcGUgeWFuZyBkaWltcG9yIGRhcmkgcGFja2FnZSBgbWFncml0dHJgIG9sZWggU3RlZmFuIEJhY2hlLiBJbmkgYWthbiBtZW5ndWJhaCBrZWhpZHVwYW4gYW5hbGl0aWsgZGF0YSBBbmRhLiBBbmRhIHRpZGFrIHBlcmx1IGxhZ2kgbWVtYmVybGFrdWthbiBwZXJpbnRhaCBtdWx0aS1vcGVyYXNpIGRlbmdhbiBtZW55YXR1a2FubnlhIGRpIGRhbGFtIHNhdHUgc2FtYSBsYWluLiBTaW50YWtzIGJhcnUgaW5pIG1lbmdhcmFoIGtlIGtvZGUgeWFuZyBsZWJpaCBtdWRhaCB1bnR1ayBkaXR1bGlzIGRhbiBkaWJhY2EuDQoNCkJlZ2luaSB0YW1waWxhbm55YTogYCU+JWAuIFBpbnRhc2FuIGtleWJvYXJkIFJTdHVkaW86IGBDdHJsICsgU2hpZnQgKyBNYCAoV2luZG93cyksIGBDbWQgKyBTaGlmdCArIE1gIChNYWMpLiBMZWJpaCBsYW5qdXQgbWVuZ2VuYWkgb3BlcmF0b3IgYCU+JWAgc2lsYWhrYW4gYmFjYSBbcGVuamVsYXNhbiBvcGVyYXRvciBwaXBlXShodHRwOi8vcnB1YnMuY29tL2FlcGhpZGF5YXR1bG9oL3BpcGVzKS4NCg0KIyBFa3NwbG9yYXNpIGRhbiBWaXN1YWxpc2FzaSBEYXRhDQoNCktpdGEgbGloYXQgdGVybGViaWggZHVsdSBkYXRhIHlhbmcgYWthbiBraXRhIGd1bmFrYW4uIERhdGEgeWFuZyBha2FuIGRpZ3VuYWthbiBhZGEgMywgeWFpdHUgYGZsaWdodHNgLCBgYWlybGluZXNgIGRhbiBgd2VhdGhlcmAuDQoNCmBgYHtyIGhlYWRmbH0NCmZsaWdodHMNCmBgYA0KDQpBZGEgMzM2LDc3NiBqYWR3YWwgcGVuZXJiYW5nYW4gc2VsYW1hIHRhaHVuIDIwMTMuIFZhcmlhYmVsIGBkZXBfZGVsYXlgIGRlbmdhbiBuaWxhaSBwb3NpdGlmIChgZGVwX2RlbGF5ID4gMGApIG1lbnVuanVra2FuIGJhaHdhIHBlbmVyYmFuZ2FuIHRlcnNlYnV0IG1lbmdhbGFtaSBrZXRlcmxhbWJhdGFuIGRhcmkgamFkd2FsIGJlcmFuZ2thdCB5YW5nIHNlaGFydXNueWEsIHNlZGFuZ2thbiBgZGVwX2RlbGF5YCBuZWdhdGlmIChgZGVwX2RlbGF5IDwgMGApIG1lbnVuanVra2FuIHBlbmVyYmFuZ2EgZGlsYWt1a2FuIGxlYmloIGF3YWwgZGFyaSB5YW5nIHNlaGFydXNueWEsIGRhbGFtIHNhdHVhbiBtZW5pdC4gQWRhcHVuIGBkZXBfZGVsYXlgIHlhbmcgYE5BYCAoa29zb25nIGF0YXUgbWlzc2luZyB2YWx1ZSkgbWVudW5qdWtrYW4gcGVuZXJiYW5nYW4gZGliYXRhbGthbiBhdGF1IGNhbmNlbC4NCg0KYGBge3IgaGVhZGFpcmxpbmVzfQ0KYWlybGluZXMNCmBgYA0KDQpEaSBkYXRhIGluaSB0ZXJkYXBhdCAxNiBwZXJ1c2FoYWFuIG1hc2thcGFpIHBlbmVyYmFuZ2FuLiBWYXJpYWJlbCBgY2FycmllcmAgbmFudGlueWEgZGlndW5ha2FuIHVudHVrIGRpLWpvaW4gZGVuZ2FuIHZhcmlhYmVsIGBjYXJyaWVyYCBqdWdhIHBhZGEgZGF0YSBgZmxpZ2h0c2AuDQoNCmBgYHtyIGhlYWR3ZWF0aGVyfQ0Kd2VhdGhlcg0KYGBgDQoNCkRhdGEgZGkgYXRhcyBhZGFsYWggZGF0YSBjdWFjYSBiZXJkYXNhcmthbiBiYW5kYXJhIHlhbmcgYWRhIHBhZGEgdmFyaWJlbCBgb3JpZ2luYCBzZWxhbWEgdGFodW4gMjAxMyBkZW5nYW4gcmVudGFuZyB3YWt0dSBzZXRpYXAgc2F0dSBqYW0gKGxpaGF0IGB0aW1lX2hvdXJgKS4gDQoNClNla2FyYW5nIGtpdGEgbGloYXQgZHVsdSBzZWNhcmEgc2VraWxhcyBzZXBlcnRpIGFwYSBkYXRhIGBmbGlnaHRzYCB5YW5nIGFrYW4ga2l0YSBndW5ha2FuLg0KDQpgYGB7ciBzdHJmbH0NCnN0cihmbGlnaHRzKQ0KYGBgDQoNCg0KYGBge3Igc3VtbWFyeWZsfQ0Kc3VtbWFyeShmbGlnaHRzKQ0KYGBgDQoNCkRhcmkgaGFzaWwgZGkgYXRhcyBzYWphIHN1ZGFoIGJhbnlhayBoYWwgeWFuZyBraXRhIGRhcGF0a2FuLiBQZXJ0YW1hLCBpc2kgZGFyaSB2YXJpYWJlbCBgeWVhcmAgc2VtdWFueWEgYWRhbGFoIGAyMDEzYC4gVGlkYWsgYWRhIG5pbGFpIGxhaW4gc2VsYWluIGl0dS4gVmFyaWFiZWwgc2VwZXJ0aSBpbmkgYmlhc2FueWEgYWthbiBsYW5nc3VuZyBkaWJ1YW5nIGthcmVuYSB0aWRhayBtZW1wdW55YWkgaW5mb3JtYXNpIHlhbmcgZGFwYXQgZGlndW5ha2FuIHVudHVrIGFuYWxpc2lzLiBBdGF1IGRpZ3VuYWthbiB1bnR1ayBtZW1idWF0IHZhcmlhYmVsIGJhcnUuIE1pc2FsbnlhIGRlbmdhbiBtZW5nZ2FidW5na2FuIHZhcmlhYmVsIGB5ZWFyYCwgYG1vbnRoYCBkYW4gYGRheWAgbWVuamFkaSBzZWJ1YWggdmFyaWFiZWwgdGFuZ2dhbC4NCg0KS2VkdWEsIHBhZGEgdmFyaWFiZWwgYGRlcF90aW1lYCwgYGRlcF9kZWxheWAsIGBhcnJfdGltZWAsIGBhcnJfZGVsYXlgIGRhbiBgYWlyX3RpbWVgIHRlcmRhcGF0IGJlYmVyYXBhIGRhdGEgeWFuZyBuaWxhaW55YSBgTkFgLiBBcnRpbnlhIGFkYSBkYXRhIHBlbmVyYmFuZ2FuIHlhbmcgdGlkYWsgbWVtaWxpa2kgZGF0YS1kYXRhIHRlcnNlYnV0LiBQZXJsdSBkaWtldGFodWkgZHVsdSBwZW55ZWJhYiBkYW4ga29udGVrcyBkYXRhIHRlcnNlYnV0IGBOQWAuIE1pc2FsbnlhLCBqaWthIHN1YXR1IHBlbmVyYmFuZ2FuIHRpZGFrIG1lbWlsaWtpIGRhdGEgYGRlcF90aW1lYCBhcnRpbnlhIHBlbmVyYmFuZ2FuIHRlcnNlYnV0IHRpZGFrIG1lbXB1bnlhaSBjYXRhdGFuIHdha3R1ICp0YWtlLW9mZiouIEJpc2EgamFkaSBwZW5lcmJhbmdhbiB0ZXJzZWJ1dCBkaS0qY2FuY2VsKi4gSmlrYSBzdWF0dSBwZW5lcmJhbmdhbiBtZW1wdW55YWkgZGF0YSBgZGVwX3RpbWVgIHRhcGkgdGlkYWsgbWVtaWxpa2kgZGF0YSBgYXJyX3RpbWVgIG1ha2EgYmlzYSBqYWRpIHBlbmVyYmFuZ2FuIHRlcnNlYnV0IG1lbmdhbGFtaSBrZWNlbGFrYWFuIGF0YXUgaGFsIGxhaW5ueWEuDQoNClNpYXBrYW4gZGF0YSB5YW5nIGFrYW4gZGlndW5ha2FuLiBLaXRhIGpvaW4gZGF0YSBgZmxpZ2h0c2AgZGVuZ2FuIGBhaXJsaW5lc2AgdW50dWsgbWVuZGFwYXRrYW4gdmFyaWFiZWwgbmFtYSBwZXJ1c2FoYWFuIG1hc2thcGFpIHBlbmVyYmFuZ2FuIChgbmFtZWApLCBrZW11ZGlhbiBqb2luIGxhZ2kgZGVuZ2FuIGB3ZWF0aGVyYCB1bnR1ayBtZW5kYXBhdGthbiBkYXRhIGN1YWNhLg0KDQpgYGB7cn0NCmZsaWdodHNfdGJsIDwtIGZsaWdodHMgJT4lIA0KICBsZWZ0X2pvaW4oYWlybGluZXMsIGJ5ID0gImNhcnJpZXIiKSAlPiUgDQogIGxlZnRfam9pbih3ZWF0aGVyLCBzdWZmaXggPSBjKCJfZmxpZ2h0IiwgIl93ZWF0aGVyIikpDQpgYGANCg0KVW50dWsgbGViaWggbWVuZ2V0YWh1aSBtZW5nZW5haSBqb2luIG1lbmdndW5ha2FuIGBkcGx5cmAgc2lsYWhrYW4gYmFjYSBhcnRpa2VsIFtpbmldKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvam9pbi5odG1sKSBkYW4gW2luaV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9yZWxhdGlvbmFsLWRhdGEuaHRtbCkuDQoNCmBgYHtyfQ0Kc3RyKGZsaWdodHNfdGJsKQ0KYGBgDQoNCiMgRGFzYXItZGFzYXIgZ2dwbG90Mg0KDQpQYWNrYWdlIGBnZ3Bsb3QyYCBtZXJ1cGFrYW4gc2FsYWggc2F0dSBwYWNrYWdlIHVudHVrIHZpc3VhbGlzYXNpIHlhbmcgcGFsaW5nIGJhbnlhayBkaWd1bmFrYW4gb2xlaCBwZW5nZ3VuYSBSLiBQYWNrYWdlIGluaSBqdWdhIHlhbmcgbWVuamFkaWthbiBzYWxhaCBzYXR1IGtldXRhbWFhbiBSIGRpYmFuZGluZyBzb2Z0d2FyZSBwZW1yb2dyYW1hbiBkYW4gYW5hbGlzaXMgZGF0YSB5YW5nIGxhaW4uDQoNCmBnZ3Bsb3QyYCBkaWRlc2FpbiB1bnR1ayBiZWtlcmphIHNlY2FyYSBpdGVyYXRpZi4gS2F0YSBgZ2dwbG90YCBzZW5kaXJpIG1lcnVwYWthIGtlcGVuZGVrYW4gZGFyaSBbKipncmFtbWFyIG9mIGdyYXBoaWNzIHBsb3QqKl0oKS4gVGVyZGFwYXQgZHVhIGZ1bmdzaSB1dGFtYSB5YW5nIGRpZ3VuYWthbiB1bnR1ayB2aXN1YWxpc2FzaSBkYXRhLiBGdW5nc2kgYHFwbG90KClgLCB5YW5nIG1lcnVwYWthbiBrZXBlbmRla2FuIGRhcmkgKnF1aWNrLXBsb3QqLiBQZW5nZ3VuYWFuIGBxcGxvdCgpYCBzZW5kaXJpIHRpZGFrIHRlcmxhbHUgYmFueWFrLCBiYWhrYW4gcGVtYnVhdG55YSBzZW5kaXJpIG1lbmdhdGFrYW4gYmFod2EgYHFwbG90KClgIGRpYnVhdCB1bnR1ayBtZXJla2EgeWFuZyBtZW1hbmcgc3VkYWggc2FuZ2F0IHRlcmJpYXNhIG1lbmdndW5ha2FuIGZ1bmdzaSBgcGxvdCgpYCBwYWRhIGJhc2UgUi4gDQoNCkZ1bmdzaSBrZWR1YSwgZGFuIHlhbmcgcGFsaW5nIHNlcmluZyBkaWd1bmFrYW4sIGFkYWxhaCBgZ2dwbG90KClgLiBQZXJiZWRhYW4geWFuZyBwYWxpbmcgbWVuY29sb2sgZGFyaSBmdW5nc2kgYHFwbG90KClgIGRhbiBgZ2dwbG90KClgIGFkYWxhaCB0aXBlIGRhdGEgeWFuZyBkYXBhdCBkaWd1bmFrYW4uIEZ1bmdzaSBgcXBsb3QoKWAgZGFwYXQgbWVuZ2d1bmFrYW4gdmVjdG9yIGF0YXUgZGF0YWZyYW1lLCBzZWRhbmdrYW4gYGdncGxvdCgpYGhhbnlhIG1lbmVyaW1hIGRhdGFmcmFtZS4gRnVuZ3NpLWZ1bmdzaSBwYWRhIGBnZ3Bsb3QyYCBiZXJwZXJhbiBzZWJhZ2FpIGxheWVyIHlhbmcgZGl0YW5kYWkgZGVuZ2FuIGArYC4gDQoNCkJlcmlrdXQgY29udG9oIGRhcmkgcGVuZ2d1bmFhbiBgcXBsb3QoKWAuIA0KDQpgYGB7cn0NCm5vdF9jYW5jZWwgPC0gZmxpZ2h0c190YmwgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGRlcF9kZWxheSkpDQpgYGANCg0KYGBge3J9DQpxcGxvdCh4ID0gbmFtZSwgZGF0YSA9IG5vdF9jYW5jZWwpDQpgYGANCg0KVGVudHUgc2FqYSB0YW1waWxhbiBncmFmaWsgc2VwZXJ0aSBkaSBhdGFzIHRpZGFrIGJhaWsga2FyZW5hIGluZm9ybWFzaSB5YW5nIGRpYmVyaWthbiBrdXJhbmcgc2VtcHVybmEuIE5hbWEgbWFza2FwYWkgcGVuZXJiYW5nYW4geWFuZyBzYWxpbmcgdHVtcGFuZyB0aW5kaWgganVnYSBtZW1idWF0IGdyYWZpayB0ZXJzZWJ1dCB0aWRhayBtZW5hcmlrLg0KDQpgYGB7cn0NCnFwbG90KHggPSBuYW1lLCBkYXRhID0gbm90X2NhbmNlbCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpGdW5nc2kgYHRoZW1lKClgIGFrYW4gZGlhYmhhcyBsZWJpaCBiYW55YWsgZGkgYmFnaWFuIGJlcmlrdXRueWEuDQoNCiMgVmlzdWFsaXNhc2kgZGVuZ2FuIGdncGxvdCgpDQoNCkZ1bmdzaSB5YW5nIHBhbGluZyBzZXJpbmcgZGlndW5ha2FuIGRhcmkgcGFja2FnZSBgZ2dwbG90MmAgYWRhbGFoIGBnZ3Bsb3QoKWAuIFNlY2FyYSB1bXVtIHZpc3VhbGlzYXNpIG1lbmdndW5ha2FuIGBnZ3Bsb3QoKWAgYWRhbGFoIHNlcGVydGkgYmVyaWt1dC4NCg0KYGBge3IgZ2dwbG90LCBldmFsPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSA8REFUQT4sIG1hcHBpbmcgPSBhZXMoeCA9IDxWQVI+LCB5ID0gPFZBUj4pKSArIA0KICA8R0VPTV9GVU5DVElPTj4oKQ0KYGBgDQoNCkFuZGEgZGFwYXQgbWVtcGVsYWphcmkgdGVudGFuZyBgZ2dwbG90MmAgZGFyaSBidWt1ICpnZ3Bsb3QyIEVsZWdhbnQgR3JhcGhpY3MgZm9yIERhdGEgQW5hbHlzaXMgc2Vjb25kIGVkaXRpb24qLg0KDQoNCiMjIEJhcnBsb3QNCg0KWWFuZyBwZXJ0YW1hIGtpdGEgYWthbiBtZWxha3VrYW4gZWtzcGxvcmFzaSBkYXRhIGRlbmdhbiBtZW5nZ3VuYWthbiBkaWFncmFtIGJhdGFuZyBhdGF1IGJhcnBsb3QuIEdyYWZpayB5YW5nIGFrYW4gZGloYXNpbGthbiBzYW1hIGRlbmdhbiB5YW5nIGRpaGFzaWxrYW4gb2xlaCBgcXBsb3QoKWAgc2ViZWx1bW55YS4NCg0KYGBge3IgYmFyMX0NCmdncGxvdChkYXRhID0gbm90X2NhbmNlbCwgbWFwcGluZyA9IGFlcyh4ID0gbmFtZSkpICsNCiAgICBnZW9tX2JhcigpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpHZW9tIGBnZW9tX2JhcigpYCBkYXBhdCBtZW5lcmltYSBkYXRhIGRlbmdhbiBmb3JtYXQgbWVtYW5qYW5nIChyYXcpIGF0YXUgdGFidWxhc2kuDQoNCmBgYHtyfQ0Kbm90X2NhbmNlbCAlPiUgDQogIHNlbGVjdChuYW1lKQ0KYGBgDQoNCkppa2EgYmVudHVrIGRhdGFueWEgbWVtYW5qYW5nIHNlcGVydGkgaW5pIG1ha2EgY3VrdXAgbWVueWVidXRrYW4gdmFyaWFiZWxueWEgZGkgYXJndW1lbiBgeCA9IGAgcGFkYSBgYWVzKClgLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbm90X2NhbmNlbCwgbWFwcGluZyA9IGFlcyh4ID0gbmFtZSkpICsNCiAgICBnZW9tX2JhcigpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpKaWthIGRhdGFueWEgZGFsYW0gYmVudHVrIHRhYnVsYXNpLCBzZWJ1dGthbiBrYXRlZ29yaW55YSBkaSBhcmd1bWVuIGB4ID0gYCBkYW4gbmlsYWlueWEgZGkgYXJndW1lbiBgeSA9IGAsIGtlbXVkaWFuIHRhbWJhaGthbiBgc3RhdCA9ICJpZGVudGl0eSJgIHBhZGEgYGdlb21fYmFyKClgLg0KDQpgYGB7cn0NCm5vdF9jYW5jZWwgPC0gbm90X2NhbmNlbCAlPiUgDQogIGNvdW50KG5hbWUpIA0Kbm90X2NhbmNlbA0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBub3RfY2FuY2VsLCBtYXBwaW5nID0gYWVzKHggPSBuYW1lLCB5ID0gbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQpgYGANCg0KU2VjYXJhIGBkZWZhdWx0YCB0YW1waWxhbiBiYXJwbG90IGRpdXJ1dGthbiBiZXJkYXNhcmthbiBhbGZhYmV0IGthdGVnb3JpIHBhZGEgYXJndW1lbiBgeGAuIEppa2EgaW5naW4gYmFycGxvdCBkaXVydXRrYW4gYmVyZGFzYXJrYW4gbmlsYWlueWEsIGd1bmFrYW4gZnVuZ3NpIGByZW9yZGVyKClgLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbm90X2NhbmNlbCwgbWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihuYW1lLCAtbiksIHkgPSBuKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpVbnR1ayBtZW5ndXJ1dGthbiBiYXJwbG90IGJlcmRhc2Fya2FuIHZhbHVlDQoNCiAxLiBCdWF0IHRlcmxlYmloIGRhaHVsdSB0YWJlbCBmcmVrdWVuc2kgZGFyaSBrYXRlZ29yaSB5YW5nIGRpaW5naW5rYW4uDQogMi4gZ3VuYWthbiBmdW5nc2kgcmVvcmRlcigpIHBhZGEgYWVzdGV0aGljIGB4YCBkYW4gbiBzYmcgYHlgLg0KIDMuIGd1bmFrYW4gYHN0YXQgPSAiaWRlbnRpdHkiYCBwYWRhIGBnZW9tX2JhcigpYC4NCg0KYGBge3J9DQpub3RfY2FuY2VsIDwtIG5vdF9jYW5jZWwgJT4lIA0KICBtdXRhdGUocGN0ID0gbi9zdW0obikpDQoNCmdncGxvdChkYXRhID0gbm90X2NhbmNlbCwgbWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihuYW1lLCAtcGN0KSwgeSA9IHBjdCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQpgYGANCg0KYGBge3J9DQpjYW5jZWxlZCA8LSBmbGlnaHRzX3RibCAlPiUgDQogIGZpbHRlcihpcy5uYShkZXBfZGVsYXkpKSAlPiUgDQogIGNvdW50KG5hbWUpICU+JSANCiAgbXV0YXRlKHBjdCA9IG4vc3VtKG4pKQ0KY2FuY2VsZWQNCmBgYA0KDQpEYXJpIHRhYmVsIGRpIGF0YXMga2l0YSBkYXBhdCBtZW5nZXRhaHVpIGJhaHdhIEV4cHJlc3NKZXQgQWlybGluZXMgSW5jLiB5YW5nIHBhbGluZyBiYW55YWsgbWVsYWt1a2FuIGNhbmNlbCBzZWxhbWEgdGFodW4gMjAxMy4gU2VrYXJhbmcgbWFyaSBraXRhIHRhbXBpbGthbiBkYWxhbSB2aXN1YWxpc2FzaS4NCg0KYGBge3J9DQpnIDwtIGdncGxvdChkYXRhID0gY2FuY2VsZWQsIG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIobmFtZSwgLXBjdCksIHkgPSBwY3QpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpnDQpgYGANCg0KYGBge3J9DQpnICsNCiAgbGFicyh0aXRsZSA9ICJQZXJzZW50YXNlIE1hc2thcGFpIFlhbmcgU2VyaW5nIE1lbGFrdWthbiBDYW5jZWwiLA0KICAgICAgIHggPSAiTWFza2FwYWkiLA0KICAgICAgIHkgPSAiUGVyc2VudGFzZSIpICsNCiAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAxKSkNCmBgYA0KDQpIYXNpbCBkYXJpIGBnZ3Bsb3RgIGRhcGF0IGRpc2ltcGFuIGRhbGFtIHNlYnVhaCBvYmplayBkaSBSIGtlbXVkaWFuIGRpdGFtYmFoa2FuIGxheWVyIGRlbmdhbiBgK2AgZGFuIGBnZW9tYCBhdGF1IGtvbXBvbmVuIGxhaW4uDQoNCktpdGEganVnYSBkYXBhdCBtZW5lbnR1a2FuIHdhcm5hIHVudHVrIG1hc2luZy1tYXNpbmcgYmF0YW5nIHBhZGEgYmFycGxvdC4gTWlzYWxueWEsIHNldGlhcCBiYXRhbmcgYmVyYmVkYSB3YXJuYW55YSBiZXJkYXNhcmthbiBuYW1hIGthdGVnb3JpbnlhIHNlY2FyYSBkZWZhdWx0Lg0KDQpVbnR1ayBtZW5hbWJhaGthbiBqdWR1bCAoYHRpdGxlYCksIG1lbmdnYW50aSBqdWR1bCBtYXNpbmctbWFzaW5nIGF4aXMgYHhgIGRhbiBgeWAgYXRhdSBtZW5hbWJhaGthbiBgc3VidGl0bGVgZGFwYXQgbWVuZ2d1bmFrYW4gYGxhYnMoKWAuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBjYW5jZWxlZCwgbWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihuYW1lLCAtcGN0KSwgeSA9IHBjdCwgZmlsbCA9IG5hbWUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgbGFicyh0aXRsZSA9ICJQZXJzZW50YXNlIE1hc2thcGFpIFlhbmcgU2VyaW5nIE1lbGFrdWthbiBDYW5jZWwiLA0KICAgICAgIHggPSAiTWFza2FwYWkiLA0KICAgICAgIHkgPSAiUGVyc2VudGFzZSIpDQpgYGANCg0KQXJndW1lbiBgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiYCBkaWd1bmFrYW4gdW50dWsgbWVuZ2hpbGFuZ2thbiBsZWdlbmQgZGFyaSBncmFmaWsgeWFuZyBkaWJ1YXQuIENvYmFsYWggdW50dWsgbWVuZ2hhcHVzIGFyZ3VtZW4gYGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lImAgZGFuIGxpaGF0IGhhc2lsbnlhLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTZ9DQpnZ3Bsb3QoZGF0YSA9IGNhbmNlbGVkLCBtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKG5hbWUsIC1wY3QpLCB5ID0gcGN0KjEwMCwgZmlsbCA9IG5hbWUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZShyb3VuZChwY3QqMTAwLCAyKSwgIiUiKSksIHZqdXN0ID0gLTAuMjUpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHZqdXN0ID0gMSksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKHRpdGxlID0gIlBlcnNlbnRhc2UgTWFza2FwYWkgWWFuZyBTZXJpbmcgTWVsYWt1a2FuIENhbmNlbCIsDQogICAgICAgeCA9ICJNYXNrYXBhaSIsDQogICAgICAgeSA9ICJQZXJzZW50YXNlIikNCmBgYA0KDQpBbmRhIGp1Z2EgZGFwYXQgbWVsYWt1a2FuIG9wZXJhc2kgbWF0ZW1hdGlrYSBzZWRlcmhhbmEgdW50dWsgdmFyaWFiZWwgeWFuZyBha2FuIGRpZ3VuYWthbi4gTWlzYWxueWEgbWVuZ3ViYWggc2F0dWFuIGBwY3RgIGRlbmdhbiBkaWthbGlrYW4gMTAwLiBgZ2VvbV90ZXh0KClgIGRpZ3VuYWthbiB1bnR1ayBtZW5hbWJhaGthbiBrb21wb25lbiBsYXllciB0ZWtzIHBhZGEgZ3JhZmlrLiBEYWxhbSBrYXN1cyBpbmkgZGlndW5ha2FuIHVudHVrIG1lbmFtcGlsa2FuIG5pbGFpIGRpIGF0YXMgbWFzaW5nLW1hc2luZyBiYXRhbmcuIGB2anVzdCA9IC0wLjI1YCBhZ2FyIHRla3MgYmVyYWRhIGRpIGF0YXMgYmF0YW5nLg0KDQpgYGB7ciBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodD0xMH0NCmdncGxvdChkYXRhID0gY2FuY2VsZWQsIG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIobmFtZSwgcGN0KSwgeSA9IHBjdCoxMDAsIGZpbGwgPSBuYW1lKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUocm91bmQocGN0KjEwMCwgMiksICIlIikpLCBoanVzdCA9IC0wLjAxKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBsYWJzKHRpdGxlID0gIlBlcnNlbnRhc2UgTWFza2FwYWkgWWFuZyBTZXJpbmcgTWVsYWt1a2FuIENhbmNlbCIsDQogICAgICAgeCA9ICJNYXNrYXBhaSIsDQogICAgICAgeSA9ICJQZXJzZW50YXNlIikgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpBZ2FyIHRhbXBpbGFuIGJhcnBsb3QgZGVuZ2FuIGBheGlzLnRleHQueGAgbGViaWggbWVuYXJpaywgZ3VuYWthbiBgY29vcmRfZmxpcCgpYCB1bnR1ayBtZW11dGFyIGdyYWZpay4gUG9zaXNpIGF4aXMgYHhgIGRpIHBvc2lzaSBgeWAgZGFuIHNlYmFsaWtueWEuDQoNCiMjIEhpc3RvZ3JhbSAmIERlbnNpdHkNCg0KSGlzdG9ncmFtIGF0YXUgRGVuc2l0eSBkYXBhdCBkaWd1bmFrYW4gdW50dWsgbWVtdmlzdWFsaXNhc2lrYW4gc2ViYXJhbiBkYXJpIHNlYnVhaCB2YXJpYWJlbCBudW1lcmlrLg0KDQoNCmBgYHtyfQ0KZyA8LSBnZ3Bsb3QoZGF0YSA9IGZsaWdodHNfdGJsLCBtYXBwaW5nID0gYWVzKHggPSBhaXJfdGltZSkpDQpnDQpgYGANCg0KS2FyZW5hIHZhcmlhYmVsIHlhbmcgYWthbiBraXRhIGd1bmFrYW4gc2FtYSwgeWFpdHUgaGFueWEgYGFpcl90aW1lYCBtYWthIGtpdGEgc2ltcGFuIGRhaHVsdSBoYXNpbCBkYXJpIGdncGxvdCBrZSBkYWxhbSBvYmplayBgZ2Agc2VoaW5nZ2Ega2l0YSBkYXBhdCBtZW5nZ2FudGkgYXJndW1lbiBwYWRhIGBnZW9tX2hpc3RvZ3JhbSgpYCB0YW5wYSBwZXJsdSBtZW1hbmdnaWwgbGFnaSBmdW5nc2kgYGdncGxvdCgpYCBkZW5nYW4gYXJndW1lbiB5YW5nIHNhbWEgc2VwZXJ0aXNlYmVsdW1ueWEuIEtldGlrYSBraXRhIHBhbmdnaWwgb2JqZWsgZGFyaSBgZ2dwbG90YCB0ZXJzZWJ1dCwgbWFrYSBobmF5YSBtZW5hcGlsa2FuIHNlYnVhaCBrYW52YXMga29zb25nIGthcmVuYSBraXRhIGJlbHVtIG1lbmFtYmFoa2FuIGxheWVyIGBnZW9tYCBhcGEgeWFuZyBha2FuIGRpZ3VuYWthbi4NCg0KYGBge3J9DQpnICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KYGBgDQoNCktldGlrYSBraXRhIHRhbWJhaGthbiBgZ2VvbV9oaXN0b2dyYW0oKWAgbWFrYSBha2FuIGRpdGFtYmFoa2FuIGhpc3RvZ3JhbS4gU2VjYXJhIGRlZmF1bHQgYGdlb21faGlzdG9ncmFtKClgIG1lbmdndW5ha2FuIDMwIGJpbnMuIGBiaW5zYCBhZGFsYWggYmFueWFrbnlhIGtvdGFrL2JhdGFuZywgc2VkYW5na2FuIGxlYmFyIGJhdGFuZyBkaXNlYnV0IGBiaW53aWR0aGAuIEppa2EgYWRhIGBOQWAgbWFrYSBzZWNhcmEgb3RvbWF0aXMgYWthbiBkaWJ1YW5nLg0KDQpgYGB7cn0NCmcgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAic2t5Ymx1ZSIsIGNvbG9yID0gIndoaXRlIikNCmBgYA0KDQpEZW5nYW4gYGJpbnMgPSA1MGAgYXJ0aW55YSBwYWRhIGhpc3RvZ3JhbSB0ZXJzZWJ1dCBha2FuIGRpZ3VuYWthbiA1MCBiYXRhbmcuIEFyZ3VtZW4gYGZpbGwgPSAic2t5Ymx1ZSJgIHVudHVrIG1lbWJlcmlrYW4gd2FybmEgcGFkYSBiYXRhbmcgaGlzdG9ncmFtLiBBbmRhIGp1Z2EgZGFwYXQgbWVuZ2d1bmFrYW4gd2FybmEgbGFpbiwgbWlzYWxueWEgYGZpbGwgPSAicGluayJgIGF0YXUgYGZpbGwgPSAibGlnaHRibHVlImAgYXRhdSBiYWhrYW4gbWVuZ2d1bmFrYW4gW2tvZGUgd2FybmEgSGV4XShodHRwczovL3d3dy5nb29nbGUuY29tL3NlYXJjaD9zYWZlPXN0cmljdCZlaT1HUzcxWE4yNkw1clh6N3NQcDl1bHdBdyZxPSUyM2ZmZmZmZiZvcT0lMjNmZmZmZmYmZ3NfbD1wc3ktYWIuMy4uLjUyMjQuNTIyNC4uNTgyNC4uLjAuMC4uMC4yNTEuMjUxLjItMS4uLi4uLjAuLi4uMS4uZ3dzLXdpei4uLi4uLi4waTcxLjgzdmlYcHJVWGE4KS4NCg0KU2ViYWdpYW4gYmVzYXIgbGFtYW55YSBwZW5lcmJhbmdhbiBrdXJhbmcgZGFyaSAyMDAgbWVuaXQuIE5hbXVuIGRhcmkgZ3JhZmlrIGRpIGF0YXMgdGVybGloYXQgYWRhIGJlYmVyYXBhIHB1bmNhayB5YW5nIHRlcmphZGkuIE1hcmkga2l0YSBsaWhhdCBtZW5nZ3VuYWthbiBgZ2VvbV9kZW5zaXR5KClgIA0KDQpgYGB7cn0NCmcgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlucyA9IDUwLCBmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gImRhcmtncmVlbiIsIHNpemUgPSAwLjcpDQpgYGANCg0KYGBge3J9DQpnICsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAic2t5Ymx1ZSIsIGFscGhhID0gMC41KQ0KYGBgDQoNCk5hbXVuIGppa2EgZGlwZXJoYXRpa2FuLCBhZGEganVnYSBwZW5lcmJhbmdhbiB5YW5nIGxhbWEgd2FrdHUgdGVyYmFuZ255YSBsZWJpaCBkYXJpIDYwMCBtZW5pdCBhdGF1IDEwIGphbS4gS2l0YSBsaWhhdCBkYXRhIGRlbmdhbiBwZW5lcmJhbmdhbiBzZWxhbWEgc2VraXRhciAxMCBqYW0gdGVyc2VidXQuDQoNCmBgYHtyfQ0KZmxpZ2h0czEwaCA8LSBmbGlnaHRzX3RibCAlPiUgDQogIGZpbHRlcihhaXJfdGltZSA+IDUwMCkNCg0KZmxpZ2h0czEwaCAlPiUgDQogIGdyb3VwX2J5KG9yaWdpbiwgZGVzdCkgJT4lIA0KICBzdW1tYXJpc2UobWluID0gbWluKGFpcl90aW1lKSwgYXZnID0gbWVhbihhaXJfdGltZSksIHN0ZCA9IHNkKGFpcl90aW1lKSwgbWF4ID0gbWF4KGFpcl90aW1lKSkNCmBgYA0KDQpUZXJueWF0YSBwZW5lcmJhbmdhbiBkYXJpIGJhbmRhcmEgYEVXUmAgZGFuIGBKRktgIG1lbnVqdSBiYW5kYXJhIGBITkxgIHJhdGEtcmF0YSBtZW1idXR1aGthbiB3YWt0dSB0ZXJiYW5nIGxlYmloIGRhcmkgNjAwIG1lbml0IGF0YXUgMTAgamFtLiBBcGEgaXR1IGBITkxgPw0KDQpgYGB7cn0NCmFpcnBvcnRzICU+JSANCiAgZmlsdGVyKGZhYSA9PSAiSE5MIikNCmBgYA0KDQoNCiMjIEJveHBsb3QNCg0KU2VjYXJhIGRlZmF1bHQsIGJveHBsb3QgZGkgYGdncGxvdDJgIG1lbWVybHVrYW4gdmFyaWFiZWwga2F0ZWdvcmlrIHNlYmFnYWkgYXJndW1lbiBgeGAgZGFuIHZhcmlhYmVsIG51bWVyaWsgc2ViYWdhaSBhcmd1bWVuIGB5YC4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGZsaWdodHNfdGJsLCBtYXBwaW5nID0gYWVzKHggPSBuYW1lLCB5ID0gd2luZF9zcGVlZCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpKaWthIGhhbnlhIGluZ2luIHNhdHUgYm94cGxvdCB1bnR1ayBzYXR1IHZhcmlhYmVsIHRhbnBhIGRpYmVkYWthbiBiZXJkYXNhcmthbiBrYXRlZ29yaSBsYWluIG1ha2EgY3VrdXAgZ3VuYWthbiBgeCA9ICcnYCBhdGF1IHN0cmluZyBsYWluIHNlcGVydGkgY29udG9oIGJlcmlrdXQuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBmbGlnaHRzX3RibCwgbWFwcGluZyA9IGFlcyh4ID0gIlN0YXRpc3RpY3MiLCB5ID0gdGVtcCkpICsNCiAgZ2VvbV9ib3hwbG90KCkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZmxpZ2h0c190YmwsIG1hcHBpbmcgPSBhZXMoeCA9IG9yaWdpbiwgeSA9IHRlbXApKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGZsaWdodHNfdGJsLCBtYXBwaW5nID0gYWVzKHggPSBvcmlnaW4sIHkgPSB0ZW1wKSkgKw0KICBnZW9tX2JveHBsb3QoY29sb3IgPSAic2t5Ymx1ZSIpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KQW5kYSBkYXBhdCBtZW1iYWNhIGJlYmVyYXBhIGFydGlrZWwgdGVudGFuZyBgZ2VvbV9ib3hwbG90KClgLCBzYWxhaCBzYXR1bnlhIFtnZW9tX2JveHBsb3RdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZW9tX2JveHBsb3QuaHRtbCkuDQoNCg0KIyMgU2NhdHRlciBwbG90DQoNClNjYXR0ZXIgcGxvdCBhZGFsYWggdmlzdWFsaXNhc2kgZGF0YSBkYXJpIGR1YSBidWFoIHZhcmlhYmVsIG51bWVyaWsuIE1pc2Fsa2FuIGRhcmkgZGF0YSBgd2VhdGhlcmAga2l0YSBhbWJpbCBkYXRhIGN1YWNhIGRpIGJhbmRhcmEgYEpGS2Agc2FqYSBzZWxhbWEgdGFodW4gMjAxMy4NCg0KYGBge3J9DQp3ZWF0aGVyX2pmayA8LSB3ZWF0aGVyICU+JSANCiAgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIikgDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHdlYXRoZXJfamZrLCBtYXBwaW5nID0gYWVzKHggPSB0aW1lX2hvdXIsIHkgPSB0ZW1wKSkgKyANCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KQW5kYSBkYXBhdCBtZXJ1YmFoIGBzaGFwZWAgZGFyaSBgZ2VvbV9wb2ludGAgZGVuZ2FuIHNlYnVhaCBiaWxhbmdhbiBpbnRlZ2VyLg0KDQo8cCBhbGlnbj0iY2VudGVyIj4NCiAgICA8aW1nIHNyYz0icG9pbnRzaGFwZS5wbmciIGFsdD0iUG9pbnQgU2hhcGUiPg0KICAgIDxici8+DQogICAgPGJyLz4NCiAgICA8ZW0+UG9pbnQgU2hhcGU8L2VtPg0KPC9wPg0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSB3ZWF0aGVyX2pmaywgbWFwcGluZyA9IGFlcyh4ID0gdGltZV9ob3VyLCB5ID0gdGVtcCkpICsgDQogIGdlb21fcG9pbnQoc2hhcGUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiU3VodSBCYW5kYXJhIEpGSyBTZWxhbWEgVGFodW4gMjAxMyIsDQogICAgICAgeCA9ICJ3YWt0dSIsDQogICAgICAgeSA9ICJTdWh1IikNCmBgYA0KDQojIyBMaW5lIHBsb3QvdGltZSBzZXJpZXMgcGxvdA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gd2VhdGhlcl9qZmssIG1hcHBpbmcgPSBhZXMoeCA9IHRpbWVfaG91ciwgeSA9IHRlbXApKSArIA0KICBnZW9tX2xpbmUoKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSB3ZWF0aGVyX2pmaywgbWFwcGluZyA9IGFlcyh4ID0gdGltZV9ob3VyKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gdGVtcCksIGNvbG9yID0gInNreWJsdWUiKQ0KYGBgDQoNCktldGViYWxhbiBnYXJpcyBkYXBhdCBkaXNlc3VhaWthbiBkZW5nYW4gYHNpemUgPWAsIG1pc2FsbnlhIGBzaXplID0gMWAgdW50dWsgZ2FyaXMgeWFuZyBsZWJpaCB0ZWJhbCBkYXJpIGRlZmF1bHQuIA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gd2VhdGhlcl9qZmssIG1hcHBpbmcgPSBhZXMoeCA9IHRpbWVfaG91ciwgeSA9IHRlbXApKSArIA0KICBnZW9tX2xpbmUoY29sb3IgPSAic2t5Ymx1ZSIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX3hfZGF0ZXRpbWUoYnJlYWtzID0gIjEgbW9udGgiLCBkYXRlX2xhYmVscyA9ICIlYiAlZCIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHdlYXRoZXJfamZrLCBtYXBwaW5nID0gYWVzKHggPSB0aW1lX2hvdXIsIHkgPSB0ZW1wKSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsNCiAgc2NhbGVfeF9kYXRldGltZShicmVha3MgPSAiZGF5cyIsIGRhdGVfbGFiZWxzID0gIiViICVkIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gd2VhdGhlcl9qZmssIG1hcHBpbmcgPSBhZXMoeCA9IHRpbWVfaG91ciwgeSA9IHRlbXApKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkgKw0KICBzY2FsZV94X2RhdGV0aW1lKGJyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIgJWQiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArDQogIGxhYnModGl0bGUgPSAiU3VodSBCYW5kYXJhIEpGSyBTZWxhbWEgVGFodW4gMjAxMyIsDQogICAgICAgeCA9ICJXYWt0dSIsDQogICAgICAgeSA9ICJTdWh1IikNCmBgYA0KDQoNCmBgYHtyfQ0Kd2VhdGhlcl9qZmsgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gdGltZV9ob3VyLCB5ID0gdGVtcCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3Ntb290aCgpDQpgYGANCg0KYGBge3J9DQp3ZWF0aGVyICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IHRpbWVfaG91ciwgeSA9IHRlbXAsIGNvbG9yID0gb3JpZ2luKSkgKw0KICAjIGdlb21fbGluZSgpICsNCiAgZ2VvbV9zbW9vdGgoKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjZWE1NDU0IiwgIiM2ZjQ1ZDgiLCAiIzU3YzE1OCIpKQ0KYGBgDQoNCiMgRmFjZXQNCg0KYGBge3J9DQpmbGlnaHRzX2F1ZzIgPC0gZmxpZ2h0c190YmwgJT4lIA0KICBpbm5lcl9qb2luKGFpcnBvcnRzLCBieSA9IGMoIm9yaWdpbiIgPSAiZmFhIiksIHN1ZmZpeCA9IGMoIl9jYXJyaWVyIiwgIl9vcmlnaW5haXJwb3J0cyIpKSAlPiUgDQogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSAmIG1vbnRoID09IDgpICU+JSANCiAgbXV0YXRlKHRnbCA9IGFzLkRhdGUocGFzdGUoeWVhciwgbW9udGgsIGRheSwgc2VwID0gIi0iKSkpICU+JSANCiAgZ3JvdXBfYnkobmFtZV9vcmlnaW5haXJwb3J0cywgdGdsKSAlPiUgDQogIHN1bW1hcmlzZShuID0gbigpKSANCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZmxpZ2h0c19hdWcyLCBtYXBwaW5nID0gYWVzKHggPSB0Z2wsIHkgPSBuKSkgKyANCiAgZ2VvbV9saW5lKGNvbG9yID0gInNreWJsdWUiKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMobmFtZV9vcmlnaW5haXJwb3J0cykpICsNCiAgc2NhbGVfeF9kYXRlKGJyZWFrcyA9ICJkYXlzIiwgZGF0ZV9sYWJlbHMgPSAiJWQiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArDQogIGxhYnModGl0bGUgPSAiSnVtbGFoIFBlbmVyYmFuZ2FuIEhhcmlhbiBCdWxhbiBBZ3VzdHVzIDIwMTMiLA0KICAgICAgIHggPSAiVGFuZ2dhbCIsDQogICAgICAgeSA9ICJKdW1sYWgiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBmbGlnaHRzX2F1ZzIsIG1hcHBpbmcgPSBhZXMoeCA9IHRnbCwgeSA9IG4pKSArIA0KICBnZW9tX2xpbmUoY29sb3IgPSAic2t5Ymx1ZSIpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZmFjZXRfZ3JpZChuYW1lX29yaWdpbmFpcnBvcnRzIH4gLiApICsNCiAgc2NhbGVfeF9kYXRlKGJyZWFrcyA9ICJkYXlzIiwgZGF0ZV9sYWJlbHMgPSAiJWQiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArDQogIGxhYnModGl0bGUgPSAiSnVtbGFoIFBlbmVyYmFuZ2FuIEhhcmlhbiBCdWxhbiBBZ3VzdHVzIDIwMTMiLA0KICAgICAgIHggPSAiVGFuZ2dhbCIsDQogICAgICAgeSA9ICJKdW1sYWgiKQ0KYGBgDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YSA9IGZsaWdodHNfYXVnMiwgbWFwcGluZyA9IGFlcyh4ID0gdGdsLCB5ID0gbikpICsgDQogIGdlb21fbGluZShjb2xvciA9ICJza3libHVlIikgKw0KICBnZW9tX3BvaW50KCkgKw0KICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKG5hbWVfb3JpZ2luYWlycG9ydHMpKSArDQogIGxhYnModGl0bGUgPSAiSnVtbGFoIFBlbmVyYmFuZ2FuIEhhcmlhbiBCdWxhbiBBZ3VzdHVzIDIwMTMiLA0KICAgICAgIHggPSAiVGFuZ2dhbCIsDQogICAgICAgeSA9ICJKdW1sYWgiKQ0KYGBgDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YSA9IGZsaWdodHNfYXVnMiwgbWFwcGluZyA9IGFlcyh4ID0gdGdsLCB5ID0gbikpICsgDQogIGdlb21fbGluZShjb2xvciA9ICJza3libHVlIikgKw0KICBnZW9tX3BvaW50KCkgKw0KICBmYWNldF9ncmlkKCAuIH4gbmFtZV9vcmlnaW5haXJwb3J0cykgKw0KICBsYWJzKHRpdGxlID0gIkp1bWxhaCBQZW5lcmJhbmdhbiBIYXJpYW4gQnVsYW4gQWd1c3R1cyAyMDEzIiwNCiAgICAgICB4ID0gIlRhbmdnYWwiLA0KICAgICAgIHkgPSAiSnVtbGFoIikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZmxpZ2h0c19hdWcyLCBtYXBwaW5nID0gYWVzKHggPSB0Z2wsIHkgPSBuKSkgKyANCiAgZ2VvbV9saW5lKGNvbG9yID0gInNreWJsdWUiKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoKSwgY29scyA9IHZhcnMobmFtZV9vcmlnaW5haXJwb3J0cykpICsNCiAgbGFicyh0aXRsZSA9ICJKdW1sYWggUGVuZXJiYW5nYW4gSGFyaWFuIEJ1bGFuIEFndXN0dXMgMjAxMyIsDQogICAgICAgeCA9ICJUYW5nZ2FsIiwNCiAgICAgICB5ID0gIkp1bWxhaCIpDQpgYGANCg0KU2V0ZWxhaCBzZWxlc2FpIG1lbWJ1YXQgZ3JhZmlrIHlhbmcgQW5kYSBpbmdpbmthbiwgQW5kYSBkYXBhdCBtZW55aW1wYW4gZ3JhZmlrIHRlcnNlYnV0IGRlbmdhbiBmdW5nc2kgYGdnc2F2ZSgpYC4NCg0KYGBge3IgZ2dzYXZlfQ0KZyA8LSBmbGlnaHRzX3RibCAlPiUgDQogIGZpbHRlcihvcmlnaW4gPT0gIkpGSyIpICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IHRpbWVfaG91ciwgeSA9IHRlbXApKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9zbW9vdGgoKQ0KDQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdFIuanBnIiwgcGxvdCA9IGcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcpDQpgYGANCg0KSmlrYSBBbmRhIHRpZGFrIG1lbnllYnV0a2FuIG9iamVrIGBnZ3Bsb3QyYCBwYWRhIGBwbG90ID1gIG1ha2Egc2VjYXJhIG90b21hdGlzIHBsb3QgeWFuZyB0ZXJha2hpciBkaWJ1YXQgeWFuZyBha2FuIGRpcGlsaWguDQo=