1 Objective

Visualisasi data dengan peta dari data shapefile dan data tambahan.

2 Map & Additional Data

Data yang digunakan terdiri dari dua bagian. Pertama data untuk map, yang diantaranya terdapat kolom geometry sebagai polygon. Data kedua adalah data berisi nilai yang akan ditampilkan. Kedua data tersebut di-join berdasarkan kolom yang sesuai. Dalam hal ini di-join berdasarkan kolom NAME_1 (data shp) dan Provinsi (data tambahan).

2.1 Map Data

Download data dengan format .shp dari web berikut. Pilih Indonesia untuk Country dan pilih Administrative areas untuk Subject. Klik OK dan Download, kemudian simpan file IDN_adm.zip dan extract pada suatu folder.

Download Shapefile

Download Shapefile

Buka https://mapshaper.org untuk membuat ukuran file .shp yang akan digunakan menjadi lebih kecil, sehingga lebih cepat ketika diimport ke R.

mapshaper.org

mapshaper.org

Upload file .shp dan file pendukung lainnya untuk level provinsi, yaitu IDN_adm1 (kecuali file .csv).

Upload File

Upload File

Upload File

Upload File

Pilih menu Simplify kemudian klik Apply.

Simplify

Simplify

Atur parameter yang ada. Semakin kecil nilainya maka semakin sederhana peta yang dibuat dan ukuran filenya pun semakin kecil.

Simplify

Simplify

Jika sudah selesai pengaturannya, kemudian export dalam format shapefile dan extract dalam sebuah folder. Sebaiknya jangan me-replace file .shp asli.

Upload File

Upload File

2.2 Additional Data

Untuk data tambahan yang akan ditampilkan dapat kita gunakan data dari BPS. Unduh data tersebut dalam format Excel file.

Agar lebih mudah, simpan dalam format .csv.

3 Mapping

library(sf)
library(plotly)
library(dplyr)
library(tidyr)
library(readr)
shp <- sf::read_sf("IDN_adm1.shp")
str(shp)
Classes ‘sf’, ‘tbl_df’, ‘tbl’ and 'data.frame': 34 obs. of  10 variables:
 $ ID_0     : num  106 106 106 106 106 106 106 106 106 106 ...
 $ ISO      : chr  "IDN" "IDN" "IDN" "IDN" ...
 $ NAME_0   : chr  "Indonesia" "Indonesia" "Indonesia" "Indonesia" ...
 $ ID_1     : num  1 2 3 4 5 6 7 8 9 10 ...
 $ NAME_1   : chr  "Aceh" "Bali" "Bangka-Belitung" "Banten" ...
 $ TYPE_1   : chr  "Propinsi" "Propinsi" "Propinsi" "Propinsi" ...
 $ ENGTYPE_1: chr  "Autonomous Province" "Province" "Province" "Province" ...
 $ NL_NAME_1: chr  NA NA NA NA ...
 $ VARNAME_1: chr  "Achin|Atjeh|Nanggroe Aceh Darussalam" "Penida|Lembongan|Ceningan|Menjangan" "Babel|Kepulauan Bangka Belitung" NA ...
 $ geometry :sfc_MULTIPOLYGON of length 34; first list element: List of 6
  ..$ :List of 1
  .. ..$ : num [1:5, 1:2] 97.1 97.2 97.1 97.1 97.1 ...
  ..$ :List of 1
  .. ..$ : num [1:7, 1:2] 97.2 97.3 97.4 97.3 97.3 ...
  ..$ :List of 1
  .. ..$ : num [1:25, 1:2] 95.8 95.9 95.9 96 96 ...
  ..$ :List of 1
  .. ..$ : num [1:100, 1:2] 96.2 96.2 96.1 96 95.9 ...
  ..$ :List of 1
  .. ..$ : num [1:4, 1:2] 95.06 95.13 95.07 95.06 5.75 ...
  ..$ :List of 1
  .. ..$ : num [1:6, 1:2] 95.2 95.3 95.4 95.3 95.3 ...
  ..- attr(*, "class")= chr  "XY" "MULTIPOLYGON" "sfg"
 - attr(*, "sf_column")= chr "geometry"
 - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA
  ..- attr(*, "names")= chr  "ID_0" "ISO" "NAME_0" "ID_1" ...

