1 Zakład Bioinformatyki, Instytut Informatyki, Uniwersytet w Białymstoku

Correspondence: Jarosław Kotowicz <>

1 Mapy w R

1.1 Zródła konkturów państw (mapy)

  1. Strona gadm.org kontury krajów do wykorzystania niekomercyjnego
  2. Biblioteki R
  • map
  • mapdata
  • sp
  • rnaturalearth
  • rnaturalearthdata
  1. Polska geoprtal.gov.pl Główny Urząd Geodezji i Kartografii

1.2 Mapy tradycyjne

  1. Biblioteki
  • RgoogleMaps
  • leaflet
  • leafletR

1.3 Tworzenie map

  1. Biblioteki
  • sp
  • sf
  • ggplot2
  • ggmap
  • maptools
  • maps
  • tmap
  • tmaptools
  • ggspatial
  • ggrepel

1.4 Miasta świata (współrzędne geograficzne)

  1. Bazy danych

1.5 Wybrane strony

  1. https://www.r-spatial.org/r/2018/10/25/ggplot2-sf.html
  2. https://www.r-spatial.org/r/2018/10/25/ggplot2-sf-2.html
  3. https://www.r-spatial.org/r/2018/10/25/ggplot2-sf-3.html
  4. https://eriqande.github.io/rep-res-web/lectures/making-maps-with-R.html
  5. https://github.com/Robinlovelace/Creating-maps-in-R
  6. https://pjbartlein.github.io/GeogDataAnalysis/
  7. http://geog.uoregon.edu/bartlein/courses/geog495/ex06.html
  8. https://rpubs.com/rbatzing/mapping
rm(list = ls())
library(tidyverse)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
<U+221A> ggplot2 3.3.0     <U+221A> purrr   0.3.4
<U+221A> tibble  3.0.0     <U+221A> dplyr   0.8.5
<U+221A> tidyr   1.0.2     <U+221A> stringr 1.4.0
<U+221A> readr   1.3.1     <U+221A> forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

2 Mapy świata i ich prezentacja

Rozdział ten jest inspirowany artukułem Drawing beautiful maps programmatically with R, sf and ggplot2 — Part 1: Basics autorstwa Mela Moreno i Mathieu Basille

library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
class(world)
[1] "sf"         "data.frame"
ggplot(data = world) +
  geom_sf()

ggplot(data = world) +
  geom_sf() +
  xlab("Longitude") + ylab("Latitude") +
  ggtitle("World map", subtitle = paste0("(", length(unique(world$name)), " countries)"))

ggplot(data = world) + 
  geom_sf(color = "black", fill = "lightgreen")

ggplot(data = world) +
  geom_sf(aes(fill = pop_est)) +
  scale_fill_viridis_c(option = "plasma", trans = "sqrt")

ggplot(data = world) +
  geom_sf() +
  coord_sf(crs = "+proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m +no_defs ")

ggplot(data = world) +
  geom_sf() +
  coord_sf(crs = "+init=epsg:3035")

library(sf)
Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
ggplot(data = world) +
  geom_sf() +
  coord_sf(crs = st_crs(3035))

Kod źródłowy pochodzi z artykułu Drawing beautiful maps programmatically with R, sf and ggplot2 — Part 1: Basics autorstwa Mela Moreno i Mathieu Basille

ggplot(data = world) +
  geom_sf() +
  coord_sf(xlim = c(-102.15, -74.12), ylim = c(7.65, 33.97), expand = FALSE)

world_points<- st_centroid(world)
st_centroid assumes attributes are constant over geometries of xst_centroid does not give correct centroids for longitude/latitude data
world_points <- cbind(world, st_coordinates(st_centroid(world$geometry)))
st_centroid does not give correct centroids for longitude/latitude data
library(ggrepel) 
library(ggspatial)
ggplot(data = world) + 
  geom_sf(fill= "antiquewhite") + 
  geom_text(data= world_points,aes(x=X, y=Y, label=name), color = "darkblue", 
            fontface = "bold", check_overlap = FALSE) + 
  annotate(geom = "text", x = -90, y = 26, label = "Gulf of Mexico", 
           fontface = "italic", color = "grey22", size = 6) + 
  annotation_scale(location = "bl", width_hint = 0.5) + 
  annotation_north_arrow(location = "bl", which_north = "true", pad_x = unit(0.75, "in"), 
                         pad_y = unit(0.5, "in"), style = north_arrow_fancy_orienteering) + 
  coord_sf(xlim = c(-102.15, -74.12), ylim = c(7.65, 33.97), expand = FALSE) + 
  xlab("Longitude") + ylab("Latitude") + 
  ggtitle("Map of the Gulf of Mexico and the Caribbean Sea") + 
  theme(panel.grid.major = element_line(color = gray(.5), linetype = "dashed", size = 0.5), 
        panel.background = element_rect(fill = "aliceblue"))

3 Różne projekcje korzystamy z

PROJ

library(tidyverse)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=aea +lat_1=29.5 +lat_2=42.5") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja Albers Equal Area)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=eqc") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja eqc)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=cea") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja cea)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=eck1") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja eck1)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=eck2") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja eck2)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=eck3") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja eck3)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

world_proj <- st_transform(world, "+proj=eck3")
ggplot(world_proj["continent"]) +
  geom_sf(aes(fill = continent) ) +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

world_proj <- st_transform(world, "+proj=eck4")
ggplot(world_proj["continent"]) +
  geom_sf(aes(fill = continent) ) +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(aes(fill = continent)) +
  coord_sf(crs = "+init=epsg:4326") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane kodem autorstwa Mela Moreno i Mathieu Basille'a.")

ggplot(data = world) +
  geom_sf(aes(fill = continent), alpha = .5) +
  coord_sf(crs = "+proj=moll") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja Mollweide)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(alpha = .5) +
  coord_sf(crs = "+proj=moll") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata (projekcja Mollweide)",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

3.1 Projekcje sferyczne (globusy)

ggplot(data = world) +
  geom_sf(aes(fill = continent)) +
  coord_sf(crs = "+init=epsg:3035") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane kodem autorstwa Mela Moreno i Mathieu Basille'a.")

ggplot(data = world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=laea +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs ")  +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(aes(fill = subregion) ) +
  coord_sf(crs = "+proj=laea +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs ")  +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(aes(fill = name) ) +
  coord_sf(crs = "+proj=laea +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs ")  +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(aes(fill = continent) ) +
  coord_sf(crs = "+proj=laea +lat_0=30 +lon_0=-100 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs ")  +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf(aes(fill = name) ) +
  coord_sf(crs = "+proj=laea +lat_0=30 +lon_0=-100 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs ")  +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

ggplot(data = world) +
  geom_sf() +
  coord_sf(crs = "+proj=laea +x_0=0 +y_0=0 +lon_0=-74 +lat_0=40") +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "lightgrey"),
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Mapa świata",
       caption = "Źródło: opracowanie własne inspirowane ilustracją z książki Geocomputation with R.")

4 Polska (województwa, powiaty, gminy)

4.1 Wykorzystanie plików sp

4.1.1 Użycie tylko funkcji plot do danych w formacie sp

4.1.1.1 Pierwsze wprawki

library(sp)
gadm_3sp <- readRDS("dane/gadm36_POL_3_sp.rds")
gadm_2sp <- readRDS("dane/gadm36_POL_2_sp.rds")
gadm_1sp <- readRDS("dane/gadm36_POL_1_sp.rds")
gadm_0sp <- readRDS("dane/gadm36_POL_0_sp.rds")
plot(gadm_0sp, border = 'darkgrey')

plot(gadm_1sp, border = 'darkgrey')

plot(gadm_2sp, border = 'darkgrey')

plot(gadm_3sp, border = 'darkgrey')

4.1.1.2 Poprawiamy rysunki

plot(gadm_0sp, border = 'darkgrey')
title(main = "Kontur Polski",
      sub = "Źródło: Opracowanie własne na podstawie danych z GADM.",
      font.main = 4, font.sub = 3,
      cex.main = 1.5, cex.sub = .75,
      col.main = "indianred4", col.sub = "bisque4")

plot(gadm_1sp, border = 'coral')
title(main = "Kontur Polski wraz z województwami",
      sub = "Źródło: Opracowanie własne na podstawie danych z GADM.",
      font.main = 2, font.sub = 3,
      cex.main = 1.5, cex.sub = .75,
      col.main = "indianred4", col.sub = "lightsalmon4")

