Citizen Science
Task Load CS dataset and clean data
install.packages(c("tidyverse", "skimr", "janitor", "corrplot"))
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/tidyverse_2.0.0.tgz'
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/skimr_2.2.2.tgz'
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/janitor_2.2.1.tgz'
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/corrplot_0.95.tgz'
The downloaded binary packages are in
/var/folders/5_/qmm6kpd90mggm8b4nhx7s09c0000gn/T//RtmpR5woME/downloaded_packages
library(tidyverse)
library(skimr)
library(janitor)
library(corrplot)
library(tidyr)
#load CS dataset from CSV
cs_raw <- read.csv("BA_records.csv",
header = TRUE, stringsAsFactors = FALSE)
#omit "incorrect" verification substatus
clean_data <- subset(cs_raw, verification_substatus_text !="incorrect")
#clean latitude values to only include entries in ireland
clean_latdata <- subset(clean_data, lat >= 51 & lat <= 55.5)
cs_data <- subset(clean_latdata, lon >= -10.25 & lon <= -5.5)
#remove "notes" column (irrelevant data)
cs_data$notes <- NULL
#remove "location" column (irrelevant data)
cs_data$location <- NULL
##Marine Data
Task Load professional datasets, merge
marine datasets, and clean data
#load marine datasets
#1997 to 2016 data
marine1_data <- read.csv("HABs_raw_CoCliME.csv",
header = TRUE, stringsAsFactors = FALSE)
#2011 to 2019 data
marine2_data <- read.csv("HABs_Biotoxin_weekly_max_2011_2019.csv",
header = TRUE, stringsAsFactors = FALSE)
#clean marine2 dataset to match columns
marine2_data$species <- NULL
marine2_data$HY_OA <- NULL
marine2_data$HY_DTX1 <- NULL
marine2_data$HY_DTX2 <- NULL
marine2_data$PTX1 <- NULL
marine2_data$PTX2 <- NULL
marine2_data$D_spp <- NULL
marine2_rdata <- rename(marine2_data, "sample_date" = "End_of_Week")
#merge marine datasets
marine12_data <- rbind(marine1_data, marine2_rdata)
#remove duplicate points
marine_cdata <- marine12_data[!duplicated(marine_data),]
#remove rows that sum to zeros (no species recorded)
marine_data <- marine_cdata[rowSums(marine_cdata[, c(5, 6, 7, 8, 9, 10, 11, 12)] > 0) != 0, ]
##Freshwater Data
Task Load professional dataset and clean
data
#load freshwater dataset
fw_raw <- read.csv("PhytoplanktonSurveyData_2007_2025.csv",)
#remove extra column
fw_raw$Local.Authority <- NULL
fw_raw$WFD.Lake.Waterbody.Code <- NULL
#change "Not found" coordinate entries to NA
fw_raw$Easting[fw_raw$Easting == "Not found"] <- NA
fw_raw$Northing[fw_raw$Northing == "Not found"] <- NA
#drop any rows with NA
fw_data <- drop_na(fw_raw)
#reformat dates
fw_data$Sample.date <- as.Date(fw_data$Sample.date, format = "%m/%d/%y")
#reformat northings and eastings to Irish Grid coordinates
install.packages("sf")
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/sf_1.1-2.tgz'
Content type 'application/x-gzip' length 31655373 bytes (30.2 MB)
==================================================
downloaded 30.2 MB
The downloaded binary packages are in
/var/folders/5_/qmm6kpd90mggm8b4nhx7s09c0000gn/T//RtmpR5woME/downloaded_packages
library(sf)
# Convert Easting/Northing to an sf object
sites_sf <- st_as_sf(fw_data,
coords = c("Easting", "Northing"),
crs = 29903)
# Transform to WGS84 (latitude/longitude)
sites_ll <- st_transform(sites_sf, 4326)
# Extract coordinates
coords <- st_coordinates(sites_ll)
fw_data$Longitude <- coords[, 1]
fw_data$Latitude <- coords[, 2]
#remove "Easting" and "Northing" columns
fw_data$Easting <- NULL
fw_data$Northing <- NULL
#reorder columns
fw_data <- fw_data[, c(3, 2, 1, 14:15, 4:13:ncol(fw_data))]
#remove repeat columns
fw_data$Longitude.1 <- NULL
fw_data$Latitude.1 <- NULL
#remove rows that sum to zeros (no species recorded)
fw_data <- fw_data[rowSums(fw_data[, c(7, 8, 9, 10, 11, 12, 13, 14, 15)] > 0) != 0, ]
#Time Series Trends
#yearly counts
#load packages
library(dplyr)
library(lubridate)
#CS yearly
cs_yearly <- cs_data %>%
mutate(Year = year(sample_date)) %>%
group_by(Year) %>%
summarise(Observations = n()) %>%
mutate(Dataset = "Blooming Algae CS Data")
#marine yearly
marine_yearly <- marine_data %>%
mutate(Year = year(sample_date)) %>%
group_by(Year) %>%
summarise(Observations = n()) %>%
mutate(Dataset = "Marine Institute Coastal Data")
#FW yearly
fw_yearly <- fw_data %>%
mutate(Year = year(Sample.date)) %>%
group_by(Year) %>%
summarise(Observations = n()) %>%
mutate(Dataset = "EPA Freshwater Data")
#combine yearly counts
annual_counts <- bind_rows(
cs_yearly,
marine_yearly,
fw_yearly
)
#remove any observation counts that do not have a year
annual_counts <- drop_na(annual_counts)
#plot
library(ggplot2)
ggplot(annual_counts,
aes(x = Year,
y = Observations,
colour = Dataset)) +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
geom_smooth(
method = "lm",
se = FALSE,
linetype = "dashed"
) +
labs(
title = "Annual Harmful Algal Bloom Observations",
x = "Year",
y = "Number of observations",
colour = "Dataset"
) +
theme_classic(base_size = 14)