Variabel NAME_1 adalah nama provinsi.

plot_ly(shp)
bps_file1 <- read_csv("bps-file1.csv", col_names = FALSE, skip = 3)
bps_file1 <- bps_file1 %>% 
  rename(Provinsi = X1,
         LuasPanen = X2,
         Produktivitas = X3,
         Produksi = X4)

bps_file1 <- bps_file1 %>% 
  mutate(Provinsi = if_else(Provinsi == "DKI JAKARTA", "JAKARTA RAYA", 
                    if_else(Provinsi == "DI YOGYAKARTA", "YOGYAKARTA",
                    if_else(Provinsi == "KEP. BANGKA BELITUNG", "BANGKA-BELITUNG",
                    if_else(Provinsi == "PAPUA BARAT", "IRIAN JAYA BARAT", 
                    if_else(Provinsi == "KEP. RIAU", "KEPULAUAN RIAU", 
                            Provinsi))))),
         Provinsi = stringr::str_to_title(Provinsi))
head(bps_file1)

Join data shp dengan bps_file1 berdasarkan variabel NAME_1 = Provinsi

shp <- shp %>% 
  left_join(bps_file1, by = c("NAME_1" = "Provinsi"))
head(shp)
Simple feature collection with 6 features and 12 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 95.05889 ymin: -8.849167 xmax: 123.5241 ymax: 5.907781
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs

3.1 Basic Map

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1,
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text")

3.2 Hide Legend

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1,
        span = I(1), showlegend = FALSE,
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text")

3.3 Modify Colorbar Title

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1, span = I(1), 
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text", showlegend = FALSE) %>% 
  colorbar(title = "Luas Panen 2018")

3.4 Hide Colorbar

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1, span = I(1), 
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text", showlegend = FALSE) %>% 
  colorbar(title = "Luas Panen 2018") %>% 
  hide_colorbar()

3.5 Hide Plotly Logo on Mode Bar

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1, span = I(1), 
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text", showlegend = FALSE) %>% 
  colorbar(title = "Luas Panen 2018") %>% 
  hide_colorbar() %>% 
  config(displaylogo = FALSE)

3.6 Hide Entire Mode Bar

plot_ly(shp, color = ~LuasPanen, split = ~NAME_1, span = I(1), 
        text = ~paste("<b>", NAME_1, "</b><br>",
                      "<b>Luas Panen</b>:", LuasPanen, "(ha)"),
        hoveron = "fills", hoverinfo = "text", showlegend = FALSE) %>% 
  colorbar(title = "Luas Panen 2018") %>% 
  hide_colorbar() %>% 
  config(displayModeBar = FALSE)

4 Conclusion

Gunakan file .shp yang mudah didapatkan di internet untuk visualisasi spasial berupa map. Import file .shp dan beberapa file pendukungnya dengan fungsi read_sf() dari package sf. Kemudian gunakan fungsi plot_ly() dari package plotly dan untuk menampilkan visualisasi map dan data tambahannya.

