Motivations
Chức năng của Graph là truyền tải các insights cho người tiếp nhận thông tin. Khi nào chức năng này mà không làm được, hoặc gây hiểu lầm, hoặc não người mất quá nhiều thời gian để hiểu insight trong graph được trình bày, thì coi như graph chưa làm được chức năng của nó. Một Graph tốt thì nên là self-explanatory (tự cái hình đã giải thích mọi thứ). Một trong những ví dụ như vậy là hình số 2 của báo cáo có tên ĐÁNH GIÁ TÁC ĐỘNG CỦA COVID-19 ĐẾN NỀN KINH TẾ VÀ CÁC KHUYẾN NGHỊ CHÍNH SÁCH (có thể xem tại đây). Chúng ta có thể cải tiến lại như sau:

R codes
R codes để thực hiện hình này như sau:
# Load some packages:
library(tidyverse)
library(lubridate)
# Data links (source: https://github.com/CSSEGISandData/COVID-19):
rm(list = ls())
link1 <- "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv"
link2 <- "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv"
link3 <- "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv"
# Clean and prepare data:
link1 %>%
read_csv() %>%
rename(Province = `Province/State`, Country = `Country/Region`) %>%
gather(Date, Confirmed, -Province, -Country, -Lat, -Long) %>%
mutate(Date = mdy(Date)) %>%
filter(Country == "Vietnam", Date <= ymd("2020-04-04")) -> df_confirmed
df_confirmed %>%
mutate(before = lag(Confirmed)) %>%
mutate(NewConfirmed = Confirmed - before) %>%
slice(-1) -> df_for_g1
end_stage1 <- dmy("13-02-2020")
start_stage2 <- dmy("06-03-2020")
end_stage2 <- dmy("21-03-2020")
df_for_g1 %>%
mutate(Stage = case_when(Date <= end_stage1 ~ "Stage 1",
Date > end_stage1 & Date < start_stage2 ~ "Standby",
Date >= start_stage2 & Date <= end_stage2 ~ "Stage 2",
TRUE ~ "Stage 3")) -> df
df %>%
select(TotalConfirmed = Confirmed, NewConfirmed, Date) %>%
gather(Type, Value, -Date) -> df_plot
df_plot$Date %>% unique() -> my_date
df_labels <- data.frame(Date = my_date)
df_labels %>%
mutate(label_x = case_when(Date == min(Date) ~ as.character(Date),
Date == end_stage1 ~ as.character(end_stage1),
Date == start_stage2 ~ as.character(start_stage2),
Date == end_stage2 ~ as.character(end_stage2),
Date == max(Date) ~ as.character(Date),
TRUE ~ "")) %>%
mutate(Stage = case_when(Date <= end_stage1 ~ "Stage 1",
Date > end_stage1 & Date < start_stage2 ~ "Standby",
Date >= start_stage2 & Date <= end_stage2 ~ "Stage 2",
TRUE ~ "Stage 3")) %>%
mutate(label_x = case_when(label_x == "2020-01-23" ~ "23-01",
label_x == "2020-02-13" ~ "13-02",
label_x == "2020-03-06" ~ "06-03",
label_x == "2020-03-21" ~ "21-03",
label_x == "2020-04-04" ~ "04-04",
TRUE ~ label_x)) -> df_labels
df_for_g1 %>%
filter(Date == max(Date)) %>%
mutate(Date = Date + 2) %>%
select(TotalConfirmed = Confirmed, NewConfirmed, Date) %>%
gather(Type, Value, -Date) %>%
mutate(label = case_when(Value == 4 ~ paste0(Value, " "),
TRUE ~ as.character(Value))) -> df_an
fill_colors <- c("#fff5f0", "#fcbba1", "#fc9272", "#fb6a4a")
line_colors <- c("#e41a1c", "#1f78b4")
h <- 250
k <- -0.5
my_font <- "Ubuntu Condensed"
ggplot() +
theme_minimal() +
geom_rect(aes(xmin = min(my_date), xmax = end_stage1, ymin = -Inf, ymax = Inf, fill = "Stage 1"), fill = "#a1d99b", alpha = 0.3, show.legend = FALSE) +
geom_rect(aes(xmin = end_stage1, xmax = start_stage2, ymin = -Inf, ymax = Inf, fill = "Standby"), fill = fill_colors[2], alpha = 0.3, show.legend = FALSE) +
geom_rect(aes(xmin = start_stage2, xmax = end_stage2, ymin = -Inf, ymax = Inf, fill = "Stage 2"), fill = fill_colors[3], alpha = 0.3, show.legend = FALSE) +
geom_rect(aes(xmin = end_stage2, xmax = max(my_date), ymin = -Inf, ymax = Inf, fill = "Stage 3"), fill = fill_colors[4], alpha = 0.3, show.legend = FALSE) +
geom_line(data = df_plot, aes(Date, Value, color = Type), size = 1.5) +
scale_color_manual(values = line_colors, name = "", labels = c("New", "Total")) +
scale_y_continuous(breaks = seq(0, 250, 25), limits = c(0, 250)) +
theme(panel.grid.minor.y = element_blank()) +
theme(legend.position = "top") +
scale_x_date(limits = c(min(my_date), max(my_date) + 3), breaks = seq(min(my_date), max(my_date), 1),
labels = df_labels$label_x, position = "top", expand = c(0, 0)) +
theme(panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank()) +
geom_text(data = df_an, aes(Date, Value, label = label), show.legend = FALSE, color = line_colors[2:1], size = 4.5,
fontface = "bold", hjust = 0.6, family = my_font) +
labs(x = NULL, y = NULL,
title = "Figure 1: Coronavirus cases in Vietnam, as of 04-04-2020",
caption = "Source: Ministry of Health of Vietnam") +
geom_text(data = data.frame(Date = ymd("2020-01-23") + 10, Value = h), aes(Date, Value), label = "Stage 1", size = 4, vjust = k, family = my_font) +
geom_text(data = data.frame(Date = ymd("2020-02-13") + 11, Value = h), aes(Date, Value), label = "Standby", size = 4, vjust = k, family = my_font) +
geom_text(data = data.frame(Date = ymd("2020-03-06") + 7, Value = h), aes(Date, Value), label = "Stage 2", size = 4, vjust = k, family = my_font) +
geom_text(data = data.frame(Date = ymd("2020-03-21") + 7, Value = h), aes(Date, Value), label = "Stage 3", size = 4, vjust = k, family = my_font) +
theme(axis.text.x = element_text(size = 10, family = my_font)) +
theme(axis.text.y = element_text(size = 13, family = my_font)) +
theme(plot.margin = unit(c(1, 1, 1, 1), "cm")) +
theme(plot.title = element_text(family = my_font, size = 20)) +
theme(plot.caption = element_text(family = my_font, size = 10, color = "grey30")) +
theme(legend.text = element_text(family = my_font, size = 10, face = "bold", color = "grey30"))
LS0tDQp0aXRsZTogJ0Nvcm9uYXZpcnVzIGNhc2VzIGluIFZpZXRuYW0nDQphdXRob3I6ICdBdXRob3I6IE5ndXllbiBDaGkgRHVuZycNCnN1YnRpdGxlOiAiRGFpbHkgR3JhcGggU2VyaWVzIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgIyBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNikNCmBgYA0KDQoNCiMgTW90aXZhdGlvbnMNCg0KQ2jhu6ljIG7Eg25nIGPhu6dhIEdyYXBoIGzDoCB0cnV54buBbiB04bqjaSBjw6FjIGluc2lnaHRzIGNobyBuZ8aw4budaSB0aeG6v3Agbmjhuq1uIHRow7RuZyB0aW4uIEtoaSBuw6BvIGNo4bupYyBuxINuZyBuw6B5IG3DoCBraMO0bmcgbMOgbSDEkcaw4bujYywgaG/hurdjIGfDonkgaGnhu4N1IGzhuqdtLCBob+G6t2MgbsOjbyBuZ8aw4budaSBt4bqldCBxdcOhIG5oaeG7gXUgdGjhu51pIGdpYW4gxJHhu4MgaGnhu4N1IGluc2lnaHQgdHJvbmcgZ3JhcGggxJHGsOG7o2MgdHLDrG5oIGLDoHksIHRow6wgY29pIG5oxrAgZ3JhcGggY2jGsGEgbMOgbSDEkcaw4bujYyBjaOG7qWMgbsSDbmcgY+G7p2EgbsOzLiBN4buZdCBHcmFwaCB04buRdCB0aMOsIG7Dqm4gbMOgIHNlbGYtZXhwbGFuYXRvcnkgKHThu7EgY8OhaSBow6xuaCDEkcOjIGdp4bqjaSB0aMOtY2ggbeG7jWkgdGjhu6kpLiBN4buZdCB0cm9uZyBuaOG7r25nIHbDrSBk4bulIG5oxrAgduG6rXkgbMOgIGjDrG5oIHPhu5EgMiBj4bunYSBiw6FvIGPDoW8gY8OzIHTDqm4gKsSQw4FOSCBHScOBIFTDgUMgxJDhu5hORyBD4bumQSBDT1ZJRC0xOSDEkOG6vk4gTuG7gE4gS0lOSCBU4bq+IFbDgCBDw4FDIEtIVVnhur5OIE5HSOG7iiBDSMONTkggU8OBQ0gqIChjw7MgdGjhu4MgeGVtIFt04bqhaSDEkcOieV0oaHR0cHM6Ly9uZXUuZWR1LnZuL1Jlc291cmNlcy9Eb2NzL1N1YkRvbWFpbi9Ib21lUGFnZS9UaG9uZ0Jhby8yMDIwLzIwMjBfNC9Gb3JtYXRGYWN0b3J5JTIwUERGJTIwSm9pbmVyJTIwQklBJTIwMSUyMGJhbyUyMGNhb18xLnBkZj9mYmNsaWQ9SXdBUjFmNll6ZGZTYURINjlsZmEwNUhuQ3dwQXVFRjI1SFNEMHFraG5HSm1TVE14LUxaMmVBREZxeVd4cykpLiBDaMO6bmcgdGEgY8OzIHRo4buDIGPhuqNpIHRp4bq/biBs4bqhaSBuaMawIHNhdTogDQoNCiFbXShDOlxcVXNlcnNcXEFETUlOXFxEZXNrdG9wXFxjb3JvbmEuanBnKQ0KDQojIFIgY29kZXMgDQoNClIgY29kZXMgxJHhu4MgdGjhu7FjIGhp4buHbiBow6xuaCBuw6B5IG5oxrAgc2F1OiANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgTG9hZCBzb21lIHBhY2thZ2VzOiANCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCiMgRGF0YSBsaW5rcyAoc291cmNlOiBodHRwczovL2dpdGh1Yi5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkpOiANCnJtKGxpc3QgPSBscygpKQ0KbGluazEgPC0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOS9tYXN0ZXIvY3NzZV9jb3ZpZF8xOV9kYXRhL2Nzc2VfY292aWRfMTlfdGltZV9zZXJpZXMvdGltZV9zZXJpZXNfY292aWQxOV9jb25maXJtZWRfZ2xvYmFsLmNzdiINCmxpbmsyIDwtICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfcmVjb3ZlcmVkX2dsb2JhbC5jc3YiDQpsaW5rMyA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NTU0VHSVNhbmREYXRhL0NPVklELTE5L21hc3Rlci9jc3NlX2NvdmlkXzE5X2RhdGEvY3NzZV9jb3ZpZF8xOV90aW1lX3Nlcmllcy90aW1lX3Nlcmllc19jb3ZpZDE5X3JlY292ZXJlZF9nbG9iYWwuY3N2Ig0KDQojIENsZWFuIGFuZCBwcmVwYXJlIGRhdGE6IA0KDQpsaW5rMSAlPiUgDQogIHJlYWRfY3N2KCkgJT4lIA0KICByZW5hbWUoUHJvdmluY2UgPSBgUHJvdmluY2UvU3RhdGVgLCBDb3VudHJ5ID0gYENvdW50cnkvUmVnaW9uYCkgJT4lIA0KICBnYXRoZXIoRGF0ZSwgQ29uZmlybWVkLCAtUHJvdmluY2UsIC1Db3VudHJ5LCAtTGF0LCAtTG9uZykgJT4lIA0KICBtdXRhdGUoRGF0ZSA9IG1keShEYXRlKSkgJT4lIA0KICBmaWx0ZXIoQ291bnRyeSA9PSAiVmlldG5hbSIsIERhdGUgPD0geW1kKCIyMDIwLTA0LTA0IikpIC0+IGRmX2NvbmZpcm1lZA0KDQpkZl9jb25maXJtZWQgJT4lIA0KICBtdXRhdGUoYmVmb3JlID0gbGFnKENvbmZpcm1lZCkpICU+JSANCiAgbXV0YXRlKE5ld0NvbmZpcm1lZCA9IENvbmZpcm1lZCAtIGJlZm9yZSkgJT4lIA0KICBzbGljZSgtMSkgLT4gZGZfZm9yX2cxDQoNCmVuZF9zdGFnZTEgPC0gZG15KCIxMy0wMi0yMDIwIikNCnN0YXJ0X3N0YWdlMiA8LSBkbXkoIjA2LTAzLTIwMjAiKQ0KZW5kX3N0YWdlMiA8LSBkbXkoIjIxLTAzLTIwMjAiKQ0KDQpkZl9mb3JfZzEgJT4lIA0KICBtdXRhdGUoU3RhZ2UgPSBjYXNlX3doZW4oRGF0ZSA8PSBlbmRfc3RhZ2UxIH4gIlN0YWdlIDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIERhdGUgPiBlbmRfc3RhZ2UxICYgRGF0ZSA8IHN0YXJ0X3N0YWdlMiB+ICJTdGFuZGJ5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBEYXRlID49IHN0YXJ0X3N0YWdlMiAmIERhdGUgPD0gZW5kX3N0YWdlMiB+ICJTdGFnZSAyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlN0YWdlIDMiKSkgLT4gZGYNCg0KZGYgJT4lIA0KICBzZWxlY3QoVG90YWxDb25maXJtZWQgPSBDb25maXJtZWQsIE5ld0NvbmZpcm1lZCwgRGF0ZSkgJT4lIA0KICBnYXRoZXIoVHlwZSwgVmFsdWUsIC1EYXRlKSAtPiBkZl9wbG90DQoNCmRmX3Bsb3QkRGF0ZSAlPiUgdW5pcXVlKCkgLT4gbXlfZGF0ZQ0KDQpkZl9sYWJlbHMgPC0gZGF0YS5mcmFtZShEYXRlID0gbXlfZGF0ZSkNCg0KZGZfbGFiZWxzICU+JSANCiAgbXV0YXRlKGxhYmVsX3ggPSBjYXNlX3doZW4oRGF0ZSA9PSBtaW4oRGF0ZSkgfiBhcy5jaGFyYWN0ZXIoRGF0ZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEYXRlID09IGVuZF9zdGFnZTEgfiBhcy5jaGFyYWN0ZXIoZW5kX3N0YWdlMSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEYXRlID09IHN0YXJ0X3N0YWdlMiB+IGFzLmNoYXJhY3RlcihzdGFydF9zdGFnZTIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZSA9PSBlbmRfc3RhZ2UyIH4gYXMuY2hhcmFjdGVyKGVuZF9zdGFnZTIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZSA9PSBtYXgoRGF0ZSkgfiBhcy5jaGFyYWN0ZXIoRGF0ZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIiIpKSAlPiUgDQogIG11dGF0ZShTdGFnZSA9IGNhc2Vfd2hlbihEYXRlIDw9IGVuZF9zdGFnZTEgfiAiU3RhZ2UgMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZSA+IGVuZF9zdGFnZTEgJiBEYXRlIDwgc3RhcnRfc3RhZ2UyIH4gIlN0YW5kYnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIERhdGUgPj0gc3RhcnRfc3RhZ2UyICYgRGF0ZSA8PSBlbmRfc3RhZ2UyIH4gIlN0YWdlIDIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiU3RhZ2UgMyIpKSAlPiUgDQogIG11dGF0ZShsYWJlbF94ID0gY2FzZV93aGVuKGxhYmVsX3ggPT0gIjIwMjAtMDEtMjMiIH4gIjIzLTAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3ggPT0gIjIwMjAtMDItMTMiIH4gIjEzLTAyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3ggPT0gIjIwMjAtMDMtMDYiIH4gIjA2LTAzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3ggPT0gIjIwMjAtMDMtMjEiIH4gIjIxLTAzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3ggPT0gIjIwMjAtMDQtMDQiIH4gIjA0LTA0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBsYWJlbF94KSkgLT4gZGZfbGFiZWxzDQoNCg0KDQpkZl9mb3JfZzEgJT4lIA0KICBmaWx0ZXIoRGF0ZSA9PSBtYXgoRGF0ZSkpICU+JSANCiAgbXV0YXRlKERhdGUgPSBEYXRlICsgMikgJT4lIA0KICBzZWxlY3QoVG90YWxDb25maXJtZWQgPSBDb25maXJtZWQsIE5ld0NvbmZpcm1lZCwgRGF0ZSkgJT4lIA0KICBnYXRoZXIoVHlwZSwgVmFsdWUsIC1EYXRlKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGNhc2Vfd2hlbihWYWx1ZSA9PSA0IH4gcGFzdGUwKFZhbHVlLCAiICAiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gYXMuY2hhcmFjdGVyKFZhbHVlKSkpIC0+IGRmX2FuIA0KDQoNCmZpbGxfY29sb3JzIDwtIGMoIiNmZmY1ZjAiLCAiI2ZjYmJhMSIsICIjZmM5MjcyIiwgIiNmYjZhNGEiKQ0KbGluZV9jb2xvcnMgPC0gYygiI2U0MWExYyIsICIjMWY3OGI0IikNCmggPC0gMjUwDQprIDwtIC0wLjUNCm15X2ZvbnQgPC0gIlVidW50dSBDb25kZW5zZWQiDQoNCmdncGxvdCgpICsgDQogIHRoZW1lX21pbmltYWwoKSArIA0KICBnZW9tX3JlY3QoYWVzKHhtaW4gPSBtaW4obXlfZGF0ZSksIHhtYXggPSBlbmRfc3RhZ2UxLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJTdGFnZSAxIiksIGZpbGwgPSAiI2ExZDk5YiIsIGFscGhhID0gMC4zLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBnZW9tX3JlY3QoYWVzKHhtaW4gPSBlbmRfc3RhZ2UxLCB4bWF4ID0gc3RhcnRfc3RhZ2UyLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJTdGFuZGJ5IiksIGZpbGwgPSBmaWxsX2NvbG9yc1syXSwgYWxwaGEgPSAwLjMsIHNob3cubGVnZW5kID0gRkFMU0UpICsgDQogIGdlb21fcmVjdChhZXMoeG1pbiA9IHN0YXJ0X3N0YWdlMiwgeG1heCA9IGVuZF9zdGFnZTIsIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBmaWxsID0gIlN0YWdlIDIiKSwgZmlsbCA9IGZpbGxfY29sb3JzWzNdLCBhbHBoYSA9IDAuMywgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyANCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0gZW5kX3N0YWdlMiwgeG1heCA9IG1heChteV9kYXRlKSwgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsIGZpbGwgPSAiU3RhZ2UgMyIpLCBmaWxsID0gZmlsbF9jb2xvcnNbNF0sIGFscGhhID0gMC4zLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBnZW9tX2xpbmUoZGF0YSA9IGRmX3Bsb3QsIGFlcyhEYXRlLCBWYWx1ZSwgY29sb3IgPSBUeXBlKSwgc2l6ZSA9IDEuNSkgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGxpbmVfY29sb3JzLCBuYW1lID0gIiIsIGxhYmVscyA9IGMoIk5ldyIsICJUb3RhbCIpKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDI1MCwgMjUpLCBsaW1pdHMgPSBjKDAsIDI1MCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsgDQogIHNjYWxlX3hfZGF0ZShsaW1pdHMgPSBjKG1pbihteV9kYXRlKSwgbWF4KG15X2RhdGUpICsgMyksIGJyZWFrcyA9IHNlcShtaW4obXlfZGF0ZSksIG1heChteV9kYXRlKSwgMSksIA0KICAgICAgICAgICAgICAgbGFiZWxzID0gZGZfbGFiZWxzJGxhYmVsX3gsIHBvc2l0aW9uID0gInRvcCIsIGV4cGFuZCA9IGMoMCwgMCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICBnZW9tX3RleHQoZGF0YSA9IGRmX2FuLCBhZXMoRGF0ZSwgVmFsdWUsIGxhYmVsID0gbGFiZWwpLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvciA9IGxpbmVfY29sb3JzWzI6MV0sIHNpemUgPSA0LjUsIA0KICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC42LCBmYW1pbHkgPSBteV9mb250KSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCANCiAgICAgICB0aXRsZSA9ICJGaWd1cmUgMTogQ29yb25hdmlydXMgY2FzZXMgaW4gVmlldG5hbSwgYXMgb2YgMDQtMDQtMjAyMCIsIA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBNaW5pc3RyeSBvZiBIZWFsdGggb2YgVmlldG5hbSIpICsgDQogIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZShEYXRlID0geW1kKCIyMDIwLTAxLTIzIikgKyAxMCwgVmFsdWUgPSBoKSwgYWVzKERhdGUsIFZhbHVlKSwgbGFiZWwgPSAiU3RhZ2UgMSIsIHNpemUgPSA0LCB2anVzdCA9IGssIGZhbWlseSA9IG15X2ZvbnQpICsgDQogIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZShEYXRlID0geW1kKCIyMDIwLTAyLTEzIikgKyAxMSwgVmFsdWUgPSBoKSwgYWVzKERhdGUsIFZhbHVlKSwgbGFiZWwgPSAiU3RhbmRieSIsIHNpemUgPSA0LCB2anVzdCA9IGssIGZhbWlseSA9IG15X2ZvbnQpICsgDQogIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZShEYXRlID0geW1kKCIyMDIwLTAzLTA2IikgKyA3LCBWYWx1ZSA9IGgpLCBhZXMoRGF0ZSwgVmFsdWUpLCBsYWJlbCA9ICJTdGFnZSAyIiwgc2l6ZSA9IDQsIHZqdXN0ID0gaywgZmFtaWx5ID0gbXlfZm9udCkgKyANCiAgZ2VvbV90ZXh0KGRhdGEgPSBkYXRhLmZyYW1lKERhdGUgPSB5bWQoIjIwMjAtMDMtMjEiKSArIDcsIFZhbHVlID0gaCksIGFlcyhEYXRlLCBWYWx1ZSksIGxhYmVsID0gIlN0YWdlIDMiLCBzaXplID0gNCwgdmp1c3QgPSBrLCBmYW1pbHkgPSBteV9mb250KSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhbWlseSA9IG15X2ZvbnQpKSArIA0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhbWlseSA9IG15X2ZvbnQpKSArIA0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygxLCAxLCAxLCAxKSwgImNtIikpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDIwKSkgKyANCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxMCwgY29sb3IgPSAiZ3JleTMwIikpICsgDQogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiZ3JleTMwIikpDQoNCmBgYA0KDQoNCg0KDQoNCg==