#standardize datasets
annual_standardized <- annual_counts %>%
group_by(Dataset) %>%
mutate(
Std_Obs = (Observations - min(Observations)) /
(max(Observations) - min(Observations))
) %>%
ungroup()
library(ggplot2)
#plot
ggplot(
annual_standardized,
aes(
x = Year,
y = Std_Obs,
colour = Dataset
)
) +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
geom_smooth(
method = "lm",
se = FALSE,
linetype = "dashed"
) +
labs(
title = "Standardized Annual HAB Observation Trends",
subtitle = "Comparison of temporal patterns between monitoring programmes",
x = "Year",
y = "Standardized Observation Frequency",
colour = "Dataset"
) +
theme_classic(base_size = 14)

NA
NA
NA
#percentage of maximum
annual_standardized2 <- annual_counts %>%
group_by(Dataset) %>%
mutate(
Percent_Max = Observations /
max(Observations) * 100
)
library(ggplot2)
#plot
ggplot(
annual_standardized2,
aes(
x = Year,
y = Percent_Max,
colour = Dataset
)
) +
geom_line(linewidth = 1.2) +
geom_point(size = 0) +
geom_smooth(
method = "lm",
se = FALSE,
linetype = "dashed"
) +
labs(
title = "Standardized Annual HAB Observation Trends",
subtitle = "Comparison of temporal patterns between monitoring programmes",
x = "Year",
y = "Standardized Observation Frequency",
colour = "Dataset"
) +
theme_classic(base_size = 14)

NA
NA
NA
#Z-score standardization
annual_standardized <- annual_counts %>%
group_by(Dataset) %>%
mutate(
Zscore = scale(Observations)[,1]
)
library(ggplot2)
#plot
ggplot(
annual_standardized,
aes(
x = Year,
y = Zscore,
colour = Dataset
)
) +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
geom_smooth(
method = "lm",
se = FALSE,
linetype = "dashed"
) +
labs(
title = "Standardized Annual HAB Observation Trends",
subtitle = "Comparison of temporal patterns between monitoring programmes",
x = "Year",
y = "Standardized Observation Frequency",
colour = "Dataset"
) +
theme_classic(base_size = 14)