LS0tDQp0aXRsZTogIlBsb3RseSBTcGF0aWFsIFZpc3VhbGl6YXRpb24iDQphdXRob3I6ICJCeSBBZXAgSGlkYXlhdHVsb2giDQpkYXRlOiAiTGFzdCBVcGRhdGU6IGByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQgJWIgJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpib2R5eyAvKiBOb3JtYWwgICovDQogICAgICBmb250LXNpemU6IDEycHg7DQogIH0NCnRkIHsgIC8qIFRhYmxlICAqLw0KICBmb250LXNpemU6IDEycHg7DQp9DQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMzhweDsNCiAgY29sb3I6IGxpZ2h0Ymx1ZTsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IC8qIEhlYWRlciAxICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMiAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmgzIHsgLyogSGVhZGVyIDMgKi8NCiAgZm9udC1zaXplOiAxNnB4Ow0KIyAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmg0IHsgLyogSGVhZGVyIDQgKi8NCiAgZm9udC1zaXplOiAxNHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8NCiAgICBmb250LXNpemU6IDEycHg7DQp9DQpwcmUgeyAvKiBDb2RlIGJsb2NrIC0gZGV0ZXJtaW5lcyBjb2RlIHNwYWNpbmcgYmV0d2VlbiBsaW5lcyAqLw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoja25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcud2lkdGggPSA5LjUsIHJlc3VsdHMgPSAnaG9sZCcsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLnNob3cgPSAnaG9sZCcsIG1lc3NhZ2UgPSBGQUxTRSkgDQpvcHRpb25zKHNjaXBlbiA9IDk5KQ0KYGBgDQoNCiMgT2JqZWN0aXZlDQoNClZpc3VhbGlzYXNpIGRhdGEgZGVuZ2FuIHBldGEgZGFyaSBkYXRhIHNoYXBlZmlsZSBkYW4gZGF0YSB0YW1iYWhhbi4NCg0KIyBNYXAgJiBBZGRpdGlvbmFsIERhdGENCg0KRGF0YSB5YW5nIGRpZ3VuYWthbiB0ZXJkaXJpIGRhcmkgZHVhIGJhZ2lhbi4gUGVydGFtYSBkYXRhIHVudHVrIG1hcCwgeWFuZyBkaWFudGFyYW55YSB0ZXJkYXBhdCBrb2xvbSBgZ2VvbWV0cnlgIHNlYmFnYWkgcG9seWdvbi4gRGF0YSBrZWR1YSBhZGFsYWggZGF0YSBiZXJpc2kgbmlsYWkgeWFuZyBha2FuIGRpdGFtcGlsa2FuLiBLZWR1YSBkYXRhIHRlcnNlYnV0IGRpLWpvaW4gYmVyZGFzYXJrYW4ga29sb20geWFuZyBzZXN1YWkuIERhbGFtIGhhbCBpbmkgZGktam9pbiBiZXJkYXNhcmthbiBrb2xvbSBgTkFNRV8xYCAoZGF0YSBzaHApIGRhbiBgUHJvdmluc2lgIChkYXRhIHRhbWJhaGFuKS4NCg0KIyMgTWFwIERhdGENCkRvd25sb2FkIGRhdGEgZGVuZ2FuIGZvcm1hdCAuc2hwIGRhcmkgW3dlYiBiZXJpa3V0XShodHRwczovL3d3dy5kaXZhLWdpcy5vcmcvZ2RhdGEpLiBQaWxpaCAqKkluZG9uZXNpYSoqIHVudHVrICpDb3VudHJ5KiBkYW4gcGlsaWggKipBZG1pbmlzdHJhdGl2ZSBhcmVhcyoqIHVudHVrICpTdWJqZWN0Ki4gS2xpayAqKk9LKiogZGFuICoqRG93bmxvYWQqKiwga2VtdWRpYW4gc2ltcGFuIGZpbGUgKklETl9hZG0uemlwKiBkYW4gZXh0cmFjdCBwYWRhIHN1YXR1IGZvbGRlci4NCg0KIVtEb3dubG9hZCBTaGFwZWZpbGVdKGRvd25sb2FkX3NocC5wbmcpDQoNCkJ1a2EgPGh0dHBzOi8vbWFwc2hhcGVyLm9yZz4gdW50dWsgbWVtYnVhdCB1a3VyYW4gZmlsZSAuc2hwIHlhbmcgYWthbiBkaWd1bmFrYW4gbWVuamFkaSBsZWJpaCBrZWNpbCwgc2VoaW5nZ2EgbGViaWggY2VwYXQga2V0aWthIGRpaW1wb3J0IGtlIFIuIA0KDQohW21hcHNoYXBlci5vcmddKG1hcHNoYXBlci5wbmcpDQoNClVwbG9hZCBmaWxlIC5zaHAgZGFuIGZpbGUgcGVuZHVrdW5nIGxhaW5ueWEgdW50dWsgbGV2ZWwgcHJvdmluc2ksIHlhaXR1IElETl9hZG0xIChrZWN1YWxpIGZpbGUgLmNzdikuDQoNCiFbVXBsb2FkIEZpbGVdKHVwbG9hZF9zaHAucG5nKQ0KDQohW1VwbG9hZCBGaWxlXSh1cGxvYWRfc2hwMi5wbmcpDQoNClBpbGloIG1lbnUgKipTaW1wbGlmeSoqIGtlbXVkaWFuIGtsaWsgKipBcHBseSoqLg0KDQohW1NpbXBsaWZ5XSh1cGxvYWRfc2hwMy5wbmcpDQoNCkF0dXIgcGFyYW1ldGVyIHlhbmcgYWRhLiBTZW1ha2luIGtlY2lsIG5pbGFpbnlhIG1ha2Egc2VtYWtpbiBzZWRlcmhhbmEgcGV0YSB5YW5nIGRpYnVhdCBkYW4gdWt1cmFuIGZpbGVueWEgcHVuIHNlbWFraW4ga2VjaWwuDQoNCiFbU2ltcGxpZnldKHNldF9zaHAucG5nKQ0KDQpKaWthIHN1ZGFoIHNlbGVzYWkgcGVuZ2F0dXJhbm55YSwga2VtdWRpYW4gZXhwb3J0IGRhbGFtIGZvcm1hdCBzaGFwZWZpbGUgZGFuIGV4dHJhY3QgZGFsYW0gc2VidWFoIGZvbGRlci4gU2ViYWlrbnlhIGphbmdhbiBtZS1yZXBsYWNlIGZpbGUgLnNocCBhc2xpLg0KDQohW1VwbG9hZCBGaWxlXShleHBvcnRfc2hwLnBuZykNCg0KDQojIyBBZGRpdGlvbmFsIERhdGENClVudHVrIGRhdGEgdGFtYmFoYW4geWFuZyBha2FuIGRpdGFtcGlsa2FuIGRhcGF0IGtpdGEgZ3VuYWthbiBbZGF0YSBkYXJpIEJQU10oaHR0cHM6Ly93d3cuYnBzLmdvLmlkL2R5bmFtaWN0YWJsZS8yMDE5LzA0LzE1LzE2MDgvbHVhcy1wYW5lbi1wcm9kdWtzaS1kYW4tcHJvZHVrdGl2aXRhcy1wYWRpLW1lbnVydXQtcHJvdmluc2ktMjAxOC5odG1sKS4gVW5kdWggZGF0YSB0ZXJzZWJ1dCBkYWxhbSBmb3JtYXQgRXhjZWwgZmlsZS4gDQoNCkFnYXIgbGViaWggbXVkYWgsIHNpbXBhbiBkYWxhbSBmb3JtYXQgLmNzdi4NCg0KIyBNYXBwaW5nDQoNCmBgYHtyfQ0KbGlicmFyeShzZikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHJlYWRyKQ0KYGBgDQoNCmBgYHtyfQ0Kc2hwIDwtIHNmOjpyZWFkX3NmKCJJRE5fYWRtMS5zaHAiKQ0Kc3RyKHNocCkNCmBgYA0KDQpWYXJpYWJlbCBgTkFNRV8xYCBhZGFsYWggbmFtYSBwcm92aW5zaS4NCg0KYGBge3IgZmlnLndpZHRoPTh9DQpwbG90X2x5KHNocCkNCmBgYA0KDQoNCmBgYHtyfQ0KYnBzX2ZpbGUxIDwtIHJlYWRfY3N2KCJicHMtZmlsZTEuY3N2IiwgY29sX25hbWVzID0gRkFMU0UsIHNraXAgPSAzKQ0KYnBzX2ZpbGUxIDwtIGJwc19maWxlMSAlPiUgDQogIHJlbmFtZShQcm92aW5zaSA9IFgxLA0KICAgICAgICAgTHVhc1BhbmVuID0gWDIsDQogICAgICAgICBQcm9kdWt0aXZpdGFzID0gWDMsDQogICAgICAgICBQcm9kdWtzaSA9IFg0KQ0KDQpicHNfZmlsZTEgPC0gYnBzX2ZpbGUxICU+JSANCiAgbXV0YXRlKFByb3ZpbnNpID0gaWZfZWxzZShQcm92aW5zaSA9PSAiREtJIEpBS0FSVEEiLCAiSkFLQVJUQSBSQVlBIiwgDQogICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoUHJvdmluc2kgPT0gIkRJIFlPR1lBS0FSVEEiLCAiWU9HWUFLQVJUQSIsDQogICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoUHJvdmluc2kgPT0gIktFUC4gQkFOR0tBIEJFTElUVU5HIiwgIkJBTkdLQS1CRUxJVFVORyIsDQogICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoUHJvdmluc2kgPT0gIlBBUFVBIEJBUkFUIiwgIklSSUFOIEpBWUEgQkFSQVQiLCANCiAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShQcm92aW5zaSA9PSAiS0VQLiBSSUFVIiwgIktFUFVMQVVBTiBSSUFVIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdmluc2kpKSkpKSwNCiAgICAgICAgIFByb3ZpbnNpID0gc3RyaW5ncjo6c3RyX3RvX3RpdGxlKFByb3ZpbnNpKSkNCmhlYWQoYnBzX2ZpbGUxKQ0KYGBgDQoNCkpvaW4gZGF0YSBgc2hwYCBkZW5nYW4gYGJwc19maWxlMWAgYmVyZGFzYXJrYW4gdmFyaWFiZWwgYE5BTUVfMSA9IFByb3ZpbnNpYA0KDQpgYGB7cn0NCnNocCA8LSBzaHAgJT4lIA0KICBsZWZ0X2pvaW4oYnBzX2ZpbGUxLCBieSA9IGMoIk5BTUVfMSIgPSAiUHJvdmluc2kiKSkNCmhlYWQoc2hwKQ0KYGBgDQoNCiMjIEJhc2ljIE1hcA0KDQpgYGB7ciBmaWcud2lkdGg9OH0NCnBsb3RfbHkoc2hwLCBjb2xvciA9IH5MdWFzUGFuZW4sIHNwbGl0ID0gfk5BTUVfMSwNCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiPGI+IiwgTkFNRV8xLCAiPC9iPjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICI8Yj5MdWFzIFBhbmVuPC9iPjoiLCBMdWFzUGFuZW4sICIoaGEpIiksDQogICAgICAgIGhvdmVyb24gPSAiZmlsbHMiLCBob3ZlcmluZm8gPSAidGV4dCIpDQpgYGANCg0KIyMgSGlkZSBMZWdlbmQNCg0KYGBge3IgZmlnLndpZHRoPTh9DQpwbG90X2x5KHNocCwgY29sb3IgPSB+THVhc1BhbmVuLCBzcGxpdCA9IH5OQU1FXzEsDQogICAgICAgIHNwYW4gPSBJKDEpLCBzaG93bGVnZW5kID0gRkFMU0UsDQogICAgICAgIHRleHQgPSB+cGFzdGUoIjxiPiIsIE5BTUVfMSwgIjwvYj48YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAiPGI+THVhcyBQYW5lbjwvYj46IiwgTHVhc1BhbmVuLCAiKGhhKSIpLA0KICAgICAgICBob3Zlcm9uID0gImZpbGxzIiwgaG92ZXJpbmZvID0gInRleHQiKQ0KYGBgDQoNCiMjIE1vZGlmeSBDb2xvcmJhciBUaXRsZQ0KYGBge3IgZmlnLndpZHRoPTh9DQpwbG90X2x5KHNocCwgY29sb3IgPSB+THVhc1BhbmVuLCBzcGxpdCA9IH5OQU1FXzEsIHNwYW4gPSBJKDEpLCANCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiPGI+IiwgTkFNRV8xLCAiPC9iPjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICI8Yj5MdWFzIFBhbmVuPC9iPjoiLCBMdWFzUGFuZW4sICIoaGEpIiksDQogICAgICAgIGhvdmVyb24gPSAiZmlsbHMiLCBob3ZlcmluZm8gPSAidGV4dCIsIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lIA0KICBjb2xvcmJhcih0aXRsZSA9ICJMdWFzIFBhbmVuIDIwMTgiKQ0KYGBgDQoNCiMjIEhpZGUgQ29sb3JiYXINCg0KYGBge3IgZmlnLndpZHRoPTh9DQpwbG90X2x5KHNocCwgY29sb3IgPSB+THVhc1BhbmVuLCBzcGxpdCA9IH5OQU1FXzEsIHNwYW4gPSBJKDEpLCANCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiPGI+IiwgTkFNRV8xLCAiPC9iPjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICI8Yj5MdWFzIFBhbmVuPC9iPjoiLCBMdWFzUGFuZW4sICIoaGEpIiksDQogICAgICAgIGhvdmVyb24gPSAiZmlsbHMiLCBob3ZlcmluZm8gPSAidGV4dCIsIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lIA0KICBjb2xvcmJhcih0aXRsZSA9ICJMdWFzIFBhbmVuIDIwMTgiKSAlPiUgDQogIGhpZGVfY29sb3JiYXIoKQ0KYGBgDQoNCiMjIEhpZGUgUGxvdGx5IExvZ28gb24gTW9kZSBCYXINCg0KYGBge3IgZmlnLndpZHRoPTh9DQpwbG90X2x5KHNocCwgY29sb3IgPSB+THVhc1BhbmVuLCBzcGxpdCA9IH5OQU1FXzEsIHNwYW4gPSBJKDEpLCANCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiPGI+IiwgTkFNRV8xLCAiPC9iPjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICI8Yj5MdWFzIFBhbmVuPC9iPjoiLCBMdWFzUGFuZW4sICIoaGEpIiksDQogICAgICAgIGhvdmVyb24gPSAiZmlsbHMiLCBob3ZlcmluZm8gPSAidGV4dCIsIHNob3dsZWdlbmQgPSBGQUxTRSkgJT4lIA0KICBjb2xvcmJhcih0aXRsZSA9ICJMdWFzIFBhbmVuIDIwMTgiKSAlPiUgDQogIGhpZGVfY29sb3JiYXIoKSAlPiUgDQogIGNvbmZpZyhkaXNwbGF5bG9nbyA9IEZBTFNFKQ0KYGBgDQoNCiMjIEhpZGUgRW50aXJlIE1vZGUgQmFyDQoNCmBgYHtyIGZpZy53aWR0aD04fQ0KcGxvdF9seShzaHAsIGNvbG9yID0gfkx1YXNQYW5lbiwgc3BsaXQgPSB+TkFNRV8xLCBzcGFuID0gSSgxKSwgDQogICAgICAgIHRleHQgPSB+cGFzdGUoIjxiPiIsIE5BTUVfMSwgIjwvYj48YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAiPGI+THVhcyBQYW5lbjwvYj46IiwgTHVhc1BhbmVuLCAiKGhhKSIpLA0KICAgICAgICBob3Zlcm9uID0gImZpbGxzIiwgaG92ZXJpbmZvID0gInRleHQiLCBzaG93bGVnZW5kID0gRkFMU0UpICU+JSANCiAgY29sb3JiYXIodGl0bGUgPSAiTHVhcyBQYW5lbiAyMDE4IikgJT4lIA0KICBoaWRlX2NvbG9yYmFyKCkgJT4lIA0KICBjb25maWcoZGlzcGxheU1vZGVCYXIgPSBGQUxTRSkNCmBgYA0KDQojIENvbmNsdXNpb24NCg0KR3VuYWthbiBmaWxlIC5zaHAgeWFuZyBtdWRhaCBkaWRhcGF0a2FuIGRpIGludGVybmV0IHVudHVrIHZpc3VhbGlzYXNpIHNwYXNpYWwgYmVydXBhIG1hcC4gSW1wb3J0IGZpbGUgLnNocCBkYW4gYmViZXJhcGEgZmlsZSBwZW5kdWt1bmdueWEgZGVuZ2FuIGZ1bmdzaSBgcmVhZF9zZigpYCBkYXJpIHBhY2thZ2UgYHNmYC4gS2VtdWRpYW4gZ3VuYWthbiBmdW5nc2kgYHBsb3RfbHkoKWAgZGFyaSBwYWNrYWdlIGBwbG90bHlgIGRhbiB1bnR1ayBtZW5hbXBpbGthbiB2aXN1YWxpc2FzaSBtYXAgZGFuIGRhdGEgdGFtYmFoYW5ueWEuDQoNCmBgYHtyIHJ1bmFsbH0NCg0KYGBgDQoNCg==