Introduction

Analysis of microplastics in river mammals

Library

# install.packages("pacman")
# writeLines(pacman::p_lib(), "~/Desktop/list_of_R_packages.csv") # to quickly back up packages
# remotes::install_github("ThinkR-open/remedy")
# remotes::install_github("luisDVA/annotater")

pacman::p_load(rio, tidyverse,janitor, data.table, here,
               knitr,
               kableExtra,
               flextable,
               writexl,
               sf,
               raster,
               osmdata,
               leaflet,
              rnaturalearthdata,
               rnaturalearth,
              cowplot,
              dunn.test,
              ggthemes,
              effsize,
              rstatix,
              stats,
              viridis,
              RCzechia,
              stringr,
              scales,
              coin,
              httr,
              terra,
              czso, 
              grateful,
              annotater, 
              officer
           
              
               
               ) # just add needed packages to this line and Pacman will install and load them.

Load Data

Clean data

# 
# micro <- raw %>%
#    dplyr::mutate(across(-1, ~as.numeric(.))) %>%
#   dplyr::mutate(across(-1, ~replace_na(. , 0))) %>%
# 
#   #add country
# 
#   dplyr::mutate(
#     country = dplyr::case_when(
#       grepl("^BC", sample) ~ "Spain_dec2022",
#       grepl("^TA", sample) ~ "Spain_dec2022",
#       grepl("^7_5", sample) ~ "Austria",
#       grepl("^LLESP", sample) ~ "Spain_jun2022",
#       grepl("^MA", sample) ~ "Spain_2023",
#       TRUE ~ NA_character_
#     )
#   )
# 
# # add country2
# 
# micro2 <- micro %>%
#   dplyr::left_join(cz,by="sample",relationship = "many-to-many") %>%
#   dplyr::left_join(italy,by="sample",relationship = "many-to-many") %>%
#   dplyr::mutate (country = coalesce(country, country.x, country.y)) %>%
#   dplyr::select(-country.x, -country.y) %>%
#   janitor::clean_names() %>%
#   dplyr::mutate(country = as.factor(country))
# 
# 
# # Add new data
# 
# # Reshape the data into long format
# newdata_long <- newdataraw %>%
#   tidyr::pivot_longer(cols = !1, names_to = "sample", values_to = "Value") # Excluding the first column which might be the row names
# 
# # Now, transpose the data into wide format, making each former row a column
# transposed_newdata <- newdata_long %>%
#   tidyr::pivot_wider(names_from = V1, values_from = Value)
# 
#    #add country
# 
# newdata <- transposed_newdata %>%
#      dplyr::mutate(across(-1, ~as.numeric(.))) %>%
#   dplyr::mutate(across(-1, ~replace_na(. , 0))) %>%
# 
#   dplyr::mutate(
#     country = dplyr::case_when(
#       grepl("^BC", sample) ~ "Spain_dec2022",
#       grepl("^nrsI", sample) ~ "Netherlands",
#           TRUE ~ NA_character_
#     )
#   )%>%
#    janitor::clean_names()
# 
# # Add rows
# micro3 <- bind_rows(micro2, newdata)
# 
# # Translate
# 
# eng <- c("sample", "fibers", "fragments", "spheres", "films", "pellets", "sponges", "rubbers", "types_items", "dry_weight", "country")
# 
# 
# micro4 <- micro3 %>%
#  dplyr::rename(
#     Fibers = fibras,
#     Fragments = fragmentos,
#     Spheres = esferas,
#     Films = films,
#     Pellets = pellets,
#     Sponges = esponjas,
#     Rubbers = gomas,
#     ItemTypes = tipos_items,
#     DryWeight = peso_seco,
#     Country = country
#   ) %>%
#   janitor::clean_names() %>%
#   dplyr::mutate(
#     sample = as.factor(sample),
#     country = as.factor(country)
# )
# 
# summary(micro4)
# 
# saveRDS(micro4, here::here("data", "micro4.rds"))

# micro4 <-readRDS(here::here("data", "micro4.rds"))
# 
# # Finding all duplicated rows
# repeated_rows <- micro4 %>%
#   dplyr::filter(duplicated(.) | duplicated(., fromLast = TRUE))
# 
# repeated_rows
# 
# 
# # Remove duplicate rows, keeping only the unique ones
# micro5 <- micro4 %>%
#   distinct()
# 
# # Identify repeated sample names in 'micro5'
# repeated_sample_names <- micro5 %>%
#   dplyr::group_by(sample) %>%
#   dplyr::summarise(count = n()) %>%
#   dplyr::filter(count > 1) %>%
#   dplyr::pull(sample)
# 
# # Filter 'micro5' for these repeated sample names to show full rows
# full_rows_repeated_samples <- micro5 %>%
#   dplyr::filter(sample %in% repeated_sample_names)
# 
# 
# full_rows_repeated_samples
# 
# write_xlsx(micro5, here::here("data", "micro5.xlsx"))

Check for other errors

# summary(micro5)
# 
# # Check repeated values
# # Max fragments 60 in one sample?
# # Max weight 81g?
# # Falta GEO
# 
# 
# # Boxplot for dry_weight
# ggplot(micro5, aes(y = dry_weight)) +
#   geom_boxplot()
# 
# # Any missing values?
# colSums(is.na(micro5))
# 

Manual editing to raw2.csv (directly in excel)

  • raw2.csv comes from todaslasmuestras_rev.xlsx, sent by David Dec 5th
  • coordinates reordered manually (many lat lon are lot lan or whatever system)
  • Added S-JTSK to Czech coordinates
  • MA7 UTM ETRS89 HUSO 30 721643 4449906 (a 4 was missing in 449906)
  • MA8 UTM ETRS89 HUSO 30 721870 4449926 (an extra 0 in 7218070)
  • 2/7/24 Added WGS 84 Holland coordinates
  • 10/07/24 Added Austria coordinates from Lukas email grosser bach
raw <- rio::import(here::here("data", "raw2.csv"))

# newdataraw <- rio::import(here::here("data", "newdata.csv")) %>% 
#   slice(-n())
# 
# italy <- rio::import(here::here("data", "italy.csv"))
# cz <- rio::import(here::here("data", "cz.csv"))

Transform variables

summary(raw)
##     sample              fibers         fragments      spheres   
##  Length:346         Min.   : 1.000   Min.   : 1    Min.   :2    
##  Class :character   1st Qu.: 1.000   1st Qu.: 1    1st Qu.:2    
##  Mode  :character   Median : 1.000   Median : 1    Median :2    
##                     Mean   : 2.033   Mean   : 7    Mean   :2    
##                     3rd Qu.: 2.000   3rd Qu.: 1    3rd Qu.:2    
##                     Max.   :12.000   Max.   :60    Max.   :2    
##                     NA's   :286      NA's   :336   NA's   :345  
##      films       pellets           sponges      rubbers          item_types    
##  Min.   :1.000   Mode:logical   Min.   :1.000   Mode:logical   Min.   :0.0000  
##  1st Qu.:1.000   NA's:346       1st Qu.:1.000   NA's:346       1st Qu.:0.0000  
##  Median :1.000                  Median :1.000                  Median :0.0000  
##  Mean   :1.364                  Mean   :1.333                  Mean   :0.2543  
##  3rd Qu.:1.000                  3rd Qu.:1.000                  3rd Qu.:0.0000  
##  Max.   :5.000                  Max.   :3.000                  Max.   :2.0000  
##  NA's   :335                    NA's   :340                                    
##    dry_weight      density (items/dry_weight)   country         
##  Min.   : 0.0900   Min.   : 0.0000            Length:346        
##  1st Qu.: 0.4125   1st Qu.: 0.0000            Class :character  
##  Median : 0.8400   Median : 0.0000            Mode  :character  
##  Mean   : 2.0121   Mean   : 0.3664                              
##  3rd Qu.: 1.5725   3rd Qu.: 0.0000                              
##  Max.   :81.2600   Max.   :10.0000                              
##                                                                 
##   geo_system             lat                lon           
##  Length:346         Min.   :-1208878   Min.   :-861924.0  
##  Class :character   1st Qu.:-1130945   1st Qu.:-653396.0  
##  Mode  :character   Median :-1050191   Median :-473460.0  
##                     Mean   :  426109   Mean   :-259399.2  
##                     3rd Qu.:      53   3rd Qu.:     14.5  
##                     Max.   : 4849533   Max.   : 725585.0  
##                     NA's   :9          NA's   :9
data <- raw %>% 
  dplyr::mutate(pellets = as.numeric(pellets),
                rubbers = as.numeric(rubbers),
                sample = as.factor(sample),
                country = as.factor(country),
                geo_system = as.factor(geo_system)) %>%
  dplyr::mutate_at(vars(fibers:rubbers), ~tidyr::replace_na(., 0)) %>% 
  dplyr::mutate(total_mp = fibers + fragments + spheres + films + sponges,
                concentration = total_mp / dry_weight) %>% 
  dplyr::mutate(country = dplyr::recode(country, "Czech Republic" = "Czechia",
                "The Netherlands" = "Netherlands"))


summary(data)  
##      sample        fibers          fragments          spheres       
##  5753/6 :  2   Min.   : 0.0000   Min.   : 0.0000   Min.   :0.00000  
##  5768/1 :  2   1st Qu.: 0.0000   1st Qu.: 0.0000   1st Qu.:0.00000  
##  5943/1 :  2   Median : 0.0000   Median : 0.0000   Median :0.00000  
##  5957/4 :  2   Mean   : 0.3526   Mean   : 0.2023   Mean   :0.00578  
##  6371/4 :  2   3rd Qu.: 0.0000   3rd Qu.: 0.0000   3rd Qu.:0.00000  
##  6374/3 :  2   Max.   :12.0000   Max.   :60.0000   Max.   :2.00000  
##  (Other):334                                                        
##      films            pellets     sponges           rubbers    item_types    
##  Min.   :0.00000   Min.   :0   Min.   :0.00000   Min.   :0   Min.   :0.0000  
##  1st Qu.:0.00000   1st Qu.:0   1st Qu.:0.00000   1st Qu.:0   1st Qu.:0.0000  
##  Median :0.00000   Median :0   Median :0.00000   Median :0   Median :0.0000  
##  Mean   :0.04335   Mean   :0   Mean   :0.02312   Mean   :0   Mean   :0.2543  
##  3rd Qu.:0.00000   3rd Qu.:0   3rd Qu.:0.00000   3rd Qu.:0   3rd Qu.:0.0000  
##  Max.   :5.00000   Max.   :0   Max.   :3.00000   Max.   :0   Max.   :2.0000  
##                                                                              
##    dry_weight      density (items/dry_weight)        country   
##  Min.   : 0.0900   Min.   : 0.0000            Austria    :  9  
##  1st Qu.: 0.4125   1st Qu.: 0.0000            Czechia    :196  
##  Median : 0.8400   Median : 0.0000            Italy      : 39  
##  Mean   : 2.0121   Mean   : 0.3664            Spain      : 82  
##  3rd Qu.: 1.5725   3rd Qu.: 0.0000            Netherlands: 20  
##  Max.   :81.2600   Max.   :10.0000                             
##                                                                
##               geo_system       lat                lon           
##  Not available     :  9   Min.   :-1208878   Min.   :-861924.0  
##  S-JTSK            :191   1st Qu.:-1130945   1st Qu.:-653396.0  
##  UTM ETRS89 HUSO 29:  4   Median :-1050191   Median :-473460.0  
##  UTM ETRS89 HUSO 30: 74   Mean   :  426109   Mean   :-259399.2  
##  WGS84, Google Map : 68   3rd Qu.:      53   3rd Qu.:     14.5  
##                           Max.   : 4849533   Max.   : 725585.0  
##                           NA's   :9          NA's   :9          
##     total_mp       concentration    
##  Min.   : 0.0000   Min.   : 0.0000  
##  1st Qu.: 0.0000   1st Qu.: 0.0000  
##  Median : 0.0000   Median : 0.0000  
##  Mean   : 0.6272   Mean   : 0.7206  
##  3rd Qu.: 0.0000   3rd Qu.: 0.0000  
##  Max.   :60.0000   Max.   :78.9474  
## 
write_xlsx(data, here::here("data", "data_clean.xlsx"))
write_csv(data, here::here("data", "data_clean.csv"))

Homogenizar CRSs

Here we filter the data for which we have coordinates and transform all of them to WGS84 16/10/24 - 4 from Spain and 5 from CZ are missing.

# Define a mapping of geo_system values to EPSG codes
geo_system_mapping <- tibble::tibble(
  geo_system = c("UTM ETRS89 HUSO 29", "UTM ETRS89 HUSO 30", "S-JTSK", "WGS84"),
  epsg = c(25829, 25830, 5514, 4326)
)

# Function to transform coordinates
transform_coords <- function(df, original_crs) {
  # Skip if the subset is empty or CRS is not defined
  if (nrow(df) == 0 || is.na(original_crs)) {
    return(df)
  }
  
  # Create sf object and transform coordinates
  df_sf <- sf::st_as_sf(df, coords = c("lon", "lat"), crs = original_crs, remove = FALSE)
  df_sf_transformed <- sf::st_transform(df_sf, crs = 4326)
  return(cbind(df, sf::st_coordinates(df_sf_transformed)[, 1:2]))
}

# Transform all coordinates to WGS 84
data_wgs84 <- data %>%
  dplyr::mutate(geo_system = dplyr::recode(geo_system, `WGS84, Google Map` = "WGS84")) %>%
  dplyr::filter(geo_system != "Not available", !is.na(lon), !is.na(lat)) %>%
  dplyr::left_join(geo_system_mapping, by = "geo_system") %>%
  dplyr::group_by(geo_system) %>%
  dplyr::group_modify(~ transform_coords(.x, unique(.x$epsg)[1])) %>%
  dplyr::ungroup() %>%
  dplyr::select(-c(epsg, geo_system,lat,lon))

# Check the results
head(data_wgs84)
## # A tibble: 6 × 16
##   sample fibers fragments spheres films pellets sponges rubbers item_types
##   <fct>   <int>     <int>   <int> <int>   <dbl>   <int>   <dbl>      <int>
## 1 5668/5      0         0       0     0       0       0       0          0
## 2 5669/2      0         0       0     0       0       0       0          0
## 3 5768/1      0         0       0     0       0       0       0          0
## 4 5943/1      0         0       0     0       0       0       0          0
## 5 5753/2      1         0       0     0       0       0       0          1
## 6 5753/4      0         0       0     0       0       0       0          0
## # ℹ 7 more variables: dry_weight <dbl>, `density (items/dry_weight)` <dbl>,
## #   country <fct>, total_mp <int>, concentration <dbl>, X <dbl>, Y <dbl>
summary(data_wgs84)
##      sample        fibers         fragments          spheres        
##  5753/6 :  2   Min.   : 0.000   Min.   : 0.0000   Min.   :0.000000  
##  5768/1 :  2   1st Qu.: 0.000   1st Qu.: 0.0000   1st Qu.:0.000000  
##  5943/1 :  2   Median : 0.000   Median : 0.0000   Median :0.000000  
##  5957/4 :  2   Mean   : 0.362   Mean   : 0.2047   Mean   :0.005935  
##  6371/4 :  2   3rd Qu.: 0.000   3rd Qu.: 0.0000   3rd Qu.:0.000000  
##  6374/3 :  2   Max.   :12.000   Max.   :60.0000   Max.   :2.000000  
##  (Other):325                                                        
##      films            pellets     sponges          rubbers    item_types    
##  Min.   :0.00000   Min.   :0   Min.   :0.0000   Min.   :0   Min.   :0.0000  
##  1st Qu.:0.00000   1st Qu.:0   1st Qu.:0.0000   1st Qu.:0   1st Qu.:0.0000  
##  Median :0.00000   Median :0   Median :0.0000   Median :0   Median :0.0000  
##  Mean   :0.04154   Mean   :0   Mean   :0.0178   Mean   :0   Mean   :0.2493  
##  3rd Qu.:0.00000   3rd Qu.:0   3rd Qu.:0.0000   3rd Qu.:0   3rd Qu.:0.0000  
##  Max.   :5.00000   Max.   :0   Max.   :3.0000   Max.   :0   Max.   :2.0000  
##                                                                             
##    dry_weight     density (items/dry_weight)        country   
##  Min.   : 0.100   Min.   : 0.0000            Austria    :  9  
##  1st Qu.: 0.410   1st Qu.: 0.0000            Czechia    :191  
##  Median : 0.830   Median : 0.0000            Italy      : 39  
##  Mean   : 2.029   Mean   : 0.3659            Spain      : 78  
##  3rd Qu.: 1.550   3rd Qu.: 0.0000            Netherlands: 20  
##  Max.   :81.260   Max.   :10.0000                             
##                                                               
##     total_mp       concentration           X                Y        
##  Min.   : 0.0000   Min.   : 0.0000   Min.   :-7.935   Min.   :36.58  
##  1st Qu.: 0.0000   1st Qu.: 0.0000   1st Qu.: 6.695   1st Qu.:42.16  
##  Median : 0.0000   Median : 0.0000   Median :14.342   Median :48.98  
##  Mean   : 0.6321   Mean   : 0.7295   Mean   :10.547   Mean   :46.87  
##  3rd Qu.: 0.0000   3rd Qu.: 0.0000   3rd Qu.:16.885   3rd Qu.:49.70  
##  Max.   :60.0000   Max.   :78.9474   Max.   :18.758   Max.   :53.16  
## 
write_xlsx(data_wgs84, here::here("data", "data_wgs84.xlsx"))

Analyses

Map results

Looks like for Italy we have just three rough areas for all the 39 samples.

# Create a leaflet map
map <- leaflet(data_wgs84) %>%
  addTiles() %>%  # Add default OpenStreetMap map tiles
  addMarkers(lng = ~X, lat = ~Y, popup = ~as.character(sample))

# Show the map
map
# # In Italy we have no streams, just 3 areas
# 
# italy_temp <- data_wgs84 %>% 
#   dplyr::filter(country == "Italy")
# 
# 
# # Create a leaflet map
# map2 <- leaflet(italy_temp) %>%
#   addTiles() %>%  # Add default OpenStreetMap map tiles
#   addMarkers(lng = ~X, lat = ~Y, popup = ~as.character(sample))
# 
# # Show the map
# map2

Map figure

Fig. 1 - Location of sampling sites in Austria, Czechia, Italy, the Netherlands and Spain.

# Get world map data
world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf")

# # Ensure the country names in your data match those in the world map data
# data_wgs84$country <- dplyr::recode(data_wgs84$country, 
#                                     "Czech Republic" = "Czechia",
#                                     "The Netherlands" = "Netherlands")

# Define the countries with samples
countries_with_samples <- unique(data_wgs84$country)

# Create the main map
main_map <- ggplot() +
  geom_sf(data = world, fill = "gray90", color = "white") +
  geom_sf(data = world[world$name %in% countries_with_samples,], aes(fill = name), color = "white") +
  geom_point(data = data_wgs84, aes(x = X, y = Y), color = "black", size = 1, alpha = 0.7) +
  coord_sf(xlim = c(-10, 30), ylim = c(35, 55), expand = FALSE) +
  scale_fill_brewer(palette = "Set2") +
  theme_void() +  # Removes axis lines, ticks, and labels
  theme(legend.position = "bottom",
        legend.title = element_blank(),
        plot.title = element_text(size = 14, hjust = 0.5, face = "bold"),
        panel.background = element_rect(fill = "gray98"),
        panel.grid = element_blank()) # +
  #labs(title = "Microplastic Sampling Sites in Europe")

# Print the map
print(main_map)

# Create an inset map of Europe
# inset_map <- ggplot2::ggplot() +
#   ggplot2::geom_sf(data = world, fill = "gray90", color = "white") +
#   ggplot2::geom_sf(data = world[world$name %in% countries_with_samples,], 
#                    ggplot2::aes(fill = name), color = "white") +
#   ggplot2::coord_sf(xlim = c(-25, 40), ylim = c(35, 70), expand = FALSE) +
#   ggplot2::theme_void() +
#   ggplot2::theme(legend.position = "none")

# Combine the main map and inset map
# final_map <- cowplot::ggdraw() +
#   cowplot::draw_plot(main_map) +
#   cowplot::draw_plot(inset_map, x = 0.65, y = 0.65, width = 0.3, height = 0.3)

# # Display the map
# print(final_map)
# 
# # Save the map
# ggplot2::ggsave("europe_microplastic_sampling_map.png", final_map, width = 12, height = 10, dpi = 300)

Heatmap microplastics in CZ

Exploration: How do microplastics vary across the land in CZ?