NA
NA
NA
#Monthly Observations
cs_monthly <- cs_data %>%
mutate(Month = month(sample_date,
label = TRUE,
abbr = TRUE)) %>%
group_by(Month) %>%
summarise(Observations = n(), .groups = "drop") %>%
mutate(Dataset = "Blooming Algae CS Data")
marine_monthly <- marine_data %>%
mutate(Month = month(sample_date,
label = TRUE,
abbr = TRUE)) %>%
group_by(Month) %>%
summarise(Observations = n(), .groups = "drop") %>%
mutate(Dataset = "Marine Institute Coastal Data")
fw_monthly <- fw_data %>%
mutate(Month = month(Sample.date,
label = TRUE,
abbr = TRUE)) %>%
group_by(Month) %>%
summarise(Observations = n(), .groups = "drop") %>%
mutate(Dataset = "EPA Freshwater Data")
#combine rows
monthly_counts <- bind_rows(
cs_monthly,
marine_monthly,
fw_monthly
)
#remove any observation counts that do not have a month
monthly_counts <- drop_na(monthly_counts)
#plot
ggplot(monthly_counts,
aes(x = Month,
y = Observations,
colour = Dataset,
group = Dataset)) +
geom_line(linewidth = 1.2) +
geom_point(size = 3) +
labs(
title = "Seasonal Distribution of HAB Observations",
x = "Month",
y = "Number of observations"
) +
theme_classic(base_size = 14)

