Visualization

Data processing

# 1. load packages -----
pacman::p_load(
   data.table,
   collapse,
   sf,
   terra,
   ggplot2,
   ggrepel,
   ggpp,
   ggpubr,
   grid,
   gridExtra
)

# 2. Data processing -----
## 2.1 Import data -----
## 2.1.1 Vietnam provinces data -----
"d:/R/rpubs_project/visualization/map_co2-emission_VN_2022/00_raw_data/gadm/gadm41_VNM_1.shx" |> 
   st_read() |> as.data.table() -> province

## 2.1.2 Vietnam population by province -----
"d:/R/rpubs_project/visualization/map_co2-emission_VN_2022/00_raw_data/pop/pop_22.xlsx" |> 
   readxl::read_xlsx() |> 
   as.data.table() |> 
   province[i = _, on = .(VARNAME_1 == province)] -> 
   province

## 2.1.3 CO2 emission -----
"d:/R/rpubs_project/visualization/map_co2-emission_VN_2022/00_raw_data/co2/v8.0_FT2022_GHG_CO2_2022_TOTALS_emi.nc" |> 
   rast() -> co2_sp

## 2.2 Finalize dataset -----
# set crs of co2 matching province
st_crs(province$geometry) # EPSG: 4326
crs(co2_sp) <- "epsg:4326"

# Extract co2 data for each province by summation
exactextractr::exact_extract(co2_sp, province$geometry, "sum") -> province$co2_sum

# Calculate CO2 per capita
province[, co2_pc := co2_sum / (pop * 1000)][]

show_save <- function(plot){
   ggsave("d:/R/rpubs_project/visualization/map_co2-emission_VN_2022/03_plots/co2_map.png", plot = plot, height = 9, width = 8, dpi = 300,
          device = ragg::agg_png())
   file.show("d:/R/rpubs_project/visualization/map_co2-emission_VN_2022/03_plots/co2_map.png")
}

# 3. Visualization -----
## 3.1 Setup -----

# Color palette
cols <- hcl.colors(6, "Inferno", rev = T)[1:4]
pal <- colorRampPalette(cols)(64)

province |> st_as_sf() |> 
   sbt(co2_pc > 8, VARNAME_1) |> 
   st_centroid() |> 
   (
      \(.) data.table(.$VARNAME_1, st_coordinates(.))
   )() |> setnames(new = .c(province, x, y)) -> top5_co2_max

province |> as.data.table() |> 
   _[, top_co2_pc_max := 
        fcase(co2_pc > 8, VARNAME_1,
              co2_pc < 8, "")][] -> 
   province

province |> as.data.table() |> 
   _[, top_co2_sum_max := 
        fcase(co2_sum > 14 * 10^6, VARNAME_1,
              co2_sum < 14 * 10^6, "")][] -> 
   province

province |> tfm(co2_sum_mil = co2_sum / 10^6) -> province

province |> st_as_sf() -> province

## 3.2 Mapping -----

### 3.2.1 CO2 emission per capita by province -----



province |> 
   ggplot() +
      geom_sf(
         aes(fill = co2_pc),
         color = "white",
         size = .15
      ) +
      scale_fill_gradientn(
         name = "",
         colors = pal
         # limits = c(0, 35),
         # breaks = seq(5, 35, 5),
         # labels = c("<5", "5-10", "10-15", "15-20", "20-25", "25-30", ">30"),
         # guide = guide_colorbar(
         #    barheight = 9,
         #    barwidth = 1
         # )
      ) +
      geom_text_repel(aes(label = top_co2_pc_max,
                          geometry = geometry),
                      stat = "sf_coordinates",
                      min.segment.length = 0,
                      nudge_x = 1.5,
                      color = "gray20",     # text color
                      segment.color = "gray30",
                      family = "Merriweather Sans",
                      size = 3.3
                      ) +
      # labs(title = "Per capita CO₂ emissions by province, 2022") +
      labs(caption = "Per capita by province (tons)") +
      theme_void() +
      theme(
         legend.position = c(.2, .5),
         legend.text = element_text(
            color = "gray20",
            vjust = 1.5, size = 10,
            family = "Work Sans"
         ),
         plot.margin = unit(c(
            t = 1, b = 0, l = 0, r = 0
         ), "lines"),
         plot.caption = element_text(
            family =  "Merriweather Sans",
            size = 16, hjust = .5
         )
      ) -> p1