# Filter data for Czechia
cz_data <- data_wgs84 %>%
  dplyr::filter(country == "Czechia") %>%
    dplyr::mutate(total_microplastics = fibers + fragments + spheres + films + pellets + sponges + rubbers) %>%
    dplyr::mutate(density = as.numeric(`density (items/dry_weight)`)) %>%
    sf::st_as_sf(coords = c("X", "Y"), crs = 4326)



# Get the rivers data for the Czech Republic
cz_rivers <- RCzechia::reky()


# Heatmap  Czechia

rivers_cz <- ggplot2::ggplot(cz_data) +
  ggplot2::geom_sf(data = cz_rivers, color = "blue", size = 0.5, alpha = 0.5) +  # Add rivers layer
  ggplot2::geom_sf(ggplot2::aes(size = total_microplastics, color = density), alpha = 0.7) +
  ggplot2::scale_color_viridis_c(option = "magma", name = "Density") +  # Color represents density
  ggplot2::scale_size_continuous(name = "Total Items") +  # Size represents total number of microplastics
  ggplot2::theme_minimal() +
  ggplot2::labs(title = "Distribution of Microplastics in Otter Spraints (Czechia)")



# Save the plot
ggplot2::ggsave(here::here("output", "rivers_cz.png"), width = 10, height = 6, dpi = 300)

Interactive heatmap

There has to be an effect of sampling.

# Create a color palette function
pal <- leaflet::colorNumeric(
  palette = viridis::viridis(256),  # Use the viridis color scale
  domain = cz_data$total_microplastics  # The domain is the range of microplastics
)

# Create an interactive map with leaflet
cz_map <- cz_data %>%
  leaflet::leaflet() %>%
  leaflet::addTiles() %>%  # Add default OpenStreetMap tiles
  leaflet::addProviderTiles(providers$Esri.WorldTopoMap) %>%  # Add a topographic basemap with rivers and ponds
  leaflet::addCircleMarkers(
    radius = ~sqrt(total_microplastics) * 3,  # Marker size proportional to microplastics
    color = ~pal(total_microplastics),  # Use the color palette for the marker color
    fillOpacity = 0.8,
    label = ~paste("Microplastics:", total_microplastics),
    popup = ~paste("Sample ID:", sample, "<br>",
                   "Fibers:", fibers, "<br>",
                   "Fragments:", fragments, "<br>",
                   "Spheres:", spheres, "<br>",
                   "Films:", films)
  ) %>%
  leaflet::addLegend(
    "bottomright",
    pal = pal,
    values = cz_data$total_microplastics,
    title = "Microplastics",
    opacity = 1
  )


cz_map

Summary Table

Information for microplastics recovered from spraints collected in each country, including number of samples, abundance, type of microplastic, dry weight of each sample and average density.

# Summarise overall data
data_summary <- dplyr::summarise(
  data,
  `Samples (n)` = dplyr::n(),
  Abundance = sum(fibers + fragments + spheres + films + pellets + sponges + rubbers),
  SE = round(sd(fibers + fragments + spheres + films + pellets + sponges + rubbers) / sqrt(dplyr::n()), 2),
  dplyr::across(c(fibers, fragments, spheres, films, pellets, sponges, rubbers, dry_weight), sum, .names = "sum_{col}"),
  `Average Density` = round(mean(`density (items/dry_weight)`), 2)
) %>% 
  dplyr::select(where(~sum(.) != 0))

# Rename columns for Table1
data_table1 <- dplyr::rename(
  data_summary,
  Fibers = sum_fibers,
  Fragments = sum_fragments,
  Spheres = sum_spheres,
  Films = sum_films,
  Sponges = sum_sponges,
  `Dry Weight (g)` = sum_dry_weight
)

# Summarise by country
data_summary2 <- dplyr::group_by(data, country) %>%
  dplyr::summarise(
    `Samples (n)` = dplyr::n(),
    Abundance = sum(fibers + fragments + spheres + films + pellets + sponges + rubbers),
    SE = round(sd(fibers + fragments + spheres + films + pellets + sponges + rubbers) / sqrt(dplyr::n()), 2),
    dplyr::across(c(fibers, fragments, spheres, films, pellets, sponges, rubbers, dry_weight), sum, .names = "sum_{col}"),
    `Average Density` = round(mean(`density (items/dry_weight)`), 2)
  ) %>%
  dplyr::select(-starts_with("sum_pellets"), -starts_with("sum_rubbers"))

# Rename columns for Table2
data_table2 <- dplyr::rename(
  data_summary2,
  Country = country,
  Fibers = sum_fibers,
  Fragments = sum_fragments,
  Spheres = sum_spheres,
  Films = sum_films,
  Sponges = sum_sponges,
  `Dry Weight (g)` = sum_dry_weight
)

# Combine both tables
combined_table <- dplyr::bind_rows(data_table2, dplyr::mutate(data_table1, Country = "Total"))

# Display the table
combined_table %>%
  kableExtra::kbl() %>% 
  kableExtra::kable_paper("striped", full_width = F) %>%
  kableExtra::row_spec(nrow(combined_table), bold = TRUE)
Country Samples (n) Abundance SE Fibers Fragments Spheres Films Sponges Dry Weight (g) Average Density
Austria 9 60 6.67 0 60 0 0 0 8.08 0.15
Czechia 196 52 0.05 45 0 0 6 1 222.49 0.36
Italy 39 9 0.08 8 1 0 0 0 54.75 0.35
Spain 82 96 0.25 69 9 2 9 7 403.89 0.49
Netherlands 20 0 0.00 0 0 0 0 0 6.98 0.00
Total 346 217 0.19 122 70 2 15 8 696.19 0.37

Table 1 word

# Format the table
formatted_table <- combined_table %>%
  dplyr::mutate(dplyr::across(where(is.numeric), ~round(., 2))) %>%
  dplyr::mutate(`Average Density` = sprintf("%.2f", `Average Density`))

# Create the flextable
ft <- flextable::flextable(formatted_table) %>%
  flextable::theme_booktabs() %>%
  flextable::autofit() %>%
  flextable::align(align = "center", part = "all") %>%
  flextable::align(j = 1, align = "left", part = "all") %>%
  flextable::bold(part = "header") %>%
  flextable::bold(i = nrow(formatted_table), part = "body") %>%
  flextable::set_header_labels(
    Country = "Country",
    `Samples (n)` = "Samples (n)",
    Abundance = "Abundance",
    SE = "SE",
    Fibers = "Fibers",
    Fragments = "Fragments",
    Spheres = "Spheres",
    Films = "Films",
    Sponges = "Sponges",
    `Dry Weight (g)` = "Dry Weight (g)",
    `Average Density` = "Average Density"
  ) %>%
  flextable::add_footer_lines(
    "Table 1: Summary of microplastic occurrences in Eurasian otter (Lutra lutra) spraints across different European countries. The table shows the number of samples analyzed, total abundance of microplastics, standard error (SE), counts of different microplastic types (fibers, fragments, spheres, films, sponges), total dry weight of all samples per country, and average density of microplastics per gram of dry weight for each country and overall."
  ) %>%
  flextable::fontsize(size = 8, part = "all") %>%
  flextable::padding(padding = 2, part = "all") %>%
  flextable::border(border = officer::fp_border(color = "black", width = 1), part = "all")

# Set page layout to match STOTEN guidelines (assuming A4 page size)
ft <- flextable::set_table_properties(
  ft,
  layout = "autofit",
     width = 1  # Width in inches, adjust as needed
)

# Save the table as a Word document in the output folder
flextable::save_as_docx(ft, path = here::here("output", "table1_microplastics_summary.docx"))


ft

Country

Samples (n)

Abundance

SE

Fibers

Fragments

Spheres

Films

Sponges

Dry Weight (g)

Average Density

Austria

9

60

6.67

0

60

0

0

0

8.08

0.15

Czechia

196

52

0.05

45

0

0

6

1

222.49

0.36

Italy

39

9

0.08

8

1

0

0

0

54.75

0.35

Spain

82

96

0.25

69

9

2

9

7

403.89

0.49

Netherlands

20

0

0.00

0

0

0

0

0

6.98

0.00

Total

346

217

0.19

122

70

2

15

8

696.19

0.37

Table 1: Summary of microplastic occurrences in Eurasian otter (Lutra lutra) spraints across different European countries. The table shows the number of samples analyzed, total abundance of microplastics, standard error (SE), counts of different microplastic types (fibers, fragments, spheres, films, sponges), total dry weight of all samples per country, and average density of microplastics per gram of dry weight for each country and overall.

Presence/Absence

# Calculate presence/absence and percentage of spraints with microplastics
presence_absence <- data %>%
  dplyr::mutate(has_mp = dplyr::if_else(fibers + fragments + spheres + films + sponges > 0, 1, 0)) %>%
  dplyr::summarise(
    total_samples = dplyr::n(),
    samples_with_mp = sum(has_mp),
    percentage_with_mp = mean(has_mp) * 100
  )

# Calculate abundance (MPs/spraint)
abundance_stats <- data %>%
  dplyr::mutate(total_mp = fibers + fragments + spheres + films + sponges) %>%
  dplyr::summarise(
    mean_abundance = mean(total_mp),
    se_abundance = stats::sd(total_mp) / sqrt(dplyr::n())
  )

# Calculate concentration (MPs/g dry weight)
concentration_stats <- data %>%
  dplyr::mutate(total_mp = fibers + fragments + spheres + films + sponges,
         concentration = total_mp / dry_weight) %>%
  dplyr::summarise(
    mean_concentration = mean(concentration),
    se_concentration = stats::sd(concentration) / sqrt(dplyr::n())
  )

# Calculate proportions of particle types
particle_proportions <- data %>%
  dplyr::summarise(dplyr::across(c(fibers, fragments, spheres, films, sponges), sum)) %>%
  tidyr::pivot_longer(dplyr::everything(), names_to = "particle_type", values_to = "count") %>%
  dplyr::mutate(proportion = count / sum(count) * 100) %>%
  dplyr::arrange(dplyr::desc(proportion))



# Paragraph for results
report_text <- paste(
  "We found microplastics in", round(presence_absence$percentage_with_mp, 1), "% of spraints, at a mean abundance of", round(abundance_stats$mean_abundance, 1), "±", round(abundance_stats$se_abundance, 1),
  "microplastics (MPs)/spraint (mean ± SE),and a mean concentration of", round(concentration_stats$mean_concentration, 1), "±", round(concentration_stats$se_concentration, 1),
  "MPs/g (dry weight).\n\n")


# Print or write the report text to a file
cat(report_text)
## We found microplastics in 22.8 % of spraints, at a mean abundance of 0.6 ± 0.2 microplastics (MPs)/spraint (mean ± SE),and a mean concentration of 0.7 ± 0.2 MPs/g (dry weight).

Checking normality

# Visual inspection using Q-Q plot
ggplot2::ggplot(data, aes(sample = concentration)) +
  stat_qq() +
  stat_qq_line() +
  labs(title = "Q-Q Plot of Microplastic Concentrations",
       x = "Theoretical Quantiles", 
       y = "Sample Quantiles")

# Shapiro-Wilk test for normality
shapiro_test <- stats::shapiro.test(data$concentration)
print(shapiro_test)
## 
##  Shapiro-Wilk normality test
## 
## data:  data$concentration
## W = 0.12528, p-value < 2.2e-16
# Attempt log transformation
data <- data %>%
  dplyr::mutate(log_concentration = log(concentration))

# Q-Q plot for log-transformed data
ggplot2::ggplot(data, aes(sample = log_concentration)) +
  stat_qq() +
  stat_qq_line() +
  labs(title = "Q-Q Plot of Log-Transformed Microplastic Concentrations",
       x = "Theoretical Quantiles", 
       y = "Sample Quantiles")

Variation among regions

Non-parametric

# Remove  countries with no variation in microplastic concentration (Netherlands)
data_filtered <- data %>%
  dplyr::group_by(country) %>%
  dplyr::filter(stats::var(concentration) > 0) %>%
  dplyr::ungroup()

# Kruskal-Wallis test with effect size
kruskal_result <- data_filtered %>%
  rstatix::kruskal_test(concentration ~ country) %>%
  rstatix::add_significance()

# Calculate effect size
effect_size <- data_filtered %>%
  rstatix::kruskal_effsize(concentration ~ country)

# Pairwise Wilcoxon rank sum test with Bonferroni correction
pairwise_wilcox <- stats::pairwise.wilcox.test(data_filtered$concentration, 
                                        data_filtered$country, 
                                        p.adjust.method = "bonferroni")

# Calculate proportions of samples with microplastics
proportion_with_mp <- data %>%
  dplyr::filter(country != "Netherlands") %>%
  dplyr::group_by(country) %>%
  dplyr::summarise(
    total_samples = dplyr::n(),
    samples_with_mp = sum(concentration > 0),
    proportion = samples_with_mp / total_samples
  )

kruskal_result
## # A tibble: 1 × 7
##   .y.               n statistic    df          p method         p.signif
##   <chr>         <int>     <dbl> <int>      <dbl> <chr>          <chr>   
## 1 concentration   326      26.1     3 0.00000929 Kruskal-Wallis ****
effect_size
## # A tibble: 1 × 5
##   .y.               n effsize method  magnitude
## * <chr>         <int>   <dbl> <chr>   <ord>    
## 1 concentration   326  0.0716 eta2[H] moderate
pairwise_wilcox
## 
##  Pairwise comparisons using Wilcoxon rank sum test with continuity correction 
## 
## data:  data_filtered$concentration and data_filtered$country 
## 
##         Austria Czechia Italy
## Czechia 1.000   -       -    
## Italy   1.000   1.000   -    
## Spain   0.620   5.6e-06 0.043
## 
## P value adjustment method: bonferroni
proportion_with_mp
## # A tibble: 4 × 4
##   country total_samples samples_with_mp proportion
##   <fct>           <int>           <int>      <dbl>
## 1 Austria             9               1      0.111
## 2 Czechia           196              32      0.163
## 3 Italy              39               8      0.205
## 4 Spain              82              38      0.463
# kruskal_result
# # A tibble: 1 × 7
#   .y.               n statistic    df          p method         p.signif
#   <chr>         <int>     <dbl> <int>      <dbl> <chr>          <chr>   
# 1 concentration   326      26.1     3 0.00000929 Kruskal-Wallis ****    
# > effect_size
# # A tibble: 1 × 5
#   .y.               n effsize method  magnitude
# * <chr>         <int>   <dbl> <chr>   <ord>    
# 1 concentration   326  0.0716 eta2[H] moderate 
# > pairwise_wilcox
# 
#   Pairwise comparisons using Wilcoxon rank sum test with continuity correction 
# 
# data:  data_filtered$concentration and data_filtered$country 
# 
#         Austria Czechia Italy
# Czechia 1.000   -       -    
# Italy   1.000   1.000   -    
# Spain   0.620   5.6e-06 0.043
# 
# P value adjustment method: bonferroni 
# > proportion_with_mp
# # A tibble: 4 × 4
#   country total_samples samples_with_mp proportion
#   <fct>           <int>           <int>      <dbl>
# 1 Austria             9               1      0.111
# 2 Czechia           196              32      0.163
# 3 Italy              39               8      0.205
# 4 Spain              82              38      0.463



# Results and Interpretations

#' Microplastic Concentration Differences Among Countries
#' 
#' The Kruskal-Wallis test revealed significant differences in microplastic 
#' concentrations among the studied countries (χ2(3) = 26.1, p < 0.0001). 
#' The effect size (η2H = 0.0716) indicates a moderate practical significance, 
#' suggesting that approximately 7.16% of the variability in microplastic 
#' concentrations can be attributed to country differences.
#' 
#' Pairwise comparisons using Wilcoxon rank sum tests showed that Spain had 
#' significantly different microplastic concentrations compared to Czechia 
#' (p < 0.0001) and Italy (p = 0.043). No significant differences were found 
#' between other country pairs, due to limited sample sizes in Austria.
#' 
#' The proportion of samples containing microplastics varied considerably 
#' among countries: Spain (46.3%), Italy (20.5%), Czechia (16.3%), and 
#' Austria (11.1%). This variation suggests differing levels of microplastic 
#' pollution or detection across the studied European countries.
#' 

# Visualize results with adjusted y-axis
ggplot2::ggplot(data_filtered, ggplot2::aes(x = country, y = concentration)) +
  ggplot2::geom_boxplot(outlier.shape = NA) +
  ggplot2::geom_jitter(width = 0.2, alpha = 0.5) +
  ggplot2::labs(title = "Microplastic Concentrations by Country",
       subtitle = paste("Kruskal-Wallis test p-value <", format(kruskal_result$p, scientific = TRUE, digits = 3)),
       x = "",
       y = "Concentration (MPs/g dry weight)") +
  ggplot2::theme_minimal() +
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1)) +
  ggplot2::coord_cartesian(ylim = c(0, 12.5)) +
  ggplot2::annotate("text", x = 0.7, y = 12, 
                    label = "One sample in Austria  \n is out of scale (78.95)", 
                    hjust = 0, vjust = 1, size = 3, color = "red")

# Save the plot
ggplot2::ggsave("microplastic_concentration_by_country_adjusted.png", width = 10, height = 6, dpi = 300)

# Visualize proportion of samples with microplastics
ggplot2::ggplot(proportion_with_mp, ggplot2::aes(x = country, y = proportion, fill = country)) +
  ggplot2::geom_bar(stat = "identity") +
  ggplot2::geom_text(ggplot2::aes(label = scales::percent(proportion, accuracy = 0.1)), 
                     vjust = -0.5, size = 3.5) +
  ggplot2::labs(title = "Proportion of Samples with Microplastics by Country",
       x = "",
       y = "Proportion of Samples") +
  ggplot2::theme_minimal() +
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1),
        legend.position = "none") +
  ggplot2::scale_y_continuous(labels = scales::percent, limits = c(0, 1))

# Save the proportion plot
ggplot2::ggsave("proportion_samples_with_microplastics.png", width = 10, height = 6, dpi = 300)

CZ: Urbanisation

# Filter for Czechia data and convert to sf object
cz_data <- data_wgs84 %>%
  dplyr::filter(country == "Czechia") %>%
  sf::st_as_sf(coords = c("X", "Y"), crs = 4326)

# Load Czechia administrative boundaries and population data
cz_districts <- RCzechia::okresy("low")
census_data <- czso::czso_get_table("SLDB-VYBER") %>% 
  dplyr::select(uzkod, obyvatel = vse1111) %>% 
  dplyr::mutate(obyvatel = as.numeric(obyvatel))

# Join population data to districts
cz_districts <- cz_districts %>%
  dplyr::inner_join(census_data, by = c("KOD_OKRES" = "uzkod"))

# Calculate population density
cz_districts$pop_density <- cz_districts$obyvatel / (as.numeric(st_area(cz_districts)) / 1e6)  # population per km2

# Find which district each microplastic sample belongs to
cz_data <- sf::st_join(cz_data, cz_districts)

# Calculate urbanization index based on population density
cz_data$urban_index <- scale(cz_data$pop_density)

# Statistical analysis
cz_model <- lm(concentration ~ urban_index, data = cz_data)
cz_summary <- summary(cz_model)
cz_correlation <- cor.test(cz_data$concentration, cz_data$urban_index)

# Visualization
create_map <- function(data) {
  ggplot() +
    geom_sf(data = cz_districts, aes(fill = pop_density)) +
    geom_sf(data = data, aes(color = concentration, size = urban_index)) +
    scale_fill_viridis_c(name = "Population Density", option = "C") +
    scale_color_viridis_c(name = "Microplastic Concentration", option = "D") +
    theme_minimal() +
    labs(title = "Microplastic Concentration and Urbanization in Czechia",
         size = "Urbanization Index")
}

create_scatter <- function(data) {
  ggplot(data, aes(x = urban_index, y = concentration)) +
    geom_point() +
    geom_smooth(method = "lm") +
    labs(title = "Microplastic Concentration vs. Urbanization in Czechia",
         x = "Urbanization Index", 
         y = "Microplastic Concentration")
}

cz_map <- create_map(cz_data)
cz_scatter <- create_scatter(cz_data)

# not a good proxy with population, because sampling of course happened outside

Plots

  • Removed The Netherlands

Proportions

Composition of microplastic types across different countries.Relative proportions of fibers, fragments, spheres, films, and sponges in each country.