plot(gadm_2sp, border = 'darkgrey')
title(main = "Kontur Polski wraz z powiatami",
      sub = "Źródło: Opracowanie własne na podstawie danych z GADM.",
      font.main = 2, font.sub = 3,
      cex.main = 2, cex.sub = .75,
      col.main = "midnightblue", col.sub = "lightsalmon4")

plot(gadm_3sp, border = 'coral3')
title(main = "Kontur Polski wraz z gminami",
      sub = "Źródło: Opracowanie własne na podstawie danych z GADM.",
      font.main = 1, font.sub = 3,
      cex.main = 1.5, cex.sub = .5,
      col.main = "indianred4", col.sub = "sandybrown")

colors = rainbow(100)
plot(gadm_1sp, col = colors, border = 'darkgrey')
title(main = "Województwa Polski (pokolorowane)",
      sub = "Źródło: Opracowanie własne na podstawie danych z GADM.",
      font.main = 2, font.sub = 3,
      cex.main = 1.5, cex.sub = .75,
      col.main = "indianred4", col.sub = "lightsalmon4")

library(RColorBrewer)
paleta <- colorRampPalette(brewer.pal(9,"Blues"))(17)
colors = rep("#00FF0022", 380)
colors[gadm_2sp@data$NAME_1 == "Podlaskie"] = paleta[7]
colors[gadm_2sp@data$NAME_2 == "Białystok (City)"] = "red"
plot(gadm_2sp, col = colors, border = FALSE)
title("Polska, województow podlaskie, powiat Białystok (miasto)")

4.2 Wykorzystanie plików sf

gadm_3sf <- readRDS("dane/gadm36_POL_3_sf.rds")
gadm_2sf <- readRDS("dane/gadm36_POL_2_sf.rds")
gadm_1sf <- readRDS("dane/gadm36_POL_1_sf.rds")
gadm_0sf <- readRDS("dane/gadm36_POL_0_sf.rds")
worldcities <- read_csv("dane/worldcities.csv")
Parsed with column specification:
cols(
  city = col_character(),
  city_ascii = col_character(),
  lat = col_double(),
  lng = col_double(),
  country = col_character(),
  iso2 = col_character(),
  iso3 = col_character(),
  admin_name = col_character(),
  capital = col_character(),
  population = col_double(),
  id = col_double()
)
mista.woj <- worldcities %>%
  filter(country == "Poland", capital != "minor")
gadm_0sf %>% 
  ggplot() +
  geom_sf() + 
  theme_bw()

gadm_1sf %>% 
  ggplot() +
  geom_sf() + 
  theme_bw() +
  labs(title = "Podział administracyjny Polski (województwa)")

gadm_1sf %>% 
  ggplot() +
  geom_sf() + 
  theme_bw() +
  labs(title = "Podział administracjyny Polski (województwa)")

ggplot() +
  annotation_spatial(gadm_1sf) +
  layer_spatial(gadm_1sf) +
  theme_bw() +
  labs(title = "Podział administracjyny Polski (województwa)")

ggplot() +
  annotation_spatial(gadm_1sf) +
  layer_spatial(gadm_1sf) +
  annotation_scale(location = "tl") +
  annotation_north_arrow(location = "br", which_north = "true")

ggplot() +
  annotation_map_tile(type = "osm") +
  layer_spatial(gadm_1sf)

ggplot(mista.woj, aes(x = lng, y = lat)) +
  annotation_spatial(gadm_1sf) +
  layer_spatial(gadm_1sf, fill= "aquamarine2") +
  geom_spatial_point() +
  stat_spatial_identity(aes(label = city), geom = "text_repel", box.padding = 1) +
  coord_sf() +
  xlab("Długość geograficzna") + ylab("Szerokość geograficzna") +
  labs(title = "Mapa Polski z podziałem na województwa.") +
  annotation_scale(location = "bl", width_hint = 0.5) +
  annotation_north_arrow(location = "bl", which_north = "true", 
                         pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
                         style = north_arrow_fancy_orienteering) +
  theme_bw() +
  theme(panel.grid.major = element_line(color = gray(.5), linetype = "dashed", size = 0.5))

ggplot(mista.woj, aes(x = lng, y = lat)) +
  annotation_spatial(gadm_1sf, alpha = .3) +
  layer_spatial(gadm_1sf, alpha = .3, fill= "aquamarine2") +
  geom_spatial_point() +
  stat_spatial_identity(aes(label = city), geom = "text_repel", box.padding = 1) +
  coord_sf() +
  xlab("Długość geograficzna") + ylab("Szerokość geograficzna") +
  labs(title = "Mapa Polski z podziałem na województwa.") +
  annotation_scale(location = "bl", width_hint = 0.5) +
  annotation_north_arrow(location = "bl", which_north = "true", 
                         pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
                         style = north_arrow_fancy_orienteering) +
  theme_bw() +
  theme(panel.grid.major = element_line(color = gray(.5), linetype = "dashed", size = 0.5))

ggplot(mista.woj, aes(x = lng, y = lat)) +
  annotation_spatial(gadm_1sf, alpha = .3) +
  layer_spatial(gadm_1sf, alpha = .3, fill= "aquamarine2") +
  geom_spatial_point() +
  stat_spatial_identity(aes(label = city), geom = "label_repel", box.padding = 1) +
  coord_sf() +
  xlab("Długość geograficzna") + ylab("Szerokość geograficzna") +
  labs(title = "Mapa Polski z podziałem na województwa.") +
  annotation_scale(location = "bl", width_hint = 0.5) +
  annotation_north_arrow(location = "bl", which_north = "true", 
                         pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
                         style = north_arrow_fancy_orienteering) +
  theme_bw() +
  theme(panel.grid.major = element_line(color = gray(.5), linetype = "dashed", size = 0.5))

powiaty.podlaskie <- gadm_2sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  as.data.frame() %>%
  select(NAME_2) %>%
  distinct
powiaty.podlaskie
gadm_2sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf() + 
  theme_bw() +
  theme(axis.line = element_blank(), 
        panel.border = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        panel.grid.major = element_blank(), 
        plot.title = element_text(hjust = 0.5, size = rel(2))) +
  labs(title = "Województwo podlaskie",
       caption = "Źródło: opracowanie własne.")

library(readxl)
Koronawirus <- read_excel("dane/Koronawirus.xlsx")
library(tidyselect)
data.Koronawirus.K <- Koronawirus %>% select(-c(1:2)) %>% names() %>% vars_select(contains("K"))
CORONA.women <- Koronawirus %>% select(data.Koronawirus.K) %>% as.data.frame() %>% rowSums(na.rm = TRUE)
Note: Using an external vector in selections is ambiguous.
i Use `all_of(data.Koronawirus.K)` instead of `data.Koronawirus.K` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
data.Koronawirus.M <- Koronawirus %>% select(-c(1:2)) %>% names() %>% vars_select(contains("M"))
CORONA.men <- Koronawirus %>% select(data.Koronawirus.M) %>% as.data.frame() %>% rowSums(na.rm = TRUE)
Note: Using an external vector in selections is ambiguous.
i Use `all_of(data.Koronawirus.M)` instead of `data.Koronawirus.M` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
CORONA.all <- Koronawirus %>% select(-c(1:2)) %>% as.data.frame() %>% rowSums(na.rm = TRUE)
Koronawirus <- Koronawirus %>%
  select(1) %>% as.data.frame() %>% 
  cbind(CORONA.all) %>% cbind(CORONA.men) %>% cbind(CORONA.women)
test.sf <- gadm_2sf %>%
  as.data.frame() %>%
  left_join(Koronawirus) %>%
  st_as_sf(crs = 4326)
Joining, by = "NAME_2"
test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.all)) +
  scale_fill_viridis_c(option = "plasma", alpha = .4) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.men)) +
  scale_fill_viridis_c(option = "plasma", alpha = .4) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19 (mężczyźni).",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.men, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.women)) +
  scale_fill_viridis_c(option = "plasma", alpha = .4) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19 (kobiety).",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.women, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.all)) +
  scale_fill_viridis_c(trans = "sqrt", alpha = .4) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.all)) +
  scale_colour_gradient() +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.all)) +
  scale_fill_gradient(low = "grey90", high = "grey30") +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = CORONA.all)) +
  scale_fill_gradient(low = "skyblue", high = "red4") +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