### 3.2.2 CO2 emission by province -----
province |> 
      ggplot() +
      geom_sf(
         aes(fill = co2_sum_mil),
         color = "white",
         size = .15
      ) +
      scale_fill_gradientn(
         name = "",
         colors = pal,
         limits = c(0, 45),
         breaks = seq(5, 45, 5),
         # labels = c("<5", "5-10", "10-15", "15-20", "20-25", "25-30", "30-35", "35-40", ">40"),
         guide = guide_colorbar(
            barheight = .5,
            barwidth = 38
         )
      ) +
      geom_text_repel(aes(label = top_co2_sum_max,
                          geometry = geometry),
                      stat = "sf_coordinates",
                      min.segment.length = 0,
                      nudge_x = 1.5,
                      color = "gray20",     # text color
                      segment.color = "gray30",
                      family = "Merriweather Sans",
                      size = 3.3
      ) +
      labs(captions = "Total by province (mil. tons)") +
      theme_void() +
      theme(
         legend.position = "bottom",
         legend.text = element_text(
            color = "gray20",
            size = 13,
            family = "Work Sans",
            hjust = 1
         ), legend.ticks = element_line(
            linewidth = 2,
            colour = "white"),
         plot.margin = unit(c(
            t = 1, b = 0, l = 0, r = 0
         ), "lines"),
         plot.caption = element_text(
            family =  "Merriweather Sans",
            size = 16, hjust =.5
         )
      ) -> p2

share_leg <- get_legend(p2)



ggarrange(
   p2 + theme(legend.position = "none",
              plot.title = element_blank()),
   p1 + theme(legend.position = "none",
              plot.title = element_blank()),
   nrow = 1
   # legend.grob = share_leg,
   # legend = 'bottom'
) |> ggarrange(
      ..1 = text_grob(
         label = "CO2 emission in Vietnam, 2022",
         family = "Merriweather Sans ExtraBold",
         face = "bold",
         size = 30, just = "left", x = .04,
         color = "gray20") |> 
         as_ggplot(),
      ..2 = text_grob(
         label = "Top 5 provinces that produced the most CO2 indicated at each plot", 
         size = 16, just = "left", x = .04, 
         color = "gray30", y = .6,
         family = "Merriweather Sans"
      ),
      ..3 = _, 
      ..4 = as_ggplot(share_leg),
      nrow = 4,
      heights = c(.075, .035, .83, .07)
   ) |> grid.arrange(
      bottom = textGrob(
         "By: Duy Khanh",
         gp = gpar(family = "Libre Baskerville", 
                   fontsize = 12),
         x = .98,
         y = .5,
         just = "right"
      )
   ) |> as_ggplot() +
   annotation_custom(
      rectGrob(gp = gpar(fill = "firebrick")),
      xmin = 0, xmax = .02,
      ymin = .905, ymax = .98
   ) -> my_map