str(combined_table)
## tibble [6 × 11] (S3: tbl_df/tbl/data.frame)
##  $ Country        : chr [1:6] "Austria" "Czechia" "Italy" "Spain" ...
##  $ Samples (n)    : int [1:6] 9 196 39 82 20 346
##  $ Abundance      : num [1:6] 60 52 9 96 0 217
##  $ SE             : num [1:6] 6.67 0.05 0.08 0.25 0 0.19
##  $ Fibers         : int [1:6] 0 45 8 69 0 122
##  $ Fragments      : int [1:6] 60 0 1 9 0 70
##  $ Spheres        : int [1:6] 0 0 0 2 0 2
##  $ Films          : int [1:6] 0 6 0 9 0 15
##  $ Sponges        : int [1:6] 0 1 0 7 0 8
##  $ Dry Weight (g) : num [1:6] 8.08 222.49 54.75 403.89 6.98 ...
##  $ Average Density: num [1:6] 0.15 0.36 0.35 0.49 0 0.37
# Reshape the data for plotting
otter_data_long <- combined_table %>%
  dplyr::select(Country, `Samples (n)`, Fibers, Fragments, Spheres, Films, Sponges) %>%
  tidyr::pivot_longer(cols = Fibers:Sponges, names_to = "Type", values_to = "Count")



# Convert Country to factor and reorder levels by Count (abundance)
otter_data_long$Country <- factor(otter_data_long$Country, 
                                  levels = c("Netherlands","Italy","Austria", "Czechia","Spain", "Total"))


ggplot(otter_data_long, aes(x = Country, y = Count, fill = Type)) +
  geom_bar(stat = "identity") +
  geom_text(data = combined_table, aes(x = Country, y = max(-15), label = `Samples (n)`), 
            vjust = -0.5, size = 3, inherit.aes = FALSE) +
  labs(title = "Microplastics in Otter Spraints by Country",
       x = NULL,
       y = "Total Microplastic Abundance",
       fill = "Microplastic Type",
      caption = "Number of samples (n) shown left of bars") +
  scale_fill_brewer(palette = "Set3") +  
  theme_light() +  
  theme(plot.title = element_text(size = 14, face = "bold"),
        axis.title = element_text(size = 12),
        axis.text.x = element_text(hjust = 1),
        legend.title = element_text(size = 10),
        legend.text = element_text(size = 9),
        plot.caption = element_text(size = 9, hjust = 0))+
  coord_flip()

# Calculate proportions of each microplastic type
data_proportions <- data %>%
  dplyr::group_by(country) %>%
  dplyr::summarise(dplyr::across(c(fibers, fragments, spheres, films, sponges), sum),
            total = sum(fibers, fragments, spheres, films, sponges)) %>%
  dplyr::mutate(dplyr::across(c(fibers, fragments, spheres, films, sponges), 
                ~./total, .names = "prop_{.col}"))

# Reshape the data for plotting
data_long <- data_proportions %>%
  tidyr::pivot_longer(cols = starts_with("prop_"),
                      names_to = "microplastic_type",
                      values_to = "proportion") %>%
  dplyr::mutate(microplastic_type = stringr::str_remove(microplastic_type, "prop_")) %>% 
  dplyr::filter(country != "Netherlands")

# Create a stacked bar plot
ggplot2::ggplot(data_long, ggplot2::aes(x = country, y = proportion, fill = microplastic_type)) +
  ggplot2::geom_bar(stat = "identity", position = "stack") +
  ggplot2::scale_y_continuous(labels = scales::percent) +
  ggplot2::scale_fill_brewer(palette = "Set3") +
  ggplot2::labs(x = NULL, y = "Proportion", fill = "Microplastic Type") +
  ggplot2::theme_minimal() +
  ggplot2::coord_flip()

# Removed The Netherlands
# Composition of microplastic types across different countries.
# Relative proportions of fibers, fragments, spheres, films, and sponges in each country.

Boxplots

# Create boxplots total data
ggplot2::ggplot(data = data, ggplot2::aes(x = country, y = concentration, fill = country)) +
  ggplot2::geom_boxplot() +
  ggplot2::labs(title = "Microplastic Concentrations Across Countries",
                x = "Country",
                y = "Microplastic Concentration (MPs/g dry weight)",
                fill = "Country")  +
ggplot2::scale_fill_brewer(palette = "Set3") +
  ggplot2::theme_minimal() +
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))

# Filter out outliers with concentration > 30 MPs/g dry weight
data_no_outliers <- dplyr::filter(data, !(data$concentration > 30))

# Identify outliers for labeling
outliers <- dplyr::filter(data, data$concentration > 30)

# Create boxplots with outliers labeled
ggplot2::ggplot(data = data_no_outliers, ggplot2::aes(x = country, y = concentration, fill = country)) +
  ggplot2::geom_boxplot() +
  ggplot2::geom_text(data = outliers, ggplot2::aes(label = sample), x = outliers$country, y = 12,
                     hjust = -0.1, vjust = 0.5, color = "red", size = 3) +
  ggplot2::ylim(0, 12) +  # Limit y-axis to 12
  ggplot2::labs(title = "Microplastic Concentrations Across Countries (Outliers Labeled)",
                x = "Country",
                y = "Microplastic Concentration (MPs/g dry weight)",
                fill = "Country",
                caption = "Outliers labeled in red") +
  ggplot2::scale_fill_brewer(palette = "Set3") +
  ggplot2::theme_minimal() +
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))

Citations

cite_packages(out.format = "docx", out.dir = ".")
##   |                                                                              |                                                                      |   0%  |                                                                              |......................................................................| 100%
## "C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/pandoc" +RTS -K512m -RTS grateful-report.knit.md --to docx --from markdown+autolink_bare_uris+tex_math_single_backslash --output pandoc10cc73430f2.docx --lua-filter "C:\RLibrary\rmarkdown\rmarkdown\lua\pagebreak.lua" --highlight-style tango --citeproc
## [1] "./grateful-report.docx"
cite_packages("paragraph", out.dir = ".")

We used R version 4.4.1 [@base] and the following R packages: annotater v. 0.2.3.9000 [@annotater], coin v. 1.4.3 [@coin2006; @coin2008], cowplot v. 1.1.3 [@cowplot], czso v. 0.4.1 [@czso], data.table v. 1.16.0 [@datatable], dunn.test v. 1.3.6 [@dunntest], effsize v. 0.8.1 [@effsize], flextable v. 0.9.6 [@flextable], ggthemes v. 5.1.0 [@ggthemes], here v. 1.0.1 [@here], janitor v. 2.2.0 [@janitor], kableExtra v. 1.4.0 [@kableExtra], knitr v. 1.48 [@knitr2014; @knitr2015; @knitr2024], leaflet v. 2.2.2 [@leaflet], officer v. 0.6.6 [@officer], osmdata v. 0.2.5 [@osmdata], pacman v. 0.5.1 [@pacman], raster v. 3.6.26 [@raster], RCzechia v. 1.12.2 [@RCzechia], rio v. 1.2.2 [@rio], rmarkdown v. 2.28 [@rmarkdown2018; @rmarkdown2020; @rmarkdown2024], rnaturalearth v. 1.0.1 [@rnaturalearth], rnaturalearthdata v. 1.0.0 [@rnaturalearthdata], rsconnect v. 1.3.1 [@rsconnect], rstatix v. 0.7.2 [@rstatix], scales v. 1.3.0 [@scales], sf v. 1.0.16 [@sf2018; @sf2023], terra v. 1.7.78 [@terra], tidyverse v. 2.0.0 [@tidyverse], viridis v. 0.6.5 [@viridis], writexl v. 1.5.0 [@writexl].

“We used R version 4.4.1 [@base] , dunn.test v. 1.3.6 [@dunntest], effsize v. 0.8.1 [@effsize], rstatix v. 0.7.2 [@rstatix], sf v. 1.0.16 [@sf2018; @sf2023], tidyverse v. 2.0.0 [@tidyverse]

EXTRA

Rivers and samples CZ

# # Convert sample data to sf object
# samples_sf <- sf::st_as_sf(data_wgs84, coords = c("X", "Y"), crs = 4326)
# 
# # Filter for Czech Republic samples
# cz_samples <- samples_sf %>% 
#   dplyr::filter(country == "Czechia")
# 
# # Get Czech Republic rivers and regions
# cz_rivers <- RCzechia::reky()
# cz_regions <- RCzechia::kraje()
# 
# # Ensure the CRS matches
# cz_rivers <- sf::st_transform(cz_rivers, crs = sf::st_crs(cz_samples))
# cz_regions <- sf::st_transform(cz_regions, crs = sf::st_crs(cz_samples))
# 
# # Find the nearest river for each sample
# nearest_rivers <- cz_rivers %>%
#   sf::st_join(cz_samples, join = sf::st_nearest_feature)
# 
# # Find the region for each sample
# samples_with_regions <- sf::st_join(cz_samples, cz_regions)
# 
# # Create summary table
# cz_river_summary <- nearest_rivers %>%
#   sf::st_drop_geometry() %>%
#   dplyr::group_by(NAZEV) %>%
#   dplyr::summarise(
#     n_samples = sum(!is.na(sample))
#   ) %>%
#   dplyr::filter(n_samples > 0) %>%
#   dplyr::arrange(dplyr::desc(n_samples))
# 
# # Add region information
# cz_river_summary <- cz_river_summary %>%
#   dplyr::left_join(
#     samples_with_regions %>%
#       sf::st_drop_geometry() %>%
#       dplyr::group_by(sample) %>%
#       dplyr::summarise(river = dplyr::first(NAZEV), region = dplyr::first(NAZEV.y)) %>%
#       dplyr::group_by(river) %>%
#       dplyr::summarise(region = dplyr::first(region)),
#     by = c("NAZEV" = "river")
#   )
# 
# # Reorder columns
# cz_river_summary <- cz_river_summary %>%
#   dplyr::select(n_samples, river = NAZEV, region)
# 
# # Print summary
# print(cz_river_summary)
# 
# # Save summary to CSV
# readr::write_csv(cz_river_summary, "czech_samples_per_river.csv")

Spain vs Cz

Only for Spain and CZ

Comparison of microplastic concentrations in otter (Lutra lutra) spraints between Spain (n = 82) and Czechia (n = 196). The boxplots display the median (central line), interquartile range (box), and range (whiskers) of microplastic concentrations. Individual data points are jittered to show the distribution. Microplastic concentration is expressed as the number of microplastic particles per gram of dry weight (MPs g^-1 dw).The Mann-Whitney U test revealed a significant difference in microplastic concentrations between the two countries (W = 10323, p = 9.27e-07), with Spain showing higher levels of contamination.

# # Filter data for Spain and Czechia
# data_czsp <- data %>%
#   dplyr::filter(country %in% c("Spain", "Czechia")) %>% 
#     dplyr::mutate(concentration = as.numeric(concentration)) %>%
#   dplyr::filter(!is.na(concentration))
# 
# 
# readr::write_csv(data_czsp, file = here::here("data", "data_czsp.csv"))
# 
# 
# # # Ensure data is properly formatted
# data_czsp <- data_czsp %>%
#   dplyr::filter(!is.na(concentration), !is.na(country)) %>%
#   dplyr::mutate(concentration = as.numeric(concentration))
# 
# # Perform statistical analysis
# spain_conc <- data_czsp$concentration[data_czsp$country == "Spain"]
# czechia_conc <- data_czsp$concentration[data_czsp$country == "Czechia"]
# wilcox_result <- wilcox.test(spain_conc, czechia_conc)
# 
# 
# # Create the plot with statistical results
# plot <- ggplot2::ggplot(data_czsp, ggplot2::aes(x = country, y = concentration)) +
#   ggplot2::geom_boxplot(ggplot2::aes(fill = country), width = 0.5, outlier.shape = NA) +
#   ggplot2::geom_jitter(width = 0.2, alpha = 0.5) +
#   ggthemes::scale_fill_colorblind() +
#   ggplot2::labs(
#     title = "Microplastic Concentrations in Otter Spraints",
#     subtitle = paste0("Mann-Whitney U test: W = ", round(wilcox_result$statistic, 2), 
#                       ", p = ", format.pval(wilcox_result$p.value, digits = 3), "\n"
#                       ),
#     x = "",
#     y = expression("Microplastic Concentration (MPs g"^-1*" dry weight)"),
#     fill = "Country"
#   ) +
#   ggplot2::theme_minimal() +
#   ggplot2::theme(
#     plot.title = ggplot2::element_text(face = "bold", size = 14),
#     plot.subtitle = ggplot2::element_text(size = 10),
#     axis.title = ggplot2::element_text(size = 11),
#     axis.text = ggplot2::element_text(size = 10),
#     legend.position = "none"
#   )
# 
# print(plot)
# 
# ggplot2::ggsave(here::here("output","figs", "microplastic_concentration_comparison.png"), 
#                 plot = plot, width = 8, height = 6, dpi = 300)
# 
# # Summary statistics
# summary_stats <- data_czsp %>%
#   dplyr::group_by(country) %>%
#   dplyr::summarize(
#     mean = mean(concentration),
#     median = median(concentration),
#     sd = sd(concentration),
#     n = n()
#   )
# 
# summary_stats
# str(data)
# head(data)
# 
# 
# # Filter data for the selected countries
# data_czsp <- data %>%
#   dplyr::filter(country %in% c("Spain", "Czechia"))
# 
# # Perform Kruskal-Wallis test to compare distributions of concentrations between countries
# kw_result <- stats::kruskal.test(concentration ~ country, data = data_czsp)
# 
# kw_result
# 
# #strong evidence to reject the null hypothesis that the distributions of microplastic concentrations are the same between these two countries. 
# 
# # Perform Dunn's test for pairwise comparisons with Bonferroni adjustment
# dunn_result <- dunn.test(data_czsp$concentration, data_czsp$country, method = "bonferroni")
# 
# dunn_result 
# 
# # Microplastic concentrations are significantly lower in Spain compared to Czechia.

SP vs CZ: Types of plastic