#Compare Datasets
#calculate unique locations for each dataset
#marine
length(unique(marine_data[["location"]]))
[1] 184
#fresh water
length(unique(fw_data[["Site.Code"]]))
[1] 310
#cs data
n_distinct(cs_data$lat, cs_data$lon)
[1] 627
##EXPORT DATASETS
#cs data
write.csv(cs_data, file = "cs_data.csv")
#marine data
write.csv(marine_data, file = "marine_data.csv")
#fw data
write.csv(fw_data, file = "fw_data.csv")
LS0tCnRpdGxlOiAiQ2l0aXplbiBTY2llbmNlIHZzIFByb2Zlc3Npb25hbCBEYXRhIGNvbXBhcmlzb25zIgphdXRob3I6ICJTY2FybGV0dCBSb2JlcnRzIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyMgQ2l0aXplbiBTY2llbmNlCgoqKl9UYXNrXyoqIExvYWQgQ1MgZGF0YXNldCBhbmQgY2xlYW4gZGF0YSAKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKGMoInRpZHl2ZXJzZSIsICJza2ltciIsICJqYW5pdG9yIiwgImNvcnJwbG90IikpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShza2ltcikKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KHRpZHlyKQoKYGBgCgpgYGB7cn0KI2xvYWQgQ1MgZGF0YXNldCBmcm9tIENTVgpjc19yYXcgPC0gcmVhZC5jc3YoIkJBX3JlY29yZHMuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgoKYGBgCgpgYGB7cn0KCiNvbWl0ICJpbmNvcnJlY3QiIHZlcmlmaWNhdGlvbiBzdWJzdGF0dXMKCmNsZWFuX2RhdGEgPC0gc3Vic2V0KGNzX3JhdywgdmVyaWZpY2F0aW9uX3N1YnN0YXR1c190ZXh0ICE9ImluY29ycmVjdCIpCgojY2xlYW4gbGF0aXR1ZGUgdmFsdWVzIHRvIG9ubHkgaW5jbHVkZSBlbnRyaWVzIGluIGlyZWxhbmQKCmNsZWFuX2xhdGRhdGEgPC0gc3Vic2V0KGNsZWFuX2RhdGEsIGxhdCA+PSA1MSAmIGxhdCA8PSA1NS41KQoKY3NfZGF0YSA8LSBzdWJzZXQoY2xlYW5fbGF0ZGF0YSwgbG9uID49IC0xMC4yNSAmIGxvbiA8PSAtNS41KQoKI3JlbW92ZSAibm90ZXMiIGNvbHVtbiAoaXJyZWxldmFudCBkYXRhKQpjc19kYXRhJG5vdGVzIDwtIE5VTEwKCiNyZW1vdmUgImxvY2F0aW9uIiBjb2x1bW4gKGlycmVsZXZhbnQgZGF0YSkKY3NfZGF0YSRsb2NhdGlvbiA8LSBOVUxMCgpgYGAKCiMjTWFyaW5lIERhdGEKCioqX1Rhc2tfKiogTG9hZCBwcm9mZXNzaW9uYWwgZGF0YXNldHMsIG1lcmdlIG1hcmluZSBkYXRhc2V0cywgYW5kIGNsZWFuIGRhdGEKCmBgYHtyfQoKI2xvYWQgbWFyaW5lIGRhdGFzZXRzCgojMTk5NyB0byAyMDE2IGRhdGEKbWFyaW5lMV9kYXRhIDwtIHJlYWQuY3N2KCJIQUJzX3Jhd19Db0NsaU1FLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKCiMyMDExIHRvIDIwMTkgZGF0YQptYXJpbmUyX2RhdGEgPC0gcmVhZC5jc3YoIkhBQnNfQmlvdG94aW5fd2Vla2x5X21heF8yMDExXzIwMTkuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiNjbGVhbiBtYXJpbmUyIGRhdGFzZXQgdG8gbWF0Y2ggY29sdW1ucwoKbWFyaW5lMl9kYXRhJHNwZWNpZXMgPC0gTlVMTAptYXJpbmUyX2RhdGEkSFlfT0EgPC0gTlVMTAptYXJpbmUyX2RhdGEkSFlfRFRYMSA8LSBOVUxMCm1hcmluZTJfZGF0YSRIWV9EVFgyIDwtIE5VTEwKbWFyaW5lMl9kYXRhJFBUWDEgPC0gTlVMTAptYXJpbmUyX2RhdGEkUFRYMiA8LSBOVUxMCm1hcmluZTJfZGF0YSREX3NwcCA8LSBOVUxMCgptYXJpbmUyX3JkYXRhIDwtIHJlbmFtZShtYXJpbmUyX2RhdGEsICJzYW1wbGVfZGF0ZSIgPSAiRW5kX29mX1dlZWsiKQoKYGBgCgoKYGBge3J9CgojbWVyZ2UgbWFyaW5lIGRhdGFzZXRzCm1hcmluZTEyX2RhdGEgPC0gcmJpbmQobWFyaW5lMV9kYXRhLCBtYXJpbmUyX3JkYXRhKQoKI3JlbW92ZSBkdXBsaWNhdGUgcG9pbnRzCm1hcmluZV9jZGF0YSA8LSBtYXJpbmUxMl9kYXRhWyFkdXBsaWNhdGVkKG1hcmluZV9kYXRhKSxdCgpgYGAKCmBgYHtyfQoKI3JlbW92ZSByb3dzIHRoYXQgc3VtIHRvIHplcm9zIChubyBzcGVjaWVzIHJlY29yZGVkKQptYXJpbmVfZGF0YSA8LSBtYXJpbmVfY2RhdGFbcm93U3VtcyhtYXJpbmVfY2RhdGFbLCBjKDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIpXSA+IDApICE9IDAsIF0KYGBgCgojI0ZyZXNod2F0ZXIgRGF0YQoKKipfVGFza18qKiBMb2FkIHByb2Zlc3Npb25hbCBkYXRhc2V0IGFuZCBjbGVhbiBkYXRhCgpgYGB7cn0KCiNsb2FkIGZyZXNod2F0ZXIgZGF0YXNldAoKZndfcmF3IDwtIHJlYWQuY3N2KCJQaHl0b3BsYW5rdG9uU3VydmV5RGF0YV8yMDA3XzIwMjUuY3N2IiwpCgojcmVtb3ZlIGV4dHJhIGNvbHVtbgpmd19yYXckTG9jYWwuQXV0aG9yaXR5IDwtIE5VTEwKZndfcmF3JFdGRC5MYWtlLldhdGVyYm9keS5Db2RlIDwtIE5VTEwKCmBgYAoKCmBgYHtyfQoKI2NoYW5nZSAiTm90IGZvdW5kIiBjb29yZGluYXRlIGVudHJpZXMgdG8gTkEKZndfcmF3JEVhc3RpbmdbZndfcmF3JEVhc3RpbmcgPT0gIk5vdCBmb3VuZCJdIDwtIE5BCmZ3X3JhdyROb3J0aGluZ1tmd19yYXckTm9ydGhpbmcgPT0gIk5vdCBmb3VuZCJdIDwtIE5BCgojZHJvcCBhbnkgcm93cyB3aXRoIE5BCmZ3X2RhdGEgPC0gZHJvcF9uYShmd19yYXcpCmBgYAoKYGBge3J9CgojcmVmb3JtYXQgZGF0ZXMKZndfZGF0YSRTYW1wbGUuZGF0ZSA8LSBhcy5EYXRlKGZ3X2RhdGEkU2FtcGxlLmRhdGUsIGZvcm1hdCA9ICIlbS8lZC8leSIpCgpgYGAKCmBgYHtyfQoKI3JlZm9ybWF0IG5vcnRoaW5ncyBhbmQgZWFzdGluZ3MgdG8gSXJpc2ggR3JpZCBjb29yZGluYXRlcwoKaW5zdGFsbC5wYWNrYWdlcygic2YiKQpsaWJyYXJ5KHNmKQoKYGBgCgpgYGB7cn0KCiMgQ29udmVydCBFYXN0aW5nL05vcnRoaW5nIHRvIGFuIHNmIG9iamVjdApzaXRlc19zZiA8LSBzdF9hc19zZihmd19kYXRhLAogICAgICAgICAgICAgICAgICAgICBjb29yZHMgPSBjKCJFYXN0aW5nIiwgIk5vcnRoaW5nIiksCiAgICAgICAgICAgICAgICAgICAgIGNycyA9IDI5OTAzKQoKIyBUcmFuc2Zvcm0gdG8gV0dTODQgKGxhdGl0dWRlL2xvbmdpdHVkZSkKc2l0ZXNfbGwgPC0gc3RfdHJhbnNmb3JtKHNpdGVzX3NmLCA0MzI2KQoKIyBFeHRyYWN0IGNvb3JkaW5hdGVzCmNvb3JkcyA8LSBzdF9jb29yZGluYXRlcyhzaXRlc19sbCkKCmZ3X2RhdGEkTG9uZ2l0dWRlIDwtIGNvb3Jkc1ssIDFdCmZ3X2RhdGEkTGF0aXR1ZGUgPC0gY29vcmRzWywgMl0KYGBgCgpgYGB7cn0KI3JlbW92ZSAiRWFzdGluZyIgYW5kICJOb3J0aGluZyIgY29sdW1ucwpmd19kYXRhJEVhc3RpbmcgPC0gTlVMTApmd19kYXRhJE5vcnRoaW5nIDwtIE5VTEwKCmBgYAoKYGBge3J9CgojcmVvcmRlciBjb2x1bW5zCmZ3X2RhdGEgPC0gZndfZGF0YVssIGMoMywgMiwgMSwgMTQ6MTUsIDQ6MTM6bmNvbChmd19kYXRhKSldCgpgYGAKCmBgYHtyfQoKI3JlbW92ZSByZXBlYXQgY29sdW1ucwpmd19kYXRhJExvbmdpdHVkZS4xIDwtIE5VTEwKZndfZGF0YSRMYXRpdHVkZS4xIDwtIE5VTEwKCmBgYAoKYGBge3J9CgojcmVtb3ZlIHJvd3MgdGhhdCBzdW0gdG8gemVyb3MgKG5vIHNwZWNpZXMgcmVjb3JkZWQpCmZ3X2RhdGEgPC0gZndfZGF0YVtyb3dTdW1zKGZ3X2RhdGFbLCBjKDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUpXSA+IDApICE9IDAsIF0KYGBgCgoKI1RpbWUgU2VyaWVzIFRyZW5kcwoKYGBge3J9CgojeWVhcmx5IGNvdW50cwoKI2xvYWQgcGFja2FnZXMKbGlicmFyeShkcGx5cikKbGlicmFyeShsdWJyaWRhdGUpCgojQ1MgeWVhcmx5CmNzX3llYXJseSA8LSBjc19kYXRhICU+JQogIG11dGF0ZShZZWFyID0geWVhcihzYW1wbGVfZGF0ZSkpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIHN1bW1hcmlzZShPYnNlcnZhdGlvbnMgPSBuKCkpICU+JQogIG11dGF0ZShEYXRhc2V0ID0gIkJsb29taW5nIEFsZ2FlIENTIERhdGEiKQoKI21hcmluZSB5ZWFybHkKbWFyaW5lX3llYXJseSA8LSBtYXJpbmVfZGF0YSAlPiUKICBtdXRhdGUoWWVhciA9IHllYXIoc2FtcGxlX2RhdGUpKSAlPiUKICBncm91cF9ieShZZWFyKSAlPiUKICBzdW1tYXJpc2UoT2JzZXJ2YXRpb25zID0gbigpKSAlPiUKICBtdXRhdGUoRGF0YXNldCA9ICJNYXJpbmUgSW5zdGl0dXRlIENvYXN0YWwgRGF0YSIpCgojRlcgeWVhcmx5CmZ3X3llYXJseSA8LSBmd19kYXRhICU+JQogIG11dGF0ZShZZWFyID0geWVhcihTYW1wbGUuZGF0ZSkpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIHN1bW1hcmlzZShPYnNlcnZhdGlvbnMgPSBuKCkpICU+JQogIG11dGF0ZShEYXRhc2V0ID0gIkVQQSBGcmVzaHdhdGVyIERhdGEiKQpgYGAKCmBgYHtyfQoKI2NvbWJpbmUgeWVhcmx5IGNvdW50cwphbm51YWxfY291bnRzIDwtIGJpbmRfcm93cygKICBjc195ZWFybHksCiAgbWFyaW5lX3llYXJseSwKICBmd195ZWFybHkKKQoKI3JlbW92ZSBhbnkgb2JzZXJ2YXRpb24gY291bnRzIHRoYXQgZG8gbm90IGhhdmUgYSB5ZWFyCmFubnVhbF9jb3VudHMgPC0gZHJvcF9uYShhbm51YWxfY291bnRzKQoKCmBgYAoKYGBge3J9CiNwbG90CmxpYnJhcnkoZ2dwbG90MikKCmdncGxvdChhbm51YWxfY291bnRzLAogICAgICAgYWVzKHggPSBZZWFyLAogICAgICAgICAgIHkgPSBPYnNlcnZhdGlvbnMsCiAgICAgICAgICAgY29sb3VyID0gRGF0YXNldCkpICsKCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKCiAgZ2VvbV9zbW9vdGgoCiAgICBtZXRob2QgPSAibG0iLAogICAgc2UgPSBGQUxTRSwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKCiAgbGFicygKICAgIHRpdGxlID0gIkFubnVhbCBIYXJtZnVsIEFsZ2FsIEJsb29tIE9ic2VydmF0aW9ucyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIiwKICAgIGNvbG91ciA9ICJEYXRhc2V0IgogICkgKwoKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE0KQoKYGBgCgpgYGB7cn0KCiNzdGFuZGFyZGl6ZSBkYXRhc2V0cwphbm51YWxfc3RhbmRhcmRpemVkIDwtIGFubnVhbF9jb3VudHMgJT4lCiAgZ3JvdXBfYnkoRGF0YXNldCkgJT4lCiAgbXV0YXRlKAogICAgU3RkX09icyA9IChPYnNlcnZhdGlvbnMgLSBtaW4oT2JzZXJ2YXRpb25zKSkgLwogICAgICAgICAgICAgIChtYXgoT2JzZXJ2YXRpb25zKSAtIG1pbihPYnNlcnZhdGlvbnMpKQogICkgJT4lCiAgdW5ncm91cCgpCgpgYGAKCmBgYHtyfQoKbGlicmFyeShnZ3Bsb3QyKQoKI3Bsb3QKZ2dwbG90KAogIGFubnVhbF9zdGFuZGFyZGl6ZWQsCiAgYWVzKAogICAgeCA9IFllYXIsCiAgICB5ID0gU3RkX09icywKICAgIGNvbG91ciA9IERhdGFzZXQKICApCikgKwoKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCgogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKCiAgZ2VvbV9zbW9vdGgoCiAgICBtZXRob2QgPSAibG0iLAogICAgc2UgPSBGQUxTRSwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKCiAgbGFicygKICAgIHRpdGxlID0gIlN0YW5kYXJkaXplZCBBbm51YWwgSEFCIE9ic2VydmF0aW9uIFRyZW5kcyIsCiAgICBzdWJ0aXRsZSA9ICJDb21wYXJpc29uIG9mIHRlbXBvcmFsIHBhdHRlcm5zIGJldHdlZW4gbW9uaXRvcmluZyBwcm9ncmFtbWVzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlN0YW5kYXJkaXplZCBPYnNlcnZhdGlvbiBGcmVxdWVuY3kiLAogICAgY29sb3VyID0gIkRhdGFzZXQiCiAgKSArCgogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTQpCgoKCmBgYAoKYGBge3J9CgojcGVyY2VudGFnZSBvZiBtYXhpbXVtCmFubnVhbF9zdGFuZGFyZGl6ZWQyIDwtIGFubnVhbF9jb3VudHMgJT4lCiAgZ3JvdXBfYnkoRGF0YXNldCkgJT4lCiAgbXV0YXRlKAogICAgUGVyY2VudF9NYXggPSBPYnNlcnZhdGlvbnMgLwogICAgICAgICAgICAgICAgICBtYXgoT2JzZXJ2YXRpb25zKSAqIDEwMAogICkKCmBgYAoKYGBge3J9CgpsaWJyYXJ5KGdncGxvdDIpCgojcGxvdApnZ3Bsb3QoCiAgYW5udWFsX3N0YW5kYXJkaXplZDIsCiAgYWVzKAogICAgeCA9IFllYXIsCiAgICB5ID0gUGVyY2VudF9NYXgsCiAgICBjb2xvdXIgPSBEYXRhc2V0CiAgKQopICsKCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKwoKICBnZW9tX3BvaW50KHNpemUgPSAwKSArCgogIGdlb21fc21vb3RoKAogICAgbWV0aG9kID0gImxtIiwKICAgIHNlID0gRkFMU0UsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgKSArCgogIGxhYnMoCiAgICB0aXRsZSA9ICJTdGFuZGFyZGl6ZWQgQW5udWFsIEhBQiBPYnNlcnZhdGlvbiBUcmVuZHMiLAogICAgc3VidGl0bGUgPSAiQ29tcGFyaXNvbiBvZiB0ZW1wb3JhbCBwYXR0ZXJucyBiZXR3ZWVuIG1vbml0b3JpbmcgcHJvZ3JhbW1lcyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJTdGFuZGFyZGl6ZWQgT2JzZXJ2YXRpb24gRnJlcXVlbmN5IiwKICAgIGNvbG91ciA9ICJEYXRhc2V0IgogICkgKwoKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE0KQoKCgpgYGAKCmBgYHtyfQoKI1otc2NvcmUgc3RhbmRhcmRpemF0aW9uCmFubnVhbF9zdGFuZGFyZGl6ZWQgPC0gYW5udWFsX2NvdW50cyAlPiUKICBncm91cF9ieShEYXRhc2V0KSAlPiUKICBtdXRhdGUoCiAgICBac2NvcmUgPSBzY2FsZShPYnNlcnZhdGlvbnMpWywxXQogICkKYGBgCgpgYGB7cn0KCmxpYnJhcnkoZ2dwbG90MikKCiNwbG90CmdncGxvdCgKICBhbm51YWxfc3RhbmRhcmRpemVkLAogIGFlcygKICAgIHggPSBZZWFyLAogICAgeSA9IFpzY29yZSwKICAgIGNvbG91ciA9IERhdGFzZXQKICApCikgKwoKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCgogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKCiAgZ2VvbV9zbW9vdGgoCiAgICBtZXRob2QgPSAibG0iLAogICAgc2UgPSBGQUxTRSwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKCiAgbGFicygKICAgIHRpdGxlID0gIlN0YW5kYXJkaXplZCBBbm51YWwgSEFCIE9ic2VydmF0aW9uIFRyZW5kcyIsCiAgICBzdWJ0aXRsZSA9ICJDb21wYXJpc29uIG9mIHRlbXBvcmFsIHBhdHRlcm5zIGJldHdlZW4gbW9uaXRvcmluZyBwcm9ncmFtbWVzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlN0YW5kYXJkaXplZCBPYnNlcnZhdGlvbiBGcmVxdWVuY3kiLAogICAgY29sb3VyID0gIkRhdGFzZXQiCiAgKSArCgogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTQpCgoKCmBgYAoKCiNNb250aGx5IE9ic2VydmF0aW9ucwoKYGBge3J9Cgpjc19tb250aGx5IDwtIGNzX2RhdGEgJT4lCiAgbXV0YXRlKE1vbnRoID0gbW9udGgoc2FtcGxlX2RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoTW9udGgpICU+JQogIHN1bW1hcmlzZShPYnNlcnZhdGlvbnMgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZShEYXRhc2V0ID0gIkJsb29taW5nIEFsZ2FlIENTIERhdGEiKQoKbWFyaW5lX21vbnRobHkgPC0gbWFyaW5lX2RhdGEgJT4lCiAgbXV0YXRlKE1vbnRoID0gbW9udGgoc2FtcGxlX2RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoTW9udGgpICU+JQogIHN1bW1hcmlzZShPYnNlcnZhdGlvbnMgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZShEYXRhc2V0ID0gIk1hcmluZSBJbnN0aXR1dGUgQ29hc3RhbCBEYXRhIikKCmZ3X21vbnRobHkgPC0gZndfZGF0YSAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGUuZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgYWJiciA9IFRSVUUpKSAlPiUKICBncm91cF9ieShNb250aCkgJT4lCiAgc3VtbWFyaXNlKE9ic2VydmF0aW9ucyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgbXV0YXRlKERhdGFzZXQgPSAiRVBBIEZyZXNod2F0ZXIgRGF0YSIpCgpgYGAKCmBgYHtyfQoKI2NvbWJpbmUgcm93cwptb250aGx5X2NvdW50cyA8LSBiaW5kX3Jvd3MoCiAgY3NfbW9udGhseSwKICBtYXJpbmVfbW9udGhseSwKICBmd19tb250aGx5CikKCiNyZW1vdmUgYW55IG9ic2VydmF0aW9uIGNvdW50cyB0aGF0IGRvIG5vdCBoYXZlIGEgbW9udGgKbW9udGhseV9jb3VudHMgPC0gZHJvcF9uYShtb250aGx5X2NvdW50cykKCmBgYAoKCmBgYHtyfQoKI3Bsb3QKZ2dwbG90KG1vbnRobHlfY291bnRzLAogICAgICAgYWVzKHggPSBNb250aCwKICAgICAgICAgICB5ID0gT2JzZXJ2YXRpb25zLAogICAgICAgICAgIGNvbG91ciA9IERhdGFzZXQsCiAgICAgICAgICAgZ3JvdXAgPSBEYXRhc2V0KSkgKwoKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwoKICBsYWJzKAogICAgdGl0bGUgPSAiU2Vhc29uYWwgRGlzdHJpYnV0aW9uIG9mIEhBQiBPYnNlcnZhdGlvbnMiLAogICAgeCA9ICJNb250aCIsCiAgICB5ID0gIk51bWJlciBvZiBvYnNlcnZhdGlvbnMiCiAgKSArCgogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTQpCgpgYGAKCgojQ29tcGFyZSBEYXRhc2V0cwoKYGBge3J9CiNjYWxjdWxhdGUgdW5pcXVlIGxvY2F0aW9ucyBmb3IgZWFjaCBkYXRhc2V0CgojbWFyaW5lCmxlbmd0aCh1bmlxdWUobWFyaW5lX2RhdGFbWyJsb2NhdGlvbiJdXSkpCgojZnJlc2ggd2F0ZXIKbGVuZ3RoKHVuaXF1ZShmd19kYXRhW1siU2l0ZS5Db2RlIl1dKSkKCiNjcyBkYXRhCm5fZGlzdGluY3QoY3NfZGF0YSRsYXQsIGNzX2RhdGEkbG9uKQoKYGBgCgoKIyNFWFBPUlQgREFUQVNFVFMKCmBgYHtyfQoKI2NzIGRhdGEKd3JpdGUuY3N2KGNzX2RhdGEsIGZpbGUgPSAiY3NfZGF0YS5jc3YiKQoKYGBgCgpgYGB7cn0KCiNtYXJpbmUgZGF0YQp3cml0ZS5jc3YobWFyaW5lX2RhdGEsIGZpbGUgPSAibWFyaW5lX2RhdGEuY3N2IikKCmBgYAoKYGBge3J9CgojZncgZGF0YQp3cml0ZS5jc3YoZndfZGF0YSwgZmlsZSA9ICJmd19kYXRhLmNzdiIpCgpgYGAKCgoKCgo=