show_save(my_map)
LS0tDQp0aXRsZTogIkNPMiBlbWlzc2lvbiBpbiBWaWV0bmFtIg0KYXV0aG9yOiAiRHV5IEtoYW5oIg0KZGF0ZTogIjIwMjQtMDItMjAiDQpvdXRwdXQ6IA0KICAgaHRtbF9kb2N1bWVudDoNCiAgICAgIHRvYzogdHJ1ZQ0KICAgICAgIyB0b2NfZGVwdGg6IDINCiAgICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgICAgIyAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICAjICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICAgICMgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICB0aGVtZTogdW5pdGVkDQogICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRn0NCi5jb2RlX2NodW5rX2JnX2NvbG9yIHsNCiAgIGJhY2tncm91bmQtY29sb3I6IGJsYWNrOw0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICAgZWNobyA9IFQsDQogICByZXN1bHRzID0gRiwNCiAgIGVycm9yID0gRiwNCiAgIHdhcm5pbmcgPSBGLA0KICAgbWVzc2FnZSA9IEYsDQogICBldmFsID0gRg0KICAgIyBjbGFzcy5zb3VyY2UgPSAiY29kZV9jaHVua19iZ19jb2xvciIsDQogICAjIGNsYXNzLm91dHB1dCA9ICJiZy1wcmltYXJ5Ig0KICAgKQ0KYGBgDQoNCiMgVmlzdWFsaXphdGlvbg0KDQohW10oaW1hZ2VzL2NvMl9tYXAucG5nKQ0KDQojIERhdGEgcHJvY2Vzc2luZw0KDQpgYGB7cn0NCiMgMS4gbG9hZCBwYWNrYWdlcyAtLS0tLQ0KcGFjbWFuOjpwX2xvYWQoDQogICBkYXRhLnRhYmxlLA0KICAgY29sbGFwc2UsDQogICBzZiwNCiAgIHRlcnJhLA0KICAgZ2dwbG90MiwNCiAgIGdncmVwZWwsDQogICBnZ3BwLA0KICAgZ2dwdWJyLA0KICAgZ3JpZCwNCiAgIGdyaWRFeHRyYQ0KKQ0KDQojIDIuIERhdGEgcHJvY2Vzc2luZyAtLS0tLQ0KIyMgMi4xIEltcG9ydCBkYXRhIC0tLS0tDQojIyAyLjEuMSBWaWV0bmFtIHByb3ZpbmNlcyBkYXRhIC0tLS0tDQoiZDovUi9ycHVic19wcm9qZWN0L3Zpc3VhbGl6YXRpb24vbWFwX2NvMi1lbWlzc2lvbl9WTl8yMDIyLzAwX3Jhd19kYXRhL2dhZG0vZ2FkbTQxX1ZOTV8xLnNoeCIgfD4gDQogICBzdF9yZWFkKCkgfD4gYXMuZGF0YS50YWJsZSgpIC0+IHByb3ZpbmNlDQoNCiMjIDIuMS4yIFZpZXRuYW0gcG9wdWxhdGlvbiBieSBwcm92aW5jZSAtLS0tLQ0KImQ6L1IvcnB1YnNfcHJvamVjdC92aXN1YWxpemF0aW9uL21hcF9jbzItZW1pc3Npb25fVk5fMjAyMi8wMF9yYXdfZGF0YS9wb3AvcG9wXzIyLnhsc3giIHw+IA0KICAgcmVhZHhsOjpyZWFkX3hsc3goKSB8PiANCiAgIGFzLmRhdGEudGFibGUoKSB8PiANCiAgIHByb3ZpbmNlW2kgPSBfLCBvbiA9IC4oVkFSTkFNRV8xID09IHByb3ZpbmNlKV0gLT4gDQogICBwcm92aW5jZQ0KDQojIyAyLjEuMyBDTzIgZW1pc3Npb24gLS0tLS0NCiJkOi9SL3JwdWJzX3Byb2plY3QvdmlzdWFsaXphdGlvbi9tYXBfY28yLWVtaXNzaW9uX1ZOXzIwMjIvMDBfcmF3X2RhdGEvY28yL3Y4LjBfRlQyMDIyX0dIR19DTzJfMjAyMl9UT1RBTFNfZW1pLm5jIiB8PiANCiAgIHJhc3QoKSAtPiBjbzJfc3ANCg0KIyMgMi4yIEZpbmFsaXplIGRhdGFzZXQgLS0tLS0NCiMgc2V0IGNycyBvZiBjbzIgbWF0Y2hpbmcgcHJvdmluY2UNCnN0X2Nycyhwcm92aW5jZSRnZW9tZXRyeSkgIyBFUFNHOiA0MzI2DQpjcnMoY28yX3NwKSA8LSAiZXBzZzo0MzI2Ig0KDQojIEV4dHJhY3QgY28yIGRhdGEgZm9yIGVhY2ggcHJvdmluY2UgYnkgc3VtbWF0aW9uDQpleGFjdGV4dHJhY3RyOjpleGFjdF9leHRyYWN0KGNvMl9zcCwgcHJvdmluY2UkZ2VvbWV0cnksICJzdW0iKSAtPiBwcm92aW5jZSRjbzJfc3VtDQoNCiMgQ2FsY3VsYXRlIENPMiBwZXIgY2FwaXRhDQpwcm92aW5jZVssIGNvMl9wYyA6PSBjbzJfc3VtIC8gKHBvcCAqIDEwMDApXVtdDQoNCnNob3dfc2F2ZSA8LSBmdW5jdGlvbihwbG90KXsNCiAgIGdnc2F2ZSgiZDovUi9ycHVic19wcm9qZWN0L3Zpc3VhbGl6YXRpb24vbWFwX2NvMi1lbWlzc2lvbl9WTl8yMDIyLzAzX3Bsb3RzL2NvMl9tYXAucG5nIiwgcGxvdCA9IHBsb3QsIGhlaWdodCA9IDksIHdpZHRoID0gOCwgZHBpID0gMzAwLA0KICAgICAgICAgIGRldmljZSA9IHJhZ2c6OmFnZ19wbmcoKSkNCiAgIGZpbGUuc2hvdygiZDovUi9ycHVic19wcm9qZWN0L3Zpc3VhbGl6YXRpb24vbWFwX2NvMi1lbWlzc2lvbl9WTl8yMDIyLzAzX3Bsb3RzL2NvMl9tYXAucG5nIikNCn0NCg0KIyAzLiBWaXN1YWxpemF0aW9uIC0tLS0tDQojIyAzLjEgU2V0dXAgLS0tLS0NCg0KIyBDb2xvciBwYWxldHRlDQpjb2xzIDwtIGhjbC5jb2xvcnMoNiwgIkluZmVybm8iLCByZXYgPSBUKVsxOjRdDQpwYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xzKSg2NCkNCg0KcHJvdmluY2UgfD4gc3RfYXNfc2YoKSB8PiANCiAgIHNidChjbzJfcGMgPiA4LCBWQVJOQU1FXzEpIHw+IA0KICAgc3RfY2VudHJvaWQoKSB8PiANCiAgICgNCiAgICAgIFwoLikgZGF0YS50YWJsZSguJFZBUk5BTUVfMSwgc3RfY29vcmRpbmF0ZXMoLikpDQogICApKCkgfD4gc2V0bmFtZXMobmV3ID0gLmMocHJvdmluY2UsIHgsIHkpKSAtPiB0b3A1X2NvMl9tYXgNCg0KcHJvdmluY2UgfD4gYXMuZGF0YS50YWJsZSgpIHw+IA0KICAgX1ssIHRvcF9jbzJfcGNfbWF4IDo9IA0KICAgICAgICBmY2FzZShjbzJfcGMgPiA4LCBWQVJOQU1FXzEsDQogICAgICAgICAgICAgIGNvMl9wYyA8IDgsICIiKV1bXSAtPiANCiAgIHByb3ZpbmNlDQoNCnByb3ZpbmNlIHw+IGFzLmRhdGEudGFibGUoKSB8PiANCiAgIF9bLCB0b3BfY28yX3N1bV9tYXggOj0gDQogICAgICAgIGZjYXNlKGNvMl9zdW0gPiAxNCAqIDEwXjYsIFZBUk5BTUVfMSwNCiAgICAgICAgICAgICAgY28yX3N1bSA8IDE0ICogMTBeNiwgIiIpXVtdIC0+IA0KICAgcHJvdmluY2UNCg0KcHJvdmluY2UgfD4gdGZtKGNvMl9zdW1fbWlsID0gY28yX3N1bSAvIDEwXjYpIC0+IHByb3ZpbmNlDQoNCnByb3ZpbmNlIHw+IHN0X2FzX3NmKCkgLT4gcHJvdmluY2UNCg0KIyMgMy4yIE1hcHBpbmcgLS0tLS0NCg0KIyMjIDMuMi4xIENPMiBlbWlzc2lvbiBwZXIgY2FwaXRhIGJ5IHByb3ZpbmNlIC0tLS0tDQoNCg0KDQpwcm92aW5jZSB8PiANCiAgIGdncGxvdCgpICsNCiAgICAgIGdlb21fc2YoDQogICAgICAgICBhZXMoZmlsbCA9IGNvMl9wYyksDQogICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICBzaXplID0gLjE1DQogICAgICApICsNCiAgICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKA0KICAgICAgICAgbmFtZSA9ICIiLA0KICAgICAgICAgY29sb3JzID0gcGFsDQogICAgICAgICAjIGxpbWl0cyA9IGMoMCwgMzUpLA0KICAgICAgICAgIyBicmVha3MgPSBzZXEoNSwgMzUsIDUpLA0KICAgICAgICAgIyBsYWJlbHMgPSBjKCI8NSIsICI1LTEwIiwgIjEwLTE1IiwgIjE1LTIwIiwgIjIwLTI1IiwgIjI1LTMwIiwgIj4zMCIpLA0KICAgICAgICAgIyBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKA0KICAgICAgICAgIyAgICBiYXJoZWlnaHQgPSA5LA0KICAgICAgICAgIyAgICBiYXJ3aWR0aCA9IDENCiAgICAgICAgICMgKQ0KICAgICAgKSArDQogICAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gdG9wX2NvMl9wY19tYXgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gZ2VvbWV0cnkpLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiLA0KICAgICAgICAgICAgICAgICAgICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuNSwNCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmF5MjAiLCAgICAgIyB0ZXh0IGNvbG9yDQogICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICJncmF5MzAiLA0KICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJNZXJyaXdlYXRoZXIgU2FucyIsDQogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMuMw0KICAgICAgICAgICAgICAgICAgICAgICkgKw0KICAgICAgIyBsYWJzKHRpdGxlID0gIlBlciBjYXBpdGEgQ0/igoIgZW1pc3Npb25zIGJ5IHByb3ZpbmNlLCAyMDIyIikgKw0KICAgICAgbGFicyhjYXB0aW9uID0gIlBlciBjYXBpdGEgYnkgcHJvdmluY2UgKHRvbnMpIikgKw0KICAgICAgdGhlbWVfdm9pZCgpICsNCiAgICAgIHRoZW1lKA0KICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYyguMiwgLjUpLA0KICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICAgICAgICBjb2xvciA9ICJncmF5MjAiLA0KICAgICAgICAgICAgdmp1c3QgPSAxLjUsIHNpemUgPSAxMCwNCiAgICAgICAgICAgIGZhbWlseSA9ICJXb3JrIFNhbnMiDQogICAgICAgICApLA0KICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoDQogICAgICAgICAgICB0ID0gMSwgYiA9IDAsIGwgPSAwLCByID0gMA0KICAgICAgICAgKSwgImxpbmVzIiksDQogICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoDQogICAgICAgICAgICBmYW1pbHkgPSAgIk1lcnJpd2VhdGhlciBTYW5zIiwNCiAgICAgICAgICAgIHNpemUgPSAxNiwgaGp1c3QgPSAuNQ0KICAgICAgICAgKQ0KICAgICAgKSAtPiBwMQ0KDQojIyMgMy4yLjIgQ08yIGVtaXNzaW9uIGJ5IHByb3ZpbmNlIC0tLS0tDQpwcm92aW5jZSB8PiANCiAgICAgIGdncGxvdCgpICsNCiAgICAgIGdlb21fc2YoDQogICAgICAgICBhZXMoZmlsbCA9IGNvMl9zdW1fbWlsKSwNCiAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgIHNpemUgPSAuMTUNCiAgICAgICkgKw0KICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oDQogICAgICAgICBuYW1lID0gIiIsDQogICAgICAgICBjb2xvcnMgPSBwYWwsDQogICAgICAgICBsaW1pdHMgPSBjKDAsIDQ1KSwNCiAgICAgICAgIGJyZWFrcyA9IHNlcSg1LCA0NSwgNSksDQogICAgICAgICAjIGxhYmVscyA9IGMoIjw1IiwgIjUtMTAiLCAiMTAtMTUiLCAiMTUtMjAiLCAiMjAtMjUiLCAiMjUtMzAiLCAiMzAtMzUiLCAiMzUtNDAiLCAiPjQwIiksDQogICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKA0KICAgICAgICAgICAgYmFyaGVpZ2h0ID0gLjUsDQogICAgICAgICAgICBiYXJ3aWR0aCA9IDM4DQogICAgICAgICApDQogICAgICApICsNCiAgICAgIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSB0b3BfY28yX3N1bV9tYXgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gZ2VvbWV0cnkpLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiLA0KICAgICAgICAgICAgICAgICAgICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuNSwNCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmF5MjAiLCAgICAgIyB0ZXh0IGNvbG9yDQogICAgICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICJncmF5MzAiLA0KICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJNZXJyaXdlYXRoZXIgU2FucyIsDQogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMuMw0KICAgICAgKSArDQogICAgICBsYWJzKGNhcHRpb25zID0gIlRvdGFsIGJ5IHByb3ZpbmNlIChtaWwuIHRvbnMpIikgKw0KICAgICAgdGhlbWVfdm9pZCgpICsNCiAgICAgIHRoZW1lKA0KICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgICAgICAgIGNvbG9yID0gImdyYXkyMCIsDQogICAgICAgICAgICBzaXplID0gMTMsDQogICAgICAgICAgICBmYW1pbHkgPSAiV29yayBTYW5zIiwNCiAgICAgICAgICAgIGhqdXN0ID0gMQ0KICAgICAgICAgKSwgbGVnZW5kLnRpY2tzID0gZWxlbWVudF9saW5lKA0KICAgICAgICAgICAgbGluZXdpZHRoID0gMiwNCiAgICAgICAgICAgIGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoDQogICAgICAgICAgICB0ID0gMSwgYiA9IDAsIGwgPSAwLCByID0gMA0KICAgICAgICAgKSwgImxpbmVzIiksDQogICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoDQogICAgICAgICAgICBmYW1pbHkgPSAgIk1lcnJpd2VhdGhlciBTYW5zIiwNCiAgICAgICAgICAgIHNpemUgPSAxNiwgaGp1c3QgPS41DQogICAgICAgICApDQogICAgICApIC0+IHAyDQoNCnNoYXJlX2xlZyA8LSBnZXRfbGVnZW5kKHAyKQ0KDQoNCg0KZ2dhcnJhbmdlKA0KICAgcDIgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLA0KICAgcDEgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLA0KICAgbnJvdyA9IDENCiAgICMgbGVnZW5kLmdyb2IgPSBzaGFyZV9sZWcsDQogICAjIGxlZ2VuZCA9ICdib3R0b20nDQopIHw+IGdnYXJyYW5nZSgNCiAgICAgIC4uMSA9IHRleHRfZ3JvYigNCiAgICAgICAgIGxhYmVsID0gIkNPMiBlbWlzc2lvbiBpbiBWaWV0bmFtLCAyMDIyIiwNCiAgICAgICAgIGZhbWlseSA9ICJNZXJyaXdlYXRoZXIgU2FucyBFeHRyYUJvbGQiLA0KICAgICAgICAgZmFjZSA9ICJib2xkIiwNCiAgICAgICAgIHNpemUgPSAzMCwganVzdCA9ICJsZWZ0IiwgeCA9IC4wNCwNCiAgICAgICAgIGNvbG9yID0gImdyYXkyMCIpIHw+IA0KICAgICAgICAgYXNfZ2dwbG90KCksDQogICAgICAuLjIgPSB0ZXh0X2dyb2IoDQogICAgICAgICBsYWJlbCA9ICJUb3AgNSBwcm92aW5jZXMgdGhhdCBwcm9kdWNlZCB0aGUgbW9zdCBDTzIgaW5kaWNhdGVkIGF0IGVhY2ggcGxvdCIsIA0KICAgICAgICAgc2l6ZSA9IDE2LCBqdXN0ID0gImxlZnQiLCB4ID0gLjA0LCANCiAgICAgICAgIGNvbG9yID0gImdyYXkzMCIsIHkgPSAuNiwNCiAgICAgICAgIGZhbWlseSA9ICJNZXJyaXdlYXRoZXIgU2FucyINCiAgICAgICksDQogICAgICAuLjMgPSBfLCANCiAgICAgIC4uNCA9IGFzX2dncGxvdChzaGFyZV9sZWcpLA0KICAgICAgbnJvdyA9IDQsDQogICAgICBoZWlnaHRzID0gYyguMDc1LCAuMDM1LCAuODMsIC4wNykNCiAgICkgfD4gZ3JpZC5hcnJhbmdlKA0KICAgICAgYm90dG9tID0gdGV4dEdyb2IoDQogICAgICAgICAiQnk6IER1eSBLaGFuaCIsDQogICAgICAgICBncCA9IGdwYXIoZmFtaWx5ID0gIkxpYnJlIEJhc2tlcnZpbGxlIiwgDQogICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMiksDQogICAgICAgICB4ID0gLjk4LA0KICAgICAgICAgeSA9IC41LA0KICAgICAgICAganVzdCA9ICJyaWdodCINCiAgICAgICkNCiAgICkgfD4gYXNfZ2dwbG90KCkgKw0KICAgYW5ub3RhdGlvbl9jdXN0b20oDQogICAgICByZWN0R3JvYihncCA9IGdwYXIoZmlsbCA9ICJmaXJlYnJpY2siKSksDQogICAgICB4bWluID0gMCwgeG1heCA9IC4wMiwNCiAgICAgIHltaW4gPSAuOTA1LCB5bWF4ID0gLjk4DQogICApIC0+IG15X21hcA0Kc2hvd19zYXZlKG15X21hcCkNCmBgYA0K