# Load required libraries
library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(plotly)
library(tidyverse)
library(scales)
library(ggrepel)
library(stringr)
library(GGally)
theme_set(theme_minimal())
Data Preprocessing
lpi <- read.csv(
"living-planet-index.csv",
sep = ";"
)
colnames(lpi) <- c(
"Region",
"Year",
"AverageIndex",
"UpperIndex",
"LowerIndex"
)
lpi$Year <- as.numeric(lpi$Year)
lpi$AverageIndex <- as.numeric(lpi$AverageIndex)
lpi$UpperIndex <- as.numeric(lpi$UpperIndex)
lpi$LowerIndex <- as.numeric(lpi$LowerIndex)
species <- read.csv(
"Species.csv",
check.names = FALSE
)
species$Threatened <- as.numeric(
gsub(",", "", species$`Subtotal (threatened spp.)`)
)
species$Total <- as.numeric(
gsub(",", "", species$Total)
)
species$ThreatenedPercent <-
(species$Threatened / species$Total) * 100
species$EN <- as.numeric(
gsub(",", "", species$EN)
)
species$VU <- as.numeric(
gsub(",", "", species$VU)
)
species$CR <- as.numeric(gsub(",", "", species$CR))
species_clean <- species %>%
arrange(desc(ThreatenedPercent)) %>%
slice(1:20)
top15 <- species %>%
arrange(desc(Threatened)) %>%
slice(1:15)
species_long <- top15 %>%
select(Name, VU, EN, CR) %>%
pivot_longer(
cols = c(VU, EN, CR),
names_to = "ThreatLevel",
values_to = "Count"
)
protected <- read.csv(
"161a1ce8-f2e3-46c2-b830-1f9149c4f66d_Data.csv"
)
protected <- protected %>%
select(
Country.Name,
X2024..YR2024.
) %>%
rename(
Country = Country.Name,
ProtectedArea = X2024..YR2024.
)
protected <- protected %>%
filter(ProtectedArea != "..")
protected$ProtectedArea <- as.numeric(
protected$ProtectedArea
)
top_protected <- protected %>%
arrange(desc(ProtectedArea)) %>%
slice(1:20)
df <- read_csv("Biodiversity habitat loss (Williams et al. 2021).csv")
aggregates <- c("Europe", "Latin America", "North Africa", "North America",
"South and East Asia", "Sub-Saharan Africa", "World")
clean_story <- df %>%
filter(!Entity %in% aggregates) %>%
summarise(
Amphibians_BAU = mean(bau_habitat_loss_amphibians, na.rm = TRUE),
Amphibians_Waste = mean(waste_habitat_loss_amphibians, na.rm = TRUE),
Amphibians_Diets = mean(diets_habitat_loss_amphibians, na.rm = TRUE),
Amphibians_Yields = mean(yields_habitat_loss_amphibians, na.rm = TRUE),
Amphibians_Combined = mean(combined_habitat_loss_amphibians, na.rm = TRUE),
Birds_BAU = mean(bau_habitat_loss_birds, na.rm = TRUE),
Birds_Waste = mean(waste_habitat_loss_birds, na.rm = TRUE),
Birds_Diets = mean(diets_habitat_loss_birds, na.rm = TRUE),
Birds_Yields = mean(yields_habitat_loss_birds, na.rm = TRUE),
Birds_Combined = mean(combined_habitat_loss_birds, na.rm = TRUE),
Mammals_BAU = mean(bau_habitat_loss_mammals, na.rm = TRUE),
Mammals_Waste = mean(waste_habitat_loss_mammals, na.rm = TRUE),
Mammals_Diets = mean(diets_habitat_loss_mammals, na.rm = TRUE),
Mammals_Yields = mean(yields_habitat_loss_mammals, na.rm = TRUE),
Mammals_Combined = mean(combined_habitat_loss_mammals, na.rm = TRUE)
) %>%
pivot_longer(
cols = everything(),
names_to = c("Species", "Scenario"),
names_sep = "_"
) %>%
mutate(
Scenario = recode(Scenario,
"BAU" = "Business As Usual",
"Waste" = "Reduce Food Waste",
"Diets" = "Dietary Shifts",
"Yields" = "Improve Crop Yields",
"Combined" = "All Interventions Combined"),
Scenario = factor(Scenario, levels = c(
"Business As Usual",
"Reduce Food Waste",
"Dietary Shifts",
"Improve Crop Yields",
"All Interventions Combined"
))
)
Chart 1: Wildlife Populations Over Time (2025)
global_lpi <- lpi %>%
group_by(Year) %>%
summarise(
AvgIndex = mean(
AverageIndex,
na.rm = TRUE
)
)
p1 <- ggplot(
global_lpi,
aes(
x = Year,
y = AvgIndex,
text = paste(
"Year:", Year,
"<br>Index:", round(AvgIndex,1)
)
)
) +
geom_line(
linewidth = 1.3,
colour = "darkgreen"
) +
geom_point(size = 2) +
labs(
title = "Wildlife Populations Over Time",
x = "Year",
y = "Living Planet Index"
)
ggplotly(
p1,
tooltip = "text"
)
Chart 2: Biodiversity Loss Across Regions
latest <- lpi %>%
filter(
Year == max(Year)
)
p2 <- ggplot(
latest,
aes(
reorder(
Region,
AverageIndex
),
AverageIndex,
text = paste(
Region,
"<br>Index:",
round(AverageIndex,1)
)
)
) +
geom_col(
fill = "steelblue"
) +
coord_flip() +
labs(
title = "Biodiversity By Region",
x = "",
y = "Index"
)
ggplotly(
p2,
tooltip = "text"
)
Chart 3: Threat Composition Across Species Groups
species_heat <- species %>%
select(Name, CR, EN, VU)
species_heat$CR <- as.numeric(gsub(",", "", species_heat$CR))
species_heat$EN <- as.numeric(gsub(",", "", species_heat$EN))
species_heat$VU <- as.numeric(gsub(",", "", species_heat$VU))
species_heat <- species_heat %>%
pivot_longer(
cols = c(CR, EN, VU),
names_to = "ThreatLevel",
values_to = "Count"
)
top_species <- species %>%
mutate(
Threatened = as.numeric(
gsub(",", "", `Subtotal (threatened spp.)`)
)
) %>%
arrange(desc(Threatened)) %>%
slice(1:15)
species_heat <- species_heat %>%
filter(Name %in% top_species$Name)
p3 <- ggplot(
species_heat,
aes(
x = ThreatLevel,
y = reorder(Name, Count),
fill = Count
)
) +
geom_tile() +
scale_fill_gradient(
low = "#fee8c8",
high = "#e34a33"
) +
labs(
title = "Threat Composition Across Species Groups"
)+
theme(
strip.text = element_text(size = 9),
plot.title = element_text(size = 11),
plot.subtitle = element_text(size = 7),
panel.spacing = unit(2, "lines"),
panel.grid.minor = element_blank()
)
ggplotly(
p3,
tooltip = c("x", "y")
)
Chart 4: Countries Most In Need Of Conservation Action
priority_countries <- protected %>%
filter(!is.na(ProtectedArea)) %>%
arrange(ProtectedArea) %>%
slice(1:20)
p4 <- ggplot(
priority_countries,
aes(
x = reorder(Country, ProtectedArea),
y = ProtectedArea
)
) +
geom_segment(
aes(
xend = Country,
y = 0,
yend = ProtectedArea
),
colour = "grey70"
) +
geom_point(
aes(
colour = ProtectedArea,
size = ProtectedArea
)
) +
coord_flip() +
labs(
title = "Countries Most In Need Of Conservation Action",
subtitle = "Countries with the smallest share of protected land",
x = "",
y = "Protected Area (%)"
) +
theme_minimal()+
theme(
strip.text = element_text(size = 9),
plot.title = element_text(size = 11),
plot.subtitle = element_text(size = 7)
)
ggplotly(
p4,
tooltip = c("x", "y")
)
Chart 5: What Could Save Wildlife by 2050?
# Split data by animal class
data_amphibians <- clean_story %>% filter(Species == "Amphibians")
data_birds <- clean_story %>% filter(Species == "Birds")
data_mammals <- clean_story %>% filter(Species == "Mammals")
# Color mapping matching performance hierarchy (Red to Green)
scenario_colors <- c(
"Business As Usual" = "#d73027",
"Reduce Food Waste" = "#f46d43",
"Dietary Shifts" = "#fdae61",
"Improve Crop Yields" = "#a6d96a",
"All Interventions Combined" = "#1a9850"
)
# 2. Build individual subplots
create_subplot <- function(sub_data, title_text) {
plot_ly(
data = sub_data,
y = ~Scenario,
x = ~value,
type = 'bar',
orientation = 'h',
color = ~Scenario,
colors = scenario_colors,
text = ~paste0(round(value, 2), "%"),
textposition = 'outside',
textfont = list(size = 10),
hovertemplate = paste0("<b>%{y}</b><br>Habitat Change: %{x:.2f}%<extra></extra>"),
showlegend = FALSE
) %>%
layout(
# FIX: Changed xref and yref to "paper" and adjusted coordinates
# This explicitly locks the heading right in the middle top of the column grid
annotations = list(
list(
x = 0.5, y = 1.05,
text = paste0("<b>", title_text, "</b>"),
xref = "paper", yref = "paper",
xanchor = "center", yanchor = "bottom",
showarrow = FALSE,
font = list(size = 13, color = "black")
)
),
xaxis = list(
title = list(text = "Habitat Change (%)", standoff = 15),
ticksuffix = "%"
),
yaxis = list(title = "", categoryorder = "array", categoryarray = levels(sub_data$Scenario)),
shapes = list(
list(type = "line", x0 = 0, x1 = 0, y0 = -0.5, y1 = 4.5,
line = list(color = "grey40", width = 1.5, dash = "dash"))
)
)
}
p1 <- create_subplot(data_amphibians, "Amphibians")
p2 <- create_subplot(data_birds, "Birds")
p3 <- create_subplot(data_mammals, "Mammals")
# 3. Combine subplots and set structural spacing layout
interactive_chart <- subplot(p1, p2, p3, nrows = 1, shareY = TRUE, titleX = TRUE, margin = 0.06) %>%
layout(
title = list(
text = "<b>Which Action Actually Saves Wildlife Habitats by 2050?</b><br><span style='font-size:11px;color:gray;'>Global average projected habitat change. Negative values indicate habitat destruction.</span>",
font = list(size = 14),
x = 0.02
),
margin = list(t = 120, b = 70, l = 180, r = 30), # Expanded top margin slightly for the headings
barmode = 'group'
)
# View chart
interactive_chart
LS0tCnRpdGxlOiAiTUFUSDIyNzAgQXNzaWdubWVudCAzIC0gU3Rvcnl0ZWxsaW5nIHdpdGggT3BlbiBEYXRhIgphdXRob3I6ICJTd2FwbmlrYSBHYWRpZGFzdSAoUzQxNDU1NzkpIgpkYXRlOiAiMjAyNi0wNi0wOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShHR2FsbHkpCgp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQpgYGAKIyMgRGF0YSBQcmVwcm9jZXNzaW5nCgpgYGB7cn0KbHBpIDwtIHJlYWQuY3N2KAogICJsaXZpbmctcGxhbmV0LWluZGV4LmNzdiIsCiAgc2VwID0gIjsiCikKCmNvbG5hbWVzKGxwaSkgPC0gYygKICAiUmVnaW9uIiwKICAiWWVhciIsCiAgIkF2ZXJhZ2VJbmRleCIsCiAgIlVwcGVySW5kZXgiLAogICJMb3dlckluZGV4IgopCgpscGkkWWVhciA8LSBhcy5udW1lcmljKGxwaSRZZWFyKQpscGkkQXZlcmFnZUluZGV4IDwtIGFzLm51bWVyaWMobHBpJEF2ZXJhZ2VJbmRleCkKbHBpJFVwcGVySW5kZXggPC0gYXMubnVtZXJpYyhscGkkVXBwZXJJbmRleCkKbHBpJExvd2VySW5kZXggPC0gYXMubnVtZXJpYyhscGkkTG93ZXJJbmRleCkKYGBgCgpgYGB7cn0Kc3BlY2llcyA8LSByZWFkLmNzdigKICAiU3BlY2llcy5jc3YiLAogIGNoZWNrLm5hbWVzID0gRkFMU0UKKQpzcGVjaWVzJFRocmVhdGVuZWQgPC0gYXMubnVtZXJpYygKICBnc3ViKCIsIiwgIiIsIHNwZWNpZXMkYFN1YnRvdGFsICh0aHJlYXRlbmVkIHNwcC4pYCkKKQoKc3BlY2llcyRUb3RhbCA8LSBhcy5udW1lcmljKAogIGdzdWIoIiwiLCAiIiwgc3BlY2llcyRUb3RhbCkKKQoKc3BlY2llcyRUaHJlYXRlbmVkUGVyY2VudCA8LQogIChzcGVjaWVzJFRocmVhdGVuZWQgLyBzcGVjaWVzJFRvdGFsKSAqIDEwMAoKc3BlY2llcyRFTiA8LSBhcy5udW1lcmljKAogIGdzdWIoIiwiLCAiIiwgc3BlY2llcyRFTikKKQoKc3BlY2llcyRWVSA8LSBhcy5udW1lcmljKAogIGdzdWIoIiwiLCAiIiwgc3BlY2llcyRWVSkKKQoKc3BlY2llcyRDUiA8LSBhcy5udW1lcmljKGdzdWIoIiwiLCAiIiwgc3BlY2llcyRDUikpCgpzcGVjaWVzX2NsZWFuIDwtIHNwZWNpZXMgJT4lCiAgYXJyYW5nZShkZXNjKFRocmVhdGVuZWRQZXJjZW50KSkgJT4lCiAgc2xpY2UoMToyMCkKCnRvcDE1IDwtIHNwZWNpZXMgJT4lCiAgYXJyYW5nZShkZXNjKFRocmVhdGVuZWQpKSAlPiUKICBzbGljZSgxOjE1KQoKc3BlY2llc19sb25nIDwtIHRvcDE1ICU+JQogIHNlbGVjdChOYW1lLCBWVSwgRU4sIENSKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhWVSwgRU4sIENSKSwKICAgIG5hbWVzX3RvID0gIlRocmVhdExldmVsIiwKICAgIHZhbHVlc190byA9ICJDb3VudCIKICApCmBgYAoKYGBge3J9CnByb3RlY3RlZCA8LSByZWFkLmNzdigKICAiMTYxYTFjZTgtZjJlMy00NmMyLWI4MzAtMWY5MTQ5YzRmNjZkX0RhdGEuY3N2IgopCgpwcm90ZWN0ZWQgPC0gcHJvdGVjdGVkICU+JQogIHNlbGVjdCgKICAgIENvdW50cnkuTmFtZSwKICAgIFgyMDI0Li5ZUjIwMjQuCiAgKSAlPiUKICByZW5hbWUoCiAgICBDb3VudHJ5ID0gQ291bnRyeS5OYW1lLAogICAgUHJvdGVjdGVkQXJlYSA9IFgyMDI0Li5ZUjIwMjQuCiAgKQoKcHJvdGVjdGVkIDwtIHByb3RlY3RlZCAlPiUKICBmaWx0ZXIoUHJvdGVjdGVkQXJlYSAhPSAiLi4iKQoKcHJvdGVjdGVkJFByb3RlY3RlZEFyZWEgPC0gYXMubnVtZXJpYygKICBwcm90ZWN0ZWQkUHJvdGVjdGVkQXJlYQopCgp0b3BfcHJvdGVjdGVkIDwtIHByb3RlY3RlZCAlPiUKICBhcnJhbmdlKGRlc2MoUHJvdGVjdGVkQXJlYSkpICU+JQogIHNsaWNlKDE6MjApCmBgYAoKYGBge3J9CmRmIDwtIHJlYWRfY3N2KCJCaW9kaXZlcnNpdHkgaGFiaXRhdCBsb3NzIChXaWxsaWFtcyBldCBhbC4gMjAyMSkuY3N2IikKCmFnZ3JlZ2F0ZXMgPC0gYygiRXVyb3BlIiwgIkxhdGluIEFtZXJpY2EiLCAiTm9ydGggQWZyaWNhIiwgIk5vcnRoIEFtZXJpY2EiLCAKICAgICAgICAgICAgICAgICJTb3V0aCBhbmQgRWFzdCBBc2lhIiwgIlN1Yi1TYWhhcmFuIEFmcmljYSIsICJXb3JsZCIpCmNsZWFuX3N0b3J5IDwtIGRmICU+JQogIGZpbHRlcighRW50aXR5ICVpbiUgYWdncmVnYXRlcykgJT4lCiAgc3VtbWFyaXNlKAogICAgQW1waGliaWFuc19CQVUgPSBtZWFuKGJhdV9oYWJpdGF0X2xvc3NfYW1waGliaWFucywgbmEucm0gPSBUUlVFKSwKICAgIEFtcGhpYmlhbnNfV2FzdGUgPSBtZWFuKHdhc3RlX2hhYml0YXRfbG9zc19hbXBoaWJpYW5zLCBuYS5ybSA9IFRSVUUpLAogICAgQW1waGliaWFuc19EaWV0cyA9IG1lYW4oZGlldHNfaGFiaXRhdF9sb3NzX2FtcGhpYmlhbnMsIG5hLnJtID0gVFJVRSksCiAgICBBbXBoaWJpYW5zX1lpZWxkcyA9IG1lYW4oeWllbGRzX2hhYml0YXRfbG9zc19hbXBoaWJpYW5zLCBuYS5ybSA9IFRSVUUpLAogICAgQW1waGliaWFuc19Db21iaW5lZCA9IG1lYW4oY29tYmluZWRfaGFiaXRhdF9sb3NzX2FtcGhpYmlhbnMsIG5hLnJtID0gVFJVRSksCiAgICAKICAgIEJpcmRzX0JBVSA9IG1lYW4oYmF1X2hhYml0YXRfbG9zc19iaXJkcywgbmEucm0gPSBUUlVFKSwKICAgIEJpcmRzX1dhc3RlID0gbWVhbih3YXN0ZV9oYWJpdGF0X2xvc3NfYmlyZHMsIG5hLnJtID0gVFJVRSksCiAgICBCaXJkc19EaWV0cyA9IG1lYW4oZGlldHNfaGFiaXRhdF9sb3NzX2JpcmRzLCBuYS5ybSA9IFRSVUUpLAogICAgQmlyZHNfWWllbGRzID0gbWVhbih5aWVsZHNfaGFiaXRhdF9sb3NzX2JpcmRzLCBuYS5ybSA9IFRSVUUpLAogICAgQmlyZHNfQ29tYmluZWQgPSBtZWFuKGNvbWJpbmVkX2hhYml0YXRfbG9zc19iaXJkcywgbmEucm0gPSBUUlVFKSwKICAgIAogICAgTWFtbWFsc19CQVUgPSBtZWFuKGJhdV9oYWJpdGF0X2xvc3NfbWFtbWFscywgbmEucm0gPSBUUlVFKSwKICAgIE1hbW1hbHNfV2FzdGUgPSBtZWFuKHdhc3RlX2hhYml0YXRfbG9zc19tYW1tYWxzLCBuYS5ybSA9IFRSVUUpLAogICAgTWFtbWFsc19EaWV0cyA9IG1lYW4oZGlldHNfaGFiaXRhdF9sb3NzX21hbW1hbHMsIG5hLnJtID0gVFJVRSksCiAgICBNYW1tYWxzX1lpZWxkcyA9IG1lYW4oeWllbGRzX2hhYml0YXRfbG9zc19tYW1tYWxzLCBuYS5ybSA9IFRSVUUpLAogICAgTWFtbWFsc19Db21iaW5lZCA9IG1lYW4oY29tYmluZWRfaGFiaXRhdF9sb3NzX21hbW1hbHMsIG5hLnJtID0gVFJVRSkKICApICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBldmVyeXRoaW5nKCksCiAgICBuYW1lc190byA9IGMoIlNwZWNpZXMiLCAiU2NlbmFyaW8iKSwKICAgIG5hbWVzX3NlcCA9ICJfIgogICkgJT4lCiAgbXV0YXRlKAogICAgU2NlbmFyaW8gPSByZWNvZGUoU2NlbmFyaW8sIAogICAgICAgICAgICAgICAgICAgICAgIkJBVSIgPSAiQnVzaW5lc3MgQXMgVXN1YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICJXYXN0ZSIgPSAiUmVkdWNlIEZvb2QgV2FzdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICJEaWV0cyIgPSAiRGlldGFyeSBTaGlmdHMiLCAKICAgICAgICAgICAgICAgICAgICAgICJZaWVsZHMiID0gIkltcHJvdmUgQ3JvcCBZaWVsZHMiLCAKICAgICAgICAgICAgICAgICAgICAgICJDb21iaW5lZCIgPSAiQWxsIEludGVydmVudGlvbnMgQ29tYmluZWQiKSwKICAgIFNjZW5hcmlvID0gZmFjdG9yKFNjZW5hcmlvLCBsZXZlbHMgPSBjKAogICAgICAiQnVzaW5lc3MgQXMgVXN1YWwiLCAKICAgICAgIlJlZHVjZSBGb29kIFdhc3RlIiwgCiAgICAgICJEaWV0YXJ5IFNoaWZ0cyIsIAogICAgICAiSW1wcm92ZSBDcm9wIFlpZWxkcyIsIAogICAgICAiQWxsIEludGVydmVudGlvbnMgQ29tYmluZWQiCiAgICApKQogICkKYGBgCiMjIENoYXJ0IDE6IFdpbGRsaWZlIFBvcHVsYXRpb25zIE92ZXIgVGltZSAoMjAyNSkKYGBge3J9Cmdsb2JhbF9scGkgPC0gbHBpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIHN1bW1hcmlzZSgKICAgIEF2Z0luZGV4ID0gbWVhbigKICAgICAgQXZlcmFnZUluZGV4LAogICAgICBuYS5ybSA9IFRSVUUKICAgICkKICApCgpwMSA8LSBnZ3Bsb3QoCiAgZ2xvYmFsX2xwaSwKICBhZXMoCiAgICB4ID0gWWVhciwKICAgIHkgPSBBdmdJbmRleCwKICAgIHRleHQgPSBwYXN0ZSgKICAgICAgIlllYXI6IiwgWWVhciwKICAgICAgIjxicj5JbmRleDoiLCByb3VuZChBdmdJbmRleCwxKQogICAgKQogICkKKSArCiAgZ2VvbV9saW5lKAogICAgbGluZXdpZHRoID0gMS4zLAogICAgY29sb3VyID0gImRhcmtncmVlbiIKICApICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgbGFicygKICAgIHRpdGxlID0gIldpbGRsaWZlIFBvcHVsYXRpb25zIE92ZXIgVGltZSIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJMaXZpbmcgUGxhbmV0IEluZGV4IgogICkKCmdncGxvdGx5KAogIHAxLAogIHRvb2x0aXAgPSAidGV4dCIKKQpgYGAKCiMjIENoYXJ0IDI6IEJpb2RpdmVyc2l0eSBMb3NzIEFjcm9zcyBSZWdpb25zCmBgYHtyfQpsYXRlc3QgPC0gbHBpICU+JQogIGZpbHRlcigKICAgIFllYXIgPT0gbWF4KFllYXIpCiAgKQoKcDIgPC0gZ2dwbG90KAogIGxhdGVzdCwKICBhZXMoCiAgICByZW9yZGVyKAogICAgICBSZWdpb24sCiAgICAgIEF2ZXJhZ2VJbmRleAogICAgKSwKICAgIEF2ZXJhZ2VJbmRleCwKICAgIHRleHQgPSBwYXN0ZSgKICAgICAgUmVnaW9uLAogICAgICAiPGJyPkluZGV4OiIsCiAgICAgIHJvdW5kKEF2ZXJhZ2VJbmRleCwxKQogICAgKQogICkKKSArCiAgZ2VvbV9jb2woCiAgICBmaWxsID0gInN0ZWVsYmx1ZSIKICApICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJCaW9kaXZlcnNpdHkgQnkgUmVnaW9uIiwKICAgIHggPSAiIiwKICAgIHkgPSAiSW5kZXgiCiAgKQoKZ2dwbG90bHkoCiAgcDIsCiAgdG9vbHRpcCA9ICJ0ZXh0IgopCmBgYAoKIyMgQ2hhcnQgMzogVGhyZWF0IENvbXBvc2l0aW9uIEFjcm9zcyBTcGVjaWVzIEdyb3VwcwpgYGB7cn0Kc3BlY2llc19oZWF0IDwtIHNwZWNpZXMgJT4lCiAgc2VsZWN0KE5hbWUsIENSLCBFTiwgVlUpCgpzcGVjaWVzX2hlYXQkQ1IgPC0gYXMubnVtZXJpYyhnc3ViKCIsIiwgIiIsIHNwZWNpZXNfaGVhdCRDUikpCnNwZWNpZXNfaGVhdCRFTiA8LSBhcy5udW1lcmljKGdzdWIoIiwiLCAiIiwgc3BlY2llc19oZWF0JEVOKSkKc3BlY2llc19oZWF0JFZVIDwtIGFzLm51bWVyaWMoZ3N1YigiLCIsICIiLCBzcGVjaWVzX2hlYXQkVlUpKQoKc3BlY2llc19oZWF0IDwtIHNwZWNpZXNfaGVhdCAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhDUiwgRU4sIFZVKSwKICAgIG5hbWVzX3RvID0gIlRocmVhdExldmVsIiwKICAgIHZhbHVlc190byA9ICJDb3VudCIKICApCgp0b3Bfc3BlY2llcyA8LSBzcGVjaWVzICU+JQogIG11dGF0ZSgKICAgIFRocmVhdGVuZWQgPSBhcy5udW1lcmljKAogICAgICBnc3ViKCIsIiwgIiIsIGBTdWJ0b3RhbCAodGhyZWF0ZW5lZCBzcHAuKWApCiAgICApCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoVGhyZWF0ZW5lZCkpICU+JQogIHNsaWNlKDE6MTUpCgpzcGVjaWVzX2hlYXQgPC0gc3BlY2llc19oZWF0ICU+JQogIGZpbHRlcihOYW1lICVpbiUgdG9wX3NwZWNpZXMkTmFtZSkKCnAzIDwtIGdncGxvdCgKICBzcGVjaWVzX2hlYXQsCiAgYWVzKAogICAgeCA9IFRocmVhdExldmVsLAogICAgeSA9IHJlb3JkZXIoTmFtZSwgQ291bnQpLAogICAgZmlsbCA9IENvdW50CiAgKQopICsKICBnZW9tX3RpbGUoKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudCgKICAgIGxvdyA9ICIjZmVlOGM4IiwKICAgIGhpZ2ggPSAiI2UzNGEzMyIKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiVGhyZWF0IENvbXBvc2l0aW9uIEFjcm9zcyBTcGVjaWVzIEdyb3VwcyIKICApKwogIHRoZW1lKAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDIsICJsaW5lcyIpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmdncGxvdGx5KAogIHAzLAogIHRvb2x0aXAgPSBjKCJ4IiwgInkiKQopCmBgYAoKIyMgQ2hhcnQgNDogQ291bnRyaWVzIE1vc3QgSW4gTmVlZCBPZiBDb25zZXJ2YXRpb24gQWN0aW9uCmBgYHtyfQpwcmlvcml0eV9jb3VudHJpZXMgPC0gcHJvdGVjdGVkICU+JQogIGZpbHRlcighaXMubmEoUHJvdGVjdGVkQXJlYSkpICU+JQogIGFycmFuZ2UoUHJvdGVjdGVkQXJlYSkgJT4lCiAgc2xpY2UoMToyMCkKcDQgPC0gZ2dwbG90KAogIHByaW9yaXR5X2NvdW50cmllcywKICBhZXMoCiAgICB4ID0gcmVvcmRlcihDb3VudHJ5LCBQcm90ZWN0ZWRBcmVhKSwKICAgIHkgPSBQcm90ZWN0ZWRBcmVhCiAgKQopICsKCiAgZ2VvbV9zZWdtZW50KAogICAgYWVzKAogICAgICB4ZW5kID0gQ291bnRyeSwKICAgICAgeSA9IDAsCiAgICAgIHllbmQgPSBQcm90ZWN0ZWRBcmVhCiAgICApLAogICAgY29sb3VyID0gImdyZXk3MCIKICApICsKCiAgZ2VvbV9wb2ludCgKICAgIGFlcygKICAgICAgY29sb3VyID0gUHJvdGVjdGVkQXJlYSwKICAgICAgc2l6ZSA9IFByb3RlY3RlZEFyZWEKICAgICkKICApICsKCiAgY29vcmRfZmxpcCgpICsKCiAgbGFicygKICAgIHRpdGxlID0gIkNvdW50cmllcyBNb3N0IEluIE5lZWQgT2YgQ29uc2VydmF0aW9uIEFjdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICJDb3VudHJpZXMgd2l0aCB0aGUgc21hbGxlc3Qgc2hhcmUgb2YgcHJvdGVjdGVkIGxhbmQiLAogICAgeCA9ICIiLAogICAgeSA9ICJQcm90ZWN0ZWQgQXJlYSAoJSkiCiAgKSArCgogIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZSgKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykKICApCgpnZ3Bsb3RseSgKICBwNCwKICB0b29sdGlwID0gYygieCIsICJ5IikKKQpgYGAKCiMjIENoYXJ0IDU6IFdoYXQgQ291bGQgU2F2ZSBXaWxkbGlmZSBieSAyMDUwPwpgYGB7cn0KIyBTcGxpdCBkYXRhIGJ5IGFuaW1hbCBjbGFzcwpkYXRhX2FtcGhpYmlhbnMgPC0gY2xlYW5fc3RvcnkgJT4lIGZpbHRlcihTcGVjaWVzID09ICJBbXBoaWJpYW5zIikKZGF0YV9iaXJkcyAgICAgIDwtIGNsZWFuX3N0b3J5ICU+JSBmaWx0ZXIoU3BlY2llcyA9PSAiQmlyZHMiKQpkYXRhX21hbW1hbHMgICAgPC0gY2xlYW5fc3RvcnkgJT4lIGZpbHRlcihTcGVjaWVzID09ICJNYW1tYWxzIikKCiMgQ29sb3IgbWFwcGluZyBtYXRjaGluZyBwZXJmb3JtYW5jZSBoaWVyYXJjaHkgKFJlZCB0byBHcmVlbikKc2NlbmFyaW9fY29sb3JzIDwtIGMoCiAgIkJ1c2luZXNzIEFzIFVzdWFsIiA9ICIjZDczMDI3IiwgCiAgIlJlZHVjZSBGb29kIFdhc3RlIiA9ICIjZjQ2ZDQzIiwgCiAgIkRpZXRhcnkgU2hpZnRzIiA9ICIjZmRhZTYxIiwgCiAgIkltcHJvdmUgQ3JvcCBZaWVsZHMiID0gIiNhNmQ5NmEiLCAKICAiQWxsIEludGVydmVudGlvbnMgQ29tYmluZWQiID0gIiMxYTk4NTAiCikKCiMgMi4gQnVpbGQgaW5kaXZpZHVhbCBzdWJwbG90cwpjcmVhdGVfc3VicGxvdCA8LSBmdW5jdGlvbihzdWJfZGF0YSwgdGl0bGVfdGV4dCkgewogIHBsb3RfbHkoCiAgICBkYXRhID0gc3ViX2RhdGEsCiAgICB5ID0gflNjZW5hcmlvLAogICAgeCA9IH52YWx1ZSwKICAgIHR5cGUgPSAnYmFyJywKICAgIG9yaWVudGF0aW9uID0gJ2gnLAogICAgY29sb3IgPSB+U2NlbmFyaW8sCiAgICBjb2xvcnMgPSBzY2VuYXJpb19jb2xvcnMsCiAgICB0ZXh0ID0gfnBhc3RlMChyb3VuZCh2YWx1ZSwgMiksICIlIiksCiAgICB0ZXh0cG9zaXRpb24gPSAnb3V0c2lkZScsCiAgICB0ZXh0Zm9udCA9IGxpc3Qoc2l6ZSA9IDEwKSwgCiAgICBob3ZlcnRlbXBsYXRlID0gcGFzdGUwKCI8Yj4le3l9PC9iPjxicj5IYWJpdGF0IENoYW5nZTogJXt4Oi4yZn0lPGV4dHJhPjwvZXh0cmE+IiksCiAgICBzaG93bGVnZW5kID0gRkFMU0UKICApICU+JQogICAgbGF5b3V0KAogICAgICAjIEZJWDogQ2hhbmdlZCB4cmVmIGFuZCB5cmVmIHRvICJwYXBlciIgYW5kIGFkanVzdGVkIGNvb3JkaW5hdGVzCiAgICAgICMgVGhpcyBleHBsaWNpdGx5IGxvY2tzIHRoZSBoZWFkaW5nIHJpZ2h0IGluIHRoZSBtaWRkbGUgdG9wIG9mIHRoZSBjb2x1bW4gZ3JpZAogICAgICBhbm5vdGF0aW9ucyA9IGxpc3QoCiAgICAgICAgbGlzdCgKICAgICAgICAgIHggPSAwLjUsIHkgPSAxLjA1LCAKICAgICAgICAgIHRleHQgPSBwYXN0ZTAoIjxiPiIsIHRpdGxlX3RleHQsICI8L2I+IiksCiAgICAgICAgICB4cmVmID0gInBhcGVyIiwgeXJlZiA9ICJwYXBlciIsIAogICAgICAgICAgeGFuY2hvciA9ICJjZW50ZXIiLCB5YW5jaG9yID0gImJvdHRvbSIsCiAgICAgICAgICBzaG93YXJyb3cgPSBGQUxTRSwgCiAgICAgICAgICBmb250ID0gbGlzdChzaXplID0gMTMsIGNvbG9yID0gImJsYWNrIikKICAgICAgICApCiAgICAgICksCiAgICAgIHhheGlzID0gbGlzdCgKICAgICAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICJIYWJpdGF0IENoYW5nZSAoJSkiLCBzdGFuZG9mZiA9IDE1KSwgCiAgICAgICAgdGlja3N1ZmZpeCA9ICIlIgogICAgICApLAogICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiIiwgY2F0ZWdvcnlvcmRlciA9ICJhcnJheSIsIGNhdGVnb3J5YXJyYXkgPSBsZXZlbHMoc3ViX2RhdGEkU2NlbmFyaW8pKSwKICAgICAgc2hhcGVzID0gbGlzdCgKICAgICAgICBsaXN0KHR5cGUgPSAibGluZSIsIHgwID0gMCwgeDEgPSAwLCB5MCA9IC0wLjUsIHkxID0gNC41LCAKICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImdyZXk0MCIsIHdpZHRoID0gMS41LCBkYXNoID0gImRhc2giKSkKICAgICAgKQogICAgKQp9CgpwMSA8LSBjcmVhdGVfc3VicGxvdChkYXRhX2FtcGhpYmlhbnMsICJBbXBoaWJpYW5zIikKcDIgPC0gY3JlYXRlX3N1YnBsb3QoZGF0YV9iaXJkcywgIkJpcmRzIikKcDMgPC0gY3JlYXRlX3N1YnBsb3QoZGF0YV9tYW1tYWxzLCAiTWFtbWFscyIpCgojIDMuIENvbWJpbmUgc3VicGxvdHMgYW5kIHNldCBzdHJ1Y3R1cmFsIHNwYWNpbmcgbGF5b3V0CmludGVyYWN0aXZlX2NoYXJ0IDwtIHN1YnBsb3QocDEsIHAyLCBwMywgbnJvd3MgPSAxLCBzaGFyZVkgPSBUUlVFLCB0aXRsZVggPSBUUlVFLCBtYXJnaW4gPSAwLjA2KSAlPiUKICBsYXlvdXQoCiAgICB0aXRsZSA9IGxpc3QoCiAgICAgIHRleHQgPSAiPGI+V2hpY2ggQWN0aW9uIEFjdHVhbGx5IFNhdmVzIFdpbGRsaWZlIEhhYml0YXRzIGJ5IDIwNTA/PC9iPjxicj48c3BhbiBzdHlsZT0nZm9udC1zaXplOjExcHg7Y29sb3I6Z3JheTsnPkdsb2JhbCBhdmVyYWdlIHByb2plY3RlZCBoYWJpdGF0IGNoYW5nZS4gTmVnYXRpdmUgdmFsdWVzIGluZGljYXRlIGhhYml0YXQgZGVzdHJ1Y3Rpb24uPC9zcGFuPiIsCiAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxNCksCiAgICAgIHggPSAwLjAyCiAgICApLAogICAgbWFyZ2luID0gbGlzdCh0ID0gMTIwLCBiID0gNzAsIGwgPSAxODAsIHIgPSAzMCksICMgRXhwYW5kZWQgdG9wIG1hcmdpbiBzbGlnaHRseSBmb3IgdGhlIGhlYWRpbmdzCiAgICBiYXJtb2RlID0gJ2dyb3VwJwogICkKCiMgVmlldyBjaGFydAppbnRlcmFjdGl2ZV9jaGFydApgYGAK