Motivations

Báo cáo CPI2018 khá đẹp nhưng vẫn còn vài thiếu sót như không nhất quán trong trình bày, lúc thì thừa lúc thì thiếu và sử dụng màu sắc, legend không tốt. Chúng ta có thể cải tiến, ví dụ, Bar Plot ở trang 26 của báo cáo này.

R Codes

# Reference: http://pci2018.pcivietnam.vn/uploads/2019/ho-so-63-tinh-vie.pdf
# Data Source: http://pci2018.pcivietnam.vn/


# cpi_colors <- c("#892890", "#034EA2", "#4792CF", "#8ED8F8", "#BAE1D1")

rm(list = ls())

library(viridis)
library(tidyverse)
library(readxl)
library(extrafont)

df_cpi <- read_excel("C:\\Users\\Zbook\\Downloads\\du-lieu-pci-2018.xlsx", sheet = 1) %>% 
  select(1:3) %>% 
  slice(1:63)

names(df_cpi) <- c("Province", "Rank", "Score")



df_cpi %>% 
  mutate(Province = case_when(str_detect(Province, "BRVT") ~ "Bà Rịa - Vũng Tàu", TRUE ~ Province)) %>% 
  mutate(fake_rank = case_when(Rank < 10 ~ paste0("0", Rank), TRUE ~ as.character(Rank))) %>% 
  mutate(Province = paste(Province, fake_rank)) %>% 
  mutate(my_colors = case_when(Rank <= 2 ~ "Excellent", 
                               Rank >= 3 & Rank <= 9 ~ "Good", 
                               Rank >= 10 & Rank <= 41 ~ "Fair", 
                               Rank >= 42 & Rank <= 61 ~ "Mediocre", 
                               TRUE ~ "Poor")) %>% 
  arrange(-Rank) %>% 
  mutate(Province = factor(Province, levels = Province)) %>% 
  mutate(my_colors = factor(my_colors, levels = my_colors %>% unique() %>% .[5:1])) %>% 
  mutate(label = round(Score, 2) %>% as.character()) %>% 
  mutate(label = case_when(str_count(label) == 2 ~ paste0(label, ".00"), 
                           str_count(label) == 4 ~ paste0(label, "0"), 
                           TRUE ~ label)) -> df_ploting2


#-------------
#  Bar Plot 
#-------------


my_font <- "Roboto Condensed"

df_ploting2 %>% 
  ggplot(aes(Province, Score, fill = my_colors)) + 
  geom_col(width = 0.85) + 
  coord_flip() + 
  scale_fill_viridis(discrete = TRUE, name = "", option = "D") + 
  geom_text(aes(label = label), size = 3, hjust = -0.1) + 
  scale_y_continuous(limits = c(0, 80), expand = c(0.001, 0)) +
  theme_minimal() + 
  theme(panel.grid = element_blank()) + 
  theme(axis.text.x = element_blank()) + 
  theme(axis.text.y = element_text(size = 8, family = my_font, color = "black")) +
  theme(plot.title = element_text(family = my_font, color = "grey20", size = 22, face = "bold")) + 
  theme(plot.subtitle = element_text(family = my_font, size = 13, color = "gray40")) + 
  theme(plot.caption = element_text(family = my_font, size = 11, colour = "grey40", face = "italic")) + 
  theme(legend.text = element_text(family = my_font, size = 10)) + 
  theme(plot.margin = unit(c(1, 1, 1, 2), "cm")) +
  labs(x = NULL, y = NULL, 
       title = "Vietnam CPI Index 2018", 
       subtitle = "R Used for Data Visualization", 
       caption = "Data Source: http://pci2018.pcivietnam.vn") -> p1

#--------------
#  Mapping
#--------------


# Get geospatial data for Viet Nam: 

library(raster)
vietnam_province <- getData("GADM", country = "Vietnam", level = 1)

detach(package:raster)
vietnam_df <- vietnam_province %>% fortify(region = "NAME_1")


library(stringi)

vietnam_df %>% 
  mutate(id_prov = stri_trans_general(id, "Latin-ASCII")) %>% 
  mutate(id_prov = case_when(str_detect(id_prov, "Ba Ria") ~ "BRVT", 
                             str_detect(id_prov, "Ho Chi Minh") ~ "TP.HCM", 
                             str_detect(id_prov, "Thua Thien Hue") ~ "TT-Hue", 
                             TRUE ~ id_prov)) -> vietnam_df

df_cpi %>% 
  mutate(id_prov = stri_trans_general(Province, "Latin-ASCII")) -> df_cpi


# Joint data sets: 

df_cpi_mapping <- right_join(vietnam_df, df_cpi, by = "id_prov")