library(cartography)
test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = as.factor(CORONA.all))) +
  scale_fill_manual(values = carto.pal(pal1 = "red.pal", n1 = 16)) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.all, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = as.factor(CORONA.men))) +
  scale_fill_manual(values = carto.pal(pal1 = "green.pal", n1 = 13)) +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19 (mężczyźni).",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.men, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych") +
  theme(panel.grid.major = NULL, panel.grid.minor = NULL, 
        panel.background = NULL)

test.sf %>% 
  filter(NAME_1 == "Podlaskie") %>%
  ggplot() +
  geom_sf(aes(fill = as.factor(CORONA.women))) +
  scale_fill_brewer(palette = "Greens") +
  theme_bw() +
  labs(title = "Liczba potwierdzonych chorych COVID-19 (kobiety)",
       subtitle = paste0("Stan na dzień 20.04.2020r. na godz. 24.00. \nLiczba zarażonych: ", sum(test.sf$CORONA.women, na.rm = TRUE)),
       caption = "Źródło: Opracowanie własne na podstawie Komunikatów PUW.",
       fill = "Liczba zakażanych")

detach(package:RColorBrewer)

detach(package:ggspatial)
detach(package:ggrepel) 

detach(package:tidyverse)
detach(package:ggplot2)
detach(package:tibble)
detach(package:tidyr)
detach(package:readr)
detach(package:purrr)
detach(package:dplyr)
detach(package:stringr)
detach(package:forcats)

