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=