# Function creates new theme: 



ggplot() + 
  geom_polygon(data = df_cpi_mapping, aes(long, lat, group = group, fill = Score), color = "white") +
  coord_map("albers", lat0 = 30, lat1 = 40) + 
  labs(title = "Vietnam CPI Index 2018",
       subtitle = "Vietnam's Paracel and Spratly Islands\nare not shown in this map.",
       caption = "Data Source: http://pci2018.pcivietnam.vn") + 
  theme(axis.line = element_blank(),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.grid = element_blank(),
        plot.background = element_rect(fill = "white", color = NA),
        panel.background = element_rect(fill = "white", color = NA),
        legend.background = element_rect(fill = "white", color = NA),
        panel.border = element_blank()) +
  theme(plot.title = element_text(family = my_font, color = "grey20", size = 22, face = "bold")) + 
  theme(plot.subtitle = element_text(family = my_font, size = 13, color = "gray40")) + 
  theme(plot.caption = element_text(family = my_font, size = 11, colour = "grey40", face = "italic")) + 
  theme(legend.text = element_text(family = my_font, color = "grey40", size = 12)) + 
  theme(legend.title = element_text(family = my_font, color = "grey20", size = 12)) + 
  theme(plot.margin = unit(c(1, 1, 1, 1), "cm")) + 
  # theme(legend.position = "top") + 
  theme(legend.position = c(0.3, 0.5)) + 
  scale_fill_viridis(direction = -1, 
                     option = "D", 
                     name = "CPI Index", 
                     guide = guide_colourbar(direction = "horizontal",
                                             barheight = unit(3, units = "mm"),
                                             barwidth = unit(40, units = "mm"),
                                             title.hjust = 0.5,
                                             label.hjust = 0.5, 
                                             title.position = "top")) -> p2


gridExtra::grid.arrange(p2, p1, ncol = 2)