detach(package:sf)
detach(package:rnaturalearth)
detach(package:rnaturalearthdata)
LS0tDQp0aXRsZTogIkluZm9ybWF0eWthIGVrb25vbWljem5hIC0gd3lrxYJhZCA1IChraWVydW5layBpbmZvcm1hdHlrYSBpIGVrb25vbWV0cmlhKSINCnN1YnRpdGxlOiAiTWFweSBpIGFuYWxpemEgZ2VvcHJ6ZXN0cnplbm5hIHcgUiBjemXFm8SHIHBpZXJ3c3phIg0KYXV0aG9yOg0KLSBKYXJvc8WCYXcgS290b3dpY3o6DQogICAgY29ycmVzcG9uZGVuY2U6IG5vDQogICAgZW1haWw6IGoua290b3dpY3pAdXdiLmVkdS5wbA0KICAgIGluc3RpdHV0ZTogSUlVd0INCmRhdGU6ICIyOCBrd2lldG5pYSAyMDIwci4iDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGhpZ2hsaWdodDogaGFkZG9jaw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgcGFuZG9jX2FyZ3M6DQogICAgLSAtLWx1YS1maWx0ZXI9c2Nob2xhcmx5LW1ldGFkYXRhLmx1YQ0KICAgIC0gLS1sdWEtZmlsdGVyPWF1dGhvci1pbmZvLWJsb2Nrcy5sdWENCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICB0b2M6IHllcw0KaW5zdGl0dXRlOg0KLSBJSVV3QjogWmFrxYJhZCBCaW9pbmZvcm1hdHlraSwgSW5zdHl0dXQgSW5mb3JtYXR5a2ksIFVuaXdlcnN5dGV0IHcgQmlhxYJ5bXN0b2t1DQpjc2w6IGJpZy1kYXRhLWFuZC1pbmZvcm1hdGlvbi1hbmFseXRpY3MuY3NsDQphbHdheXNfYWxsb3dfaHRtbDogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyBNYXB5IHcgUg0KDQojIyBacsOzZMWCYSBrb25rdHVyw7N3IHBhxYRzdHcgKG1hcHkpDQoNCjEuIFN0cm9uYSBbZ2FkbS5vcmddKGh0dHBzOi8vZ2FkbS5vcmcvKSBrb250dXJ5IGtyYWrDs3cgZG8gd3lrb3J6eXN0YW5pYSBuaWVrb21lcmN5am5lZ28NCjIuIEJpYmxpb3Rla2kgKlIqDQogIC0gKm1hcCoNCiAgLSAqbWFwZGF0YSoNCiAgLSAqc3AqDQogIC0gKnJuYXR1cmFsZWFydGgqDQogIC0gKnJuYXR1cmFsZWFydGhkYXRhKg0KMy4gUG9sc2thIGdlb3BydGFsLmdvdi5wbCBbR8WCw7N3bnkgVXJ6xIVkIEdlb2RlemppIGkgS2FydG9ncmFmaWldKGh0dHA6Ly93d3cuZ3VnaWsuZ292LnBsL3B6Z2lrL2RhbmUtYmV6LW9wbGF0L2RhbmUtei1wYW5zdHdvd2Vnby1yZWplc3RydS1ncmFuaWMtaS1wb3dpZXJ6Y2huaS1qZWRub3N0ZWstcG9kemlhbG93LXRlcnl0b3JpYWxueWNoLWtyYWp1LXByZykNCg0KIyMgTWFweSB0cmFkeWN5am5lDQoNCjEuIEJpYmxpb3Rla2kNCiAgLSAqUmdvb2dsZU1hcHMqDQogIC0gKmxlYWZsZXQqDQogIC0gKmxlYWZsZXRSKg0KICANCiMjIFR3b3J6ZW5pZSBtYXANCg0KMS4gQmlibGlvdGVraQ0KICAtICpzcCoNCiAgLSAqc2YqDQogIC0gKmdncGxvdDIqDQogIC0gKmdnbWFwKg0KICAtICptYXB0b29scyoNCiAgLSAqbWFwcyoNCiAgLSAqdG1hcCoNCiAgLSAqdG1hcHRvb2xzKg0KICAtICpnZ3NwYXRpYWwqDQogIC0gKmdncmVwZWwqDQoNCiMjIE1pYXN0YSDFm3dpYXRhICh3c3DDs8WCcnrEmWRuZSBnZW9ncmFmaWN6bmUpDQoNCjEuIEJhenkgZGFueWNoDQogIC0gW3NpbXBsZW1hcHNdKGh0dHBzOi8vc2ltcGxlbWFwcy5jb20vZGF0YS93b3JsZC1jaXRpZXMpDQogIC0gW3RhZ2VvLmNvbV0oaHR0cDovL3d3dy50YWdlby5jb20vaW5kZXgtZS1wbC1jaXRpZXMtUEwuaHRtKQ0KICAtIGJpYmxpb3Rla2kgKlIqDQogIA0KIyMgV3licmFuZSBzdHJvbnkNCg0KMS4gW2h0dHBzOi8vd3d3LnItc3BhdGlhbC5vcmcvci8yMDE4LzEwLzI1L2dncGxvdDItc2YuaHRtbF0oaHR0cHM6Ly93d3cuci1zcGF0aWFsLm9yZy9yLzIwMTgvMTAvMjUvZ2dwbG90Mi1zZi5odG1sKQ0KMi4gW2h0dHBzOi8vd3d3LnItc3BhdGlhbC5vcmcvci8yMDE4LzEwLzI1L2dncGxvdDItc2YtMi5odG1sXShodHRwczovL3d3dy5yLXNwYXRpYWwub3JnL3IvMjAxOC8xMC8yNS9nZ3Bsb3QyLXNmLTIuaHRtbCkNCjMuIFtodHRwczovL3d3dy5yLXNwYXRpYWwub3JnL3IvMjAxOC8xMC8yNS9nZ3Bsb3QyLXNmLTMuaHRtbF0oaHR0cHM6Ly93d3cuci1zcGF0aWFsLm9yZy9yLzIwMTgvMTAvMjUvZ2dwbG90Mi1zZi0zLmh0bWwpDQo0LiBbaHR0cHM6Ly9lcmlxYW5kZS5naXRodWIuaW8vcmVwLXJlcy13ZWIvbGVjdHVyZXMvbWFraW5nLW1hcHMtd2l0aC1SLmh0bWxdKGh0dHBzOi8vZXJpcWFuZGUuZ2l0aHViLmlvL3JlcC1yZXMtd2ViL2xlY3R1cmVzL21ha2luZy1tYXBzLXdpdGgtUi5odG1sKQ0KNS4gW2h0dHBzOi8vZ2l0aHViLmNvbS9Sb2JpbmxvdmVsYWNlL0NyZWF0aW5nLW1hcHMtaW4tUl0oaHR0cHM6Ly9naXRodWIuY29tL1JvYmlubG92ZWxhY2UvQ3JlYXRpbmctbWFwcy1pbi1SKQ0KNi4gW2h0dHBzOi8vcGpiYXJ0bGVpbi5naXRodWIuaW8vR2VvZ0RhdGFBbmFseXNpcy9dKGh0dHBzOi8vcGpiYXJ0bGVpbi5naXRodWIuaW8vR2VvZ0RhdGFBbmFseXNpcy8pDQo3LiBbaHR0cDovL2dlb2cudW9yZWdvbi5lZHUvYmFydGxlaW4vY291cnNlcy9nZW9nNDk1L2V4MDYuaHRtbF0oaHR0cDovL2dlb2cudW9yZWdvbi5lZHUvYmFydGxlaW4vY291cnNlcy9nZW9nNDk1L2V4MDYuaHRtbCkNCjguIFtodHRwczovL3JwdWJzLmNvbS9yYmF0emluZy9tYXBwaW5nXShodHRwczovL3JwdWJzLmNvbS9yYmF0emluZy9tYXBwaW5nKQ0KDQogIA0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCiMgTWFweSDFm3dpYXRhIGkgaWNoIHByZXplbnRhY2phDQoNClJvemR6aWHFgiB0ZW4gamVzdCBpbnNwaXJvd2FueSBhcnR1a3XFgmVtIFtEcmF3aW5nIGJlYXV0aWZ1bCBtYXBzIHByb2dyYW1tYXRpY2FsbHkgd2l0aCBSLCBzZiBhbmQgZ2dwbG90MiDigJQgUGFydCAxOiBCYXNpY3MgYXV0b3JzdHdhIE1lbGEgTW9yZW5vIGkgTWF0aGlldSBCYXNpbGxlXShodHRwczovL3d3dy5yLXNwYXRpYWwub3JnL3IvMjAxOC8xMC8yNS9nZ3Bsb3QyLXNmLmh0bWwpDQpgYGB7cn0NCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkNCmxpYnJhcnkocm5hdHVyYWxlYXJ0aGRhdGEpDQpgYGANCg0KYGBge3J9DQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQ0KY2xhc3Mod29ybGQpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZigpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZigpICsNCiAgeGxhYigiTG9uZ2l0dWRlIikgKyB5bGFiKCJMYXRpdHVkZSIpICsNCiAgZ2d0aXRsZSgiV29ybGQgbWFwIiwgc3VidGl0bGUgPSBwYXN0ZTAoIigiLCBsZW5ndGgodW5pcXVlKHdvcmxkJG5hbWUpKSwgIiBjb3VudHJpZXMpIikpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdChkYXRhID0gd29ybGQpICsgDQogIGdlb21fc2YoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImxpZ2h0Z3JlZW4iKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gMTB9DQpnZ3Bsb3QoZGF0YSA9IHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBwb3BfZXN0KSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAicGxhc21hIiwgdHJhbnMgPSAic3FydCIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKCkgKw0KICBjb29yZF9zZihjcnMgPSAiK3Byb2o9bGFlYSArbGF0XzA9NTIgK2xvbl8wPTEwICt4XzA9NDMyMTAwMCAreV8wPTMyMTAwMDAgK2VsbHBzPUdSUzgwICt1bml0cz1tICtub19kZWZzICIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKCkgKw0KICBjb29yZF9zZihjcnMgPSAiK2luaXQ9ZXBzZzozMDM1IikNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHNmKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKCkgKw0KICBjb29yZF9zZihjcnMgPSBzdF9jcnMoMzAzNSkpDQpgYGANCktvZCDFunLDs2TFgm93eSBwb2Nob2R6aSB6IGFydHlrdcWCdSBbRHJhd2luZyBiZWF1dGlmdWwgbWFwcyBwcm9ncmFtbWF0aWNhbGx5IHdpdGggUiwgc2YgYW5kIGdncGxvdDIg4oCUIFBhcnQgMTogQmFzaWNzIGF1dG9yc3R3YSBNZWxhIE1vcmVubyBpIE1hdGhpZXUgQmFzaWxsZV0oaHR0cHM6Ly93d3cuci1zcGF0aWFsLm9yZy9yLzIwMTgvMTAvMjUvZ2dwbG90Mi1zZi5odG1sKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKCkgKw0KICBjb29yZF9zZih4bGltID0gYygtMTAyLjE1LCAtNzQuMTIpLCB5bGltID0gYyg3LjY1LCAzMy45NyksIGV4cGFuZCA9IEZBTFNFKQ0KYGBgDQpgYGB7cn0NCndvcmxkX3BvaW50czwtIHN0X2NlbnRyb2lkKHdvcmxkKQ0Kd29ybGRfcG9pbnRzIDwtIGNiaW5kKHdvcmxkLCBzdF9jb29yZGluYXRlcyhzdF9jZW50cm9pZCh3b3JsZCRnZW9tZXRyeSkpKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZ2dyZXBlbCkgDQpsaWJyYXJ5KGdnc3BhdGlhbCkNCmBgYA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKyANCiAgZ2VvbV9zZihmaWxsPSAiYW50aXF1ZXdoaXRlIikgKyANCiAgZ2VvbV90ZXh0KGRhdGE9IHdvcmxkX3BvaW50cyxhZXMoeD1YLCB5PVksIGxhYmVsPW5hbWUpLCBjb2xvciA9ICJkYXJrYmx1ZSIsIA0KICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIGNoZWNrX292ZXJsYXAgPSBGQUxTRSkgKyANCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IC05MCwgeSA9IDI2LCBsYWJlbCA9ICJHdWxmIG9mIE1leGljbyIsIA0KICAgICAgICAgICBmb250ZmFjZSA9ICJpdGFsaWMiLCBjb2xvciA9ICJncmV5MjIiLCBzaXplID0gNikgKyANCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjUpICsgDQogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsgDQogIGNvb3JkX3NmKHhsaW0gPSBjKC0xMDIuMTUsIC03NC4xMiksIHlsaW0gPSBjKDcuNjUsIDMzLjk3KSwgZXhwYW5kID0gRkFMU0UpICsgDQogIHhsYWIoIkxvbmdpdHVkZSIpICsgeWxhYigiTGF0aXR1ZGUiKSArIA0KICBnZ3RpdGxlKCJNYXAgb2YgdGhlIEd1bGYgb2YgTWV4aWNvIGFuZCB0aGUgQ2FyaWJiZWFuIFNlYSIpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSBncmF5KC41KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDAuNSksIA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYWxpY2VibHVlIikpDQpgYGANCiMgUsOzxbxuZSBwcm9qZWtjamUga29yenlzdGFteSB6IA0KDQpbUFJPSl0oaHR0cHM6Ly9wcm9qLm9yZy9vcGVyYXRpb25zL3Byb2plY3Rpb25zL2luZGV4Lmh0bWwpDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShybmF0dXJhbGVhcnRoKQ0KbGlicmFyeShybmF0dXJhbGVhcnRoZGF0YSkNCmBgYA0KDQpgYGB7cn0NCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQpnZ3Bsb3Qod29ybGQpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkgKSArDQogIGNvb3JkX3NmKGNycyA9ICIrcHJvaj1hZWEgK2xhdF8xPTI5LjUgK2xhdF8yPTQyLjUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSAocHJvamVrY2phIEFsYmVycyBFcXVhbCBBcmVhKSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdCh3b3JsZCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gY29udGluZW50KSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWVxYyIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIChwcm9qZWtjamEgZXFjKSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMn0NCmdncGxvdCh3b3JsZCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gY29udGluZW50KSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWNlYSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIChwcm9qZWtjamEgY2VhKSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdCh3b3JsZCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gY29udGluZW50KSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWVjazEiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSAocHJvamVrY2phIGVjazEpIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBpbHVzdHJhY2rEhSB6IGtzacSFxbxraSBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDEwfQ0KZ2dwbG90KHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjb250aW5lbnQpICkgKw0KICBjb29yZF9zZihjcnMgPSAiK3Byb2o9ZWNrMiIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIChwcm9qZWtjamEgZWNrMikiLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBvcHJhY293YW5pZSB3xYJhc25lIGluc3Bpcm93YW5lIGlsdXN0cmFjasSFIHoga3NpxIXFvGtpIEdlb2NvbXB1dGF0aW9uIHdpdGggUi4iKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gMTB9DQpnZ3Bsb3Qod29ybGQpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkgKSArDQogIGNvb3JkX3NmKGNycyA9ICIrcHJvaj1lY2szIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJsaWdodGdyZXkiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IHJlbCgyKSkpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIMWbd2lhdGEgKHByb2pla2NqYSBlY2szKSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCndvcmxkX3Byb2ogPC0gc3RfdHJhbnNmb3JtKHdvcmxkLCAiK3Byb2o9ZWNrMyIpDQpnZ3Bsb3Qod29ybGRfcHJvalsiY29udGluZW50Il0pICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCndvcmxkX3Byb2ogPC0gc3RfdHJhbnNmb3JtKHdvcmxkLCAiK3Byb2o9ZWNrNCIpDQpnZ3Bsb3Qod29ybGRfcHJvalsiY29udGluZW50Il0pICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSAxMH0NCmdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkpICsNCiAgY29vcmRfc2YoY3JzID0gIitpbml0PWVwc2c6NDMyNiIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBrb2RlbSBhdXRvcnN0d2EgTWVsYSBNb3Jlbm8gaSBNYXRoaWV1IEJhc2lsbGUnYS4iKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gMTB9DQpnZ3Bsb3QoZGF0YSA9IHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjb250aW5lbnQpLCBhbHBoYSA9IC41KSArDQogIGNvb3JkX3NmKGNycyA9ICIrcHJvaj1tb2xsIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJsaWdodGdyZXkiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IHJlbCgyKSkpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIMWbd2lhdGEgKHByb2pla2NqYSBNb2xsd2VpZGUpIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBpbHVzdHJhY2rEhSB6IGtzacSFxbxraSBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDEwfQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKGFscGhhID0gLjUpICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPW1vbGwiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSAocHJvamVrY2phIE1vbGx3ZWlkZSkiLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBvcHJhY293YW5pZSB3xYJhc25lIGluc3Bpcm93YW5lIGlsdXN0cmFjasSFIHoga3NpxIXFvGtpIEdlb2NvbXB1dGF0aW9uIHdpdGggUi4iKQ0KYGBgDQojIyBQcm9qZWtjamUgc2Zlcnljem5lIChnbG9idXN5KQ0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCmdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkpICsNCiAgY29vcmRfc2YoY3JzID0gIitpbml0PWVwc2c6MzAzNSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBrb2RlbSBhdXRvcnN0d2EgTWVsYSBNb3Jlbm8gaSBNYXRoaWV1IEJhc2lsbGUnYS4iKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCmdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvbnRpbmVudCkgKSArDQogIGNvb3JkX3NmKGNycyA9ICIrcHJvaj1sYWVhICtsYXRfMD0wICtsb25fMD0wICt4XzA9MCAreV8wPTAgK2VsbHBzPUdSUzgwICt1bml0cz1tICtub19kZWZzICIpICArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gc3VicmVnaW9uKSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWxhZWEgK2xhdF8wPTAgK2xvbl8wPTAgK3hfMD0wICt5XzA9MCArZWxscHM9R1JTODAgK3VuaXRzPW0gK25vX2RlZnMgIikgICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBpbHVzdHJhY2rEhSB6IGtzacSFxbxraSBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQpnZ3Bsb3QoZGF0YSA9IHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBuYW1lKSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWxhZWEgK2xhdF8wPTAgK2xvbl8wPTAgK3hfMD0wICt5XzA9MCArZWxscHM9R1JTODAgK3VuaXRzPW0gK25vX2RlZnMgIikgICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBpbHVzdHJhY2rEhSB6IGtzacSFxbxraSBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQpnZ3Bsb3QoZGF0YSA9IHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjb250aW5lbnQpICkgKw0KICBjb29yZF9zZihjcnMgPSAiK3Byb2o9bGFlYSArbGF0XzA9MzAgK2xvbl8wPS0xMDAgK3hfMD0wICt5XzA9MCArZWxscHM9R1JTODAgK3VuaXRzPW0gK25vX2RlZnMgIikgICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAibGlnaHRncmV5IiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSDFm3dpYXRhIiwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogb3ByYWNvd2FuaWUgd8WCYXNuZSBpbnNwaXJvd2FuZSBpbHVzdHJhY2rEhSB6IGtzacSFxbxraSBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQpnZ3Bsb3QoZGF0YSA9IHdvcmxkKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBuYW1lKSApICsNCiAgY29vcmRfc2YoY3JzID0gIitwcm9qPWxhZWEgK2xhdF8wPTMwICtsb25fMD0tMTAwICt4XzA9MCAreV8wPTAgK2VsbHBzPUdSUzgwICt1bml0cz1tICtub19kZWZzICIpICArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JleSIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gcmVsKDIpKSkgKw0KICBsYWJzKHRpdGxlID0gIk1hcGEgxZt3aWF0YSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUgaW5zcGlyb3dhbmUgaWx1c3RyYWNqxIUgeiBrc2nEhcW8a2kgR2VvY29tcHV0YXRpb24gd2l0aCBSLiIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKCkgKw0KICBjb29yZF9zZihjcnMgPSAiK3Byb2o9bGFlYSAreF8wPTAgK3lfMD0wICtsb25fMD0tNzQgK2xhdF8wPTQwIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJsaWdodGdyZXkiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IHJlbCgyKSkpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIMWbd2lhdGEiLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBvcHJhY293YW5pZSB3xYJhc25lIGluc3Bpcm93YW5lIGlsdXN0cmFjasSFIHoga3NpxIXFvGtpIEdlb2NvbXB1dGF0aW9uIHdpdGggUi4iKQ0KYGBgDQojIFBvbHNrYSAod29qZXfDs2R6dHdhLCBwb3dpYXR5LCBnbWlueSkNCg0KIyMgV3lrb3J6eXN0YW5pZSBwbGlrw7N3ICoqc3AqKg0KDQojIyMgVcW8eWNpZSB0eWxrbyBmdW5rY2ppICpwbG90KiBkbyBkYW55Y2ggdyBmb3JtYWNpZSAqKnNwKioNCg0KIyMjIyBQaWVyd3N6ZSB3cHJhd2tpDQoNCmBgYHtyfQ0KbGlicmFyeShzcCkNCmBgYA0KDQpgYGB7cn0NCmdhZG1fM3NwIDwtIHJlYWRSRFMoImRhbmUvZ2FkbTM2X1BPTF8zX3NwLnJkcyIpDQpnYWRtXzJzcCA8LSByZWFkUkRTKCJkYW5lL2dhZG0zNl9QT0xfMl9zcC5yZHMiKQ0KZ2FkbV8xc3AgPC0gcmVhZFJEUygiZGFuZS9nYWRtMzZfUE9MXzFfc3AucmRzIikNCmdhZG1fMHNwIDwtIHJlYWRSRFMoImRhbmUvZ2FkbTM2X1BPTF8wX3NwLnJkcyIpDQpgYGANCg0KYGBge3J9DQpwbG90KGdhZG1fMHNwLCBib3JkZXIgPSAnZGFya2dyZXknKQ0KYGBgDQpgYGB7cn0NCnBsb3QoZ2FkbV8xc3AsIGJvcmRlciA9ICdkYXJrZ3JleScpDQpgYGANCg0KYGBge3J9DQpwbG90KGdhZG1fMnNwLCBib3JkZXIgPSAnZGFya2dyZXknKQ0KYGBgDQpgYGB7cn0NCnBsb3QoZ2FkbV8zc3AsIGJvcmRlciA9ICdkYXJrZ3JleScpDQpgYGANCg0KIyMjIyBQb3ByYXdpYW15IHJ5c3Vua2kNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KcGxvdChnYWRtXzBzcCwgYm9yZGVyID0gJ2RhcmtncmV5JykNCnRpdGxlKG1haW4gPSAiS29udHVyIFBvbHNraSIsDQogICAgICBzdWIgPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBkYW55Y2ggeiBHQURNLiIsDQogICAgICBmb250Lm1haW4gPSA0LCBmb250LnN1YiA9IDMsDQogICAgICBjZXgubWFpbiA9IDEuNSwgY2V4LnN1YiA9IC43NSwNCiAgICAgIGNvbC5tYWluID0gImluZGlhbnJlZDQiLCBjb2wuc3ViID0gImJpc3F1ZTQiKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KcGxvdChnYWRtXzFzcCwgYm9yZGVyID0gJ2NvcmFsJykNCnRpdGxlKG1haW4gPSAiS29udHVyIFBvbHNraSB3cmF6IHogd29qZXfDs2R6dHdhbWkiLA0KICAgICAgc3ViID0gIsW5csOzZMWCbzogT3ByYWNvd2FuaWUgd8WCYXNuZSBuYSBwb2RzdGF3aWUgZGFueWNoIHogR0FETS4iLA0KICAgICAgZm9udC5tYWluID0gMiwgZm9udC5zdWIgPSAzLA0KICAgICAgY2V4Lm1haW4gPSAxLjUsIGNleC5zdWIgPSAuNzUsDQogICAgICBjb2wubWFpbiA9ICJpbmRpYW5yZWQ0IiwgY29sLnN1YiA9ICJsaWdodHNhbG1vbjQiKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KcGxvdChnYWRtXzJzcCwgYm9yZGVyID0gJ2RhcmtncmV5JykNCnRpdGxlKG1haW4gPSAiS29udHVyIFBvbHNraSB3cmF6IHogcG93aWF0YW1pIiwNCiAgICAgIHN1YiA9ICLFuXLDs2TFgm86IE9wcmFjb3dhbmllIHfFgmFzbmUgbmEgcG9kc3Rhd2llIGRhbnljaCB6IEdBRE0uIiwNCiAgICAgIGZvbnQubWFpbiA9IDIsIGZvbnQuc3ViID0gMywNCiAgICAgIGNleC5tYWluID0gMiwgY2V4LnN1YiA9IC43NSwNCiAgICAgIGNvbC5tYWluID0gIm1pZG5pZ2h0Ymx1ZSIsIGNvbC5zdWIgPSAibGlnaHRzYWxtb240IikNCmBgYA0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCnBsb3QoZ2FkbV8zc3AsIGJvcmRlciA9ICdjb3JhbDMnKQ0KdGl0bGUobWFpbiA9ICJLb250dXIgUG9sc2tpIHdyYXogeiBnbWluYW1pIiwNCiAgICAgIHN1YiA9ICLFuXLDs2TFgm86IE9wcmFjb3dhbmllIHfFgmFzbmUgbmEgcG9kc3Rhd2llIGRhbnljaCB6IEdBRE0uIiwNCiAgICAgIGZvbnQubWFpbiA9IDEsIGZvbnQuc3ViID0gMywNCiAgICAgIGNleC5tYWluID0gMS41LCBjZXguc3ViID0gLjUsDQogICAgICBjb2wubWFpbiA9ICJpbmRpYW5yZWQ0IiwgY29sLnN1YiA9ICJzYW5keWJyb3duIikNCmBgYA0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCmNvbG9ycyA9IHJhaW5ib3coMTAwKQ0KcGxvdChnYWRtXzFzcCwgY29sID0gY29sb3JzLCBib3JkZXIgPSAnZGFya2dyZXknKQ0KdGl0bGUobWFpbiA9ICJXb2pld8OzZHp0d2EgUG9sc2tpIChwb2tvbG9yb3dhbmUpIiwNCiAgICAgIHN1YiA9ICLFuXLDs2TFgm86IE9wcmFjb3dhbmllIHfFgmFzbmUgbmEgcG9kc3Rhd2llIGRhbnljaCB6IEdBRE0uIiwNCiAgICAgIGZvbnQubWFpbiA9IDIsIGZvbnQuc3ViID0gMywNCiAgICAgIGNleC5tYWluID0gMS41LCBjZXguc3ViID0gLjc1LA0KICAgICAgY29sLm1haW4gPSAiaW5kaWFucmVkNCIsIGNvbC5zdWIgPSAibGlnaHRzYWxtb240IikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KYGBgDQoNCmBgYHtyfQ0KcGFsZXRhIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCJCbHVlcyIpKSgxNykNCmNvbG9ycyA9IHJlcCgiIzAwRkYwMDIyIiwgMzgwKQ0KY29sb3JzW2dhZG1fMnNwQGRhdGEkTkFNRV8xID09ICJQb2RsYXNraWUiXSA9IHBhbGV0YVs3XQ0KY29sb3JzW2dhZG1fMnNwQGRhdGEkTkFNRV8yID09ICJCaWHFgnlzdG9rIChDaXR5KSJdID0gInJlZCINCnBsb3QoZ2FkbV8yc3AsIGNvbCA9IGNvbG9ycywgYm9yZGVyID0gRkFMU0UpDQp0aXRsZSgiUG9sc2thLCB3b2pld8OzZHp0b3cgcG9kbGFza2llLCBwb3dpYXQgQmlhxYJ5c3RvayAobWlhc3RvKSIpDQpgYGANCiMjIFd5a29yenlzdGFuaWUgcGxpa8OzdyAqKnNmKioNCg0KYGBge3J9DQpnYWRtXzNzZiA8LSByZWFkUkRTKCJkYW5lL2dhZG0zNl9QT0xfM19zZi5yZHMiKQ0KZ2FkbV8yc2YgPC0gcmVhZFJEUygiZGFuZS9nYWRtMzZfUE9MXzJfc2YucmRzIikNCmdhZG1fMXNmIDwtIHJlYWRSRFMoImRhbmUvZ2FkbTM2X1BPTF8xX3NmLnJkcyIpDQpnYWRtXzBzZiA8LSByZWFkUkRTKCJkYW5lL2dhZG0zNl9QT0xfMF9zZi5yZHMiKQ0KYGBgDQoNCmBgYHtyfQ0Kd29ybGRjaXRpZXMgPC0gcmVhZF9jc3YoImRhbmUvd29ybGRjaXRpZXMuY3N2IikNCm1pc3RhLndvaiA8LSB3b3JsZGNpdGllcyAlPiUNCiAgZmlsdGVyKGNvdW50cnkgPT0gIlBvbGFuZCIsIGNhcGl0YWwgIT0gIm1pbm9yIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmdhZG1fMHNmICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKCkgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2FkbV8xc2YgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoKSArIA0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJQb2R6aWHFgiBhZG1pbmlzdHJhY3lqbnkgUG9sc2tpICh3b2pld8OzZHp0d2EpIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmdhZG1fMXNmICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKCkgKyANCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAiUG9kemlhxYIgYWRtaW5pc3RyYWNqeW55IFBvbHNraSAod29qZXfDs2R6dHdhKSIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQpnZ3Bsb3QoKSArDQogIGFubm90YXRpb25fc3BhdGlhbChnYWRtXzFzZikgKw0KICBsYXllcl9zcGF0aWFsKGdhZG1fMXNmKSArDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlID0gIlBvZHppYcWCIGFkbWluaXN0cmFjanlueSBQb2xza2kgKHdvamV3w7NkenR3YSkiKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2dwbG90KCkgKw0KICBhbm5vdGF0aW9uX3NwYXRpYWwoZ2FkbV8xc2YpICsNCiAgbGF5ZXJfc3BhdGlhbChnYWRtXzFzZikgKw0KICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gInRsIikgKw0KICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJyIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQpnZ3Bsb3QoKSArDQogIGFubm90YXRpb25fbWFwX3RpbGUodHlwZSA9ICJvc20iKSArDQogIGxheWVyX3NwYXRpYWwoZ2FkbV8xc2YpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQpnZ3Bsb3QobWlzdGEud29qLCBhZXMoeCA9IGxuZywgeSA9IGxhdCkpICsNCiAgYW5ub3RhdGlvbl9zcGF0aWFsKGdhZG1fMXNmKSArDQogIGxheWVyX3NwYXRpYWwoZ2FkbV8xc2YsIGZpbGw9ICJhcXVhbWFyaW5lMiIpICsNCiAgZ2VvbV9zcGF0aWFsX3BvaW50KCkgKw0KICBzdGF0X3NwYXRpYWxfaWRlbnRpdHkoYWVzKGxhYmVsID0gY2l0eSksIGdlb20gPSAidGV4dF9yZXBlbCIsIGJveC5wYWRkaW5nID0gMSkgKw0KICBjb29yZF9zZigpICsNCiAgeGxhYigiRMWCdWdvxZvEhyBnZW9ncmFmaWN6bmEiKSArIHlsYWIoIlN6ZXJva2/Fm8SHIGdlb2dyYWZpY3puYSIpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIFBvbHNraSB6IHBvZHppYcWCZW0gbmEgd29qZXfDs2R6dHdhLiIpICsNCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjUpICsNCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gZ3JheSguNSksIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAwLjUpKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2dwbG90KG1pc3RhLndvaiwgYWVzKHggPSBsbmcsIHkgPSBsYXQpKSArDQogIGFubm90YXRpb25fc3BhdGlhbChnYWRtXzFzZiwgYWxwaGEgPSAuMykgKw0KICBsYXllcl9zcGF0aWFsKGdhZG1fMXNmLCBhbHBoYSA9IC4zLCBmaWxsPSAiYXF1YW1hcmluZTIiKSArDQogIGdlb21fc3BhdGlhbF9wb2ludCgpICsNCiAgc3RhdF9zcGF0aWFsX2lkZW50aXR5KGFlcyhsYWJlbCA9IGNpdHkpLCBnZW9tID0gInRleHRfcmVwZWwiLCBib3gucGFkZGluZyA9IDEpICsNCiAgY29vcmRfc2YoKSArDQogIHhsYWIoIkTFgnVnb8WbxIcgZ2VvZ3JhZmljem5hIikgKyB5bGFiKCJTemVyb2tvxZvEhyBnZW9ncmFmaWN6bmEiKSArDQogIGxhYnModGl0bGUgPSAiTWFwYSBQb2xza2kgeiBwb2R6aWHFgmVtIG5hIHdvamV3w7NkenR3YS4iKSArDQogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC41KSArDQogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9IGdyYXkoLjUpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gMC41KSkNCmBgYA0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmdncGxvdChtaXN0YS53b2osIGFlcyh4ID0gbG5nLCB5ID0gbGF0KSkgKw0KICBhbm5vdGF0aW9uX3NwYXRpYWwoZ2FkbV8xc2YsIGFscGhhID0gLjMpICsNCiAgbGF5ZXJfc3BhdGlhbChnYWRtXzFzZiwgYWxwaGEgPSAuMywgZmlsbD0gImFxdWFtYXJpbmUyIikgKw0KICBnZW9tX3NwYXRpYWxfcG9pbnQoKSArDQogIHN0YXRfc3BhdGlhbF9pZGVudGl0eShhZXMobGFiZWwgPSBjaXR5KSwgZ2VvbSA9ICJsYWJlbF9yZXBlbCIsIGJveC5wYWRkaW5nID0gMSkgKw0KICBjb29yZF9zZigpICsNCiAgeGxhYigiRMWCdWdvxZvEhyBnZW9ncmFmaWN6bmEiKSArIHlsYWIoIlN6ZXJva2/Fm8SHIGdlb2dyYWZpY3puYSIpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIFBvbHNraSB6IHBvZHppYcWCZW0gbmEgd29qZXfDs2R6dHdhLiIpICsNCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjUpICsNCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gZ3JheSguNSksIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAwLjUpKQ0KYGBgDQoNCmBgYHtyfQ0KcG93aWF0eS5wb2RsYXNraWUgPC0gZ2FkbV8yc2YgJT4lIA0KICBmaWx0ZXIoTkFNRV8xID09ICJQb2RsYXNraWUiKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBzZWxlY3QoTkFNRV8yKSAlPiUNCiAgZGlzdGluY3QNCmBgYA0KDQpgYGB7cn0NCnBvd2lhdHkucG9kbGFza2llDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoID0gN30NCmdhZG1fMnNmICU+JSANCiAgZmlsdGVyKE5BTUVfMSA9PSAiUG9kbGFza2llIikgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZigpICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMikpKSArDQogIGxhYnModGl0bGUgPSAiV29qZXfDs2R6dHdvIHBvZGxhc2tpZSIsDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IG9wcmFjb3dhbmllIHfFgmFzbmUuIikNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHJlYWR4bCkNCmBgYA0KDQpgYGB7cn0NCktvcm9uYXdpcnVzIDwtIHJlYWRfZXhjZWwoImRhbmUvS29yb25hd2lydXMueGxzeCIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHlzZWxlY3QpDQpgYGANCg0KYGBge3J9DQpkYXRhLktvcm9uYXdpcnVzLksgPC0gS29yb25hd2lydXMgJT4lIHNlbGVjdCgtYygxOjIpKSAlPiUgbmFtZXMoKSAlPiUgdmFyc19zZWxlY3QoY29udGFpbnMoIksiKSkNCkNPUk9OQS53b21lbiA8LSBLb3JvbmF3aXJ1cyAlPiUgc2VsZWN0KGRhdGEuS29yb25hd2lydXMuSykgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93U3VtcyhuYS5ybSA9IFRSVUUpDQpkYXRhLktvcm9uYXdpcnVzLk0gPC0gS29yb25hd2lydXMgJT4lIHNlbGVjdCgtYygxOjIpKSAlPiUgbmFtZXMoKSAlPiUgdmFyc19zZWxlY3QoY29udGFpbnMoIk0iKSkNCkNPUk9OQS5tZW4gPC0gS29yb25hd2lydXMgJT4lIHNlbGVjdChkYXRhLktvcm9uYXdpcnVzLk0pICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd1N1bXMobmEucm0gPSBUUlVFKQ0KQ09ST05BLmFsbCA8LSBLb3JvbmF3aXJ1cyAlPiUgc2VsZWN0KC1jKDE6MikpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd1N1bXMobmEucm0gPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KS29yb25hd2lydXMgPC0gS29yb25hd2lydXMgJT4lDQogIHNlbGVjdCgxKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSANCiAgY2JpbmQoQ09ST05BLmFsbCkgJT4lIGNiaW5kKENPUk9OQS5tZW4pICU+JSBjYmluZChDT1JPTkEud29tZW4pDQpgYGANCg0KYGBge3J9DQp0ZXN0LnNmIDwtIGdhZG1fMnNmICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGxlZnRfam9pbihLb3JvbmF3aXJ1cykgJT4lDQogIHN0X2FzX3NmKGNycyA9IDQzMjYpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KdGVzdC5zZiAlPiUgDQogIGZpbHRlcihOQU1FXzEgPT0gIlBvZGxhc2tpZSIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBDT1JPTkEuYWxsKSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAicGxhc21hIiwgYWxwaGEgPSAuNCkgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJMaWN6YmEgcG90d2llcmR6b255Y2ggY2hvcnljaCBDT1ZJRC0xOSIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIlN0YW4gbmEgZHppZcWEIDIwLjA0LjIwMjByLiBuYSBnb2R6LiAyNC4wMC4gXG5MaWN6YmEgemFyYcW8b255Y2g6ICIsIHN1bSh0ZXN0LnNmJENPUk9OQS5hbGwsIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCnRlc3Quc2YgJT4lIA0KICBmaWx0ZXIoTkFNRV8xID09ICJQb2RsYXNraWUiKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gQ09ST05BLm1lbikpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gInBsYXNtYSIsIGFscGhhID0gLjQpICsNCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAiTGljemJhIHBvdHdpZXJkem9ueWNoIGNob3J5Y2ggQ09WSUQtMTkgKG3EmcW8Y3p5xbpuaSkuIiwNCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiU3RhbiBuYSBkemllxYQgMjAuMDQuMjAyMHIuIG5hIGdvZHouIDI0LjAwLiBcbkxpY3piYSB6YXJhxbxvbnljaDogIiwgc3VtKHRlc3Quc2YkQ09ST05BLm1lbiwgbmEucm0gPSBUUlVFKSksDQogICAgICAgY2FwdGlvbiA9ICLFuXLDs2TFgm86IE9wcmFjb3dhbmllIHfFgmFzbmUgbmEgcG9kc3Rhd2llIEtvbXVuaWthdMOzdyBQVVcuIiwNCiAgICAgICBmaWxsID0gIkxpY3piYSB6YWthxbxhbnljaCIpDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KdGVzdC5zZiAlPiUgDQogIGZpbHRlcihOQU1FXzEgPT0gIlBvZGxhc2tpZSIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBDT1JPTkEud29tZW4pKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiLCBhbHBoYSA9IC40KSArDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlID0gIkxpY3piYSBwb3R3aWVyZHpvbnljaCBjaG9yeWNoIENPVklELTE5IChrb2JpZXR5KS4iLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJTdGFuIG5hIGR6aWXFhCAyMC4wNC4yMDIwci4gbmEgZ29kei4gMjQuMDAuIFxuTGljemJhIHphcmHFvG9ueWNoOiAiLCBzdW0odGVzdC5zZiRDT1JPTkEud29tZW4sIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCnRlc3Quc2YgJT4lIA0KICBmaWx0ZXIoTkFNRV8xID09ICJQb2RsYXNraWUiKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gQ09ST05BLmFsbCkpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2ModHJhbnMgPSAic3FydCIsIGFscGhhID0gLjQpICsNCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAiTGljemJhIHBvdHdpZXJkem9ueWNoIGNob3J5Y2ggQ09WSUQtMTkiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJTdGFuIG5hIGR6aWXFhCAyMC4wNC4yMDIwci4gbmEgZ29kei4gMjQuMDAuIFxuTGljemJhIHphcmHFvG9ueWNoOiAiLCBzdW0odGVzdC5zZiRDT1JPTkEuYWxsLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogT3ByYWNvd2FuaWUgd8WCYXNuZSBuYSBwb2RzdGF3aWUgS29tdW5pa2F0w7N3IFBVVy4iLA0KICAgICAgIGZpbGwgPSAiTGljemJhIHpha2HFvGFueWNoIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQp0ZXN0LnNmICU+JSANCiAgZmlsdGVyKE5BTUVfMSA9PSAiUG9kbGFza2llIikgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IENPUk9OQS5hbGwpKSArDQogIHNjYWxlX2NvbG91cl9ncmFkaWVudCgpICsNCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAiTGljemJhIHBvdHdpZXJkem9ueWNoIGNob3J5Y2ggQ09WSUQtMTkiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJTdGFuIG5hIGR6aWXFhCAyMC4wNC4yMDIwci4gbmEgZ29kei4gMjQuMDAuIFxuTGljemJhIHphcmHFvG9ueWNoOiAiLCBzdW0odGVzdC5zZiRDT1JPTkEuYWxsLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogT3ByYWNvd2FuaWUgd8WCYXNuZSBuYSBwb2RzdGF3aWUgS29tdW5pa2F0w7N3IFBVVy4iLA0KICAgICAgIGZpbGwgPSAiTGljemJhIHpha2HFvGFueWNoIikNCmBgYA0KYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9DQp0ZXN0LnNmICU+JSANCiAgZmlsdGVyKE5BTUVfMSA9PSAiUG9kbGFza2llIikgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IENPUk9OQS5hbGwpKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImdyZXk5MCIsIGhpZ2ggPSAiZ3JleTMwIikgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJMaWN6YmEgcG90d2llcmR6b255Y2ggY2hvcnljaCBDT1ZJRC0xOSIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIlN0YW4gbmEgZHppZcWEIDIwLjA0LjIwMjByLiBuYSBnb2R6LiAyNC4wMC4gXG5MaWN6YmEgemFyYcW8b255Y2g6ICIsIHN1bSh0ZXN0LnNmJENPUk9OQS5hbGwsIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCnRlc3Quc2YgJT4lIA0KICBmaWx0ZXIoTkFNRV8xID09ICJQb2RsYXNraWUiKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gQ09ST05BLmFsbCkpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAic2t5Ymx1ZSIsIGhpZ2ggPSAicmVkNCIpICsNCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAiTGljemJhIHBvdHdpZXJkem9ueWNoIGNob3J5Y2ggQ09WSUQtMTkiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJTdGFuIG5hIGR6aWXFhCAyMC4wNC4yMDIwci4gbmEgZ29kei4gMjQuMDAuIFxuTGljemJhIHphcmHFvG9ueWNoOiAiLCBzdW0odGVzdC5zZiRDT1JPTkEuYWxsLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICBjYXB0aW9uID0gIsW5csOzZMWCbzogT3ByYWNvd2FuaWUgd8WCYXNuZSBuYSBwb2RzdGF3aWUgS29tdW5pa2F0w7N3IFBVVy4iLA0KICAgICAgIGZpbGwgPSAiTGljemJhIHpha2HFvGFueWNoIikNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KGNhcnRvZ3JhcGh5KQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KdGVzdC5zZiAlPiUgDQogIGZpbHRlcihOQU1FXzEgPT0gIlBvZGxhc2tpZSIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBhcy5mYWN0b3IoQ09ST05BLmFsbCkpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNhcnRvLnBhbChwYWwxID0gInJlZC5wYWwiLCBuMSA9IDE2KSkgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJMaWN6YmEgcG90d2llcmR6b255Y2ggY2hvcnljaCBDT1ZJRC0xOSIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIlN0YW4gbmEgZHppZcWEIDIwLjA0LjIwMjByLiBuYSBnb2R6LiAyNC4wMC4gXG5MaWN6YmEgemFyYcW8b255Y2g6ICIsIHN1bSh0ZXN0LnNmJENPUk9OQS5hbGwsIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQ0KdGVzdC5zZiAlPiUgDQogIGZpbHRlcihOQU1FXzEgPT0gIlBvZGxhc2tpZSIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBhcy5mYWN0b3IoQ09ST05BLm1lbikpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNhcnRvLnBhbChwYWwxID0gImdyZWVuLnBhbCIsIG4xID0gMTMpKSArDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlID0gIkxpY3piYSBwb3R3aWVyZHpvbnljaCBjaG9yeWNoIENPVklELTE5IChtxJnFvGN6ecW6bmkpLiIsDQogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIlN0YW4gbmEgZHppZcWEIDIwLjA0LjIwMjByLiBuYSBnb2R6LiAyNC4wMC4gXG5MaWN6YmEgemFyYcW8b255Y2g6ICIsIHN1bSh0ZXN0LnNmJENPUk9OQS5tZW4sIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBOVUxMLCBwYW5lbC5ncmlkLm1pbm9yID0gTlVMTCwgDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBOVUxMKQ0KYGBgDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30NCnRlc3Quc2YgJT4lIA0KICBmaWx0ZXIoTkFNRV8xID09ICJQb2RsYXNraWUiKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gYXMuZmFjdG9yKENPUk9OQS53b21lbikpKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiR3JlZW5zIikgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJMaWN6YmEgcG90d2llcmR6b255Y2ggY2hvcnljaCBDT1ZJRC0xOSAoa29iaWV0eSkiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJTdGFuIG5hIGR6aWXFhCAyMC4wNC4yMDIwci4gbmEgZ29kei4gMjQuMDAuIFxuTGljemJhIHphcmHFvG9ueWNoOiAiLCBzdW0odGVzdC5zZiRDT1JPTkEud29tZW4sIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIGNhcHRpb24gPSAixblyw7NkxYJvOiBPcHJhY293YW5pZSB3xYJhc25lIG5hIHBvZHN0YXdpZSBLb211bmlrYXTDs3cgUFVXLiIsDQogICAgICAgZmlsbCA9ICJMaWN6YmEgemFrYcW8YW55Y2giKQ0KYGBgDQpgYGB7cn0NCmRldGFjaChwYWNrYWdlOlJDb2xvckJyZXdlcikNCg0KZGV0YWNoKHBhY2thZ2U6Z2dzcGF0aWFsKQ0KZGV0YWNoKHBhY2thZ2U6Z2dyZXBlbCkgDQoNCmRldGFjaChwYWNrYWdlOnRpZHl2ZXJzZSkNCmRldGFjaChwYWNrYWdlOmdncGxvdDIpDQpkZXRhY2gocGFja2FnZTp0aWJibGUpDQpkZXRhY2gocGFja2FnZTp0aWR5cikNCmRldGFjaChwYWNrYWdlOnJlYWRyKQ0KZGV0YWNoKHBhY2thZ2U6cHVycnIpDQpkZXRhY2gocGFja2FnZTpkcGx5cikNCmRldGFjaChwYWNrYWdlOnN0cmluZ3IpDQpkZXRhY2gocGFja2FnZTpmb3JjYXRzKQ0KDQpkZXRhY2gocGFja2FnZTpzZikNCmRldGFjaChwYWNrYWdlOnJuYXR1cmFsZWFydGgpDQpkZXRhY2gocGFja2FnZTpybmF0dXJhbGVhcnRoZGF0YSkNCg0KYGBgDQoNCg==