# # Calculate the proportion of each plastic type for each country
# plastic_proportions <- data_czsp %>%
#   dplyr::group_by(country) %>%
#   dplyr::summarise(dplyr::across(c(fibers, fragments, spheres, films), sum)) %>%
#   dplyr::mutate(total = fibers + fragments + spheres + films) %>%
#   dplyr::mutate(dplyr::across(c(fibers, fragments, spheres, films), ~./total, .names = "prop_{.col}"))
# 
# # Reshape the data for plotting
# plastic_long <- plastic_proportions %>%
#   tidyr::pivot_longer(cols = dplyr::starts_with("prop_"),
#                names_to = "plastic_type",
#                values_to = "proportion") %>%
#   dplyr::mutate(plastic_type = stringr::str_remove(plastic_type, "prop_"))
# 
# # Create a stacked bar plot
# ggplot2::ggplot(plastic_long, ggplot2::aes(x = country, y = proportion, fill = plastic_type)) +
#   ggplot2::geom_bar(stat = "identity", position = "stack") +
#   ggplot2::scale_y_continuous(labels = scales::percent) +
#   ggplot2::scale_fill_brewer(palette = "Set3") +
#   ggplot2::labs(title = "Proportion of Microplastic Types in Otter Spraints",       x = "",
#        y = "",
#        fill = "Microplastic Type") +
#   ggplot2::theme_minimal() +
#   ggplot2::theme(legend.position = "right")
# 
# ggplot2::ggsave("microplastic_types_comparison.png", width = 10, height = 6, dpi = 300)
# 
# # Statistical comparison for each plastic type
# plastic_types <- c("fibers", "fragments", "spheres", "films")
# 
# statistical_results <- lapply(plastic_types, function(type) {
#   wilcox_test <- stats::wilcox.test(data_czsp[[type]] ~ data_czsp$country)
#   data.frame(
#     plastic_type = type,
#     statistic = wilcox_test$statistic,
#     p_value = wilcox_test$p.value
#   )
# })
# 
# statistical_results_df <- do.call(rbind, statistical_results)
# 
# print(statistical_results_df)
# 
# # Calculate effect sizes
# effect_sizes <- data_czsp %>%
#   tidyr::gather(key = "plastic_type", value = "count", fibers, fragments, spheres, films) %>%
#   dplyr::group_by(plastic_type) %>%
#   rstatix::wilcox_effsize(count ~ country)
# 
# print(effect_sizes)
LS0tDQphdXRob3I6ICJGZXJuYW5kbyBNYXRlb3MtR29uesOhbGV6Ig0KZGF0ZTogTGFzdCB1cGRhdGUgImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICAgIHNtb290aF9zY3JvbGw6IG5vDQogIG1kX2RvY3VtZW50Og0KICAgIHZhcmlhbnQ6IG1hcmtkb3duX2dpdGh1Yg0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCnRpdGxlOiAiTWljcm9wbGFzdGljcyBpbiByaXZlciBtYW1tYWxzIg0Ka25pdDogKGZ1bmN0aW9uKGlucHV0RmlsZSwgZW5jb2RpbmcpIHsNCiAgDQogIHJtYXJrZG93bjo6cmVuZGVyKGlucHV0RmlsZSwgZW5jb2RpbmcgPSBlbmNvZGluZywgb3V0cHV0X2RpciA9ICJvdXRwdXQiKSB9KQ0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQojIEludHJvZHVjdGlvbg0KDQpBbmFseXNpcyBvZiBtaWNyb3BsYXN0aWNzIGluIHJpdmVyIG1hbW1hbHMNCg0KDQpgYGB7ciBnbG9iYWxfb3B0aW9ucywgZWNobz1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NiwgZmlnLmFzcCA9IDAuNjE4LCBmaWcucGF0aD0nb3V0cHV0L2ZpZ3MvJywNCiAgICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPSBGQUxTRSkNCmxpYnJhcnkoYW5ub3RhdGVyKSAjIEFubm90YXRlIFBhY2thZ2UgTG9hZCBDYWxscw0KICANCg0Kb3B0aW9ucyhhbGxvd19odG1sX2luX2FsbF9vdXRwdXRzPVRSVUUpDQpgYGANCg0KIyBMaWJyYXJ5DQoNCmBgYHtyIGxpYnJhcnksIGFubm90YXRlPVRSVUV9DQojIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQojIHdyaXRlTGluZXMocGFjbWFuOjpwX2xpYigpLCAifi9EZXNrdG9wL2xpc3Rfb2ZfUl9wYWNrYWdlcy5jc3YiKSAjIHRvIHF1aWNrbHkgYmFjayB1cCBwYWNrYWdlcw0KIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiVGhpbmtSLW9wZW4vcmVtZWR5IikNCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImx1aXNEVkEvYW5ub3RhdGVyIikNCg0KcGFjbWFuOjpwX2xvYWQocmlvLCB0aWR5dmVyc2UsamFuaXRvciwgZGF0YS50YWJsZSwgaGVyZSwNCiAgICAgICAgICAgICAgIGtuaXRyLA0KICAgICAgICAgICAgICAga2FibGVFeHRyYSwNCiAgICAgICAgICAgICAgIGZsZXh0YWJsZSwNCiAgICAgICAgICAgICAgIHdyaXRleGwsDQogICAgICAgICAgICAgICBzZiwNCiAgICAgICAgICAgICAgIHJhc3RlciwNCiAgICAgICAgICAgICAgIG9zbWRhdGEsDQogICAgICAgICAgICAgICBsZWFmbGV0LA0KICAgICAgICAgICAgICBybmF0dXJhbGVhcnRoZGF0YSwNCiAgICAgICAgICAgICAgIHJuYXR1cmFsZWFydGgsDQogICAgICAgICAgICAgIGNvd3Bsb3QsDQogICAgICAgICAgICAgIGR1bm4udGVzdCwNCiAgICAgICAgICAgICAgZ2d0aGVtZXMsDQogICAgICAgICAgICAgIGVmZnNpemUsDQogICAgICAgICAgICAgIHJzdGF0aXgsDQogICAgICAgICAgICAgIHN0YXRzLA0KICAgICAgICAgICAgICB2aXJpZGlzLA0KICAgICAgICAgICAgICBSQ3plY2hpYSwNCiAgICAgICAgICAgICAgc3RyaW5nciwNCiAgICAgICAgICAgICAgc2NhbGVzLA0KICAgICAgICAgICAgICBjb2luLA0KICAgICAgICAgICAgICBodHRyLA0KICAgICAgICAgICAgICB0ZXJyYSwNCiAgICAgICAgICAgICAgY3pzbywgDQogICAgICAgICAgICAgIGdyYXRlZnVsLA0KICAgICAgICAgICAgICBhbm5vdGF0ZXIsIA0KICAgICAgICAgICAgICBvZmZpY2VyDQogICAgICAgICAgIA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgKSAjIGp1c3QgYWRkIG5lZWRlZCBwYWNrYWdlcyB0byB0aGlzIGxpbmUgYW5kIFBhY21hbiB3aWxsIGluc3RhbGwgYW5kIGxvYWQgdGhlbS4NCg0KDQpgYGANCg0KIyBMb2FkIERhdGENCg0KDQojIyBDbGVhbiBkYXRhDQoNCmBgYHtyfQ0KIyANCiMgbWljcm8gPC0gcmF3ICU+JQ0KIyAgICBkcGx5cjo6bXV0YXRlKGFjcm9zcygtMSwgfmFzLm51bWVyaWMoLikpKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlKGFjcm9zcygtMSwgfnJlcGxhY2VfbmEoLiAsIDApKSkgJT4lDQojIA0KIyAgICNhZGQgY291bnRyeQ0KIyANCiMgICBkcGx5cjo6bXV0YXRlKA0KIyAgICAgY291bnRyeSA9IGRwbHlyOjpjYXNlX3doZW4oDQojICAgICAgIGdyZXBsKCJeQkMiLCBzYW1wbGUpIH4gIlNwYWluX2RlYzIwMjIiLA0KIyAgICAgICBncmVwbCgiXlRBIiwgc2FtcGxlKSB+ICJTcGFpbl9kZWMyMDIyIiwNCiMgICAgICAgZ3JlcGwoIl43XzUiLCBzYW1wbGUpIH4gIkF1c3RyaWEiLA0KIyAgICAgICBncmVwbCgiXkxMRVNQIiwgc2FtcGxlKSB+ICJTcGFpbl9qdW4yMDIyIiwNCiMgICAgICAgZ3JlcGwoIl5NQSIsIHNhbXBsZSkgfiAiU3BhaW5fMjAyMyIsDQojICAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfDQojICAgICApDQojICAgKQ0KIyANCiMgIyBhZGQgY291bnRyeTINCiMgDQojIG1pY3JvMiA8LSBtaWNybyAlPiUNCiMgICBkcGx5cjo6bGVmdF9qb2luKGN6LGJ5PSJzYW1wbGUiLHJlbGF0aW9uc2hpcCA9ICJtYW55LXRvLW1hbnkiKSAlPiUNCiMgICBkcGx5cjo6bGVmdF9qb2luKGl0YWx5LGJ5PSJzYW1wbGUiLHJlbGF0aW9uc2hpcCA9ICJtYW55LXRvLW1hbnkiKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlIChjb3VudHJ5ID0gY29hbGVzY2UoY291bnRyeSwgY291bnRyeS54LCBjb3VudHJ5LnkpKSAlPiUNCiMgICBkcGx5cjo6c2VsZWN0KC1jb3VudHJ5LngsIC1jb3VudHJ5LnkpICU+JQ0KIyAgIGphbml0b3I6OmNsZWFuX25hbWVzKCkgJT4lDQojICAgZHBseXI6Om11dGF0ZShjb3VudHJ5ID0gYXMuZmFjdG9yKGNvdW50cnkpKQ0KIyANCiMgDQojICMgQWRkIG5ldyBkYXRhDQojIA0KIyAjIFJlc2hhcGUgdGhlIGRhdGEgaW50byBsb25nIGZvcm1hdA0KIyBuZXdkYXRhX2xvbmcgPC0gbmV3ZGF0YXJhdyAlPiUNCiMgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSAhMSwgbmFtZXNfdG8gPSAic2FtcGxlIiwgdmFsdWVzX3RvID0gIlZhbHVlIikgIyBFeGNsdWRpbmcgdGhlIGZpcnN0IGNvbHVtbiB3aGljaCBtaWdodCBiZSB0aGUgcm93IG5hbWVzDQojIA0KIyAjIE5vdywgdHJhbnNwb3NlIHRoZSBkYXRhIGludG8gd2lkZSBmb3JtYXQsIG1ha2luZyBlYWNoIGZvcm1lciByb3cgYSBjb2x1bW4NCiMgdHJhbnNwb3NlZF9uZXdkYXRhIDwtIG5ld2RhdGFfbG9uZyAlPiUNCiMgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFYxLCB2YWx1ZXNfZnJvbSA9IFZhbHVlKQ0KIyANCiMgICAgI2FkZCBjb3VudHJ5DQojIA0KIyBuZXdkYXRhIDwtIHRyYW5zcG9zZWRfbmV3ZGF0YSAlPiUNCiMgICAgICBkcGx5cjo6bXV0YXRlKGFjcm9zcygtMSwgfmFzLm51bWVyaWMoLikpKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlKGFjcm9zcygtMSwgfnJlcGxhY2VfbmEoLiAsIDApKSkgJT4lDQojIA0KIyAgIGRwbHlyOjptdXRhdGUoDQojICAgICBjb3VudHJ5ID0gZHBseXI6OmNhc2Vfd2hlbigNCiMgICAgICAgZ3JlcGwoIl5CQyIsIHNhbXBsZSkgfiAiU3BhaW5fZGVjMjAyMiIsDQojICAgICAgIGdyZXBsKCJebnJzSSIsIHNhbXBsZSkgfiAiTmV0aGVybGFuZHMiLA0KIyAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8NCiMgICAgICkNCiMgICApJT4lDQojICAgIGphbml0b3I6OmNsZWFuX25hbWVzKCkNCiMgDQojICMgQWRkIHJvd3MNCiMgbWljcm8zIDwtIGJpbmRfcm93cyhtaWNybzIsIG5ld2RhdGEpDQojIA0KIyAjIFRyYW5zbGF0ZQ0KIyANCiMgZW5nIDwtIGMoInNhbXBsZSIsICJmaWJlcnMiLCAiZnJhZ21lbnRzIiwgInNwaGVyZXMiLCAiZmlsbXMiLCAicGVsbGV0cyIsICJzcG9uZ2VzIiwgInJ1YmJlcnMiLCAidHlwZXNfaXRlbXMiLCAiZHJ5X3dlaWdodCIsICJjb3VudHJ5IikNCiMgDQojIA0KIyBtaWNybzQgPC0gbWljcm8zICU+JQ0KIyAgZHBseXI6OnJlbmFtZSgNCiMgICAgIEZpYmVycyA9IGZpYnJhcywNCiMgICAgIEZyYWdtZW50cyA9IGZyYWdtZW50b3MsDQojICAgICBTcGhlcmVzID0gZXNmZXJhcywNCiMgICAgIEZpbG1zID0gZmlsbXMsDQojICAgICBQZWxsZXRzID0gcGVsbGV0cywNCiMgICAgIFNwb25nZXMgPSBlc3BvbmphcywNCiMgICAgIFJ1YmJlcnMgPSBnb21hcywNCiMgICAgIEl0ZW1UeXBlcyA9IHRpcG9zX2l0ZW1zLA0KIyAgICAgRHJ5V2VpZ2h0ID0gcGVzb19zZWNvLA0KIyAgICAgQ291bnRyeSA9IGNvdW50cnkNCiMgICApICU+JQ0KIyAgIGphbml0b3I6OmNsZWFuX25hbWVzKCkgJT4lDQojICAgZHBseXI6Om11dGF0ZSgNCiMgICAgIHNhbXBsZSA9IGFzLmZhY3RvcihzYW1wbGUpLA0KIyAgICAgY291bnRyeSA9IGFzLmZhY3Rvcihjb3VudHJ5KQ0KIyApDQojIA0KIyBzdW1tYXJ5KG1pY3JvNCkNCiMgDQojIHNhdmVSRFMobWljcm80LCBoZXJlOjpoZXJlKCJkYXRhIiwgIm1pY3JvNC5yZHMiKSkNCg0KIyBtaWNybzQgPC1yZWFkUkRTKGhlcmU6OmhlcmUoImRhdGEiLCAibWljcm80LnJkcyIpKQ0KIyANCiMgIyBGaW5kaW5nIGFsbCBkdXBsaWNhdGVkIHJvd3MNCiMgcmVwZWF0ZWRfcm93cyA8LSBtaWNybzQgJT4lDQojICAgZHBseXI6OmZpbHRlcihkdXBsaWNhdGVkKC4pIHwgZHVwbGljYXRlZCguLCBmcm9tTGFzdCA9IFRSVUUpKQ0KIyANCiMgcmVwZWF0ZWRfcm93cw0KIyANCiMgDQojICMgUmVtb3ZlIGR1cGxpY2F0ZSByb3dzLCBrZWVwaW5nIG9ubHkgdGhlIHVuaXF1ZSBvbmVzDQojIG1pY3JvNSA8LSBtaWNybzQgJT4lDQojICAgZGlzdGluY3QoKQ0KIyANCiMgIyBJZGVudGlmeSByZXBlYXRlZCBzYW1wbGUgbmFtZXMgaW4gJ21pY3JvNScNCiMgcmVwZWF0ZWRfc2FtcGxlX25hbWVzIDwtIG1pY3JvNSAlPiUNCiMgICBkcGx5cjo6Z3JvdXBfYnkoc2FtcGxlKSAlPiUNCiMgICBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiMgICBkcGx5cjo6ZmlsdGVyKGNvdW50ID4gMSkgJT4lDQojICAgZHBseXI6OnB1bGwoc2FtcGxlKQ0KIyANCiMgIyBGaWx0ZXIgJ21pY3JvNScgZm9yIHRoZXNlIHJlcGVhdGVkIHNhbXBsZSBuYW1lcyB0byBzaG93IGZ1bGwgcm93cw0KIyBmdWxsX3Jvd3NfcmVwZWF0ZWRfc2FtcGxlcyA8LSBtaWNybzUgJT4lDQojICAgZHBseXI6OmZpbHRlcihzYW1wbGUgJWluJSByZXBlYXRlZF9zYW1wbGVfbmFtZXMpDQojIA0KIyANCiMgZnVsbF9yb3dzX3JlcGVhdGVkX3NhbXBsZXMNCiMgDQojIHdyaXRlX3hsc3gobWljcm81LCBoZXJlOjpoZXJlKCJkYXRhIiwgIm1pY3JvNS54bHN4IikpDQoNCg0KYGBgDQoNCiMjIENoZWNrIGZvciBvdGhlciBlcnJvcnMNCg0KYGBge3J9DQojIHN1bW1hcnkobWljcm81KQ0KIyANCiMgIyBDaGVjayByZXBlYXRlZCB2YWx1ZXMNCiMgIyBNYXggZnJhZ21lbnRzIDYwIGluIG9uZSBzYW1wbGU/DQojICMgTWF4IHdlaWdodCA4MWc/DQojICMgRmFsdGEgR0VPDQojIA0KIyANCiMgIyBCb3hwbG90IGZvciBkcnlfd2VpZ2h0DQojIGdncGxvdChtaWNybzUsIGFlcyh5ID0gZHJ5X3dlaWdodCkpICsNCiMgICBnZW9tX2JveHBsb3QoKQ0KIyANCiMgIyBBbnkgbWlzc2luZyB2YWx1ZXM/DQojIGNvbFN1bXMoaXMubmEobWljcm81KSkNCiMgDQoNCg0KDQoNCg0KYGBgDQoNCg0KDQpNYW51YWwgZWRpdGluZyB0byByYXcyLmNzdiAoZGlyZWN0bHkgaW4gZXhjZWwpDQoNCi0gcmF3Mi5jc3YgY29tZXMgZnJvbSB0b2Rhc2xhc211ZXN0cmFzX3Jldi54bHN4LCBzZW50IGJ5IERhdmlkIERlYyA1dGgNCi0gY29vcmRpbmF0ZXMgcmVvcmRlcmVkIG1hbnVhbGx5IChtYW55IGxhdCBsb24gYXJlIGxvdCBsYW4gb3Igd2hhdGV2ZXIgc3lzdGVtKQ0KLSBBZGRlZCBTLUpUU0sgdG8gQ3plY2ggY29vcmRpbmF0ZXMNCi0gTUE3CVVUTSBFVFJTODkgSFVTTyAzMAk3MjE2NDMJNDQ0OTkwNiAoYSA0IHdhcyBtaXNzaW5nIGluIDQ0OTkwNikNCi0gTUE4CVVUTSBFVFJTODkgSFVTTyAzMAk3MjE4NzAJNDQ0OTkyNiAoYW4gZXh0cmEgMCBpbiA3MjE4MDcwKQ0KLSAyLzcvMjQgQWRkZWQgV0dTIDg0IEhvbGxhbmQgY29vcmRpbmF0ZXMNCi0gMTAvMDcvMjQgQWRkZWQgQXVzdHJpYSBjb29yZGluYXRlcyBmcm9tIEx1a2FzIGVtYWlsIGdyb3NzZXIgYmFjaA0KDQpgYGB7cn0NCg0KcmF3IDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdGEiLCAicmF3Mi5jc3YiKSkNCg0KIyBuZXdkYXRhcmF3IDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdGEiLCAibmV3ZGF0YS5jc3YiKSkgJT4lIA0KIyAgIHNsaWNlKC1uKCkpDQojIA0KIyBpdGFseSA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRhIiwgIml0YWx5LmNzdiIpKQ0KIyBjeiA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRhIiwgImN6LmNzdiIpKQ0KDQpgYGANCg0KIyMgVHJhbnNmb3JtIHZhcmlhYmxlcw0KDQpgYGB7cn0NCnN1bW1hcnkocmF3KQ0KDQpkYXRhIDwtIHJhdyAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVsbGV0cyA9IGFzLm51bWVyaWMocGVsbGV0cyksDQogICAgICAgICAgICAgICAgcnViYmVycyA9IGFzLm51bWVyaWMocnViYmVycyksDQogICAgICAgICAgICAgICAgc2FtcGxlID0gYXMuZmFjdG9yKHNhbXBsZSksDQogICAgICAgICAgICAgICAgY291bnRyeSA9IGFzLmZhY3Rvcihjb3VudHJ5KSwNCiAgICAgICAgICAgICAgICBnZW9fc3lzdGVtID0gYXMuZmFjdG9yKGdlb19zeXN0ZW0pKSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKGZpYmVyczpydWJiZXJzKSwgfnRpZHlyOjpyZXBsYWNlX25hKC4sIDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbXAgPSBmaWJlcnMgKyBmcmFnbWVudHMgKyBzcGhlcmVzICsgZmlsbXMgKyBzcG9uZ2VzLA0KICAgICAgICAgICAgICAgIGNvbmNlbnRyYXRpb24gPSB0b3RhbF9tcCAvIGRyeV93ZWlnaHQpICU+JSANCiAgZHBseXI6Om11dGF0ZShjb3VudHJ5ID0gZHBseXI6OnJlY29kZShjb3VudHJ5LCAiQ3plY2ggUmVwdWJsaWMiID0gIkN6ZWNoaWEiLA0KICAgICAgICAgICAgICAgICJUaGUgTmV0aGVybGFuZHMiID0gIk5ldGhlcmxhbmRzIikpDQoNCg0Kc3VtbWFyeShkYXRhKSAgDQoNCndyaXRlX3hsc3goZGF0YSwgaGVyZTo6aGVyZSgiZGF0YSIsICJkYXRhX2NsZWFuLnhsc3giKSkNCndyaXRlX2NzdihkYXRhLCBoZXJlOjpoZXJlKCJkYXRhIiwgImRhdGFfY2xlYW4uY3N2IikpDQoNCmBgYA0KICANCiMjIEhvbW9nZW5pemFyIENSU3MNCg0KSGVyZSB3ZSBmaWx0ZXIgdGhlIGRhdGEgZm9yIHdoaWNoIHdlIGhhdmUgY29vcmRpbmF0ZXMgYW5kIHRyYW5zZm9ybSBhbGwgb2YgdGhlbSB0byBXR1M4NA0KMTYvMTAvMjQgLSA0IGZyb20gU3BhaW4gYW5kIDUgZnJvbSBDWiBhcmUgbWlzc2luZy4NCg0KYGBge3J9DQoNCiMgRGVmaW5lIGEgbWFwcGluZyBvZiBnZW9fc3lzdGVtIHZhbHVlcyB0byBFUFNHIGNvZGVzDQpnZW9fc3lzdGVtX21hcHBpbmcgPC0gdGliYmxlOjp0aWJibGUoDQogIGdlb19zeXN0ZW0gPSBjKCJVVE0gRVRSUzg5IEhVU08gMjkiLCAiVVRNIEVUUlM4OSBIVVNPIDMwIiwgIlMtSlRTSyIsICJXR1M4NCIpLA0KICBlcHNnID0gYygyNTgyOSwgMjU4MzAsIDU1MTQsIDQzMjYpDQopDQoNCiMgRnVuY3Rpb24gdG8gdHJhbnNmb3JtIGNvb3JkaW5hdGVzDQp0cmFuc2Zvcm1fY29vcmRzIDwtIGZ1bmN0aW9uKGRmLCBvcmlnaW5hbF9jcnMpIHsNCiAgIyBTa2lwIGlmIHRoZSBzdWJzZXQgaXMgZW1wdHkgb3IgQ1JTIGlzIG5vdCBkZWZpbmVkDQogIGlmIChucm93KGRmKSA9PSAwIHx8IGlzLm5hKG9yaWdpbmFsX2NycykpIHsNCiAgICByZXR1cm4oZGYpDQogIH0NCiAgDQogICMgQ3JlYXRlIHNmIG9iamVjdCBhbmQgdHJhbnNmb3JtIGNvb3JkaW5hdGVzDQogIGRmX3NmIDwtIHNmOjpzdF9hc19zZihkZiwgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnMgPSBvcmlnaW5hbF9jcnMsIHJlbW92ZSA9IEZBTFNFKQ0KICBkZl9zZl90cmFuc2Zvcm1lZCA8LSBzZjo6c3RfdHJhbnNmb3JtKGRmX3NmLCBjcnMgPSA0MzI2KQ0KICByZXR1cm4oY2JpbmQoZGYsIHNmOjpzdF9jb29yZGluYXRlcyhkZl9zZl90cmFuc2Zvcm1lZClbLCAxOjJdKSkNCn0NCg0KIyBUcmFuc2Zvcm0gYWxsIGNvb3JkaW5hdGVzIHRvIFdHUyA4NA0KZGF0YV93Z3M4NCA8LSBkYXRhICU+JQ0KICBkcGx5cjo6bXV0YXRlKGdlb19zeXN0ZW0gPSBkcGx5cjo6cmVjb2RlKGdlb19zeXN0ZW0sIGBXR1M4NCwgR29vZ2xlIE1hcGAgPSAiV0dTODQiKSkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoZ2VvX3N5c3RlbSAhPSAiTm90IGF2YWlsYWJsZSIsICFpcy5uYShsb24pLCAhaXMubmEobGF0KSkgJT4lDQogIGRwbHlyOjpsZWZ0X2pvaW4oZ2VvX3N5c3RlbV9tYXBwaW5nLCBieSA9ICJnZW9fc3lzdGVtIikgJT4lDQogIGRwbHlyOjpncm91cF9ieShnZW9fc3lzdGVtKSAlPiUNCiAgZHBseXI6Omdyb3VwX21vZGlmeSh+IHRyYW5zZm9ybV9jb29yZHMoLngsIHVuaXF1ZSgueCRlcHNnKVsxXSkpICU+JQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKGVwc2csIGdlb19zeXN0ZW0sbGF0LGxvbikpDQoNCiMgQ2hlY2sgdGhlIHJlc3VsdHMNCmhlYWQoZGF0YV93Z3M4NCkNCnN1bW1hcnkoZGF0YV93Z3M4NCkNCg0Kd3JpdGVfeGxzeChkYXRhX3dnczg0LCBoZXJlOjpoZXJlKCJkYXRhIiwgImRhdGFfd2dzODQueGxzeCIpKQ0KDQoNCmBgYA0KDQoNCiMgQW5hbHlzZXMNCg0KDQoNCiMjIE1hcCByZXN1bHRzDQoNCg0KDQpMb29rcyBsaWtlIGZvciBJdGFseSB3ZSBoYXZlIGp1c3QgdGhyZWUgcm91Z2ggYXJlYXMgZm9yIGFsbCB0aGUgMzkgc2FtcGxlcy4NCg0KYGBge3J9DQojIENyZWF0ZSBhIGxlYWZsZXQgbWFwDQptYXAgPC0gbGVhZmxldChkYXRhX3dnczg0KSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUgICMgQWRkIGRlZmF1bHQgT3BlblN0cmVldE1hcCBtYXAgdGlsZXMNCiAgYWRkTWFya2VycyhsbmcgPSB+WCwgbGF0ID0gflksIHBvcHVwID0gfmFzLmNoYXJhY3RlcihzYW1wbGUpKQ0KDQojIFNob3cgdGhlIG1hcA0KbWFwDQoNCiMgIyBJbiBJdGFseSB3ZSBoYXZlIG5vIHN0cmVhbXMsIGp1c3QgMyBhcmVhcw0KIyANCiMgaXRhbHlfdGVtcCA8LSBkYXRhX3dnczg0ICU+JSANCiMgICBkcGx5cjo6ZmlsdGVyKGNvdW50cnkgPT0gIkl0YWx5IikNCiMgDQojIA0KIyAjIENyZWF0ZSBhIGxlYWZsZXQgbWFwDQojIG1hcDIgPC0gbGVhZmxldChpdGFseV90ZW1wKSAlPiUNCiMgICBhZGRUaWxlcygpICU+JSAgIyBBZGQgZGVmYXVsdCBPcGVuU3RyZWV0TWFwIG1hcCB0aWxlcw0KIyAgIGFkZE1hcmtlcnMobG5nID0gflgsIGxhdCA9IH5ZLCBwb3B1cCA9IH5hcy5jaGFyYWN0ZXIoc2FtcGxlKSkNCiMgDQojICMgU2hvdyB0aGUgbWFwDQojIG1hcDINCg0KDQpgYGANCg0KIyMjIE1hcCBmaWd1cmUNCkZpZy4gMSAtIExvY2F0aW9uIG9mIHNhbXBsaW5nIHNpdGVzIGluIEF1c3RyaWEsIEN6ZWNoaWEsIEl0YWx5LCB0aGUgTmV0aGVybGFuZHMgYW5kIFNwYWluLg0KDQpgYGB7cn0NCg0KIyBHZXQgd29ybGQgbWFwIGRhdGENCndvcmxkIDwtIHJuYXR1cmFsZWFydGg6Om5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCiMgIyBFbnN1cmUgdGhlIGNvdW50cnkgbmFtZXMgaW4geW91ciBkYXRhIG1hdGNoIHRob3NlIGluIHRoZSB3b3JsZCBtYXAgZGF0YQ0KIyBkYXRhX3dnczg0JGNvdW50cnkgPC0gZHBseXI6OnJlY29kZShkYXRhX3dnczg0JGNvdW50cnksIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3plY2ggUmVwdWJsaWMiID0gIkN6ZWNoaWEiLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGhlIE5ldGhlcmxhbmRzIiA9ICJOZXRoZXJsYW5kcyIpDQoNCiMgRGVmaW5lIHRoZSBjb3VudHJpZXMgd2l0aCBzYW1wbGVzDQpjb3VudHJpZXNfd2l0aF9zYW1wbGVzIDwtIHVuaXF1ZShkYXRhX3dnczg0JGNvdW50cnkpDQoNCiMgQ3JlYXRlIHRoZSBtYWluIG1hcA0KbWFpbl9tYXAgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSB3b3JsZCwgZmlsbCA9ICJncmF5OTAiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV9zZihkYXRhID0gd29ybGRbd29ybGQkbmFtZSAlaW4lIGNvdW50cmllc193aXRoX3NhbXBsZXMsXSwgYWVzKGZpbGwgPSBuYW1lKSwgY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGRhdGFfd2dzODQsIGFlcyh4ID0gWCwgeSA9IFkpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNykgKw0KICBjb29yZF9zZih4bGltID0gYygtMTAsIDMwKSwgeWxpbSA9IGMoMzUsIDU1KSwgZXhwYW5kID0gRkFMU0UpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKw0KICB0aGVtZV92b2lkKCkgKyAgIyBSZW1vdmVzIGF4aXMgbGluZXMsIHRpY2tzLCBhbmQgbGFiZWxzDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5OTgiKSwNCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkgIyArDQogICNsYWJzKHRpdGxlID0gIk1pY3JvcGxhc3RpYyBTYW1wbGluZyBTaXRlcyBpbiBFdXJvcGUiKQ0KDQojIFByaW50IHRoZSBtYXANCnByaW50KG1haW5fbWFwKQ0KDQojIENyZWF0ZSBhbiBpbnNldCBtYXAgb2YgRXVyb3BlDQojIGluc2V0X21hcCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoKSArDQojICAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gd29ybGQsIGZpbGwgPSAiZ3JheTkwIiwgY29sb3IgPSAid2hpdGUiKSArDQojICAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gd29ybGRbd29ybGQkbmFtZSAlaW4lIGNvdW50cmllc193aXRoX3NhbXBsZXMsXSwgDQojICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjphZXMoZmlsbCA9IG5hbWUpLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiMgICBnZ3Bsb3QyOjpjb29yZF9zZih4bGltID0gYygtMjUsIDQwKSwgeWxpbSA9IGMoMzUsIDcwKSwgZXhwYW5kID0gRkFMU0UpICsNCiMgICBnZ3Bsb3QyOjp0aGVtZV92b2lkKCkgKw0KIyAgIGdncGxvdDI6OnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KIyBDb21iaW5lIHRoZSBtYWluIG1hcCBhbmQgaW5zZXQgbWFwDQojIGZpbmFsX21hcCA8LSBjb3dwbG90OjpnZ2RyYXcoKSArDQojICAgY293cGxvdDo6ZHJhd19wbG90KG1haW5fbWFwKSArDQojICAgY293cGxvdDo6ZHJhd19wbG90KGluc2V0X21hcCwgeCA9IDAuNjUsIHkgPSAwLjY1LCB3aWR0aCA9IDAuMywgaGVpZ2h0ID0gMC4zKQ0KDQojICMgRGlzcGxheSB0aGUgbWFwDQojIHByaW50KGZpbmFsX21hcCkNCiMgDQojICMgU2F2ZSB0aGUgbWFwDQojIGdncGxvdDI6Omdnc2F2ZSgiZXVyb3BlX21pY3JvcGxhc3RpY19zYW1wbGluZ19tYXAucG5nIiwgZmluYWxfbWFwLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQ0KDQoNCg0KYGBgDQoNCiMjIyBIZWF0bWFwIG1pY3JvcGxhc3RpY3MgaW4gQ1oNCkV4cGxvcmF0aW9uOiBIb3cgZG8gbWljcm9wbGFzdGljcyB2YXJ5IGFjcm9zcyB0aGUgbGFuZCBpbiBDWj8NCg0KYGBge3J9DQoNCiMgRmlsdGVyIGRhdGEgZm9yIEN6ZWNoaWENCmN6X2RhdGEgPC0gZGF0YV93Z3M4NCAlPiUNCiAgZHBseXI6OmZpbHRlcihjb3VudHJ5ID09ICJDemVjaGlhIikgJT4lDQogICAgZHBseXI6Om11dGF0ZSh0b3RhbF9taWNyb3BsYXN0aWNzID0gZmliZXJzICsgZnJhZ21lbnRzICsgc3BoZXJlcyArIGZpbG1zICsgcGVsbGV0cyArIHNwb25nZXMgKyBydWJiZXJzKSAlPiUNCiAgICBkcGx5cjo6bXV0YXRlKGRlbnNpdHkgPSBhcy5udW1lcmljKGBkZW5zaXR5IChpdGVtcy9kcnlfd2VpZ2h0KWApKSAlPiUNCiAgICBzZjo6c3RfYXNfc2YoY29vcmRzID0gYygiWCIsICJZIiksIGNycyA9IDQzMjYpDQoNCg0KDQojIEdldCB0aGUgcml2ZXJzIGRhdGEgZm9yIHRoZSBDemVjaCBSZXB1YmxpYw0KY3pfcml2ZXJzIDwtIFJDemVjaGlhOjpyZWt5KCkNCg0KDQojIEhlYXRtYXAgIEN6ZWNoaWENCg0Kcml2ZXJzX2N6IDwtIGdncGxvdDI6OmdncGxvdChjel9kYXRhKSArDQogIGdncGxvdDI6Omdlb21fc2YoZGF0YSA9IGN6X3JpdmVycywgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArICAjIEFkZCByaXZlcnMgbGF5ZXINCiAgZ2dwbG90Mjo6Z2VvbV9zZihnZ3Bsb3QyOjphZXMoc2l6ZSA9IHRvdGFsX21pY3JvcGxhc3RpY3MsIGNvbG9yID0gZGVuc2l0eSksIGFscGhhID0gMC43KSArDQogIGdncGxvdDI6OnNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhvcHRpb24gPSAibWFnbWEiLCBuYW1lID0gIkRlbnNpdHkiKSArICAjIENvbG9yIHJlcHJlc2VudHMgZGVuc2l0eQ0KICBnZ3Bsb3QyOjpzY2FsZV9zaXplX2NvbnRpbnVvdXMobmFtZSA9ICJUb3RhbCBJdGVtcyIpICsgICMgU2l6ZSByZXByZXNlbnRzIHRvdGFsIG51bWJlciBvZiBtaWNyb3BsYXN0aWNzDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIE1pY3JvcGxhc3RpY3MgaW4gT3R0ZXIgU3ByYWludHMgKEN6ZWNoaWEpIikNCg0KDQoNCiMgU2F2ZSB0aGUgcGxvdA0KZ2dwbG90Mjo6Z2dzYXZlKGhlcmU6OmhlcmUoIm91dHB1dCIsICJyaXZlcnNfY3oucG5nIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KYGBgDQoNCiMjIyBJbnRlcmFjdGl2ZSBoZWF0bWFwDQpUaGVyZSBoYXMgdG8gYmUgYW4gZWZmZWN0IG9mIHNhbXBsaW5nLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgY29sb3IgcGFsZXR0ZSBmdW5jdGlvbg0KcGFsIDwtIGxlYWZsZXQ6OmNvbG9yTnVtZXJpYygNCiAgcGFsZXR0ZSA9IHZpcmlkaXM6OnZpcmlkaXMoMjU2KSwgICMgVXNlIHRoZSB2aXJpZGlzIGNvbG9yIHNjYWxlDQogIGRvbWFpbiA9IGN6X2RhdGEkdG90YWxfbWljcm9wbGFzdGljcyAgIyBUaGUgZG9tYWluIGlzIHRoZSByYW5nZSBvZiBtaWNyb3BsYXN0aWNzDQopDQoNCiMgQ3JlYXRlIGFuIGludGVyYWN0aXZlIG1hcCB3aXRoIGxlYWZsZXQNCmN6X21hcCA8LSBjel9kYXRhICU+JQ0KICBsZWFmbGV0OjpsZWFmbGV0KCkgJT4lDQogIGxlYWZsZXQ6OmFkZFRpbGVzKCkgJT4lICAjIEFkZCBkZWZhdWx0IE9wZW5TdHJlZXRNYXAgdGlsZXMNCiAgbGVhZmxldDo6YWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5Xb3JsZFRvcG9NYXApICU+JSAgIyBBZGQgYSB0b3BvZ3JhcGhpYyBiYXNlbWFwIHdpdGggcml2ZXJzIGFuZCBwb25kcw0KICBsZWFmbGV0OjphZGRDaXJjbGVNYXJrZXJzKA0KICAgIHJhZGl1cyA9IH5zcXJ0KHRvdGFsX21pY3JvcGxhc3RpY3MpICogMywgICMgTWFya2VyIHNpemUgcHJvcG9ydGlvbmFsIHRvIG1pY3JvcGxhc3RpY3MNCiAgICBjb2xvciA9IH5wYWwodG90YWxfbWljcm9wbGFzdGljcyksICAjIFVzZSB0aGUgY29sb3IgcGFsZXR0ZSBmb3IgdGhlIG1hcmtlciBjb2xvcg0KICAgIGZpbGxPcGFjaXR5ID0gMC44LA0KICAgIGxhYmVsID0gfnBhc3RlKCJNaWNyb3BsYXN0aWNzOiIsIHRvdGFsX21pY3JvcGxhc3RpY3MpLA0KICAgIHBvcHVwID0gfnBhc3RlKCJTYW1wbGUgSUQ6Iiwgc2FtcGxlLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIkZpYmVyczoiLCBmaWJlcnMsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiRnJhZ21lbnRzOiIsIGZyYWdtZW50cywgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJTcGhlcmVzOiIsIHNwaGVyZXMsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiRmlsbXM6IiwgZmlsbXMpDQogICkgJT4lDQogIGxlYWZsZXQ6OmFkZExlZ2VuZCgNCiAgICAiYm90dG9tcmlnaHQiLA0KICAgIHBhbCA9IHBhbCwNCiAgICB2YWx1ZXMgPSBjel9kYXRhJHRvdGFsX21pY3JvcGxhc3RpY3MsDQogICAgdGl0bGUgPSAiTWljcm9wbGFzdGljcyIsDQogICAgb3BhY2l0eSA9IDENCiAgKQ0KDQoNCmN6X21hcA0KDQpgYGANCg0KDQoNCg0KDQoNCiMjIFN1bW1hcnkgVGFibGUNCg0KSW5mb3JtYXRpb24gZm9yIG1pY3JvcGxhc3RpY3MgcmVjb3ZlcmVkIGZyb20gc3ByYWludHMgY29sbGVjdGVkIGluIGVhY2ggY291bnRyeSwgaW5jbHVkaW5nIG51bWJlciBvZiBzYW1wbGVzLCBhYnVuZGFuY2UsIHR5cGUgb2YgbWljcm9wbGFzdGljLCBkcnkgd2VpZ2h0IG9mIGVhY2ggc2FtcGxlIGFuZCBhdmVyYWdlIGRlbnNpdHkuDQoNCmBgYHtyfQ0KDQoNCiMgU3VtbWFyaXNlIG92ZXJhbGwgZGF0YQ0KZGF0YV9zdW1tYXJ5IDwtIGRwbHlyOjpzdW1tYXJpc2UoDQogIGRhdGEsDQogIGBTYW1wbGVzIChuKWAgPSBkcGx5cjo6bigpLA0KICBBYnVuZGFuY2UgPSBzdW0oZmliZXJzICsgZnJhZ21lbnRzICsgc3BoZXJlcyArIGZpbG1zICsgcGVsbGV0cyArIHNwb25nZXMgKyBydWJiZXJzKSwNCiAgU0UgPSByb3VuZChzZChmaWJlcnMgKyBmcmFnbWVudHMgKyBzcGhlcmVzICsgZmlsbXMgKyBwZWxsZXRzICsgc3BvbmdlcyArIHJ1YmJlcnMpIC8gc3FydChkcGx5cjo6bigpKSwgMiksDQogIGRwbHlyOjphY3Jvc3MoYyhmaWJlcnMsIGZyYWdtZW50cywgc3BoZXJlcywgZmlsbXMsIHBlbGxldHMsIHNwb25nZXMsIHJ1YmJlcnMsIGRyeV93ZWlnaHQpLCBzdW0sIC5uYW1lcyA9ICJzdW1fe2NvbH0iKSwNCiAgYEF2ZXJhZ2UgRGVuc2l0eWAgPSByb3VuZChtZWFuKGBkZW5zaXR5IChpdGVtcy9kcnlfd2VpZ2h0KWApLCAyKQ0KKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qod2hlcmUofnN1bSguKSAhPSAwKSkNCg0KIyBSZW5hbWUgY29sdW1ucyBmb3IgVGFibGUxDQpkYXRhX3RhYmxlMSA8LSBkcGx5cjo6cmVuYW1lKA0KICBkYXRhX3N1bW1hcnksDQogIEZpYmVycyA9IHN1bV9maWJlcnMsDQogIEZyYWdtZW50cyA9IHN1bV9mcmFnbWVudHMsDQogIFNwaGVyZXMgPSBzdW1fc3BoZXJlcywNCiAgRmlsbXMgPSBzdW1fZmlsbXMsDQogIFNwb25nZXMgPSBzdW1fc3BvbmdlcywNCiAgYERyeSBXZWlnaHQgKGcpYCA9IHN1bV9kcnlfd2VpZ2h0DQopDQoNCiMgU3VtbWFyaXNlIGJ5IGNvdW50cnkNCmRhdGFfc3VtbWFyeTIgPC0gZHBseXI6Omdyb3VwX2J5KGRhdGEsIGNvdW50cnkpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIGBTYW1wbGVzIChuKWAgPSBkcGx5cjo6bigpLA0KICAgIEFidW5kYW5jZSA9IHN1bShmaWJlcnMgKyBmcmFnbWVudHMgKyBzcGhlcmVzICsgZmlsbXMgKyBwZWxsZXRzICsgc3BvbmdlcyArIHJ1YmJlcnMpLA0KICAgIFNFID0gcm91bmQoc2QoZmliZXJzICsgZnJhZ21lbnRzICsgc3BoZXJlcyArIGZpbG1zICsgcGVsbGV0cyArIHNwb25nZXMgKyBydWJiZXJzKSAvIHNxcnQoZHBseXI6Om4oKSksIDIpLA0KICAgIGRwbHlyOjphY3Jvc3MoYyhmaWJlcnMsIGZyYWdtZW50cywgc3BoZXJlcywgZmlsbXMsIHBlbGxldHMsIHNwb25nZXMsIHJ1YmJlcnMsIGRyeV93ZWlnaHQpLCBzdW0sIC5uYW1lcyA9ICJzdW1fe2NvbH0iKSwNCiAgICBgQXZlcmFnZSBEZW5zaXR5YCA9IHJvdW5kKG1lYW4oYGRlbnNpdHkgKGl0ZW1zL2RyeV93ZWlnaHQpYCksIDIpDQogICkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJzdW1fcGVsbGV0cyIpLCAtc3RhcnRzX3dpdGgoInN1bV9ydWJiZXJzIikpDQoNCiMgUmVuYW1lIGNvbHVtbnMgZm9yIFRhYmxlMg0KZGF0YV90YWJsZTIgPC0gZHBseXI6OnJlbmFtZSgNCiAgZGF0YV9zdW1tYXJ5MiwNCiAgQ291bnRyeSA9IGNvdW50cnksDQogIEZpYmVycyA9IHN1bV9maWJlcnMsDQogIEZyYWdtZW50cyA9IHN1bV9mcmFnbWVudHMsDQogIFNwaGVyZXMgPSBzdW1fc3BoZXJlcywNCiAgRmlsbXMgPSBzdW1fZmlsbXMsDQogIFNwb25nZXMgPSBzdW1fc3BvbmdlcywNCiAgYERyeSBXZWlnaHQgKGcpYCA9IHN1bV9kcnlfd2VpZ2h0DQopDQoNCiMgQ29tYmluZSBib3RoIHRhYmxlcw0KY29tYmluZWRfdGFibGUgPC0gZHBseXI6OmJpbmRfcm93cyhkYXRhX3RhYmxlMiwgZHBseXI6Om11dGF0ZShkYXRhX3RhYmxlMSwgQ291bnRyeSA9ICJUb3RhbCIpKQ0KDQojIERpc3BsYXkgdGhlIHRhYmxlDQpjb21iaW5lZF90YWJsZSAlPiUNCiAga2FibGVFeHRyYTo6a2JsKCkgJT4lIA0KICBrYWJsZUV4dHJhOjprYWJsZV9wYXBlcigic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBGKSAlPiUNCiAga2FibGVFeHRyYTo6cm93X3NwZWMobnJvdyhjb21iaW5lZF90YWJsZSksIGJvbGQgPSBUUlVFKQ0KDQpgYGANCg0KIyMjIFRhYmxlIDEgd29yZA0KYGBge3J9DQoNCg0KIyBGb3JtYXQgdGhlIHRhYmxlDQpmb3JtYXR0ZWRfdGFibGUgPC0gY29tYmluZWRfdGFibGUgJT4lDQogIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC4sIDIpKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoYEF2ZXJhZ2UgRGVuc2l0eWAgPSBzcHJpbnRmKCIlLjJmIiwgYEF2ZXJhZ2UgRGVuc2l0eWApKQ0KDQojIENyZWF0ZSB0aGUgZmxleHRhYmxlDQpmdCA8LSBmbGV4dGFibGU6OmZsZXh0YWJsZShmb3JtYXR0ZWRfdGFibGUpICU+JQ0KICBmbGV4dGFibGU6OnRoZW1lX2Jvb2t0YWJzKCkgJT4lDQogIGZsZXh0YWJsZTo6YXV0b2ZpdCgpICU+JQ0KICBmbGV4dGFibGU6OmFsaWduKGFsaWduID0gImNlbnRlciIsIHBhcnQgPSAiYWxsIikgJT4lDQogIGZsZXh0YWJsZTo6YWxpZ24oaiA9IDEsIGFsaWduID0gImxlZnQiLCBwYXJ0ID0gImFsbCIpICU+JQ0KICBmbGV4dGFibGU6OmJvbGQocGFydCA9ICJoZWFkZXIiKSAlPiUNCiAgZmxleHRhYmxlOjpib2xkKGkgPSBucm93KGZvcm1hdHRlZF90YWJsZSksIHBhcnQgPSAiYm9keSIpICU+JQ0KICBmbGV4dGFibGU6OnNldF9oZWFkZXJfbGFiZWxzKA0KICAgIENvdW50cnkgPSAiQ291bnRyeSIsDQogICAgYFNhbXBsZXMgKG4pYCA9ICJTYW1wbGVzIChuKSIsDQogICAgQWJ1bmRhbmNlID0gIkFidW5kYW5jZSIsDQogICAgU0UgPSAiU0UiLA0KICAgIEZpYmVycyA9ICJGaWJlcnMiLA0KICAgIEZyYWdtZW50cyA9ICJGcmFnbWVudHMiLA0KICAgIFNwaGVyZXMgPSAiU3BoZXJlcyIsDQogICAgRmlsbXMgPSAiRmlsbXMiLA0KICAgIFNwb25nZXMgPSAiU3BvbmdlcyIsDQogICAgYERyeSBXZWlnaHQgKGcpYCA9ICJEcnkgV2VpZ2h0IChnKSIsDQogICAgYEF2ZXJhZ2UgRGVuc2l0eWAgPSAiQXZlcmFnZSBEZW5zaXR5Ig0KICApICU+JQ0KICBmbGV4dGFibGU6OmFkZF9mb290ZXJfbGluZXMoDQogICAgIlRhYmxlIDE6IFN1bW1hcnkgb2YgbWljcm9wbGFzdGljIG9jY3VycmVuY2VzIGluIEV1cmFzaWFuIG90dGVyIChMdXRyYSBsdXRyYSkgc3ByYWludHMgYWNyb3NzIGRpZmZlcmVudCBFdXJvcGVhbiBjb3VudHJpZXMuIFRoZSB0YWJsZSBzaG93cyB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgYW5hbHl6ZWQsIHRvdGFsIGFidW5kYW5jZSBvZiBtaWNyb3BsYXN0aWNzLCBzdGFuZGFyZCBlcnJvciAoU0UpLCBjb3VudHMgb2YgZGlmZmVyZW50IG1pY3JvcGxhc3RpYyB0eXBlcyAoZmliZXJzLCBmcmFnbWVudHMsIHNwaGVyZXMsIGZpbG1zLCBzcG9uZ2VzKSwgdG90YWwgZHJ5IHdlaWdodCBvZiBhbGwgc2FtcGxlcyBwZXIgY291bnRyeSwgYW5kIGF2ZXJhZ2UgZGVuc2l0eSBvZiBtaWNyb3BsYXN0aWNzIHBlciBncmFtIG9mIGRyeSB3ZWlnaHQgZm9yIGVhY2ggY291bnRyeSBhbmQgb3ZlcmFsbC4iDQogICkgJT4lDQogIGZsZXh0YWJsZTo6Zm9udHNpemUoc2l6ZSA9IDgsIHBhcnQgPSAiYWxsIikgJT4lDQogIGZsZXh0YWJsZTo6cGFkZGluZyhwYWRkaW5nID0gMiwgcGFydCA9ICJhbGwiKSAlPiUNCiAgZmxleHRhYmxlOjpib3JkZXIoYm9yZGVyID0gb2ZmaWNlcjo6ZnBfYm9yZGVyKGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSAxKSwgcGFydCA9ICJhbGwiKQ0KDQojIFNldCBwYWdlIGxheW91dCB0byBtYXRjaCBTVE9URU4gZ3VpZGVsaW5lcyAoYXNzdW1pbmcgQTQgcGFnZSBzaXplKQ0KZnQgPC0gZmxleHRhYmxlOjpzZXRfdGFibGVfcHJvcGVydGllcygNCiAgZnQsDQogIGxheW91dCA9ICJhdXRvZml0IiwNCiAgICAgd2lkdGggPSAxICAjIFdpZHRoIGluIGluY2hlcywgYWRqdXN0IGFzIG5lZWRlZA0KKQ0KDQojIFNhdmUgdGhlIHRhYmxlIGFzIGEgV29yZCBkb2N1bWVudCBpbiB0aGUgb3V0cHV0IGZvbGRlcg0KZmxleHRhYmxlOjpzYXZlX2FzX2RvY3goZnQsIHBhdGggPSBoZXJlOjpoZXJlKCJvdXRwdXQiLCAidGFibGUxX21pY3JvcGxhc3RpY3Nfc3VtbWFyeS5kb2N4IikpDQoNCg0KZnQNCg0KYGBgDQoNCg0KDQojIyBQcmVzZW5jZS9BYnNlbmNlDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgcHJlc2VuY2UvYWJzZW5jZSBhbmQgcGVyY2VudGFnZSBvZiBzcHJhaW50cyB3aXRoIG1pY3JvcGxhc3RpY3MNCnByZXNlbmNlX2Fic2VuY2UgPC0gZGF0YSAlPiUNCiAgZHBseXI6Om11dGF0ZShoYXNfbXAgPSBkcGx5cjo6aWZfZWxzZShmaWJlcnMgKyBmcmFnbWVudHMgKyBzcGhlcmVzICsgZmlsbXMgKyBzcG9uZ2VzID4gMCwgMSwgMCkpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIHRvdGFsX3NhbXBsZXMgPSBkcGx5cjo6bigpLA0KICAgIHNhbXBsZXNfd2l0aF9tcCA9IHN1bShoYXNfbXApLA0KICAgIHBlcmNlbnRhZ2Vfd2l0aF9tcCA9IG1lYW4oaGFzX21wKSAqIDEwMA0KICApDQoNCiMgQ2FsY3VsYXRlIGFidW5kYW5jZSAoTVBzL3NwcmFpbnQpDQphYnVuZGFuY2Vfc3RhdHMgPC0gZGF0YSAlPiUNCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tcCA9IGZpYmVycyArIGZyYWdtZW50cyArIHNwaGVyZXMgKyBmaWxtcyArIHNwb25nZXMpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIG1lYW5fYWJ1bmRhbmNlID0gbWVhbih0b3RhbF9tcCksDQogICAgc2VfYWJ1bmRhbmNlID0gc3RhdHM6OnNkKHRvdGFsX21wKSAvIHNxcnQoZHBseXI6Om4oKSkNCiAgKQ0KDQojIENhbGN1bGF0ZSBjb25jZW50cmF0aW9uIChNUHMvZyBkcnkgd2VpZ2h0KQ0KY29uY2VudHJhdGlvbl9zdGF0cyA8LSBkYXRhICU+JQ0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21wID0gZmliZXJzICsgZnJhZ21lbnRzICsgc3BoZXJlcyArIGZpbG1zICsgc3BvbmdlcywNCiAgICAgICAgIGNvbmNlbnRyYXRpb24gPSB0b3RhbF9tcCAvIGRyeV93ZWlnaHQpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIG1lYW5fY29uY2VudHJhdGlvbiA9IG1lYW4oY29uY2VudHJhdGlvbiksDQogICAgc2VfY29uY2VudHJhdGlvbiA9IHN0YXRzOjpzZChjb25jZW50cmF0aW9uKSAvIHNxcnQoZHBseXI6Om4oKSkNCiAgKQ0KDQojIENhbGN1bGF0ZSBwcm9wb3J0aW9ucyBvZiBwYXJ0aWNsZSB0eXBlcw0KcGFydGljbGVfcHJvcG9ydGlvbnMgPC0gZGF0YSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZShkcGx5cjo6YWNyb3NzKGMoZmliZXJzLCBmcmFnbWVudHMsIHNwaGVyZXMsIGZpbG1zLCBzcG9uZ2VzKSwgc3VtKSkgJT4lDQogIHRpZHlyOjpwaXZvdF9sb25nZXIoZHBseXI6OmV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAicGFydGljbGVfdHlwZSIsIHZhbHVlc190byA9ICJjb3VudCIpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHByb3BvcnRpb24gPSBjb3VudCAvIHN1bShjb3VudCkgKiAxMDApICU+JQ0KICBkcGx5cjo6YXJyYW5nZShkcGx5cjo6ZGVzYyhwcm9wb3J0aW9uKSkNCg0KDQoNCiMgUGFyYWdyYXBoIGZvciByZXN1bHRzDQpyZXBvcnRfdGV4dCA8LSBwYXN0ZSgNCiAgIldlIGZvdW5kIG1pY3JvcGxhc3RpY3MgaW4iLCByb3VuZChwcmVzZW5jZV9hYnNlbmNlJHBlcmNlbnRhZ2Vfd2l0aF9tcCwgMSksICIlIG9mIHNwcmFpbnRzLCBhdCBhIG1lYW4gYWJ1bmRhbmNlIG9mIiwgcm91bmQoYWJ1bmRhbmNlX3N0YXRzJG1lYW5fYWJ1bmRhbmNlLCAxKSwgIsKxIiwgcm91bmQoYWJ1bmRhbmNlX3N0YXRzJHNlX2FidW5kYW5jZSwgMSksDQogICJtaWNyb3BsYXN0aWNzIChNUHMpL3NwcmFpbnQgKG1lYW4gwrEgU0UpLGFuZCBhIG1lYW4gY29uY2VudHJhdGlvbiBvZiIsIHJvdW5kKGNvbmNlbnRyYXRpb25fc3RhdHMkbWVhbl9jb25jZW50cmF0aW9uLCAxKSwgIsKxIiwgcm91bmQoY29uY2VudHJhdGlvbl9zdGF0cyRzZV9jb25jZW50cmF0aW9uLCAxKSwNCiAgIk1Qcy9nIChkcnkgd2VpZ2h0KS5cblxuIikNCg0KDQojIFByaW50IG9yIHdyaXRlIHRoZSByZXBvcnQgdGV4dCB0byBhIGZpbGUNCmNhdChyZXBvcnRfdGV4dCkNCg0KYGBgDQoNCg0KIyMgQ2hlY2tpbmcgbm9ybWFsaXR5DQoNCmBgYHtyfQ0KDQoNCiMgVmlzdWFsIGluc3BlY3Rpb24gdXNpbmcgUS1RIHBsb3QNCmdncGxvdDI6OmdncGxvdChkYXRhLCBhZXMoc2FtcGxlID0gY29uY2VudHJhdGlvbikpICsNCiAgc3RhdF9xcSgpICsNCiAgc3RhdF9xcV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIlEtUSBQbG90IG9mIE1pY3JvcGxhc3RpYyBDb25jZW50cmF0aW9ucyIsDQogICAgICAgeCA9ICJUaGVvcmV0aWNhbCBRdWFudGlsZXMiLCANCiAgICAgICB5ID0gIlNhbXBsZSBRdWFudGlsZXMiKQ0KDQojIFNoYXBpcm8tV2lsayB0ZXN0IGZvciBub3JtYWxpdHkNCnNoYXBpcm9fdGVzdCA8LSBzdGF0czo6c2hhcGlyby50ZXN0KGRhdGEkY29uY2VudHJhdGlvbikNCnByaW50KHNoYXBpcm9fdGVzdCkNCg0KIyBBdHRlbXB0IGxvZyB0cmFuc2Zvcm1hdGlvbg0KZGF0YSA8LSBkYXRhICU+JQ0KICBkcGx5cjo6bXV0YXRlKGxvZ19jb25jZW50cmF0aW9uID0gbG9nKGNvbmNlbnRyYXRpb24pKQ0KDQojIFEtUSBwbG90IGZvciBsb2ctdHJhbnNmb3JtZWQgZGF0YQ0KZ2dwbG90Mjo6Z2dwbG90KGRhdGEsIGFlcyhzYW1wbGUgPSBsb2dfY29uY2VudHJhdGlvbikpICsNCiAgc3RhdF9xcSgpICsNCiAgc3RhdF9xcV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIlEtUSBQbG90IG9mIExvZy1UcmFuc2Zvcm1lZCBNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbnMiLA0KICAgICAgIHggPSAiVGhlb3JldGljYWwgUXVhbnRpbGVzIiwgDQogICAgICAgeSA9ICJTYW1wbGUgUXVhbnRpbGVzIikNCg0KDQoNCmBgYA0KDQoNCiMjIFZhcmlhdGlvbiBhbW9uZyByZWdpb25zDQoNCk5vbi1wYXJhbWV0cmljDQoNCmBgYHtyfQ0KDQoNCiMgUmVtb3ZlICBjb3VudHJpZXMgd2l0aCBubyB2YXJpYXRpb24gaW4gbWljcm9wbGFzdGljIGNvbmNlbnRyYXRpb24gKE5ldGhlcmxhbmRzKQ0KZGF0YV9maWx0ZXJlZCA8LSBkYXRhICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoY291bnRyeSkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoc3RhdHM6OnZhcihjb25jZW50cmF0aW9uKSA+IDApICU+JQ0KICBkcGx5cjo6dW5ncm91cCgpDQoNCiMgS3J1c2thbC1XYWxsaXMgdGVzdCB3aXRoIGVmZmVjdCBzaXplDQprcnVza2FsX3Jlc3VsdCA8LSBkYXRhX2ZpbHRlcmVkICU+JQ0KICByc3RhdGl4OjprcnVza2FsX3Rlc3QoY29uY2VudHJhdGlvbiB+IGNvdW50cnkpICU+JQ0KICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCkNCg0KIyBDYWxjdWxhdGUgZWZmZWN0IHNpemUNCmVmZmVjdF9zaXplIDwtIGRhdGFfZmlsdGVyZWQgJT4lDQogIHJzdGF0aXg6OmtydXNrYWxfZWZmc2l6ZShjb25jZW50cmF0aW9uIH4gY291bnRyeSkNCg0KIyBQYWlyd2lzZSBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IHdpdGggQm9uZmVycm9uaSBjb3JyZWN0aW9uDQpwYWlyd2lzZV93aWxjb3ggPC0gc3RhdHM6OnBhaXJ3aXNlLndpbGNveC50ZXN0KGRhdGFfZmlsdGVyZWQkY29uY2VudHJhdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YV9maWx0ZXJlZCRjb3VudHJ5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSIpDQoNCiMgQ2FsY3VsYXRlIHByb3BvcnRpb25zIG9mIHNhbXBsZXMgd2l0aCBtaWNyb3BsYXN0aWNzDQpwcm9wb3J0aW9uX3dpdGhfbXAgPC0gZGF0YSAlPiUNCiAgZHBseXI6OmZpbHRlcihjb3VudHJ5ICE9ICJOZXRoZXJsYW5kcyIpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoY291bnRyeSkgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgdG90YWxfc2FtcGxlcyA9IGRwbHlyOjpuKCksDQogICAgc2FtcGxlc193aXRoX21wID0gc3VtKGNvbmNlbnRyYXRpb24gPiAwKSwNCiAgICBwcm9wb3J0aW9uID0gc2FtcGxlc193aXRoX21wIC8gdG90YWxfc2FtcGxlcw0KICApDQoNCmtydXNrYWxfcmVzdWx0DQplZmZlY3Rfc2l6ZQ0KcGFpcndpc2Vfd2lsY294DQpwcm9wb3J0aW9uX3dpdGhfbXANCg0KIyBrcnVza2FsX3Jlc3VsdA0KIyAjIEEgdGliYmxlOiAxIMOXIDcNCiMgICAueS4gICAgICAgICAgICAgICBuIHN0YXRpc3RpYyAgICBkZiAgICAgICAgICBwIG1ldGhvZCAgICAgICAgIHAuc2lnbmlmDQojICAgPGNocj4gICAgICAgICA8aW50PiAgICAgPGRibD4gPGludD4gICAgICA8ZGJsPiA8Y2hyPiAgICAgICAgICA8Y2hyPiAgIA0KIyAxIGNvbmNlbnRyYXRpb24gICAzMjYgICAgICAyNi4xICAgICAzIDAuMDAwMDA5MjkgS3J1c2thbC1XYWxsaXMgKioqKiAgICANCiMgPiBlZmZlY3Rfc2l6ZQ0KIyAjIEEgdGliYmxlOiAxIMOXIDUNCiMgICAueS4gICAgICAgICAgICAgICBuIGVmZnNpemUgbWV0aG9kICBtYWduaXR1ZGUNCiMgKiA8Y2hyPiAgICAgICAgIDxpbnQ+ICAgPGRibD4gPGNocj4gICA8b3JkPiAgICANCiMgMSBjb25jZW50cmF0aW9uICAgMzI2ICAwLjA3MTYgZXRhMltIXSBtb2RlcmF0ZSANCiMgPiBwYWlyd2lzZV93aWxjb3gNCiMgDQojIAlQYWlyd2lzZSBjb21wYXJpc29ucyB1c2luZyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IHdpdGggY29udGludWl0eSBjb3JyZWN0aW9uIA0KIyANCiMgZGF0YTogIGRhdGFfZmlsdGVyZWQkY29uY2VudHJhdGlvbiBhbmQgZGF0YV9maWx0ZXJlZCRjb3VudHJ5IA0KIyANCiMgICAgICAgICBBdXN0cmlhIEN6ZWNoaWEgSXRhbHkNCiMgQ3plY2hpYSAxLjAwMCAgIC0gICAgICAgLSAgICANCiMgSXRhbHkgICAxLjAwMCAgIDEuMDAwICAgLSAgICANCiMgU3BhaW4gICAwLjYyMCAgIDUuNmUtMDYgMC4wNDMNCiMgDQojIFAgdmFsdWUgYWRqdXN0bWVudCBtZXRob2Q6IGJvbmZlcnJvbmkgDQojID4gcHJvcG9ydGlvbl93aXRoX21wDQojICMgQSB0aWJibGU6IDQgw5cgNA0KIyAgIGNvdW50cnkgdG90YWxfc2FtcGxlcyBzYW1wbGVzX3dpdGhfbXAgcHJvcG9ydGlvbg0KIyAgIDxmY3Q+ICAgICAgICAgICA8aW50PiAgICAgICAgICAgPGludD4gICAgICA8ZGJsPg0KIyAxIEF1c3RyaWEgICAgICAgICAgICAgOSAgICAgICAgICAgICAgIDEgICAgICAwLjExMQ0KIyAyIEN6ZWNoaWEgICAgICAgICAgIDE5NiAgICAgICAgICAgICAgMzIgICAgICAwLjE2Mw0KIyAzIEl0YWx5ICAgICAgICAgICAgICAzOSAgICAgICAgICAgICAgIDggICAgICAwLjIwNQ0KIyA0IFNwYWluICAgICAgICAgICAgICA4MiAgICAgICAgICAgICAgMzggICAgICAwLjQ2Mw0KDQoNCg0KIyBSZXN1bHRzIGFuZCBJbnRlcnByZXRhdGlvbnMNCg0KIycgTWljcm9wbGFzdGljIENvbmNlbnRyYXRpb24gRGlmZmVyZW5jZXMgQW1vbmcgQ291bnRyaWVzDQojJyANCiMnIFRoZSBLcnVza2FsLVdhbGxpcyB0ZXN0IHJldmVhbGVkIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIG1pY3JvcGxhc3RpYyANCiMnIGNvbmNlbnRyYXRpb25zIGFtb25nIHRoZSBzdHVkaWVkIGNvdW50cmllcyAoz4cyKDMpID0gMjYuMSwgcCA8IDAuMDAwMSkuIA0KIycgVGhlIGVmZmVjdCBzaXplICjOtzJIID0gMC4wNzE2KSBpbmRpY2F0ZXMgYSBtb2RlcmF0ZSBwcmFjdGljYWwgc2lnbmlmaWNhbmNlLCANCiMnIHN1Z2dlc3RpbmcgdGhhdCBhcHByb3hpbWF0ZWx5IDcuMTYlIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBtaWNyb3BsYXN0aWMgDQojJyBjb25jZW50cmF0aW9ucyBjYW4gYmUgYXR0cmlidXRlZCB0byBjb3VudHJ5IGRpZmZlcmVuY2VzLg0KIycgDQojJyBQYWlyd2lzZSBjb21wYXJpc29ucyB1c2luZyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0cyBzaG93ZWQgdGhhdCBTcGFpbiBoYWQgDQojJyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBtaWNyb3BsYXN0aWMgY29uY2VudHJhdGlvbnMgY29tcGFyZWQgdG8gQ3plY2hpYSANCiMnIChwIDwgMC4wMDAxKSBhbmQgSXRhbHkgKHAgPSAwLjA0MykuIE5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIHdlcmUgZm91bmQgDQojJyBiZXR3ZWVuIG90aGVyIGNvdW50cnkgcGFpcnMsIGR1ZSB0byBsaW1pdGVkIHNhbXBsZSBzaXplcyBpbiBBdXN0cmlhLg0KIycgDQojJyBUaGUgcHJvcG9ydGlvbiBvZiBzYW1wbGVzIGNvbnRhaW5pbmcgbWljcm9wbGFzdGljcyB2YXJpZWQgY29uc2lkZXJhYmx5IA0KIycgYW1vbmcgY291bnRyaWVzOiBTcGFpbiAoNDYuMyUpLCBJdGFseSAoMjAuNSUpLCBDemVjaGlhICgxNi4zJSksIGFuZCANCiMnIEF1c3RyaWEgKDExLjElKS4gVGhpcyB2YXJpYXRpb24gc3VnZ2VzdHMgZGlmZmVyaW5nIGxldmVscyBvZiBtaWNyb3BsYXN0aWMgDQojJyBwb2xsdXRpb24gb3IgZGV0ZWN0aW9uIGFjcm9zcyB0aGUgc3R1ZGllZCBFdXJvcGVhbiBjb3VudHJpZXMuDQojJyANCg0KIyBWaXN1YWxpemUgcmVzdWx0cyB3aXRoIGFkanVzdGVkIHktYXhpcw0KZ2dwbG90Mjo6Z2dwbG90KGRhdGFfZmlsdGVyZWQsIGdncGxvdDI6OmFlcyh4ID0gY291bnRyeSwgeSA9IGNvbmNlbnRyYXRpb24pKSArDQogIGdncGxvdDI6Omdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsNCiAgZ2dwbG90Mjo6Z2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFscGhhID0gMC41KSArDQogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiTWljcm9wbGFzdGljIENvbmNlbnRyYXRpb25zIGJ5IENvdW50cnkiLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIktydXNrYWwtV2FsbGlzIHRlc3QgcC12YWx1ZSA8IiwgZm9ybWF0KGtydXNrYWxfcmVzdWx0JHAsIHNjaWVudGlmaWMgPSBUUlVFLCBkaWdpdHMgPSAzKSksDQogICAgICAgeCA9ICIiLA0KICAgICAgIHkgPSAiQ29uY2VudHJhdGlvbiAoTVBzL2cgZHJ5IHdlaWdodCkiKSArDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQogIGdncGxvdDI6OnRoZW1lKGF4aXMudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDEyLjUpKSArDQogIGdncGxvdDI6OmFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuNywgeSA9IDEyLCANCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAiT25lIHNhbXBsZSBpbiBBdXN0cmlhICBcbiBpcyBvdXQgb2Ygc2NhbGUgKDc4Ljk1KSIsIA0KICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMSwgc2l6ZSA9IDMsIGNvbG9yID0gInJlZCIpDQoNCiMgU2F2ZSB0aGUgcGxvdA0KZ2dwbG90Mjo6Z2dzYXZlKCJtaWNyb3BsYXN0aWNfY29uY2VudHJhdGlvbl9ieV9jb3VudHJ5X2FkanVzdGVkLnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KIyBWaXN1YWxpemUgcHJvcG9ydGlvbiBvZiBzYW1wbGVzIHdpdGggbWljcm9wbGFzdGljcw0KZ2dwbG90Mjo6Z2dwbG90KHByb3BvcnRpb25fd2l0aF9tcCwgZ2dwbG90Mjo6YWVzKHggPSBjb3VudHJ5LCB5ID0gcHJvcG9ydGlvbiwgZmlsbCA9IGNvdW50cnkpKSArDQogIGdncGxvdDI6Omdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdncGxvdDI6Omdlb21fdGV4dChnZ3Bsb3QyOjphZXMobGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocHJvcG9ydGlvbiwgYWNjdXJhY3kgPSAwLjEpKSwgDQogICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSAzLjUpICsNCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJQcm9wb3J0aW9uIG9mIFNhbXBsZXMgd2l0aCBNaWNyb3BsYXN0aWNzIGJ5IENvdW50cnkiLA0KICAgICAgIHggPSAiIiwNCiAgICAgICB5ID0gIlByb3BvcnRpb24gb2YgU2FtcGxlcyIpICsNCiAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpICsNCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50ZXh0LnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsIGxpbWl0cyA9IGMoMCwgMSkpDQoNCiMgU2F2ZSB0aGUgcHJvcG9ydGlvbiBwbG90DQpnZ3Bsb3QyOjpnZ3NhdmUoInByb3BvcnRpb25fc2FtcGxlc193aXRoX21pY3JvcGxhc3RpY3MucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KYGBgDQoNCg0KDQoNCg0KIyMjIENaOiBVcmJhbmlzYXRpb24NCg0KYGBge3J9DQoNCiMgRmlsdGVyIGZvciBDemVjaGlhIGRhdGEgYW5kIGNvbnZlcnQgdG8gc2Ygb2JqZWN0DQpjel9kYXRhIDwtIGRhdGFfd2dzODQgJT4lDQogIGRwbHlyOjpmaWx0ZXIoY291bnRyeSA9PSAiQ3plY2hpYSIpICU+JQ0KICBzZjo6c3RfYXNfc2YoY29vcmRzID0gYygiWCIsICJZIiksIGNycyA9IDQzMjYpDQoNCiMgTG9hZCBDemVjaGlhIGFkbWluaXN0cmF0aXZlIGJvdW5kYXJpZXMgYW5kIHBvcHVsYXRpb24gZGF0YQ0KY3pfZGlzdHJpY3RzIDwtIFJDemVjaGlhOjpva3Jlc3koImxvdyIpDQpjZW5zdXNfZGF0YSA8LSBjenNvOjpjenNvX2dldF90YWJsZSgiU0xEQi1WWUJFUiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCh1emtvZCwgb2J5dmF0ZWwgPSB2c2UxMTExKSAlPiUgDQogIGRwbHlyOjptdXRhdGUob2J5dmF0ZWwgPSBhcy5udW1lcmljKG9ieXZhdGVsKSkNCg0KIyBKb2luIHBvcHVsYXRpb24gZGF0YSB0byBkaXN0cmljdHMNCmN6X2Rpc3RyaWN0cyA8LSBjel9kaXN0cmljdHMgJT4lDQogIGRwbHlyOjppbm5lcl9qb2luKGNlbnN1c19kYXRhLCBieSA9IGMoIktPRF9PS1JFUyIgPSAidXprb2QiKSkNCg0KIyBDYWxjdWxhdGUgcG9wdWxhdGlvbiBkZW5zaXR5DQpjel9kaXN0cmljdHMkcG9wX2RlbnNpdHkgPC0gY3pfZGlzdHJpY3RzJG9ieXZhdGVsIC8gKGFzLm51bWVyaWMoc3RfYXJlYShjel9kaXN0cmljdHMpKSAvIDFlNikgICMgcG9wdWxhdGlvbiBwZXIga20yDQoNCiMgRmluZCB3aGljaCBkaXN0cmljdCBlYWNoIG1pY3JvcGxhc3RpYyBzYW1wbGUgYmVsb25ncyB0bw0KY3pfZGF0YSA8LSBzZjo6c3Rfam9pbihjel9kYXRhLCBjel9kaXN0cmljdHMpDQoNCiMgQ2FsY3VsYXRlIHVyYmFuaXphdGlvbiBpbmRleCBiYXNlZCBvbiBwb3B1bGF0aW9uIGRlbnNpdHkNCmN6X2RhdGEkdXJiYW5faW5kZXggPC0gc2NhbGUoY3pfZGF0YSRwb3BfZGVuc2l0eSkNCg0KIyBTdGF0aXN0aWNhbCBhbmFseXNpcw0KY3pfbW9kZWwgPC0gbG0oY29uY2VudHJhdGlvbiB+IHVyYmFuX2luZGV4LCBkYXRhID0gY3pfZGF0YSkNCmN6X3N1bW1hcnkgPC0gc3VtbWFyeShjel9tb2RlbCkNCmN6X2NvcnJlbGF0aW9uIDwtIGNvci50ZXN0KGN6X2RhdGEkY29uY2VudHJhdGlvbiwgY3pfZGF0YSR1cmJhbl9pbmRleCkNCg0KIyBWaXN1YWxpemF0aW9uDQpjcmVhdGVfbWFwIDwtIGZ1bmN0aW9uKGRhdGEpIHsNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YoZGF0YSA9IGN6X2Rpc3RyaWN0cywgYWVzKGZpbGwgPSBwb3BfZGVuc2l0eSkpICsNCiAgICBnZW9tX3NmKGRhdGEgPSBkYXRhLCBhZXMoY29sb3IgPSBjb25jZW50cmF0aW9uLCBzaXplID0gdXJiYW5faW5kZXgpKSArDQogICAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmFtZSA9ICJQb3B1bGF0aW9uIERlbnNpdHkiLCBvcHRpb24gPSAiQyIpICsNCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobmFtZSA9ICJNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbiIsIG9wdGlvbiA9ICJEIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgbGFicyh0aXRsZSA9ICJNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbiBhbmQgVXJiYW5pemF0aW9uIGluIEN6ZWNoaWEiLA0KICAgICAgICAgc2l6ZSA9ICJVcmJhbml6YXRpb24gSW5kZXgiKQ0KfQ0KDQpjcmVhdGVfc2NhdHRlciA8LSBmdW5jdGlvbihkYXRhKSB7DQogIGdncGxvdChkYXRhLCBhZXMoeCA9IHVyYmFuX2luZGV4LCB5ID0gY29uY2VudHJhdGlvbikpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsNCiAgICBsYWJzKHRpdGxlID0gIk1pY3JvcGxhc3RpYyBDb25jZW50cmF0aW9uIHZzLiBVcmJhbml6YXRpb24gaW4gQ3plY2hpYSIsDQogICAgICAgICB4ID0gIlVyYmFuaXphdGlvbiBJbmRleCIsIA0KICAgICAgICAgeSA9ICJNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbiIpDQp9DQoNCmN6X21hcCA8LSBjcmVhdGVfbWFwKGN6X2RhdGEpDQpjel9zY2F0dGVyIDwtIGNyZWF0ZV9zY2F0dGVyKGN6X2RhdGEpDQoNCiMgbm90IGEgZ29vZCBwcm94eSB3aXRoIHBvcHVsYXRpb24sIGJlY2F1c2Ugc2FtcGxpbmcgb2YgY291cnNlIGhhcHBlbmVkIG91dHNpZGUNCg0KDQpgYGANCg0KDQojIFBsb3RzDQotIFJlbW92ZWQgVGhlIE5ldGhlcmxhbmRzDQoNCiMjIFByb3BvcnRpb25zDQpDb21wb3NpdGlvbiBvZiBtaWNyb3BsYXN0aWMgdHlwZXMgYWNyb3NzIGRpZmZlcmVudCBjb3VudHJpZXMuUmVsYXRpdmUgcHJvcG9ydGlvbnMgb2YgZmliZXJzLCBmcmFnbWVudHMsIHNwaGVyZXMsIGZpbG1zLCBhbmQgc3BvbmdlcyBpbiBlYWNoIGNvdW50cnkuDQoNCmBgYHtyfQ0Kc3RyKGNvbWJpbmVkX3RhYmxlKQ0KDQojIFJlc2hhcGUgdGhlIGRhdGEgZm9yIHBsb3R0aW5nDQpvdHRlcl9kYXRhX2xvbmcgPC0gY29tYmluZWRfdGFibGUgJT4lDQogIGRwbHlyOjpzZWxlY3QoQ291bnRyeSwgYFNhbXBsZXMgKG4pYCwgRmliZXJzLCBGcmFnbWVudHMsIFNwaGVyZXMsIEZpbG1zLCBTcG9uZ2VzKSAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gRmliZXJzOlNwb25nZXMsIG5hbWVzX3RvID0gIlR5cGUiLCB2YWx1ZXNfdG8gPSAiQ291bnQiKQ0KDQoNCg0KIyBDb252ZXJ0IENvdW50cnkgdG8gZmFjdG9yIGFuZCByZW9yZGVyIGxldmVscyBieSBDb3VudCAoYWJ1bmRhbmNlKQ0Kb3R0ZXJfZGF0YV9sb25nJENvdW50cnkgPC0gZmFjdG9yKG90dGVyX2RhdGFfbG9uZyRDb3VudHJ5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOZXRoZXJsYW5kcyIsIkl0YWx5IiwiQXVzdHJpYSIsICJDemVjaGlhIiwiU3BhaW4iLCAiVG90YWwiKSkNCg0KDQpnZ3Bsb3Qob3R0ZXJfZGF0YV9sb25nLCBhZXMoeCA9IENvdW50cnksIHkgPSBDb3VudCwgZmlsbCA9IFR5cGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChkYXRhID0gY29tYmluZWRfdGFibGUsIGFlcyh4ID0gQ291bnRyeSwgeSA9IG1heCgtMTUpLCBsYWJlbCA9IGBTYW1wbGVzIChuKWApLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMsIGluaGVyaXQuYWVzID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICJNaWNyb3BsYXN0aWNzIGluIE90dGVyIFNwcmFpbnRzIGJ5IENvdW50cnkiLA0KICAgICAgIHggPSBOVUxMLA0KICAgICAgIHkgPSAiVG90YWwgTWljcm9wbGFzdGljIEFidW5kYW5jZSIsDQogICAgICAgZmlsbCA9ICJNaWNyb3BsYXN0aWMgVHlwZSIsDQogICAgICBjYXB0aW9uID0gIk51bWJlciBvZiBzYW1wbGVzIChuKSBzaG93biBsZWZ0IG9mIGJhcnMiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsgIA0KICB0aGVtZV9saWdodCgpICsgIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBoanVzdCA9IDApKSsNCiAgY29vcmRfZmxpcCgpDQoNCg0KIyBDYWxjdWxhdGUgcHJvcG9ydGlvbnMgb2YgZWFjaCBtaWNyb3BsYXN0aWMgdHlwZQ0KZGF0YV9wcm9wb3J0aW9ucyA8LSBkYXRhICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoY291bnRyeSkgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoZHBseXI6OmFjcm9zcyhjKGZpYmVycywgZnJhZ21lbnRzLCBzcGhlcmVzLCBmaWxtcywgc3BvbmdlcyksIHN1bSksDQogICAgICAgICAgICB0b3RhbCA9IHN1bShmaWJlcnMsIGZyYWdtZW50cywgc3BoZXJlcywgZmlsbXMsIHNwb25nZXMpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGMoZmliZXJzLCBmcmFnbWVudHMsIHNwaGVyZXMsIGZpbG1zLCBzcG9uZ2VzKSwgDQogICAgICAgICAgICAgICAgfi4vdG90YWwsIC5uYW1lcyA9ICJwcm9wX3suY29sfSIpKQ0KDQojIFJlc2hhcGUgdGhlIGRhdGEgZm9yIHBsb3R0aW5nDQpkYXRhX2xvbmcgPC0gZGF0YV9wcm9wb3J0aW9ucyAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoInByb3BfIiksDQogICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibWljcm9wbGFzdGljX3R5cGUiLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwcm9wb3J0aW9uIikgJT4lDQogIGRwbHlyOjptdXRhdGUobWljcm9wbGFzdGljX3R5cGUgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKG1pY3JvcGxhc3RpY190eXBlLCAicHJvcF8iKSkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvdW50cnkgIT0gIk5ldGhlcmxhbmRzIikNCg0KIyBDcmVhdGUgYSBzdGFja2VkIGJhciBwbG90DQpnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YV9sb25nLCBnZ3Bsb3QyOjphZXMoeCA9IGNvdW50cnksIHkgPSBwcm9wb3J0aW9uLCBmaWxsID0gbWljcm9wbGFzdGljX3R5cGUpKSArDQogIGdncGxvdDI6Omdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBnZ3Bsb3QyOjpzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArDQogIGdncGxvdDI6OmxhYnMoeCA9IE5VTEwsIHkgPSAiUHJvcG9ydGlvbiIsIGZpbGwgPSAiTWljcm9wbGFzdGljIFR5cGUiKSArDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQogIGdncGxvdDI6OmNvb3JkX2ZsaXAoKQ0KDQojIFJlbW92ZWQgVGhlIE5ldGhlcmxhbmRzDQojIENvbXBvc2l0aW9uIG9mIG1pY3JvcGxhc3RpYyB0eXBlcyBhY3Jvc3MgZGlmZmVyZW50IGNvdW50cmllcy4NCiMgUmVsYXRpdmUgcHJvcG9ydGlvbnMgb2YgZmliZXJzLCBmcmFnbWVudHMsIHNwaGVyZXMsIGZpbG1zLCBhbmQgc3BvbmdlcyBpbiBlYWNoIGNvdW50cnkuDQoNCg0KDQoNCg0KYGBgDQoNCiMjIEJveHBsb3RzDQoNCmBgYHtyfQ0KDQoNCiMgQ3JlYXRlIGJveHBsb3RzIHRvdGFsIGRhdGENCmdncGxvdDI6OmdncGxvdChkYXRhID0gZGF0YSwgZ2dwbG90Mjo6YWVzKHggPSBjb3VudHJ5LCB5ID0gY29uY2VudHJhdGlvbiwgZmlsbCA9IGNvdW50cnkpKSArDQogIGdncGxvdDI6Omdlb21fYm94cGxvdCgpICsNCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbnMgQWNyb3NzIENvdW50cmllcyIsDQogICAgICAgICAgICAgICAgeCA9ICJDb3VudHJ5IiwNCiAgICAgICAgICAgICAgICB5ID0gIk1pY3JvcGxhc3RpYyBDb25jZW50cmF0aW9uIChNUHMvZyBkcnkgd2VpZ2h0KSIsDQogICAgICAgICAgICAgICAgZmlsbCA9ICJDb3VudHJ5IikgICsNCmdncGxvdDI6OnNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsNCiAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpICsNCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50ZXh0LnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KDQoNCg0KDQojIEZpbHRlciBvdXQgb3V0bGllcnMgd2l0aCBjb25jZW50cmF0aW9uID4gMzAgTVBzL2cgZHJ5IHdlaWdodA0KZGF0YV9ub19vdXRsaWVycyA8LSBkcGx5cjo6ZmlsdGVyKGRhdGEsICEoZGF0YSRjb25jZW50cmF0aW9uID4gMzApKQ0KDQojIElkZW50aWZ5IG91dGxpZXJzIGZvciBsYWJlbGluZw0Kb3V0bGllcnMgPC0gZHBseXI6OmZpbHRlcihkYXRhLCBkYXRhJGNvbmNlbnRyYXRpb24gPiAzMCkNCg0KIyBDcmVhdGUgYm94cGxvdHMgd2l0aCBvdXRsaWVycyBsYWJlbGVkDQpnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YSA9IGRhdGFfbm9fb3V0bGllcnMsIGdncGxvdDI6OmFlcyh4ID0gY291bnRyeSwgeSA9IGNvbmNlbnRyYXRpb24sIGZpbGwgPSBjb3VudHJ5KSkgKw0KICBnZ3Bsb3QyOjpnZW9tX2JveHBsb3QoKSArDQogIGdncGxvdDI6Omdlb21fdGV4dChkYXRhID0gb3V0bGllcnMsIGdncGxvdDI6OmFlcyhsYWJlbCA9IHNhbXBsZSksIHggPSBvdXRsaWVycyRjb3VudHJ5LCB5ID0gMTIsDQogICAgICAgICAgICAgICAgICAgICBoanVzdCA9IC0wLjEsIHZqdXN0ID0gMC41LCBjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKw0KICBnZ3Bsb3QyOjp5bGltKDAsIDEyKSArICAjIExpbWl0IHktYXhpcyB0byAxMg0KICBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gIk1pY3JvcGxhc3RpYyBDb25jZW50cmF0aW9ucyBBY3Jvc3MgQ291bnRyaWVzIChPdXRsaWVycyBMYWJlbGVkKSIsDQogICAgICAgICAgICAgICAgeCA9ICJDb3VudHJ5IiwNCiAgICAgICAgICAgICAgICB5ID0gIk1pY3JvcGxhc3RpYyBDb25jZW50cmF0aW9uIChNUHMvZyBkcnkgd2VpZ2h0KSIsDQogICAgICAgICAgICAgICAgZmlsbCA9ICJDb3VudHJ5IiwNCiAgICAgICAgICAgICAgICBjYXB0aW9uID0gIk91dGxpZXJzIGxhYmVsZWQgaW4gcmVkIikgKw0KICBnZ3Bsb3QyOjpzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQogIGdncGxvdDI6OnRoZW1lKGF4aXMudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KDQoNCiMgQ2l0YXRpb25zDQoNCmBgYHtyfQ0KDQpjaXRlX3BhY2thZ2VzKG91dC5mb3JtYXQgPSAiZG9jeCIsIG91dC5kaXIgPSAiLiIpDQoNCmNpdGVfcGFja2FnZXMoInBhcmFncmFwaCIsIG91dC5kaXIgPSAiLiIpDQpgYGANCg0KDQoiV2UgdXNlZCBSIHZlcnNpb24gNC40LjEgW0BiYXNlXSAsIGR1bm4udGVzdCB2LiAxLjMuNiBbQGR1bm50ZXN0XSwgZWZmc2l6ZSB2LiAwLjguMSBbQGVmZnNpemVdLCByc3RhdGl4IHYuIDAuNy4yIFtAcnN0YXRpeF0sIHNmIHYuIDEuMC4xNiBbQHNmMjAxODsgQHNmMjAyM10sICB0aWR5dmVyc2Ugdi4gMi4wLjAgW0B0aWR5dmVyc2VdIg0KDQojICMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KDQojIEVYVFJBDQojIyMgUml2ZXJzIGFuZCBzYW1wbGVzIENaDQoNCmBgYHtyfQ0KIyAjIENvbnZlcnQgc2FtcGxlIGRhdGEgdG8gc2Ygb2JqZWN0DQojIHNhbXBsZXNfc2YgPC0gc2Y6OnN0X2FzX3NmKGRhdGFfd2dzODQsIGNvb3JkcyA9IGMoIlgiLCAiWSIpLCBjcnMgPSA0MzI2KQ0KIyANCiMgIyBGaWx0ZXIgZm9yIEN6ZWNoIFJlcHVibGljIHNhbXBsZXMNCiMgY3pfc2FtcGxlcyA8LSBzYW1wbGVzX3NmICU+JSANCiMgICBkcGx5cjo6ZmlsdGVyKGNvdW50cnkgPT0gIkN6ZWNoaWEiKQ0KIyANCiMgIyBHZXQgQ3plY2ggUmVwdWJsaWMgcml2ZXJzIGFuZCByZWdpb25zDQojIGN6X3JpdmVycyA8LSBSQ3plY2hpYTo6cmVreSgpDQojIGN6X3JlZ2lvbnMgPC0gUkN6ZWNoaWE6OmtyYWplKCkNCiMgDQojICMgRW5zdXJlIHRoZSBDUlMgbWF0Y2hlcw0KIyBjel9yaXZlcnMgPC0gc2Y6OnN0X3RyYW5zZm9ybShjel9yaXZlcnMsIGNycyA9IHNmOjpzdF9jcnMoY3pfc2FtcGxlcykpDQojIGN6X3JlZ2lvbnMgPC0gc2Y6OnN0X3RyYW5zZm9ybShjel9yZWdpb25zLCBjcnMgPSBzZjo6c3RfY3JzKGN6X3NhbXBsZXMpKQ0KIyANCiMgIyBGaW5kIHRoZSBuZWFyZXN0IHJpdmVyIGZvciBlYWNoIHNhbXBsZQ0KIyBuZWFyZXN0X3JpdmVycyA8LSBjel9yaXZlcnMgJT4lDQojICAgc2Y6OnN0X2pvaW4oY3pfc2FtcGxlcywgam9pbiA9IHNmOjpzdF9uZWFyZXN0X2ZlYXR1cmUpDQojIA0KIyAjIEZpbmQgdGhlIHJlZ2lvbiBmb3IgZWFjaCBzYW1wbGUNCiMgc2FtcGxlc193aXRoX3JlZ2lvbnMgPC0gc2Y6OnN0X2pvaW4oY3pfc2FtcGxlcywgY3pfcmVnaW9ucykNCiMgDQojICMgQ3JlYXRlIHN1bW1hcnkgdGFibGUNCiMgY3pfcml2ZXJfc3VtbWFyeSA8LSBuZWFyZXN0X3JpdmVycyAlPiUNCiMgICBzZjo6c3RfZHJvcF9nZW9tZXRyeSgpICU+JQ0KIyAgIGRwbHlyOjpncm91cF9ieShOQVpFVikgJT4lDQojICAgZHBseXI6OnN1bW1hcmlzZSgNCiMgICAgIG5fc2FtcGxlcyA9IHN1bSghaXMubmEoc2FtcGxlKSkNCiMgICApICU+JQ0KIyAgIGRwbHlyOjpmaWx0ZXIobl9zYW1wbGVzID4gMCkgJT4lDQojICAgZHBseXI6OmFycmFuZ2UoZHBseXI6OmRlc2Mobl9zYW1wbGVzKSkNCiMgDQojICMgQWRkIHJlZ2lvbiBpbmZvcm1hdGlvbg0KIyBjel9yaXZlcl9zdW1tYXJ5IDwtIGN6X3JpdmVyX3N1bW1hcnkgJT4lDQojICAgZHBseXI6OmxlZnRfam9pbigNCiMgICAgIHNhbXBsZXNfd2l0aF9yZWdpb25zICU+JQ0KIyAgICAgICBzZjo6c3RfZHJvcF9nZW9tZXRyeSgpICU+JQ0KIyAgICAgICBkcGx5cjo6Z3JvdXBfYnkoc2FtcGxlKSAlPiUNCiMgICAgICAgZHBseXI6OnN1bW1hcmlzZShyaXZlciA9IGRwbHlyOjpmaXJzdChOQVpFViksIHJlZ2lvbiA9IGRwbHlyOjpmaXJzdChOQVpFVi55KSkgJT4lDQojICAgICAgIGRwbHlyOjpncm91cF9ieShyaXZlcikgJT4lDQojICAgICAgIGRwbHlyOjpzdW1tYXJpc2UocmVnaW9uID0gZHBseXI6OmZpcnN0KHJlZ2lvbikpLA0KIyAgICAgYnkgPSBjKCJOQVpFViIgPSAicml2ZXIiKQ0KIyAgICkNCiMgDQojICMgUmVvcmRlciBjb2x1bW5zDQojIGN6X3JpdmVyX3N1bW1hcnkgPC0gY3pfcml2ZXJfc3VtbWFyeSAlPiUNCiMgICBkcGx5cjo6c2VsZWN0KG5fc2FtcGxlcywgcml2ZXIgPSBOQVpFViwgcmVnaW9uKQ0KIyANCiMgIyBQcmludCBzdW1tYXJ5DQojIHByaW50KGN6X3JpdmVyX3N1bW1hcnkpDQojIA0KIyAjIFNhdmUgc3VtbWFyeSB0byBDU1YNCiMgcmVhZHI6OndyaXRlX2Nzdihjel9yaXZlcl9zdW1tYXJ5LCAiY3plY2hfc2FtcGxlc19wZXJfcml2ZXIuY3N2IikNCmBgYA0KDQoNCg0KDQoNCiMjIFNwYWluIHZzIEN6DQojIyMgT25seSBmb3IgU3BhaW4gYW5kIENaIA0KQ29tcGFyaXNvbiBvZiBtaWNyb3BsYXN0aWMgY29uY2VudHJhdGlvbnMgaW4gb3R0ZXIgKEx1dHJhIGx1dHJhKSBzcHJhaW50cyBiZXR3ZWVuIFNwYWluIChuID0gODIpIGFuZCBDemVjaGlhIChuID0gMTk2KS4gVGhlIGJveHBsb3RzIGRpc3BsYXkgdGhlIG1lZGlhbiAoY2VudHJhbCBsaW5lKSwgaW50ZXJxdWFydGlsZSByYW5nZSAoYm94KSwgYW5kIHJhbmdlICh3aGlza2Vycykgb2YgbWljcm9wbGFzdGljIGNvbmNlbnRyYXRpb25zLiBJbmRpdmlkdWFsIGRhdGEgcG9pbnRzIGFyZSBqaXR0ZXJlZCB0byBzaG93IHRoZSBkaXN0cmlidXRpb24uIE1pY3JvcGxhc3RpYyBjb25jZW50cmF0aW9uIGlzIGV4cHJlc3NlZCBhcyB0aGUgbnVtYmVyIG9mIG1pY3JvcGxhc3RpYyBwYXJ0aWNsZXMgcGVyIGdyYW0gb2YgZHJ5IHdlaWdodCAoTVBzIGdeLTEgZHcpLlRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0IHJldmVhbGVkIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBtaWNyb3BsYXN0aWMgY29uY2VudHJhdGlvbnMgYmV0d2VlbiB0aGUgdHdvIGNvdW50cmllcyAoVyA9IDEwMzIzLCBwID0gOS4yN2UtMDcpLCB3aXRoIFNwYWluIHNob3dpbmcgaGlnaGVyIGxldmVscyBvZiBjb250YW1pbmF0aW9uLiAgDQoNCmBgYHtyfQ0KDQojICMgRmlsdGVyIGRhdGEgZm9yIFNwYWluIGFuZCBDemVjaGlhDQojIGRhdGFfY3pzcCA8LSBkYXRhICU+JQ0KIyAgIGRwbHlyOjpmaWx0ZXIoY291bnRyeSAlaW4lIGMoIlNwYWluIiwgIkN6ZWNoaWEiKSkgJT4lIA0KIyAgICAgZHBseXI6Om11dGF0ZShjb25jZW50cmF0aW9uID0gYXMubnVtZXJpYyhjb25jZW50cmF0aW9uKSkgJT4lDQojICAgZHBseXI6OmZpbHRlcighaXMubmEoY29uY2VudHJhdGlvbikpDQojIA0KIyANCiMgcmVhZHI6OndyaXRlX2NzdihkYXRhX2N6c3AsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgImRhdGFfY3pzcC5jc3YiKSkNCiMgDQojIA0KIyAjICMgRW5zdXJlIGRhdGEgaXMgcHJvcGVybHkgZm9ybWF0dGVkDQojIGRhdGFfY3pzcCA8LSBkYXRhX2N6c3AgJT4lDQojICAgZHBseXI6OmZpbHRlcighaXMubmEoY29uY2VudHJhdGlvbiksICFpcy5uYShjb3VudHJ5KSkgJT4lDQojICAgZHBseXI6Om11dGF0ZShjb25jZW50cmF0aW9uID0gYXMubnVtZXJpYyhjb25jZW50cmF0aW9uKSkNCiMgDQojICMgUGVyZm9ybSBzdGF0aXN0aWNhbCBhbmFseXNpcw0KIyBzcGFpbl9jb25jIDwtIGRhdGFfY3pzcCRjb25jZW50cmF0aW9uW2RhdGFfY3pzcCRjb3VudHJ5ID09ICJTcGFpbiJdDQojIGN6ZWNoaWFfY29uYyA8LSBkYXRhX2N6c3AkY29uY2VudHJhdGlvbltkYXRhX2N6c3AkY291bnRyeSA9PSAiQ3plY2hpYSJdDQojIHdpbGNveF9yZXN1bHQgPC0gd2lsY294LnRlc3Qoc3BhaW5fY29uYywgY3plY2hpYV9jb25jKQ0KIyANCiMgDQojICMgQ3JlYXRlIHRoZSBwbG90IHdpdGggc3RhdGlzdGljYWwgcmVzdWx0cw0KIyBwbG90IDwtIGdncGxvdDI6OmdncGxvdChkYXRhX2N6c3AsIGdncGxvdDI6OmFlcyh4ID0gY291bnRyeSwgeSA9IGNvbmNlbnRyYXRpb24pKSArDQojICAgZ2dwbG90Mjo6Z2VvbV9ib3hwbG90KGdncGxvdDI6OmFlcyhmaWxsID0gY291bnRyeSksIHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsNCiMgICBnZ3Bsb3QyOjpnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgYWxwaGEgPSAwLjUpICsNCiMgICBnZ3RoZW1lczo6c2NhbGVfZmlsbF9jb2xvcmJsaW5kKCkgKw0KIyAgIGdncGxvdDI6OmxhYnMoDQojICAgICB0aXRsZSA9ICJNaWNyb3BsYXN0aWMgQ29uY2VudHJhdGlvbnMgaW4gT3R0ZXIgU3ByYWludHMiLA0KIyAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIk1hbm4tV2hpdG5leSBVIHRlc3Q6IFcgPSAiLCByb3VuZCh3aWxjb3hfcmVzdWx0JHN0YXRpc3RpYywgMiksIA0KIyAgICAgICAgICAgICAgICAgICAgICAgIiwgcCA9ICIsIGZvcm1hdC5wdmFsKHdpbGNveF9yZXN1bHQkcC52YWx1ZSwgZGlnaXRzID0gMyksICJcbiINCiMgICAgICAgICAgICAgICAgICAgICAgICksDQojICAgICB4ID0gIiIsDQojICAgICB5ID0gZXhwcmVzc2lvbigiTWljcm9wbGFzdGljIENvbmNlbnRyYXRpb24gKE1QcyBnIl4tMSoiIGRyeSB3ZWlnaHQpIiksDQojICAgICBmaWxsID0gIkNvdW50cnkiDQojICAgKSArDQojICAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpICsNCiMgICBnZ3Bsb3QyOjp0aGVtZSgNCiMgICAgIHBsb3QudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwNCiMgICAgIHBsb3Quc3VidGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiMgICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiMgICAgIGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KIyAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQojICAgKQ0KIyANCiMgcHJpbnQocGxvdCkNCiMgDQojIGdncGxvdDI6Omdnc2F2ZShoZXJlOjpoZXJlKCJvdXRwdXQiLCJmaWdzIiwgIm1pY3JvcGxhc3RpY19jb25jZW50cmF0aW9uX2NvbXBhcmlzb24ucG5nIiksIA0KIyAgICAgICAgICAgICAgICAgcGxvdCA9IHBsb3QsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KIyANCiMgIyBTdW1tYXJ5IHN0YXRpc3RpY3MNCiMgc3VtbWFyeV9zdGF0cyA8LSBkYXRhX2N6c3AgJT4lDQojICAgZHBseXI6Omdyb3VwX2J5KGNvdW50cnkpICU+JQ0KIyAgIGRwbHlyOjpzdW1tYXJpemUoDQojICAgICBtZWFuID0gbWVhbihjb25jZW50cmF0aW9uKSwNCiMgICAgIG1lZGlhbiA9IG1lZGlhbihjb25jZW50cmF0aW9uKSwNCiMgICAgIHNkID0gc2QoY29uY2VudHJhdGlvbiksDQojICAgICBuID0gbigpDQojICAgKQ0KIyANCiMgc3VtbWFyeV9zdGF0cw0KYGBgDQoNCg0KYGBge3J9DQojIHN0cihkYXRhKQ0KIyBoZWFkKGRhdGEpDQojIA0KIyANCiMgIyBGaWx0ZXIgZGF0YSBmb3IgdGhlIHNlbGVjdGVkIGNvdW50cmllcw0KIyBkYXRhX2N6c3AgPC0gZGF0YSAlPiUNCiMgICBkcGx5cjo6ZmlsdGVyKGNvdW50cnkgJWluJSBjKCJTcGFpbiIsICJDemVjaGlhIikpDQojIA0KIyAjIFBlcmZvcm0gS3J1c2thbC1XYWxsaXMgdGVzdCB0byBjb21wYXJlIGRpc3RyaWJ1dGlvbnMgb2YgY29uY2VudHJhdGlvbnMgYmV0d2VlbiBjb3VudHJpZXMNCiMga3dfcmVzdWx0IDwtIHN0YXRzOjprcnVza2FsLnRlc3QoY29uY2VudHJhdGlvbiB+IGNvdW50cnksIGRhdGEgPSBkYXRhX2N6c3ApDQojIA0KIyBrd19yZXN1bHQNCiMgDQojICNzdHJvbmcgZXZpZGVuY2UgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiBtaWNyb3BsYXN0aWMgY29uY2VudHJhdGlvbnMgYXJlIHRoZSBzYW1lIGJldHdlZW4gdGhlc2UgdHdvIGNvdW50cmllcy4gDQojIA0KIyAjIFBlcmZvcm0gRHVubidzIHRlc3QgZm9yIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHdpdGggQm9uZmVycm9uaSBhZGp1c3RtZW50DQojIGR1bm5fcmVzdWx0IDwtIGR1bm4udGVzdChkYXRhX2N6c3AkY29uY2VudHJhdGlvbiwgZGF0YV9jenNwJGNvdW50cnksIG1ldGhvZCA9ICJib25mZXJyb25pIikNCiMgDQojIGR1bm5fcmVzdWx0IA0KIyANCiMgIyBNaWNyb3BsYXN0aWMgY29uY2VudHJhdGlvbnMgYXJlIHNpZ25pZmljYW50bHkgbG93ZXIgaW4gU3BhaW4gY29tcGFyZWQgdG8gQ3plY2hpYS4NCg0KDQpgYGANCg0KDQojIyMgU1AgdnMgQ1o6IFR5cGVzIG9mIHBsYXN0aWMNCg0KYGBge3J9DQoNCg0KIyAjIENhbGN1bGF0ZSB0aGUgcHJvcG9ydGlvbiBvZiBlYWNoIHBsYXN0aWMgdHlwZSBmb3IgZWFjaCBjb3VudHJ5DQojIHBsYXN0aWNfcHJvcG9ydGlvbnMgPC0gZGF0YV9jenNwICU+JQ0KIyAgIGRwbHlyOjpncm91cF9ieShjb3VudHJ5KSAlPiUNCiMgICBkcGx5cjo6c3VtbWFyaXNlKGRwbHlyOjphY3Jvc3MoYyhmaWJlcnMsIGZyYWdtZW50cywgc3BoZXJlcywgZmlsbXMpLCBzdW0pKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gZmliZXJzICsgZnJhZ21lbnRzICsgc3BoZXJlcyArIGZpbG1zKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoYyhmaWJlcnMsIGZyYWdtZW50cywgc3BoZXJlcywgZmlsbXMpLCB+Li90b3RhbCwgLm5hbWVzID0gInByb3Bfey5jb2x9IikpDQojIA0KIyAjIFJlc2hhcGUgdGhlIGRhdGEgZm9yIHBsb3R0aW5nDQojIHBsYXN0aWNfbG9uZyA8LSBwbGFzdGljX3Byb3BvcnRpb25zICU+JQ0KIyAgIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGRwbHlyOjpzdGFydHNfd2l0aCgicHJvcF8iKSwNCiMgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAicGxhc3RpY190eXBlIiwNCiMgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInByb3BvcnRpb24iKSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlKHBsYXN0aWNfdHlwZSA9IHN0cmluZ3I6OnN0cl9yZW1vdmUocGxhc3RpY190eXBlLCAicHJvcF8iKSkNCiMgDQojICMgQ3JlYXRlIGEgc3RhY2tlZCBiYXIgcGxvdA0KIyBnZ3Bsb3QyOjpnZ3Bsb3QocGxhc3RpY19sb25nLCBnZ3Bsb3QyOjphZXMoeCA9IGNvdW50cnksIHkgPSBwcm9wb3J0aW9uLCBmaWxsID0gcGxhc3RpY190eXBlKSkgKw0KIyAgIGdncGxvdDI6Omdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiMgICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQojICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KIyAgIGdncGxvdDI6OmxhYnModGl0bGUgPSAiUHJvcG9ydGlvbiBvZiBNaWNyb3BsYXN0aWMgVHlwZXMgaW4gT3R0ZXIgU3ByYWludHMiLCAgICAgICB4ID0gIiIsDQojICAgICAgICB5ID0gIiIsDQojICAgICAgICBmaWxsID0gIk1pY3JvcGxhc3RpYyBUeXBlIikgKw0KIyAgIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQojICAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikNCiMgDQojIGdncGxvdDI6Omdnc2F2ZSgibWljcm9wbGFzdGljX3R5cGVzX2NvbXBhcmlzb24ucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KIyANCiMgIyBTdGF0aXN0aWNhbCBjb21wYXJpc29uIGZvciBlYWNoIHBsYXN0aWMgdHlwZQ0KIyBwbGFzdGljX3R5cGVzIDwtIGMoImZpYmVycyIsICJmcmFnbWVudHMiLCAic3BoZXJlcyIsICJmaWxtcyIpDQojIA0KIyBzdGF0aXN0aWNhbF9yZXN1bHRzIDwtIGxhcHBseShwbGFzdGljX3R5cGVzLCBmdW5jdGlvbih0eXBlKSB7DQojICAgd2lsY294X3Rlc3QgPC0gc3RhdHM6OndpbGNveC50ZXN0KGRhdGFfY3pzcFtbdHlwZV1dIH4gZGF0YV9jenNwJGNvdW50cnkpDQojICAgZGF0YS5mcmFtZSgNCiMgICAgIHBsYXN0aWNfdHlwZSA9IHR5cGUsDQojICAgICBzdGF0aXN0aWMgPSB3aWxjb3hfdGVzdCRzdGF0aXN0aWMsDQojICAgICBwX3ZhbHVlID0gd2lsY294X3Rlc3QkcC52YWx1ZQ0KIyAgICkNCiMgfSkNCiMgDQojIHN0YXRpc3RpY2FsX3Jlc3VsdHNfZGYgPC0gZG8uY2FsbChyYmluZCwgc3RhdGlzdGljYWxfcmVzdWx0cykNCiMgDQojIHByaW50KHN0YXRpc3RpY2FsX3Jlc3VsdHNfZGYpDQojIA0KIyAjIENhbGN1bGF0ZSBlZmZlY3Qgc2l6ZXMNCiMgZWZmZWN0X3NpemVzIDwtIGRhdGFfY3pzcCAlPiUNCiMgICB0aWR5cjo6Z2F0aGVyKGtleSA9ICJwbGFzdGljX3R5cGUiLCB2YWx1ZSA9ICJjb3VudCIsIGZpYmVycywgZnJhZ21lbnRzLCBzcGhlcmVzLCBmaWxtcykgJT4lDQojICAgZHBseXI6Omdyb3VwX2J5KHBsYXN0aWNfdHlwZSkgJT4lDQojICAgcnN0YXRpeDo6d2lsY294X2VmZnNpemUoY291bnQgfiBjb3VudHJ5KQ0KIyANCiMgcHJpbnQoZWZmZWN0X3NpemVzKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=