LS0tDQp0aXRsZTogIk1hcHBpbmcgVmlldG5hbSBQcm92aW5jaWFsIENvbXBldGl0aXZlbmVzcyBJbmRleCAyMDE4Ig0KYXV0aG9yOiAiTmd1eWVuIENoaSBEdW5nIg0Kc3VidGl0bGU6ICJEYWlseSBHcmFwaCBTZXJpZXMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcucmV0aW5hPTIpDQpgYGANCg0KIyBNb3RpdmF0aW9ucw0KDQpCw6FvIGPDoW8gW0NQSTIwMThdKGh0dHA6Ly9wY2kyMDE4LnBjaXZpZXRuYW0udm4vdXBsb2Fkcy8yMDE5L2hvLXNvLTYzLXRpbmgtdmllLnBkZikga2jDoSDEkeG6uXAgbmjGsG5nIHbhuqtuIGPDsm4gdsOgaSB0aGnhur91IHPDs3QgbmjGsCBraMO0bmcgbmjhuqV0IHF1w6FuIHRyb25nIHRyw6xuaCBiw6B5LCBsw7pjIHRow6wgdGjhu6thIGzDumMgdGjDrCB0aGnhur91IHbDoCBz4butIGThu6VuZyBtw6B1IHPhuq9jLCBsZWdlbmQga2jDtG5nIHThu5F0LiBDaMO6bmcgdGEgY8OzIHRo4buDIGPhuqNpIHRp4bq/biwgdsOtIGThu6UsIEJhciBQbG90IOG7nyB0cmFuZyAyNiBj4bunYSBiw6FvIGPDoW8gbsOgeS4gDQoNCiMgUiBDb2Rlcw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KDQoNCiMgUmVmZXJlbmNlOiBodHRwOi8vcGNpMjAxOC5wY2l2aWV0bmFtLnZuL3VwbG9hZHMvMjAxOS9oby1zby02My10aW5oLXZpZS5wZGYNCiMgRGF0YSBTb3VyY2U6IGh0dHA6Ly9wY2kyMDE4LnBjaXZpZXRuYW0udm4vDQoNCg0KIyBjcGlfY29sb3JzIDwtIGMoIiM4OTI4OTAiLCAiIzAzNEVBMiIsICIjNDc5MkNGIiwgIiM4RUQ4RjgiLCAiI0JBRTFEMSIpDQoNCnJtKGxpc3QgPSBscygpKQ0KDQpsaWJyYXJ5KHZpcmlkaXMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShleHRyYWZvbnQpDQoNCmRmX2NwaSA8LSByZWFkX2V4Y2VsKCJDOlxcVXNlcnNcXFpib29rXFxEb3dubG9hZHNcXGR1LWxpZXUtcGNpLTIwMTgueGxzeCIsIHNoZWV0ID0gMSkgJT4lIA0KICBzZWxlY3QoMTozKSAlPiUgDQogIHNsaWNlKDE6NjMpDQoNCm5hbWVzKGRmX2NwaSkgPC0gYygiUHJvdmluY2UiLCAiUmFuayIsICJTY29yZSIpDQoNCg0KDQpkZl9jcGkgJT4lIA0KICBtdXRhdGUoUHJvdmluY2UgPSBjYXNlX3doZW4oc3RyX2RldGVjdChQcm92aW5jZSwgIkJSVlQiKSB+ICJCw6AgUuG7i2EgLSBWxaluZyBUw6B1IiwgVFJVRSB+IFByb3ZpbmNlKSkgJT4lIA0KICBtdXRhdGUoZmFrZV9yYW5rID0gY2FzZV93aGVuKFJhbmsgPCAxMCB+IHBhc3RlMCgiMCIsIFJhbmspLCBUUlVFIH4gYXMuY2hhcmFjdGVyKFJhbmspKSkgJT4lIA0KICBtdXRhdGUoUHJvdmluY2UgPSBwYXN0ZShQcm92aW5jZSwgZmFrZV9yYW5rKSkgJT4lIA0KICBtdXRhdGUobXlfY29sb3JzID0gY2FzZV93aGVuKFJhbmsgPD0gMiB+ICJFeGNlbGxlbnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSYW5rID49IDMgJiBSYW5rIDw9IDkgfiAiR29vZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJhbmsgPj0gMTAgJiBSYW5rIDw9IDQxIH4gIkZhaXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSYW5rID49IDQyICYgUmFuayA8PSA2MSB+ICJNZWRpb2NyZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiUG9vciIpKSAlPiUgDQogIGFycmFuZ2UoLVJhbmspICU+JSANCiAgbXV0YXRlKFByb3ZpbmNlID0gZmFjdG9yKFByb3ZpbmNlLCBsZXZlbHMgPSBQcm92aW5jZSkpICU+JSANCiAgbXV0YXRlKG15X2NvbG9ycyA9IGZhY3RvcihteV9jb2xvcnMsIGxldmVscyA9IG15X2NvbG9ycyAlPiUgdW5pcXVlKCkgJT4lIC5bNToxXSkpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gcm91bmQoU2NvcmUsIDIpICU+JSBhcy5jaGFyYWN0ZXIoKSkgJT4lIA0KICBtdXRhdGUobGFiZWwgPSBjYXNlX3doZW4oc3RyX2NvdW50KGxhYmVsKSA9PSAyIH4gcGFzdGUwKGxhYmVsLCAiLjAwIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2NvdW50KGxhYmVsKSA9PSA0IH4gcGFzdGUwKGxhYmVsLCAiMCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBsYWJlbCkpIC0+IGRmX3Bsb3RpbmcyDQoNCg0KIy0tLS0tLS0tLS0tLS0NCiMgIEJhciBQbG90IA0KIy0tLS0tLS0tLS0tLS0NCg0KDQpteV9mb250IDwtICJSb2JvdG8gQ29uZGVuc2VkIg0KDQpkZl9wbG90aW5nMiAlPiUgDQogIGdncGxvdChhZXMoUHJvdmluY2UsIFNjb3JlLCBmaWxsID0gbXlfY29sb3JzKSkgKyANCiAgZ2VvbV9jb2wod2lkdGggPSAwLjg1KSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSwgbmFtZSA9ICIiLCBvcHRpb24gPSAiRCIpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBsYWJlbCksIHNpemUgPSAzLCBoanVzdCA9IC0wLjEpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDgwKSwgZXhwYW5kID0gYygwLjAwMSwgMCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgZmFtaWx5ID0gbXlfZm9udCwgY29sb3IgPSAiYmxhY2siKSkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIGNvbG9yID0gImdyZXkyMCIsIHNpemUgPSAyMiwgZmFjZSA9ICJib2xkIikpICsgDQogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDEzLCBjb2xvciA9ICJncmF5NDAiKSkgKyANCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxMSwgY29sb3VyID0gImdyZXk0MCIsIGZhY2UgPSAiaXRhbGljIikpICsgDQogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxMCkpICsgDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDEsIDEsIDEsIDIpLCAiY20iKSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiVmlldG5hbSBDUEkgSW5kZXggMjAxOCIsIA0KICAgICAgIHN1YnRpdGxlID0gIlIgVXNlZCBmb3IgRGF0YSBWaXN1YWxpemF0aW9uIiwgDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3BjaTIwMTgucGNpdmlldG5hbS52biIpIC0+IHAxDQoNCiMtLS0tLS0tLS0tLS0tLQ0KIyAgTWFwcGluZw0KIy0tLS0tLS0tLS0tLS0tDQoNCg0KIyBHZXQgZ2Vvc3BhdGlhbCBkYXRhIGZvciBWaWV0IE5hbTogDQoNCmxpYnJhcnkocmFzdGVyKQ0KdmlldG5hbV9wcm92aW5jZSA8LSBnZXREYXRhKCJHQURNIiwgY291bnRyeSA9ICJWaWV0bmFtIiwgbGV2ZWwgPSAxKQ0KDQpkZXRhY2gocGFja2FnZTpyYXN0ZXIpDQp2aWV0bmFtX2RmIDwtIHZpZXRuYW1fcHJvdmluY2UgJT4lIGZvcnRpZnkocmVnaW9uID0gIk5BTUVfMSIpDQoNCg0KbGlicmFyeShzdHJpbmdpKQ0KDQp2aWV0bmFtX2RmICU+JSANCiAgbXV0YXRlKGlkX3Byb3YgPSBzdHJpX3RyYW5zX2dlbmVyYWwoaWQsICJMYXRpbi1BU0NJSSIpKSAlPiUgDQogIG11dGF0ZShpZF9wcm92ID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoaWRfcHJvdiwgIkJhIFJpYSIpIH4gIkJSVlQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChpZF9wcm92LCAiSG8gQ2hpIE1pbmgiKSB+ICJUUC5IQ00iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChpZF9wcm92LCAiVGh1YSBUaGllbiBIdWUiKSB+ICJUVC1IdWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGlkX3Byb3YpKSAtPiB2aWV0bmFtX2RmDQoNCmRmX2NwaSAlPiUgDQogIG11dGF0ZShpZF9wcm92ID0gc3RyaV90cmFuc19nZW5lcmFsKFByb3ZpbmNlLCAiTGF0aW4tQVNDSUkiKSkgLT4gZGZfY3BpDQoNCg0KIyBKb2ludCBkYXRhIHNldHM6IA0KDQpkZl9jcGlfbWFwcGluZyA8LSByaWdodF9qb2luKHZpZXRuYW1fZGYsIGRmX2NwaSwgYnkgPSAiaWRfcHJvdiIpDQoNCiMgRnVuY3Rpb24gY3JlYXRlcyBuZXcgdGhlbWU6IA0KDQoNCg0KZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBkZl9jcGlfbWFwcGluZywgYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IFNjb3JlKSwgY29sb3IgPSAid2hpdGUiKSArDQogIGNvb3JkX21hcCgiYWxiZXJzIiwgbGF0MCA9IDMwLCBsYXQxID0gNDApICsgDQogIGxhYnModGl0bGUgPSAiVmlldG5hbSBDUEkgSW5kZXggMjAxOCIsDQogICAgICAgc3VidGl0bGUgPSAiVmlldG5hbSdzIFBhcmFjZWwgYW5kIFNwcmF0bHkgSXNsYW5kc1xuYXJlIG5vdCBzaG93biBpbiB0aGlzIG1hcC4iLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IGh0dHA6Ly9wY2kyMDE4LnBjaXZpZXRuYW0udm4iKSArIA0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3IgPSBOQSksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpLA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3IgPSBOQSksDQogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIGNvbG9yID0gImdyZXkyMCIsIHNpemUgPSAyMiwgZmFjZSA9ICJib2xkIikpICsgDQogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDEzLCBjb2xvciA9ICJncmF5NDAiKSkgKyANCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxMSwgY29sb3VyID0gImdyZXk0MCIsIGZhY2UgPSAiaXRhbGljIikpICsgDQogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIGNvbG9yID0gImdyZXk0MCIsIHNpemUgPSAxMikpICsgDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBteV9mb250LCBjb2xvciA9ICJncmV5MjAiLCBzaXplID0gMTIpKSArIA0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygxLCAxLCAxLCAxKSwgImNtIikpICsgDQogICMgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4zLCAwLjUpKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlyZWN0aW9uID0gLTEsIA0KICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkQiLCANCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ1BJIEluZGV4IiwgDQogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG91cmJhcihkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJoZWlnaHQgPSB1bml0KDMsIHVuaXRzID0gIm1tIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IHVuaXQoNDAsIHVuaXRzID0gIm1tIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5oanVzdCA9IDAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLmhqdXN0ID0gMC41LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnBvc2l0aW9uID0gInRvcCIpKSAtPiBwMg0KDQoNCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHAyLCBwMSwgbmNvbCA9IDIpDQpgYGANCg0KDQohW10oQzpcXFVzZXJzXFxaYm9va1xcRGVza3RvcFxccGljXFxtYXBfY3BpLmpwZyk=