1 Introduction

1.1 Contents

This script generates a working document describing the data available for an assessment of ple.27.3a.21-32; Plaice in the Kattegat, The Belt Seas and the Baltic Sea. The report generated covers the following topics:

  • Assessment Input Data
    • Catches and Landings
    • Survey Indices
    • Biological Data
    • Reference Points
  • Background Data and ad-hoc Requests are dealt with in the relevant sections.

Most of the code used to process data and create visualisations are hidden in this HTML. To view each chunk, simply click on the button to the right of the relevant section. To download the entire R-markdown (.rmd) file including all text and code chunks, use the code button at the top of the page, with the dropdown arrow.

1.2 Preparation

To run this script you require the following packages and functions:

require(mgcv)
require(data.table)
require(reshape2)
require(knitr)
require(scales)
require(bookdown)
require(ggplot2)
require(ggthemes)
require(stringr)
require(lattice)
require(plyr)
require(plotly)
require(icesAdvice)
require("stockassessment")  # available from https://github.com/fishfollower/SAM
require(parallel)
require(sf)

myprop <- function(df, nomo = "nomo", NoAtLngt = "CANoAtLngt") {
    t <- sum(df$nomo)/sum(df$CANoAtLngt)
}

catchFrac <- function(x, nm, w, frac) {
    F <- getF(x)
    Z <- F + nm
    N <- getN(x)
    C <- F/Z * (1 - exp(-Z)) * N
    return(sum(frac * w * C))
}

save_as_lowestoft <- function(df, file_path, title, rando_numbers = paste(c("1",
    "6"), collapse = "\t"), year_range = paste(c(2002, DataYear + 1), collapse = "\t"),
    age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = paste(c(1, "# 1 indicates annually varying, 2 indicates fixed values"),
        collapse = "\t")) {
    # Open a connection to the file
    con <- file(file_path, open = "wt")

    # Write the header (customize as needed)
    writeLines(paste0(title), con)
    writeLines(paste0(rando_numbers), con)
    writeLines(paste0(year_range), con)
    writeLines(paste0(age_range), con)
    writeLines(paste0(timeseries_type), con)

    # Write the dataframe to the file
    write.table(df, con, sep = "\t", row.names = FALSE, col.names = FALSE, quote = FALSE)

    # Close the connection
    close(con)
}

## Create sequences for moving window average:
an = function(n, len) c(seq.int(n), rep(n, len - n))

We also need to set a few variables manually.
The first is the DataYear, which is the year immediately preceeding the assessment year or the year for which the most recent data is available.
The second is the catch we (ICES) advised as TAC for the last assessment LastIcesAdvice, in tonnes. NOTE this value is taken from the advice sheet, to compare changes in advice, not changes in advice relative to actual Allowable Catches. The third is whether this run is exploratory, or to be used to generate the final advice. This option will determine the number of iterations used to determine the short-term forecasts.

DataYear <- 2023
LastIcesAdvice <- 21735  # Advised catch for areas 21-32 (from stock splitting table in advice)
isFinal <- FALSE
# isFinal <- TRUE

2 Assessment Input Data

2.1 Landings and Catches

Catch data, including break downs by landings/discards, are taken directly from inter-catch for each of the historic stocks (namely ple.27.21-23 and ple.27.24-32), where discards and sampled measures are raised according to the prioritisation described in the corresponding stock annexes, before the resultant catch data are combined. The imported table is the cumulative extracts from InterCatch, specifically Table 1 from the AllCatches extraction and file CatchAndSampleDataTables.txt.

Furthermore, recreational catches from Germany have been introduced late in the process. Here we describe the data that are available for incorporation into an assessment model, but also describe how these data will be further integrated to the whole assessment procedure in the near future.

## Read in the combined Intercatch output from the two old stocks.
ic_raw <- read.csv(file = "Data/CatchData/Ple.27.21-32_IntercatchTable1_2002-2023.csv",
    header = T)

## Read in historic TAC values by area
tac_raw <- read.csv(file = "Data/ple.27.21_22-32_TAC-Histories_2000-DataYear.csv",
    header = T)

These data are cleaned according to data formats and naming conventions (hidden chunk).

ic_raw$Year <- as.factor(as.character(ic_raw$Year))
# ic_raw$CatchCategory <- as.factor(gsub(pattern = 'BMS landing', replacement =
# 'BMS', x = ic_raw$CatchCategory))
ic_raw$Season <- as.factor(as.character(ic_raw$Season))
names(ic_raw)[names(ic_raw) == "CATON..Tons."] <- "CATON"
ic_raw$Fleet <- gsub(pattern = " ", replacement = "", x = ic_raw$Fleet, fixed = TRUE)
### Allocate some strange fleet types according to logic, or 'All' to 'Active'
### as the most likely.
ic_raw[ic_raw$Fleet %in% c("OTB_CRU_90-119_0_0_all", "MIS_MIS_0_0_0_HC", "Acitve ",
    "Trawl", "All", "Fleet-All"), "Fleet"] <- "Active"
ic_raw[ic_raw$Fleet %in% c("GNS_DEF_all_0_0_all", "Passive ", "Gillnet", "Trapnet",
    "Longline"), "Fleet"] <- "Passive"
ic_clean <- droplevels(ic_raw)

## Create novel fleet by management area
ic_clean$Fleet2 <- ifelse(ic_clean$Area == "27.3.a.21" & ic_clean$Fleet == "Active",
    "NS_Active", ifelse(ic_clean$Area == "27.3.a.21" & ic_clean$Fleet == "Passive",
        "NS_Passive", ifelse(ic_clean$Area != "27.3.a.21" & ic_clean$Fleet == "Active",
            "BS_Active", ifelse(ic_clean$Area != "27.3.a.21" & ic_clean$Fleet ==
                "Passive", "BS_Passive", NA))))

### Clean TAC data
tac_raw$Year <- as.factor(as.character(tac_raw$Year))

k <- c("k", "ic_clean", "myprop", "DataYear", "ebpal", "isFinal", "LastIcesAdvice",
    "save_as_lowestoft", "an", "tac_raw")
rm(ic_raw)

Historic landings and TAC values are imported from legacy records (hidden chunk). These need to be collated for the new “super stock”.

HistLand_raw <- read.csv(file = "Data/ple.27.21-23_HistoricLandings_1970-2017.csv",
    header = T)
HistLand_raw$Year <- as.factor(as.character(HistLand_raw$Year))



# === Update HistLand ====
landings <- aggregate(CATON ~ Area + Country + Year, data = ic_clean[as.numeric(as.character(ic_clean$Year)) >=
    2018 & ic_clean$CatchCategory != "Discards", ], FUN = sum)
colnames(landings)[colnames(landings) == "CATON"] <- "Landings"

# landings2018 <- aggregate(CATON~Area+Country+Year, data =
# ic_clean[ic_clean$Year == '2018' & ic_clean$CatchCategory != 'Discards', ],
# FUN = sum) landings2018$Year <- as.factor(as.character(2018))
# names(landings2018)[names(landings2018) == 'CATON'] <- 'Landings' #
# landings2018$Landings <- landings2018$Landings/1000 landings2019 <-
# aggregate(CATON~Area+Country, data = ic_clean[ic_clean$Year == '2019' &
# ic_clean$CatchCategory != 'Discards', ], FUN = sum) landings2019$Year <-
# as.factor(as.character(2019)) names(landings2019)[names(landings2019) ==
# 'CATON'] <- 'Landings' # landings2019$Landings <- landings2019$Landings/1000
# landings2020 <- aggregate(CATON~Area+Country, data = ic_clean[ic_clean$Year
# == '2020' & ic_clean$CatchCategory != 'Discards', ], FUN = sum)
# landings2020$Year <- as.factor(as.character(2020))
# names(landings2020)[names(landings2020) == 'CATON'] <- 'Landings'
# landings2021 <- aggregate(CATON~Area+Country, data = ic_clean[ic_clean$Year
# == '2021' & ic_clean$CatchCategory != 'Discards', ], FUN = sum)
# landings2021$Year <- as.factor(as.character(2021))
# names(landings2021)[names(landings2021) == 'CATON'] <- 'Landings'

# HistLand <- rbind(HistLand_raw, landings2018, landings2019, landings2020,
# landings2021)
HistLand <- rbind(HistLand_raw, landings)
getwd()

rm(list = c("HistLand_raw", "landings"))
# =====

k <- append(k, c("HistLand"))

Catch cohort matrices are set up externally in excel, according to the annually updated intercatch output (hidden chunk). This section needs to be updated so that the cohort matrices used to structure the figures are generated automagically with R, to remove the excel step

catchcohorts <- read.csv(file = "Data/ple.27.21-32_CohortMatrix_1998-WorkingYear.csv",
    header = T)
catchcohorts$Year <- as.factor(as.character(catchcohorts$Year))

# #=== # Attempts to create cohort matrix in R #==== for(i in
# 1:(length(1992:DataYear)+1)){ assign(x = paste0('cohort_',i), value =
# c(rep(NA, i-1), c(1:10),
# c(rep(NA,((length(1992:DataYear)+1)-min(10+(i-1),23)))) ) ) } catchcohorts <-
# do.call(cbind, mget(ls(pattern = 'cohort_'))) catchcohorts$Year <-
# 1992:(DataYear+1) #====

catchNum <- read.csv(file = "Data/ple.27.21-32_CatchNumAge_2002_DataYear.csv", header = T)
catchNum$Year <- as.factor(as.character(catchNum$Year))
k <- append(k, c("catchcohorts", "catchNum"))

2.1.1 Landings - Results

In more recent history, observers and other sampling programmes have been able to provide estimates of discarded portions of catch. Below we consider only the landings for the period when catch was divided into landings & discards.

# === Figure 3 Short term Landings by country ====
IC_agg_temp <- aggregate(CATON ~ Year + Country, data = ic_clean[ic_clean$CatchCategory ==
    "Landings", ], FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany",
    "Denmark", "Poland", "Latvia", "Lithuania", "Estonia", "Finland"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000

plt_land_ctry <- ggplot(data = IC_agg_temp, aes(x = Year, y = CATON, group = Country,
    fill = Country)) + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE) + ylab("Landings (t)") + theme_clean() + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1)) + scale_fill_manual(values = c("#004B87", "#000000",
    "#C60C30", ebpal))
ggplotly(plt_land_ctry)

Figure 2.1: Recent history landings by country

# ====

We can also interrogate the landings relative to the TACs for the respective management areas that this stock straddles. Namely the North Sea management area in SD21 (Kattegat), and the Baltic Sea management area covering the remainder of the stock; SD22-32.

# === Figure 4 Landings in 21 ====
IC_agg_temp <- aggregate(CATON ~ Year + Country, data = ic_clean[ic_clean$CatchCategory ==
    "Landings" & ic_clean$Area == "27.3.a.21", ], FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany",
    "Denmark"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000
TAC21 <- tac_raw[tac_raw$Area == "27.3.a.21" & tac_raw$Year %in% c(2002:DataYear),
    ]

plt_land_21 <- ggplot() + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE, data = IC_agg_temp, mapping = aes(x = Year, y = CATON, group = Country,
        fill = Country)) + geom_line(data = TAC21, mapping = aes(x = Year, y = TAC,
    group = Area, colour = Area), size = 2) + ylab("Landings (kg)") + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1)) + theme_clean() + scale_fill_manual(values = c("#004B87",
    "#000000", "#C60C30")) + scale_colour_manual(name = "TAC", values = "#7570b3",
    )

style(ggplotly(plt_land_21), showlegend = FALSE)

Figure 2.2: Recent history landings for the North Sea Management area in subdivision 21

# =====
# === Figure 5 Landings in 22 ====
IC_agg_temp <- aggregate(CATON ~ Year + Country, data = ic_clean[ic_clean$CatchCategory !=
    "Discards" & ic_clean$Area == "27.3.c.22", ], FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany",
    "Denmark"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000
TAC22 <- tac_raw[tac_raw$Area == "27.3.c.22" & tac_raw$Year %in% c(2002:DataYear),
    ]

plt_land_22 <- ggplot() + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE, data = IC_agg_temp, mapping = aes(x = Year, y = CATON, group = Country,
        fill = Country)) + geom_line(data = TAC22, mapping = aes(x = Year, y = TAC,
    group = Area), size = 2, colour = "#7570b3") + ylab("Landings (kg)") + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1)) + scale_fill_manual(values = c("#004B87", "#000000",
    "#C60C30"))

# ====
# === Figure 6 Landings in 23 ====
IC_agg_temp <- aggregate(CATON ~ Year + Country, data = ic_clean[ic_clean$CatchCategory !=
    "Discards" & ic_clean$Area == "27.3.b.23", ], FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany",
    "Denmark"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000
TAC23 <- tac_raw[tac_raw$Area == "27.3.b.23" & tac_raw$Year %in% c(2002:DataYear),
    ]

plt_land_23 <- ggplot() + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE, data = IC_agg_temp, mapping = aes(x = Year, y = CATON, group = Country,
        fill = Country)) + geom_line(data = TAC23, mapping = aes(x = Year, y = TAC,
    group = Area), size = 2, colour = "#7570b3") + ylab("Landings (kg)") + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1)) + scale_fill_manual(values = c("#004B87", "#C60C30"))

# ====
# === Figure 5 Landings in 22:32 ====
IC_agg_temp <- aggregate(CATON ~ Year + Country, data = ic_clean[ic_clean$CatchCategory ==
    "Landings" & ic_clean$Area != "27.3.a.21", ], FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany",
    "Denmark", "Poland", "Latvia", "Lithuania", "Estonia", "Finland"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000
TAC22 <- tac_raw[tac_raw$Area == "ple.27.22-32" & tac_raw$Year %in% c(2002:DataYear),
    ]

plt_land_22_32 <- ggplot() + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE, data = IC_agg_temp, mapping = aes(x = Year, y = CATON, group = Country,
        fill = Country)) + geom_line(data = TAC22, mapping = aes(x = Year, y = TAC,
    group = Area, colour = Area), size = 2) + ylab("Landings (kg)") + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1)) + theme_clean() + scale_fill_manual(values = c("#004B87",
    "#000000", "#C60C30", ebpal)) + scale_colour_manual(values = "#7570b3")

style(ggplotly(plt_land_22_32), showlegend = FALSE)

Figure 2.3: Recent history landings for the Baltic Sea Management area in subdivisions 22-32

# ====
#===
# Figure 7 Landings in all areas by country
#====
IC_agg_temp <- aggregate(CATON~Year+Country+Area,
                         data = ic_clean[ic_clean$CatchCategory != "Discards", ],
                         FUN = sum)
IC_agg_temp$Country <- factor(IC_agg_temp$Country, levels = c("Sweden", "Germany", "Denmark", "Poland", "Latvia", "Lithuania", "Estonia", "Finland"))
# IC_agg_temp$CATON <- IC_agg_temp$CATON.kg/1000
# TACall <- tac_raw[tac_raw$Year %in% c(2002:DataYear),]
TAC21 <- tac_raw[tac_raw$Area== "27.3.a.21" & tac_raw$Year %in% c(2002:DataYear+2), ]
TAC22 <- tac_raw[tac_raw$Area == "ple.27.22-32" & tac_raw$Year %in% c(2002:DataYear+2), ]


plt_land_all <- ggplot() +
  stat_summary(fun.y = sum,
               geom = "area",
               position = "stack",
               na.rm = TRUE,
               data = IC_agg_temp[IC_agg_temp$Area %in% c("27.3.a.21", "27.3.b.23", "27.3.c.22", "27.3.d.24", "27.3.d.25"),],
               mapping = aes(x = Year,
                             y = CATON,
                             group = Country,
                             fill = Country)) +
  geom_line(data = TAC21[TAC21$Area %in% c("27.3.a.21", "27.3.b.23", "27.3.c.22", "27.3.d.24", "27.3.d.25"),],
            mapping = aes(x = Year,
                          y = TAC),
            # size = 2,
            colour = ebpal[length(ebpal)-1]) +
  # geom_line(data = TAC22,
  #           mapping = aes(x = Year,
  #                         y = TAC),
  #           # size = 2,
  #           colour = ebpal[length(ebpal)-2]) +
  ylab("Landings (t)") +
  theme_clean()+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  scale_fill_manual(values = c("#004B87","#000000", "#C60C30", ebpal)) +
  facet_grid(rows = vars(Area))#, scales = "free_y")
ggplotly(plt_land_all)
#====
# === Figure of landings by gear type ====
IC_agg_temp <- aggregate(CATON ~ CatchCategory + Fleet + Year, data = ic_clean, FUN = sum)

plt_land_gear <- ggplot(data = IC_agg_temp[IC_agg_temp$CatchCategory == "Landings",
    ], aes(x = Year, y = CATON, group = Fleet, fill = Fleet)) + stat_summary(fun.y = sum,
    geom = "area", position = "stack", na.rm = TRUE) + ylab("Landings (Tons)") +
    theme_clean() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
    scale_fill_manual(values = ebpal[1:length(unique(IC_agg_temp$Fleet))])
ggplotly(plt_land_gear)

Figure 2.4: Recent history landings split by active and passive gears

2.1.2 Commercial Catches - Results

2.1.2.1 Catch Volume (Mass)

Catches for the year 2023 are summarised across different factors below and are given in tonnes.

IC_agg_temp <- aggregate(CATON ~ Area, data = ic_clean[ic_clean$Year == DataYear &
    ic_clean$CatchCategory %in% c("Landings", "Discards"), ], FUN = sum)

Proportion <- numeric()
for (i in IC_agg_temp$Area) {
    Proportion <- append(x = Proportion, values = IC_agg_temp[IC_agg_temp$Area ==
        i, "CATON"]/sum(IC_agg_temp[, "CATON"]))
}
IC_agg_temp <- cbind(IC_agg_temp, Proportion)

kable(IC_agg_temp, caption = paste0("Total commercial catch and proportion of catch of plaice, per area in ",
    DataYear, " (tonnes)."), digits = 2)
Table 2.1: Total commercial catch and proportion of catch of plaice, per area in 2023 (tonnes).
Area CATON Proportion
27.3.a.21 669.44 0.21
27.3.b.23 63.16 0.02
27.3.c.22 1808.06 0.57
27.3.d.24 551.52 0.17
27.3.d.25 96.80 0.03
27.3.d.26 3.67 0.00
27.3.d.27 0.00 0.00
27.3.d.28 0.00 0.00
27.3.d.29 0.00 0.00
27.3.d.31 0.00 0.00
kable(aggregate(CATON ~ Area + Fleet, data = ic_clean[ic_clean$Year == DataYear &
    ic_clean$CatchCategory %in% c("Landings", "Discards"), ], FUN = sum), caption = paste0("Total commercial catch of plaice, per area and by fleet, in ",
    DataYear, " (tonnes)."), digits = 2)
Table 2.2: Total commercial catch of plaice, per area and by fleet, in 2023 (tonnes).
Area Fleet CATON
27.3.a.21 Active 635.02
27.3.b.23 Active 2.09
27.3.c.22 Active 1225.14
27.3.d.24 Active 514.82
27.3.d.25 Active 82.57
27.3.d.26 Active 0.48
27.3.d.27 Active 0.00
27.3.d.28 Active 0.00
27.3.d.31 Active 0.00
27.3.a.21 Passive 34.42
27.3.b.23 Passive 61.07
27.3.c.22 Passive 582.92
27.3.d.24 Passive 36.70
27.3.d.25 Passive 14.23
27.3.d.26 Passive 3.19
27.3.d.27 Passive 0.00
27.3.d.28 Passive 0.00
27.3.d.29 Passive 0.00
kable(aggregate(CATON ~ Fleet2, data = ic_clean[ic_clean$Year == DataYear & ic_clean$CatchCategory %in%
    c("Landings", "Discards"), ], FUN = sum), caption = paste0("Total commercial catch of plaice, by new fleet concept (management area * fleet), in ",
    DataYear, " (tonnes)."), digits = 2)
Table 2.3: Total commercial catch of plaice, by new fleet concept (management area * fleet), in 2023 (tonnes).
Fleet2 CATON
BS_Active 1825.10
BS_Passive 698.11
NS_Active 635.02
NS_Passive 34.42
kable(aggregate(CATON ~ Area + Fleet2, data = ic_clean[ic_clean$Year == DataYear &
    ic_clean$CatchCategory %in% c("Landings", "Discards"), ], FUN = sum), caption = paste0("Total commercial catch of plaice, per area and new fleet concept (management area * fleet), in ",
    DataYear, " (tonnes)."), digits = 2)
Table 2.4: Total commercial catch of plaice, per area and new fleet concept (management area * fleet), in 2023 (tonnes).
Area Fleet2 CATON
27.3.b.23 BS_Active 2.09
27.3.c.22 BS_Active 1225.14
27.3.d.24 BS_Active 514.82
27.3.d.25 BS_Active 82.57
27.3.d.26 BS_Active 0.48
27.3.d.27 BS_Active 0.00
27.3.d.28 BS_Active 0.00
27.3.d.31 BS_Active 0.00
27.3.b.23 BS_Passive 61.07
27.3.c.22 BS_Passive 582.92
27.3.d.24 BS_Passive 36.70
27.3.d.25 BS_Passive 14.23
27.3.d.26 BS_Passive 3.19
27.3.d.27 BS_Passive 0.00
27.3.d.28 BS_Passive 0.00
27.3.d.29 BS_Passive 0.00
27.3.a.21 NS_Active 635.02
27.3.a.21 NS_Passive 34.42
# === Figure Catch by catch category (all areas, all countries) ====
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory + Area, data = ic_clean[!ic_clean$CatchCategory %in%
    c("BMS", "BMS landing", "Logbook Registered Discard", "Catch"), ], FUN = sum)

plt_catchcat <- ggplot() + stat_summary(fun.y = sum, geom = "area", position = "stack",
    na.rm = TRUE, data = IC_agg_temp, mapping = aes(x = Year, y = CATON, group = CatchCategory,
        fill = CatchCategory)) + ylab("Catch (Tons)") + theme_clean() + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1), strip.text = element_text(face = "bold", size = rel(0.75)),
    strip.background = element_blank()) + scale_fill_manual(values = c("#1b9e77",
    "#d95f02", "#7570b3", "grey")) + ylab("Catch (t)") + facet_wrap(facets = vars(Area),
    ncol = 2)  #, scales = 'free_y') +

style(ggplotly(plt_catchcat), showlegend = FALSE)

Figure 2.5: Commercial catch by catch category for all areas and all countries (tonnes).

# ====

2.1.2.2 Catch Numbers

We can also investigate stock structure by looking at numbers at age.

catchNumLng <- reshape(data = catchNum, varying = list(colnames(catchNum)[2:length((colnames(catchNum)))]),
    v.names = c("Number"), timevar = "Age", direction = "long")
catchNumLng$Age <- as.factor(as.character(catchNumLng$Age))
catchNumLng$Age <- factor(catchNumLng$Age, levels = c("1", "2", "3", "4", "5", "6",
    "7", "8", "9", "10"))
# catchNumLng$Year <- as.factor(as.character(catchNumLng$Year))
catchNumLng$Year <- as.numeric(as.character(catchNumLng$Year))

ggplotly(ggplot(catchNumLng) + geom_line(mapping = aes(x = Year, y = Number, colour = Age,
    group = Age)) + theme_few() + scale_colour_manual(values = ebpal))

2.1.2.3 Discards

Landings below minimum size (BMS landing) are estimated as part of the discards, due to expected poor reporting of official BMS landings. This means that in the assessment, we do not use reports of BMS. However, when reporting on BMS catch components, we must subtract official BMS landings from Discards. Prior to 2019 (<=2018), BMS landings were reported as part of landings.

## Aggregate catches by year and area
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory + Area, data = ic_clean[ic_clean$CatchCategory %in%
    c("Landings", "Discards"), ], FUN = sum)

disrat <- as.data.frame(reshape(IC_agg_temp, idvar = c("Year", "Area"), timevar = "CatchCategory",
    direction = "wide"))
disrat$DiscardRatio <- disrat$CATON.Discards/(disrat$CATON.Landings + disrat$CATON.Discards)
disrat$Area <- factor(disrat$Area, levels = c("27.3.a.21", "27.3.b.23", "27.3.c.22",
    "27.3.d.24", "27.3.d.25", "27.3.d.26", "27.3.d.27", "27.3.d.28", "27.3.d.28.2",
    "27.3.d.29", "27.3.d.30", "27.3.d.31", "27.3.d.32"))

## Aggregate catches by year and fleet
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory + Fleet2, data = ic_clean[ic_clean$CatchCategory %in%
    c("Landings", "Discards"), ], FUN = sum)

disratFleet <- as.data.frame(reshape(IC_agg_temp, idvar = c("Year", "Fleet2"), timevar = "CatchCategory",
    direction = "wide"))
disratFleet$DiscardRatio <- disratFleet$CATON.Discards/(disratFleet$CATON.Landings +
    disratFleet$CATON.Discards)


rownames(disrat) <- NULL
kable(disrat[disrat$Year == DataYear, c("Area", "DiscardRatio")], caption = paste0("Discard ratios by subdivision for ",
    DataYear, "."), digits = 3)
Table 2.5: Discard ratios by subdivision for 2023.
Area DiscardRatio
22 27.3.a.21 0.732
44 27.3.b.23 0.242
66 27.3.c.22 0.353
88 27.3.d.24 0.240
110 27.3.d.25 0.211
132 27.3.d.26 0.224
154 27.3.d.27 NA
172 27.3.d.28 NA
194 27.3.d.29 NA
222 27.3.d.31 NA
# === Figures of discard ratios ==== ## Bar chart plt_disrat_area <- ggplot() +
# geom_col(data = disrat, mapping = aes(x = Year, y = DiscardRatio, fill =
# Area), position = 'dodge') + scale_fill_manual(values = ebpal) + theme_bw() +
# theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))

## Line Chart
disrat$Year <- as.numeric(as.character(disrat$Year))
plt_disrat_area <- ggplot() + geom_line(data = disrat, mapping = aes(x = Year, y = DiscardRatio,
    colour = Area), size = 1.5, position = "dodge") + scale_colour_manual(values = ebpal) +
    theme_clean() + theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))

ggplotly(plt_disrat_area)

Figure 2.6: Discard ratios (proportion of total commercial catch discarded) by subdivision over time.

# =====

Plaice is considered a bycatch species in the Baltic Sea Management plan. In SD21 and 22 this remains to be the case where plaice are apparently caught in nephrops (SD21) and cod (SD21&22) fisheries, with some targeted coastal fisheries (especially in SD22&23). To further investigate the discard rates relative to landings by different fleets in the different managment areas, we can plot the two figures together. In doing so we make the discard ratios relative to the landings scale, thus the lines in the below figure show the relative contribution of discards to the catch compared to the maximum value (i.e. not absolute discard ratios, nor linked to the y-axis units).

# === Prepare data ====
IC_agg_temp <- droplevels(aggregate(CATON ~ Year + CatchCategory + Fleet2, data = ic_clean[ic_clean$CatchCategory ==
    "Landings", ], FUN = sum))
# disrat$Year <- as.factor(as.character(disrat$Year))
disratFleet$Year <- as.numeric(as.character(disratFleet$Year))
IC_agg_temp$Year <- as.numeric(as.character(IC_agg_temp$Year))

ylim.prim <- c(0, max(range(IC_agg_temp$CATON)))
ylim.sec <- c(0, max(range(disratFleet$DiscardRatio, na.rm = T)))
b <- diff(ylim.prim)/diff(ylim.sec)
a <- ylim.prim[1] - (b * ylim.sec[1])
# =====

# === Figure for advice after 2021: Discard Ratios and Landings over time ====
plt_catchcat <- ggplot() + geom_col(data = IC_agg_temp, mapping = aes(x = Year, y = CATON),
    fill = "#002b5f") + geom_line(data = disratFleet, mapping = aes(x = Year, y = a +
    DiscardRatio * b), colour = "#ed5f26", size = 1.5) + scale_y_continuous("Landings (tonnes)",
    sec.axis = sec_axis(~(. - a)/b, name = "Discard Ratio")) + theme_clean() + theme(axis.text.x = element_text(angle = 90,
    vjust = 0.5, hjust = 1), axis.line.y.right = element_line(color = "#ed5f26"),
    axis.ticks.y.right = element_line(color = "#ed5f26"), axis.text.y.right = element_text(color = "#ed5f26"),
    axis.title.y.right = element_text(color = "#ed5f26"), axis.line.y.left = element_line(color = "#002b5f"),
    axis.ticks.y.left = element_line(color = "#002b5f"), axis.text.y.left = element_text(color = "#002b5f"),
    axis.title.y.left = element_text(color = "#002b5f")) + facet_grid(rows = vars(Fleet2))
ggplotly(plt_catchcat)

Figure 2.7: Commercial catch as Landings (bars) and Discard Ratios as relative proportions (lines) over time by fleet and management area

# =====

In subdivision 22, the collapse of the cod fishery from the period 2015 onward, appears to show a greater retention of Plaice, while fishers were still targetting cod. Subsequently, as fishing opportunities for cod collapsed, the fisher for plaice also collapsed. This could be due to the lower overall effort, with a specific interest in what cod is available, or it could be due to the explosion in the plaice population. In the latter case, plaice are both caught more easily, while remaining unwanted, and their condition has been deteriorating, meaning a higher proportion of the catch is not marketable. Below we focus on SD22 and how catches and discard ratios have developed together over time.

# === Prepare data ====
IC_agg_temp <- droplevels(aggregate(CATON ~ Year + CatchCategory + Area, data = ic_clean[ic_clean$Area ==
    "27.3.c.22" & ic_clean$CatchCategory == "Landings", ], FUN = sum))
# disrat$Year <- as.factor(as.character(disrat$Year))
disrat$Year <- as.numeric(as.character(disrat$Year))
IC_agg_temp$Year <- as.numeric(as.character(IC_agg_temp$Year))

disrat <- disrat[disrat$Area == "27.3.c.22", ]

ylim.prim <- c(0, max(range(IC_agg_temp$CATON)))
ylim.sec <- c(0, max(range(disrat$DiscardRatio)))
b <- diff(ylim.prim)/diff(ylim.sec)
a <- ylim.prim[1] - (b * ylim.sec[1])
# =====

# === Figure of landings and discard ratios over time ====
plt_catchcat <- ggplot() + geom_col(data = IC_agg_temp, mapping = aes(x = Year, y = CATON),
    fill = "#002b5f") + geom_line(data = disrat, mapping = aes(x = Year, y = a +
    DiscardRatio * b), colour = "#ed5f26", size = 1.5) + scale_y_continuous("Landings (tonnes)",
    sec.axis = sec_axis(~(. - a)/b, name = "Discard Ratio")) + theme_clean() + theme(axis.text = element_text(size = 20),
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1), axis.line.y.right = element_line(color = "#ed5f26"),
    axis.ticks.y.right = element_line(color = "#ed5f26"), axis.text.y.right = element_text(color = "#ed5f26"),
    axis.title.y.right = element_text(color = "#ed5f26"), axis.line.y.left = element_line(color = "#002b5f"),
    axis.ticks.y.left = element_line(color = "#002b5f"), axis.text.y.left = element_text(color = "#002b5f"),
    axis.title.y.left = element_text(color = "#002b5f"))

ggplotly(plt_catchcat)

Figure 2.8: Discard Ratios (lines) and Landings (bars) over time in SD22 - the SW Baltic

# =====

These same trends are mirrored in the discard rates by country, where vessels mainly operating in 21 (i.e. Sweden) have the highest rates, those operating mainly in the Baltic (i.e. Poland and Germany) the lowest, and those operating in both have an intermediate level of discards (i.e. Denmark).

# === Prep data ====
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory + Country, data = ic_clean[ic_clean$CatchCategory %in%
    c("Landings", "Discards"), ], FUN = sum)

disrat <- as.data.frame(reshape(IC_agg_temp, idvar = c("Year", "Country"), timevar = "CatchCategory",
    direction = "wide"))
# disrat[is.na(disrat$CATON.BMS), 'CATON.BMS'] <- 0
disrat$DiscardRatio <- disrat$CATON.Discards/(disrat$CATON.Landings + disrat$CATON.Discards)
disrat$Country <- factor(disrat$Country, levels = c("Sweden", "Germany", "Denmark",
    "Poland", "Latvia", "Lithuania", "Estonia", "Finland"))
disrat$Year <- as.numeric(as.character(disrat$Year))
# =====

# === Figure Discard Ratios by Country ====
plt_disrat_country <- ggplot() + geom_line(data = disrat, mapping = aes(x = Year,
    y = DiscardRatio, colour = Country), size = 1.5, position = "dodge") + theme_clean() +
    scale_colour_manual(values = c("#004B87", "#000000", "#C60C30", ebpal))
ggplotly(plt_disrat_country)

Figure 2.9: Discard ratios (proportion of total catch discarded) by country over time

# ====

Drilling down into a bit more detail we can see where (subdivision), when (quarter) and by which general gear types the majority of catches (discards & landings) are taken.

#===
# Figure Discards/landings of DataYear by quarter and gear
#====
IC_agg_temp <- aggregate(CATON~Season+CatchCategory+Area+Fleet,
                         # data = ic_clean[ic_clean$Year == DataYear & ic_clean$Fleet %in% c("Active", "Passive"), ],
                         data = ic_clean[ic_clean$Year == DataYear & ic_clean$CatchCategory %in% c("Discards", "Landings"), ],
                         FUN = sum)
IC_agg_temp <- droplevels(IC_agg_temp)
#=====

#===
# Figure Discards/landings of DataYear by quarter and gear
#====
plt_disrat_Q_area <- ggplot() +
  geom_col(data = IC_agg_temp,
           mapping = aes(x = Season, 
                         y = CATON,
                         fill = CatchCategory)) + 
  facet_grid(rows = vars(Area),
             cols = vars(Fleet),
             scales = "free_y") +
  theme_clean() +
  theme(strip.background = element_blank(),
        strip.text = element_text(size = rel(0.75))) +
  scale_fill_manual(values = ebpal) +
  xlab("Quarter") +
  ylab("Catch (t)")

style(ggplotly(plt_disrat_Q_area), showlegend = FALSE)

Figure 2.10: Discards and landings from Current year by quarter and gear

#====
#===
# Figure Discards/landings of DataYear by quarter and gear
#====
IC_agg_temp <- aggregate(CATON~Area+CatchCategory+Fleet+Season,
                         # data = ic_clean[ic_clean$Year == DataYear & ic_clean$Fleet %in% c("Active", "Passive"), ],
                         data = ic_clean[ic_clean$Year == DataYear & ic_clean$CatchCategory %in% c("Discards", "Landings"), ],
                         FUN = sum)
IC_agg_temp <- droplevels(IC_agg_temp)
#=====

#===
# Reshape to make Quarters wide
#====
IC_agg_temp <- reshape(IC_agg_temp,
                       direction = "wide",
                       idvar = c("Area", "CatchCategory", "Fleet"),
                       timevar = "Season")
colnames(IC_agg_temp) <- c("Subdivision", "CatchCategory", "Fleet", "Q1", "Q2", "Q3", "Q4")
IC_agg_temp <- IC_agg_temp[order(IC_agg_temp$Subdivision, IC_agg_temp$CatchCategory, IC_agg_temp$Fleet), ]
#=====

kable(IC_agg_temp,
      caption = paste0("Commercial catch from ple.27.21-23 in ", DataYear, " by catch category, by fleet and over quarters (tonnes)."),
      digits = 0)
Table 2.6: Commercial catch from ple.27.21-23 in 2023 by catch category, by fleet and over quarters (tonnes).
Subdivision CatchCategory Fleet Q1 Q2 Q3 Q4
1 27.3.a.21 Discards Active 82 82 194 126
14 27.3.a.21 Discards Passive 1 1 3 1
6 27.3.a.21 Landings Active 42 21 44 45
19 27.3.a.21 Landings Passive 3 7 12 6
27 27.3.b.23 Discards Active NA 1 NA 1
15 27.3.b.23 Discards Passive 4 7 1 1
7 27.3.b.23 Landings Active 0 0 0 0
20 27.3.b.23 Landings Passive 13 14 15 5
2 27.3.c.22 Discards Active 327 129 14 154
16 27.3.c.22 Discards Passive 3 3 6 2
8 27.3.c.22 Landings Active 152 172 27 251
21 27.3.c.22 Landings Passive 237 173 101 58
3 27.3.d.24 Discards Active 1 18 75 35
17 27.3.d.24 Discards Passive 0 0 2 2
9 27.3.d.24 Landings Active 54 51 237 45
22 27.3.d.24 Landings Passive 2 14 15 2
4 27.3.d.25 Discards Active 4 8 5 3
18 27.3.d.25 Discards Passive 0 0 0 0
10 27.3.d.25 Landings Active 14 22 16 11
23 27.3.d.25 Landings Passive 2 6 4 0
5 27.3.d.26 Discards Active 0 NA NA NA
44 27.3.d.26 Discards Passive NA 0 0 1
11 27.3.d.26 Landings Active 0 0 0 0
24 27.3.d.26 Landings Passive 0 0 2 1
12 27.3.d.27 Landings Active 0 0 0 0
25 27.3.d.27 Landings Passive 0 0 0 0
13 27.3.d.28 Landings Active 0 0 0 0
52 27.3.d.28 Landings Passive NA 0 0 0
53 27.3.d.29 Landings Passive NA 0 0 0
94 27.3.d.31 Landings Active NA NA NA 0

Furthermore, we can split the discard rates by our new fleet concept, that of fleets by management area. This way different discard rates in different managemetn areas can be taken into consideration when setting TACs and other management devices.

# === Prep data ====
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory + Fleet2, data = ic_clean[ic_clean$CatchCategory %in%
    c("Landings", "Discards"), ], FUN = sum)

disrat <- as.data.frame(reshape(IC_agg_temp, idvar = c("Year", "Fleet2"), timevar = "CatchCategory",
    direction = "wide"))
# disrat[is.na(disrat$CATON.BMS), 'CATON.BMS'] <- 0
disrat$DiscardRatio <- disrat$CATON.Discards/(disrat$CATON.Landings + disrat$CATON.Discards)
disrat$Fleet2 <- factor(disrat$Fleet2, levels = c("NS_Active", "NS_Passive", "BS_Active",
    "BS_Passive"))
disrat$Year <- as.numeric(as.character(disrat$Year))
# =====

# === Figure Discard Ratios by Country ====
plt_disrat_country <- ggplot() + geom_line(data = disrat, mapping = aes(x = Year,
    y = DiscardRatio, colour = Fleet2), size = 1.5, position = "dodge") + theme_clean() +
    # facet_grid(Country~.) +
scale_colour_manual(values = ebpal)
ggplotly(plt_disrat_country)

Figure 2.11: Discard ratios (proportion of total commercial catch discarded) by management area and fleet, over time

# ====
# === Data agreggation ====
IC_agg_temp <- aggregate(CATON ~ Year + CatchCategory, data = ic_clean, FUN = sum)

disrat <- as.data.frame(reshape(IC_agg_temp, idvar = c("Year"), timevar = "CatchCategory",
    direction = "wide"))
disrat[is.na(disrat$CATON.BMS), "CATON.BMS"] <- 0
disrat$DiscardRatio <- disrat$CATON.Discards/(disrat$CATON.Landings + disrat$CATON.Discards)
mdr <- median(disrat$DiscardRatio, na.rm = T)
mdr3 <- mean(disrat[disrat$Year %in% c((DataYear - 2):(DataYear)), "DiscardRatio"],
    na.rm = T)
# =====

The general time trends for the whole stock are of less interest but are included in the report as a time series. The median of the time series is 0.3677652. The mean discard rate for the prior three years is 0.3589337.

# === Discard Ratios all together ====
plt_disrat <- ggplot() + geom_point(data = disrat, mapping = aes(x = Year, y = DiscardRatio),
    colour = ebpal[1]) + geom_line(data = disrat, mapping = aes(x = Year, y = DiscardRatio,
    group = 1), colour = ebpal[2]) + geom_hline(mapping = aes(yintercept = mdr),
    colour = ebpal[3]) + theme_clean() + theme(axis.text.x = element_text(angle = 90,
    hjust = 1, vjust = 0.5))
ggplotly(plt_disrat)

Figure 2.12: Annual discard ratio for the total stock over time. Orange line represents median of the time series.

# ====

2.1.3 Catches - advice sheet requirements

The advice sheets require specific information which is presented below

# === Aggregate catches in a format for use in the stock splitting table ====
IC_agg_temp <- aggregate(CATON ~ CatchCategory + Area, data = ic_clean[ic_clean$Year ==
    DataYear & ic_clean$CatchCategory %in% c("Landings", "Discards"), ], FUN = "sum")
IC_agg_temp <- reshape(IC_agg_temp, direction = "wide", idvar = "Area", timevar = "CatchCategory")
IC_agg_temp[is.na(IC_agg_temp$CATON.Discards), "CATON.Discards"] <- 0
IC_agg_temp$Catch <- IC_agg_temp$CATON.Discards + IC_agg_temp$CATON.Landings
# =====

kable(IC_agg_temp, caption = paste0("Catches by catch category and subdivision in ",
    DataYear, " (tonnes). _Used for the stock splitting table_."), digits = 2)
  • The catch from subdivisions 21, 22 & 23 combined in 2023 was 3192.66578 tonnes.
  • The landings from subdivisions 21, 22 & 23 combined in 2023 was 1894.59435 tonnes.
    • The percentage of landings that were taken in active gears was 63.4407624%.
    • The percentage of landings that were taken in passive gears was 36.5592376%.
  • The discards from subdivisions 21, 22 & 23 combined in 2023 was 1298.05243 tonnes.

The History of commercial catch and landings table in the advice sheet requires that BMS official landings are subtracted from the discard values. Need to determine the advice sheet resolution requirements (by stock, by management area, by subdivision etc.) before reworking this code to fit.

# === Aggregate and format Landings and Discards ====
IC_agg_temp <- aggregate(CATON ~ Area + CatchCategory + Country, data = ic_clean[ic_clean$Year ==
    DataYear, ], FUN = "sum")
adctchtble <- reshape(data = IC_agg_temp[IC_agg_temp$CatchCategory %in% c("Landings",
    "Discards"), ], direction = "wide", timevar = "Area", idvar = c("CatchCategory",
    "Country"))
# adctchtble[is.na(adctchtble$CATON.27.3.a.21), 'CATON.27.3.a.21'] <- 0
# adctchtble[is.na(adctchtble$CATON.27.3.b.23), 'CATON.27.3.b.23'] <- 0
# adctchtble[is.na(adctchtble$CATON.27.3.c.22), 'CATON.27.3.c.22'] <- 0
adctchtble <- data.table::transpose(adctchtble)
colnames(adctchtble) <- c("DK_Discards", "DK_Landings", "DE_Discards", "DE_Landings",
    "SK_Discards", "SK_Landings")
adctchtble <- adctchtble[3:5, ]
adctchtble <- as.data.frame(lapply(adctchtble, FUN = "as.numeric"))
# ====

# === Aggregate and format BMS Landings ====
IC_agg_temp1 <- aggregate(OfficialLandings.kg ~ Area + CatchCategory + Country, data = ic_clean[ic_clean$Year ==
    DataYear, ], FUN = "sum")
adbmstble <- reshape(data = IC_agg_temp1[IC_agg_temp1$CatchCategory %in% c("BMS landing"),
    ], direction = "wide", timevar = "Area", idvar = c("CatchCategory", "Country"))

# adbmstble[is.na(adbmstble$OfficialLandings.kg.27.3.a.21),
# 'OfficialLandings.kg.27.3.a.21'] <- 0
# adbmstble[is.na(adbmstble$OfficialLandings.kg.27.3.b.23),
# 'OfficialLandings.kg.27.3.b.23'] <- 0
# adbmstble[is.na(adbmstble$OfficialLandings.kg.27.3.c.22),
# 'OfficialLandings.kg.27.3.c.22'] <- 0
adbmstble <- data.table::transpose(adbmstble)
colnames(adbmstble) <- c("DK_BMS", "DE_BMS", "SK_BMS")
adbmstble <- adbmstble[3:5, ]
adbmstble <- as.data.frame(lapply(adbmstble, FUN = "as.numeric"))

## Convert from kg to tonnes
adbmstble <- adbmstble/1000
# ===== === Combine, subtract BMS from Discards & Restructure ==== Combine
adctchtble <- cbind(adctchtble, adbmstble)

## Replace NAs with zeros for accurate arithmetic
adctchtble[is.na(adctchtble)] <- 0

## Subtract BMS from discards
adctchtble$DK_Discards <- adctchtble$DK_Discards - adctchtble$DK_BMS
adctchtble$DE_Discards <- adctchtble$DE_Discards - adctchtble$DE_BMS
adctchtble$SK_Discards <- adctchtble$SK_Discards - adctchtble$SK_BMS

## Calculate total catch
IC_agg_temp <- aggregate(CATON ~ Area, data = ic_clean[ic_clean$Year == DataYear &
    ic_clean$CatchCategory %in% c("Landings", "Discards"), ], FUN = "sum")
adctchtble$TotalCatch <- IC_agg_temp$CATON

## Add subdivision information
adctchtble$Subdivision <- unique(IC_agg_temp$Area)

## Aggregate BMS across all countries
adctchtble$BMS <- rowSums(adctchtble[, c("DK_BMS", "DE_BMS", "SK_BMS")], na.rm = TRUE)

## Reformat
adctchtble <- adctchtble[, c("Subdivision", "DK_Discards", "DK_Landings", "DE_Discards",
    "DE_Landings", "SK_Discards", "SK_Landings", "BMS", "TotalCatch")]
# =====

# === Add Annual Totals ====
tots <- adctchtble[0, ]
for (i in 2:ncol(tots)) {
    tots[1, i] <- sum(adctchtble[, i], na.rm = TRUE)
}
tots$Subdivision <- as.character(DataYear)

adctchtble <- rbind(tots, adctchtble)
# =====



kable(adctchtble, caption = paste0("Official catch numbers by country and subdivision for ",
    DataYear, ".  Official landings of BMS have been subtracted from Discards. _can be copy-pasted into the advice sheet_."),
    digits = 0)

2.1.4 Commercial Sampling Coverage

Not all trips have observers or electronic monitoring to enable measurements of discard rates, or the sampling of all strata of fisheries for biological information. Therefore, raising is carried out to match unsampled strata with those where we have observations (this is currently done in intercatch). Each year, different portions of the fishery are sampled and to varying degrees, therefore there is no hard and fast rule about which strata should be matched. Rather, there are a set of priorities by which we try to match unsampled strata to sampled strata. These can be found in the stock annex. Below we explore the level of sampling coverage across the different strata for 2023 (using tonnage per category to derive proportions). Generally, this plaice stock is well covered by sampling and there are a minority of catches for which data are matched and assumptions are made.

# === Data wrangling and calculation of Raised/imported sampled/Estimated
# catches for Current Year ====
datacoverage_DY <- aggregate(CATON ~ CatchCategory + CATONRaisedOrImported + SampledOrEstimated,
    data = ic_clean[ic_clean$Year == DataYear, ], FUN = sum)
lnd_DY <- sum(datacoverage_DY[datacoverage_DY$CatchCategory == "Landings", "CATON"])
disc_DY <- sum(datacoverage_DY[datacoverage_DY$CatchCategory %in% c("Discards"),
    "CATON"])

datacoverage_DY$Proportion <- NA
datacoverage_DY[datacoverage_DY$CatchCategory == "Landings" & datacoverage_DY$SampledOrEstimated ==
    "Sampled_Distribution", "Proportion"] <- datacoverage_DY[datacoverage_DY$CatchCategory ==
    "Landings" & datacoverage_DY$SampledOrEstimated == "Sampled_Distribution", "CATON"]/lnd_DY
datacoverage_DY[datacoverage_DY$CatchCategory == "Landings" & datacoverage_DY$SampledOrEstimated ==
    "Estimated_Distribution", "Proportion"] <- datacoverage_DY[datacoverage_DY$CatchCategory ==
    "Landings" & datacoverage_DY$SampledOrEstimated == "Estimated_Distribution",
    "CATON"]/lnd_DY

datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" & datacoverage_DY$SampledOrEstimated ==
    "Sampled_Distribution" & datacoverage_DY$CATONRaisedOrImported == "Imported_Data",
    "Proportion"] <- datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" &
    datacoverage_DY$SampledOrEstimated == "Sampled_Distribution" & datacoverage_DY$CATONRaisedOrImported ==
    "Imported_Data", "CATON"]/disc_DY
datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" & datacoverage_DY$SampledOrEstimated ==
    "Estimated_Distribution" & datacoverage_DY$CATONRaisedOrImported == "Imported_Data",
    "Proportion"] <- datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" &
    datacoverage_DY$SampledOrEstimated == "Estimated_Distribution" & datacoverage_DY$CATONRaisedOrImported ==
    "Imported_Data", "CATON"]/disc_DY
datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" & datacoverage_DY$SampledOrEstimated ==
    "Estimated_Distribution" & datacoverage_DY$CATONRaisedOrImported == "Raised_Discards",
    "Proportion"] <- datacoverage_DY[datacoverage_DY$CatchCategory == "Discards" &
    datacoverage_DY$SampledOrEstimated == "Estimated_Distribution" & datacoverage_DY$CATONRaisedOrImported ==
    "Raised_Discards", "CATON"]/disc_DY

datacoverage_DY$Source <- paste(datacoverage_DY$SampledOrEstimated, datacoverage_DY$CATONRaisedOrImported,
    sep = "\n")
datacoverage_DY$Source <- as.factor(datacoverage_DY$Source)
datacoverage_DY$Source <- factor(datacoverage_DY$Source, levels = c("Estimated_Distribution\nRaised_Discards",
    "Estimated_Distribution\nImported_Data", "Sampled_Distribution\nImported_Data"))
datacoverage_DY <- droplevels(datacoverage_DY)
# =====
# === Figure of sampling coverage for DataYear ====
plt_dataCover <- ggplot() + geom_col(data = datacoverage_DY[!datacoverage_DY$CatchCategory %in%
    c("BMS", "BMS landing", "Logbook Registered Discard", "Catch"), ], mapping = aes(x = CatchCategory,
    y = Proportion, fill = Source)) + theme_clean() + scale_fill_manual(values = c("#1b9e77",
    "#d95f02", "#7570b3"))
ggplotly(plt_dataCover)

Figure 2.13: Proportions of catch components that were sampled for biological data, and the proportion of discards that were raised by pairing with reported discard data. Proportions are made with catch tonnage by strata (fleet, area, country, quarter) for the year 2023

# =====
# === Tabulate for presentation ====
dcDYtab <- datacoverage_DY[datacoverage_DY$CatchCategory %in% c("Landings", "Discards"),
    c("CatchCategory", "Source", "CATON", "Proportion")]
dcDYtab$InfoSource <- gsub(pattern = "\\\n", replacement = " and ", dcDYtab$Source)
dcDYtab <- dcDYtab[dcDYtab$CatchCategory %in% c("Landings", "Discards"), c("CatchCategory",
    "InfoSource", "CATON", "Proportion")]
rownames(dcDYtab) <- NULL
dcDYtab$CATON <- round(dcDYtab$CATON, digits = 0)
dcDYtab$Proportion <- icesRound(dcDYtab$Proportion * 100, percent = TRUE, sign = FALSE)

kable(dcDYtab, caption = paste0("Proportions of catch components that were sampled for biological data, and the proportion of discards that were raised by pairing with reported discard data.  Proportions are made with catch tonnage by strata (fleet, area, country, quarter) for the year ",
    DataYear))
Table 2.7: Proportions of catch components that were sampled for biological data, and the proportion of discards that were raised by pairing with reported discard data. Proportions are made with catch tonnage by strata (fleet, area, country, quarter) for the year 2023
CatchCategory InfoSource CATON Proportion
Discards Estimated_Distribution and Imported_Data 9 0.70%
Landings Estimated_Distribution and Imported_Data 400 21%
Discards Estimated_Distribution and Raised_Discards 201 15.5%
Discards Sampled_Distribution and Imported_Data 1088 84%
Landings Sampled_Distribution and Imported_Data 1495 79%
# =====
# === Data wrangling ====
IC_agg_temp <- aggregate(cbind(CATON, No.of.length.sanples, No.length.mesures, No.of.age.samples,
    No.of.age.readings) ~ Area + CatchCategory + Country + Fleet, data = ic_clean[ic_clean$CatchCategory %in%
    c("Landings", "Discards") & ic_clean$Year == DataYear, ], FUN = "sum")
colnames(IC_agg_temp) <- c("Subdivision", "CatchCategory", "Country", "Fleet", "Catch(tonnes)",
    "LengthSamples", "LengthsMeasured", "AgeSamples", "AgesRead")
samptable <- IC_agg_temp[order(IC_agg_temp$Subdivision, IC_agg_temp$CatchCategory,
    IC_agg_temp$Country, IC_agg_temp$Fleet), ]
samptable$`Catch(tonnes)` <- round(samptable$`Catch(tonnes)`, digits = 3)
# =====

# === ====
rownames(samptable) <- NULL
kable(samptable, caption = paste0("Sampling effort in ", DataYear, " by strata."))
Table 2.8: Sampling effort in 2023 by strata.
Subdivision CatchCategory Country Fleet Catch(tonnes) LengthSamples LengthsMeasured AgeSamples AgesRead
27.3.a.21 Discards Denmark Active 388.544 39 3072 39 551
27.3.a.21 Discards Denmark Passive 3.525 0 0 0 0
27.3.a.21 Discards Germany Active 7.554 0 0 0 0
27.3.a.21 Discards Germany Passive 0.348 0 0 0 0
27.3.a.21 Discards Sweden Active 88.018 27 2496 30 1121
27.3.a.21 Discards Sweden Passive 2.235 3 163 15 671
27.3.a.21 Landings Denmark Active 136.852 17 3050 17 616
27.3.a.21 Landings Denmark Passive 25.286 17 3050 17 616
27.3.a.21 Landings Germany Active 1.771 0 0 0 0
27.3.a.21 Landings Germany Passive 1.436 0 0 0 0
27.3.a.21 Landings Sweden Active 12.279 0 0 0 0
27.3.a.21 Landings Sweden Passive 1.592 0 0 0 0
27.3.b.23 Discards Denmark Active 1.584 0 0 0 0
27.3.b.23 Discards Denmark Passive 9.726 4 208 4 37
27.3.b.23 Discards Sweden Passive 3.987 0 0 0 0
27.3.b.23 Landings Denmark Active 0.506 0 0 0 0
27.3.b.23 Landings Denmark Passive 39.614 0 0 0 0
27.3.b.23 Landings Sweden Passive 7.744 0 0 0 0
27.3.c.22 Discards Denmark Active 265.661 6 609 6 86
27.3.c.22 Discards Denmark Passive 7.596 10 210 10 54
27.3.c.22 Discards Germany Active 358.402 4 2703 4 406
27.3.c.22 Discards Germany Passive 7.077 15 113 15 45
27.3.c.22 Landings Denmark Active 303.055 45 9032 45 1706
27.3.c.22 Landings Denmark Passive 247.115 45 9032 45 1706
27.3.c.22 Landings Germany Active 298.019 4 1372 4 536
27.3.c.22 Landings Germany Passive 321.134 21 9744 21 1289
27.3.d.24 Discards Denmark Active 44.533 0 0 0 0
27.3.d.24 Discards Denmark Passive 0.075 0 0 0 0
27.3.d.24 Discards Germany Active 58.850 5 1275 5 221
27.3.d.24 Discards Germany Passive 2.911 3 8 3 7
27.3.d.24 Discards Poland Active 25.384 0 0 0 0
27.3.d.24 Discards Poland Passive 0.748 0 0 0 0
27.3.d.24 Discards Sweden Passive 0.068 0 0 0 0
27.3.d.24 Landings Denmark Active 165.153 0 0 0 0
27.3.d.24 Landings Denmark Passive 1.091 0 0 0 0
27.3.d.24 Landings Germany Active 146.961 5 1026 5 239
27.3.d.24 Landings Germany Passive 16.144 6 594 6 204
27.3.d.24 Landings Poland Active 73.935 0 0 0 0
27.3.d.24 Landings Poland Passive 15.055 0 0 0 0
27.3.d.24 Landings Sweden Passive 0.609 0 0 0 0
27.3.d.25 Discards Denmark Active 2.148 4 358 4 60
27.3.d.25 Discards Denmark Passive 0.062 0 0 0 0
27.3.d.25 Discards Germany Active 2.130 1 5 1 5
27.3.d.25 Discards Poland Active 15.361 0 0 0 0
27.3.d.25 Discards Poland Passive 0.567 0 0 0 0
27.3.d.25 Discards Sweden Passive 0.138 0 0 0 0
27.3.d.25 Landings Denmark Active 0.757 4 123 0 0
27.3.d.25 Landings Denmark Passive 2.143 0 0 0 0
27.3.d.25 Landings Germany Active 1.260 0 0 0 0
27.3.d.25 Landings Poland Active 60.918 1 152 1 50
27.3.d.25 Landings Poland Passive 10.246 0 0 0 0
27.3.d.25 Landings Sweden Passive 1.074 0 0 0 0
27.3.d.26 Discards Germany Active 0.000 0 0 0 0
27.3.d.26 Discards Poland Passive 0.821 0 0 0 0
27.3.d.26 Landings Denmark Active 0.000 0 0 0 0
27.3.d.26 Landings Denmark Passive 0.000 0 0 0 0
27.3.d.26 Landings Germany Active 0.479 0 0 0 0
27.3.d.26 Landings Lithuania Active 0.000 0 0 0 0
27.3.d.26 Landings Lithuania Passive 0.000 0 0 0 0
27.3.d.26 Landings Poland Active 0.000 0 0 0 0
27.3.d.26 Landings Poland Passive 2.367 0 0 0 0
27.3.d.27 Landings Denmark Active 0.000 0 0 0 0
27.3.d.27 Landings Denmark Passive 0.000 0 0 0 0
27.3.d.27 Landings Sweden Passive 0.000 0 0 0 0
27.3.d.28 Landings Lithuania Active 0.000 0 0 0 0
27.3.d.28 Landings Sweden Passive 0.000 0 0 0 0
27.3.d.29 Landings Sweden Passive 0.000 0 0 0 0
27.3.d.31 Landings Sweden Active 0.000 0 0 0 0

2.2 Survey Indices

This stock utilises data from four surveys. A combination of 1st quarter NS-IBTS and the 1st quarter BITS on the one hand, and the combination of 3rd quarter NS-IBTS and 4th quarter BITS on the other.

Currently, these indices are generated by Casper Berg from DTU Aqua, using a method he published in 2014. An adaptation of Casper’s method is in progress. Description of new model and updated indices need to be provided in this section once ready.

# ## 2019 Q3/4 data excluded from calculation of indices
survTun <- read.csv(file = "Data/ple.27.21-23_SurveyTuning_IBTS-BITS_1992-DataYear_2019Q34Excluded.csv",
    header = T)
k <- append(k, "survTun")
# === Data prep ====
survTunLng <- reshape(data = survTun, varying = list(colnames(survTun)[3:length((colnames(survTun)))]),
    v.names = c("Index"), timevar = "Age", direction = "long")
survTunLng$Age <- as.factor(as.character(survTunLng$Age))
survTunLng$Year <- as.factor(as.character(survTunLng$Year))
k <- append(k, "survTunLng")
# =====

# === Figure 12 Survey Tuning Indices over time ====
set.seed(5)
plt_survTun <- ggplot() + geom_line(data = survTunLng, mapping = aes(x = Year, y = Index,
    group = Age, colour = Age), size = 1.25) + facet_grid(rows = vars(Survey), scales = "free_y") +
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + theme_clean()
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + +
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + #
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + scale_colour_manual(values
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + =
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + sample(ebpal,
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + size
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + =
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + length(levels(survTunLng$Age))))
    theme_clean() + # scale_colour_manual(values = sample(ebpal, size = length(levels(survTunLng$Age)))) + +
scale_colour_manual(values = ebpal) + theme(axis.text.x = element_text(angle = 90,
    vjust = 1))

ggplotly(plt_survTun)

Figure 2.14: NS-IBTS & BITS derived tuning indices for ple.27.21-23 Q1 and Q3/4.

# ====
# include_graphics(path = paste0('../', DataYear+1,
# '/SurveyIndices/CasperCalculations/ICQ1.png'))

# === Alternate code for including multiple plots ====
include_graphics(path = paste0("../", DataYear + 1, "/SurveyIndices/CasperCalculations/",
    list.files(path = paste0("../", DataYear + 1, "/SurveyIndices/CasperCalculations"),
        pattern = "Q1.png")))
# =====
# === Alternate code for including multiple graphics ====
xmatches <- intersect(grep(pattern = ".png", x = list.files(path = paste0("../",
    DataYear + 1, "/SurveyIndices/CasperCalculations"))), grep(pattern = "2019",
    x = list.files(path = paste0("../", DataYear + 1, "/SurveyIndices/CasperCalculations"))))
include_graphics(path = paste0("../", DataYear + 1, "/SurveyIndices/CasperCalculations/",
    list.files(path = paste0("../", DataYear + 1, "/SurveyIndices/CasperCalculations"))[xmatches]))
# =====

2.3 Biological Data

To begin with we need survey data. These can be downloaded muliple ways from DATRAS but we need the DATRAS Exchange files (HH, CA, HL). The script 01_DatrasDownloads.R downloads all exchange data for NS-IBTS and BITS surveys and saves the results as .CSV files which we can use here.

2.3.1 Reading, Subsetting and Cleaning

## Reading layer `ICES_Areas_20160601_cut_dense_3857' from data source 
##   `C:\Users\elbr\OneDrive - Danmarks Tekniske Universitet\Advisory Requests\ICES\WGBFAS\WKBPLAICE 2024\Data\ICES_areas' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 66 features and 10 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -4898058 ymin: 4300621 xmax: 7625385 ymax: 30240970
## Projected CRS: WGS 84 / Pseudo-Mercator

2.3.2 Maturity Ogives (MO)

The maturity ogives utilised in the assessment are the mean maturity at age from 2002 until the present data year. Values are mean proportion mature at ages one through ten.

The data used to derive these maturity ogives come from quarter one of the NS-IBTS and BITS surveys, where the subsetting of relevant areas and species, as well as the merging of the two data series is carried out in the above section. These data come from the raw DATRAS Exchange products, not the SMALK products. This is important because we are subsetting and combining data sources, so the raising procedure needs to be done independently.

This section contains hidden chunks of code that prepare the data, generate the current ogives for the assessment and plot these out in a figure for presentations/reporting.

# === First prepare maturity data for calculating MOs ---- === Select data for
# use in this script by removing rows without relevant observations
ca <- subset(ca_hh_fin_bits_ibts, Quarter == 1 & Age != -9 & Age != 0)
hl <- subset(hl_hh_fin_bits_ibts, Quarter == 1)

# Re-code the spawning status so that they are all uniform and simplified from
# maturity stage to binary
ca$spawner <- NA
ca$nonspawner <- NA

ca$spawner <- ifelse(ca$Maturity %in% c("61", "I", "1", "A", "B", "Bb"), 0, ifelse(ca$Maturity %in%
    c("II", "III", "IV", "IX", "M", "62", "63", "64", "65", "2", "3", "4", "5", "Ba",
        "C", "Ca", "Cb", "D", "Da", "Db", "E"), 1, "NA"))

ca$nonspawner <- ifelse(ca$Maturity %in% c("61", "I", "1", "A", "B", "Bb"), 1, ifelse(ca$Maturity %in%
    c("II", "III", "IV", "IX", "M", "62", "63", "64", "65", "2", "3", "4", "5", "Ba",
        "C", "Ca", "Cb", "D", "Da", "Db", "E"), 0, "NA"))
ca$spawner <- as.numeric(as.character(ca$spawner))
ca$nonspawner <- as.numeric(as.character(ca$nonspawner))

# Sort the data
ca <- ca[order(ca$Year, ca$SubDivisio, ca$Sex, ca$Age, ca$LngtClass, ca$spawner,
    ca$nonspawner), ]

cax <- ca[is.na(ca$spawner) & is.na(ca$nonspawner), ]

# Calculate number of fish (mature or immature) by year+sex+age+LngtClass
maturity_lngt <- aggregate(cbind(spawner, nonspawner) ~ Year + Sex + Age + LngtClass,
    data = ca, FUN = sum)
# ====

# === Calculate length frequencies from at sea observations ---- === Establish
# parameters for calculations
lencl <- c(4:60)
age <- c(1:10)
year <- c(1999:(DataYear + 1))

# Make table for length freq data
length_freq_tmp <- by(hl, list(hl$Year, round(hl$LngtClass)), function(x) {
    sum(x$HLNoAtLngt_1)
})
length_freq_tab <- t(as.table(length_freq_tmp))

Lfreq_sea <- data.frame(year = rep(year, each = length(lencl)), LngtClass = rep(lencl,
    length(year)), HLNoLngt = NA)

# Fill the table
for (i in c(1:nrow(Lfreq_sea))) {
    year_i <- Lfreq_sea[i, names(Lfreq_sea) == as.character("year")]
    lencl_i <- Lfreq_sea[i, names(Lfreq_sea) == as.character("LngtClass")]

    if (lencl_i %in% c(as.numeric(dimnames(length_freq_tab)[[1]]))) {

        data_i <- length_freq_tab[as.numeric(dimnames(length_freq_tab)[[1]]) == lencl_i,
            dimnames(length_freq_tab)[[2]] == year_i]
        Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")] <- data_i

    } else {
        Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")] <- 0
    }
}

# Replace NA with 0
Lfreq_sea[which(is.na(Lfreq_sea$HLNoLngt)), names(Lfreq_sea) == as.character("HLNoLngt")] <- 0
# ====

# === Calculate proportions from sampled data (observations) ---- === Make a
# table for number of fish sampled, for spawner and non-spawner
nr_fish_samp_sp_F <- data.frame(year = rep(year, each = length(lencl)), lencl = rep(lencl,
    times = length(year)), a1 = NA, a2 = NA, a3 = NA, a4 = NA, a5 = NA, a6 = NA,
    a7 = NA, a8 = NA, a9 = NA, a10 = NA)
nr_fish_samp_nonsp_F <- nr_fish_samp_sp_F
nr_fish_samp_sp_M <- nr_fish_samp_sp_F
nr_fish_samp_nonsp_M <- nr_fish_samp_sp_F

# Fill the table with how many fish have been sampled (mature, immature) Female
for (i in 1:nrow(nr_fish_samp_sp_F)) {
    for (j in 3:ncol(nr_fish_samp_sp_F)) {
        lencl_i <- nr_fish_samp_sp_F[i, names(nr_fish_samp_sp_F) == as.character("lencl")]
        age_i <- j - 2
        year_i <- nr_fish_samp_sp_F[i, names(nr_fish_samp_sp_F) == as.character("year")]

        if (lencl_i %in% maturity_lngt[which(maturity_lngt$Year == year_i & maturity_lngt$Sex ==
            as.character("F") & maturity_lngt$Age == age_i), names(maturity_lngt) ==
            as.character("LngtClass")]) {

            show_data <- maturity_lngt[which(maturity_lngt$Year == year_i & maturity_lngt$LngtClass ==
                lencl_i & maturity_lngt$Sex == as.character("F") & maturity_lngt$Age ==
                age_i), ]

            nr_fish_samp_sp_F[i, j] <- sum(show_data$spawner)
            nr_fish_samp_nonsp_F[i, j] <- sum(show_data$nonspawner)

        } else {

            nr_fish_samp_sp_F[i, j] <- 0
            nr_fish_samp_nonsp_F[i, j] <- 0
        }
    }
}

## Male
for (i in 1:nrow(nr_fish_samp_sp_M)) {
    for (j in 3:ncol(nr_fish_samp_sp_M)) {

        lencl_i <- nr_fish_samp_sp_M[i, names(nr_fish_samp_sp_M) == as.character("lencl")]
        age_i <- j - 2
        year_i <- nr_fish_samp_sp_M[i, names(nr_fish_samp_sp_M) == as.character("year")]

        if (lencl_i %in% maturity_lngt[which(maturity_lngt$Year == year_i & maturity_lngt$Sex ==
            as.character("M") & maturity_lngt$Age == age_i), names(maturity_lngt) ==
            as.character("LngtClass")]) {

            show_data <- maturity_lngt[which(maturity_lngt$Year == year_i & maturity_lngt$LngtClass ==
                lencl_i & maturity_lngt$Sex == as.character("M") & maturity_lngt$Age ==
                age_i), ]

            nr_fish_samp_sp_M[i, j] <- sum(show_data$spawner)
            nr_fish_samp_nonsp_M[i, j] <- sum(show_data$nonspawner)

        } else {

            nr_fish_samp_sp_M[i, j] <- 0
            nr_fish_samp_nonsp_M[i, j] <- 0
        }
    }
}

# Total number of fish sampled (immature+mature) by length
nr_fish_sampled_tot <- nr_fish_samp_sp_F[, 1:5]
nr_fish_sampled_tot[, 3:ncol(nr_fish_sampled_tot)] <- NA
names(nr_fish_sampled_tot)[3:ncol(nr_fish_sampled_tot)] <- c("F_sp_nonsp", "M_sp_nonsp",
    "F_M_tot")

for (i in 1:nrow(nr_fish_sampled_tot)) {
    f_sp <- sum(nr_fish_samp_sp_F[i, 3:ncol(nr_fish_samp_sp_F)])
    f_nonsp <- sum(nr_fish_samp_nonsp_F[i, 3:ncol(nr_fish_samp_nonsp_F)])

    m_sp <- sum(nr_fish_samp_sp_M[i, 3:ncol(nr_fish_samp_sp_M)])
    m_nonsp <- sum(nr_fish_samp_nonsp_M[i, 3:ncol(nr_fish_samp_nonsp_M)])

    nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("F_sp_nonsp")] <- f_sp +
        f_nonsp
    nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("M_sp_nonsp")] <- m_sp +
        m_nonsp
    nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("F_M_tot")] <- f_sp +
        f_nonsp + m_sp + m_nonsp
}

# Total number of fish sampled, by age
sum_nr_sampl_age_sp_F <- data.frame(year = year, a1 = NA, a2 = NA, a3 = NA, a4 = NA,
    a5 = NA, a6 = NA, a7 = NA, a8 = NA, a9 = NA, a10 = NA)
sum_nr_sampl_age_nonsp_F <- sum_nr_sampl_age_sp_F
sum_nr_sampl_age_sp_M <- sum_nr_sampl_age_sp_F
sum_nr_sampl_age_nonsp_M <- sum_nr_sampl_age_sp_F

## Female
for (i in 1:nrow(sum_nr_sampl_age_sp_F)) {
    for (j in 2:ncol(sum_nr_sampl_age_sp_F)) {

        i_year <- sum_nr_sampl_age_sp_F[i, names(sum_nr_sampl_age_sp_F) == as.character("year")]
        sum_nr_sampl_age_sp_F[i, j] <- sum(nr_fish_samp_sp_F[which(nr_fish_samp_sp_F$year ==
            i_year), names(nr_fish_samp_sp_F) == names(sum_nr_sampl_age_sp_F)[j]])
    }
}
#
for (i in 1:nrow(sum_nr_sampl_age_nonsp_F)) {
    for (j in 2:ncol(sum_nr_sampl_age_nonsp_F)) {

        i_year <- sum_nr_sampl_age_nonsp_F[i, names(sum_nr_sampl_age_nonsp_F) ==
            as.character("year")]
        sum_nr_sampl_age_nonsp_F[i, j] <- sum(nr_fish_samp_nonsp_F[which(nr_fish_samp_nonsp_F$year ==
            i_year), names(nr_fish_samp_nonsp_F) == names(sum_nr_sampl_age_nonsp_F)[j]])
    }
}

## Male
for (i in 1:nrow(sum_nr_sampl_age_sp_M)) {
    for (j in 2:ncol(sum_nr_sampl_age_sp_M)) {

        i_year <- sum_nr_sampl_age_sp_M[i, names(sum_nr_sampl_age_sp_M) == as.character("year")]
        sum_nr_sampl_age_sp_M[i, j] <- sum(nr_fish_samp_sp_M[which(nr_fish_samp_sp_M$year ==
            i_year), names(nr_fish_samp_sp_M) == names(sum_nr_sampl_age_sp_M)[j]])
    }
}
#
for (i in 1:nrow(sum_nr_sampl_age_nonsp_M)) {
    for (j in 2:ncol(sum_nr_sampl_age_nonsp_M)) {

        i_year <- sum_nr_sampl_age_nonsp_M[i, names(sum_nr_sampl_age_nonsp_M) ==
            as.character("year")]
        sum_nr_sampl_age_nonsp_M[i, j] <- sum(nr_fish_samp_nonsp_M[which(nr_fish_samp_nonsp_M$year ==
            i_year), names(nr_fish_samp_nonsp_M) == names(sum_nr_sampl_age_nonsp_M)[j]])
    }
}
# ====

# === Raise proportions to unsampled strata ---- === Make tables
nr_fish_sea_sp_F <- nr_fish_samp_sp_F
nr_fish_sea_sp_F[, 3:ncol(nr_fish_sea_sp_F)] <- NA

nr_fish_sea_nonsp_F <- nr_fish_sea_sp_F
nr_fish_sea_sp_M <- nr_fish_sea_sp_F
nr_fish_sea_nonsp_M <- nr_fish_sea_sp_F

# Numbers at sea by maturity class by length Female spawner
for (i in 1:nrow(nr_fish_sea_sp_F)) {
    for (j in 3:ncol(nr_fish_sea_sp_F)) {

        if (nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("F_sp_nonsp")] >
            0) {
            mat_tot_ratio <- nr_fish_samp_sp_F[i, j]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_sp_nonsp")]
            female_tot_ratio <- nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_sp_nonsp")]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_M_tot")]

            tot_len <- Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")]
            nr_fish_sea_sp_F[i, j] <- mat_tot_ratio * female_tot_ratio * tot_len
        } else {
            nr_fish_sea_sp_F[i, j] <- 0
        }
    }
}

## Female nonspawner
for (i in 1:nrow(nr_fish_sea_nonsp_F)) {
    for (j in 3:ncol(nr_fish_sea_nonsp_F)) {

        if (nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("F_sp_nonsp")] >
            0) {
            mat_tot_ratio <- nr_fish_samp_nonsp_F[i, j]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_sp_nonsp")]
            female_tot_ratio <- nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_sp_nonsp")]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_M_tot")]

            tot_len <- Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")]
            nr_fish_sea_nonsp_F[i, j] <- mat_tot_ratio * female_tot_ratio * tot_len
        } else {
            nr_fish_sea_nonsp_F[i, j] <- 0
        }
    }
}

## Male spawner
for (i in 1:nrow(nr_fish_sea_sp_M)) {
    for (j in 3:ncol(nr_fish_sea_sp_M)) {

        if (nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("M_sp_nonsp")] >
            0) {
            mat_tot_ratio <- nr_fish_samp_sp_M[i, j]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("M_sp_nonsp")]
            male_tot_ratio <- nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("M_sp_nonsp")]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_M_tot")]

            tot_len <- Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")]
            nr_fish_sea_sp_M[i, j] <- mat_tot_ratio * male_tot_ratio * tot_len
        } else {
            nr_fish_sea_sp_M[i, j] <- 0
        }
    }
}

## Male non-spawner
for (i in 1:nrow(nr_fish_sea_nonsp_M)) {
    for (j in 3:ncol(nr_fish_sea_nonsp_M)) {

        if (nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) == as.character("M_sp_nonsp")] >
            0) {
            mat_tot_ratio <- nr_fish_samp_nonsp_M[i, j]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("M_sp_nonsp")]
            male_tot_ratio <- nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("M_sp_nonsp")]/nr_fish_sampled_tot[i, names(nr_fish_sampled_tot) ==
                as.character("F_M_tot")]

            tot_len <- Lfreq_sea[i, names(Lfreq_sea) == as.character("HLNoLngt")]
            nr_fish_sea_nonsp_M[i, j] <- mat_tot_ratio * male_tot_ratio * tot_len
        } else {
            nr_fish_sea_nonsp_M[i, j] <- 0
        }
    }
}

# Sum of numbers at sea, by maturity class, by ages (sum over length-groups) -
# generate tables
sum_nr_sea_age_sp_F <- sum_nr_sampl_age_sp_F
sum_nr_sea_age_sp_F[, -1] <- NA

sum_nr_sea_age_nonsp_F <- sum_nr_sea_age_sp_F
sum_nr_sea_age_sp_M <- sum_nr_sea_age_sp_F
sum_nr_sea_age_nonsp_M <- sum_nr_sea_age_sp_F

## Female spawner
for (i in 1:nrow(sum_nr_sea_age_sp_F)) {
    for (j in 2:ncol(sum_nr_sea_age_sp_F)) {

        i_year <- sum_nr_sea_age_sp_F[i, names(sum_nr_sea_age_sp_F) == as.character("year")]
        sum_nr_sea_age_sp_F[i, j] <- sum(nr_fish_sea_sp_F[which(nr_fish_sea_sp_F$year ==
            i_year), names(nr_fish_sea_sp_F) == names(sum_nr_sea_age_sp_F)[j]])
    }
}

## Female non-spawner
for (i in 1:nrow(sum_nr_sea_age_nonsp_F)) {
    for (j in 2:ncol(sum_nr_sea_age_nonsp_F)) {

        i_year <- sum_nr_sea_age_nonsp_F[i, names(sum_nr_sea_age_nonsp_F) == as.character("year")]
        sum_nr_sea_age_nonsp_F[i, j] <- sum(nr_fish_sea_nonsp_F[which(nr_fish_sea_nonsp_F$year ==
            i_year), names(nr_fish_sea_nonsp_F) == names(sum_nr_sea_age_nonsp_F)[j]])
    }
}

## Male spawner
for (i in 1:nrow(sum_nr_sea_age_sp_M)) {
    for (j in 2:ncol(sum_nr_sea_age_sp_M)) {

        i_year <- sum_nr_sea_age_sp_M[i, names(sum_nr_sea_age_sp_M) == as.character("year")]
        sum_nr_sea_age_sp_M[i, j] <- sum(nr_fish_sea_sp_M[which(nr_fish_sea_sp_M$year ==
            i_year), names(nr_fish_sea_sp_M) == names(sum_nr_sea_age_sp_M)[j]])
    }
}

## Male non-spawner
for (i in 1:nrow(sum_nr_sea_age_nonsp_M)) {
    for (j in 2:ncol(sum_nr_sea_age_nonsp_M)) {

        i_year <- sum_nr_sea_age_nonsp_M[i, names(sum_nr_sea_age_nonsp_M) == as.character("year")]
        sum_nr_sea_age_nonsp_M[i, j] <- sum(nr_fish_sea_nonsp_M[which(nr_fish_sea_nonsp_M$year ==
            i_year), names(nr_fish_sea_nonsp_M) == names(sum_nr_sea_age_nonsp_M)[j]])
    }
}
# ====

# === Calculate the sex ratio ---- ===
sex_ratio_female <- sum_nr_sea_age_sp_F
sex_ratio_female[, -1] <- NA

for (j in 2:ncol(sex_ratio_female)) {
    sex_ratio_female[, j] <- (sum_nr_sea_age_nonsp_F[, j] + sum_nr_sea_age_sp_F[,
        j])/(sum_nr_sea_age_nonsp_F[, j] + sum_nr_sea_age_sp_F[, j] + sum_nr_sea_age_nonsp_M[,
        j] + sum_nr_sea_age_sp_M[, j])
}
# ====

# === Calculate Maturity Ogives ---- === Generate tables for female, male and
# combined ogives
mat_ogive_F <- sum_nr_sampl_age_sp_F
mat_ogive_F[, -1] <- NA
mat_ogive_M <- mat_ogive_F
mat_ogive_combsex <- mat_ogive_F

# Female mature
for (i in 1:nrow(mat_ogive_F)) {
    for (j in 2:ncol(mat_ogive_F)) {
        mat_ogive_F[i, j] <- sum_nr_sea_age_sp_F[i, j]/(sum_nr_sea_age_sp_F[i, j] +
            sum_nr_sea_age_nonsp_F[i, j])
    }
}
# Male mature
for (i in 1:nrow(mat_ogive_M)) {
    for (j in 2:ncol(mat_ogive_M)) {
        mat_ogive_M[i, j] <- sum_nr_sea_age_sp_M[i, j]/(sum_nr_sea_age_sp_M[i, j] +
            sum_nr_sea_age_nonsp_M[i, j])
    }
}

# Combsex mature
for (i in 1:nrow(mat_ogive_combsex)) {
    for (j in 2:ncol(mat_ogive_combsex)) {
        mat_ogive_combsex[i, j] <- (mat_ogive_F[i, j] * sex_ratio_female[i, j]) +
            (mat_ogive_M[i, j] * (1 - sex_ratio_female[i, j]))
    }
}
# ====

# === Combined Sexes reshape and calculate means +/- 95%CI for plotting ----
# === Complete timeseries of annual maturity ogives ----
mo <- reshape(mat_ogive_combsex, varying = colnames(mat_ogive_combsex)[-1], v.names = "PropMat",
    timevar = "Age", times = colnames(mat_ogive_combsex)[-1], idvar = "year", direction = "long")

## Mean of period 2002 - DataYear
rmprop <- aggregate(PropMat ~ Age, data = mo[mo$year %in% c(2002:(DataYear + 1)),
    ], FUN = mean)

## Std. error of period 2002 - DataYear
rmstdr <- aggregate(PropMat ~ Age, data = mo[mo$year %in% c(2002:(DataYear + 1)),
    ], FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
rmstdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = rmstdr$Age))
colnames(rmstdr)[colnames(rmstdr) %in% c("PropMat")] <- "StdErr"
rmstdr$PropMat <- rmprop$PropMat
rmstdr$ymax <- rmstdr$PropMat + 1.96 * rmstdr$StdErr
rmstdr$ymin <- rmstdr$PropMat - 1.96 * rmstdr$StdErr

## Combine with raw data df
rmprop$year <- as.factor(rep("Running Mean", n = nrow(rmprop)))
rownames(rmstdr) <- NULL
mo <- rbind(mo, rmprop)
mo$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = mo$Age))
mo$yearF <- as.factor(as.character(mo$year))
# =====


# === Female Only reshape and calculate means +/- 95%CI for plotting ---- ===
# Complete timeseries of annual maturity ogives ----
fmo <- reshape(mat_ogive_F, varying = colnames(mat_ogive_F)[-1], v.names = "PropMat",
    timevar = "Age", times = colnames(mat_ogive_F)[-1], idvar = "year", direction = "long")

## Mean of period 2002 - DataYear ----
rfmprop <- aggregate(PropMat ~ Age, data = fmo[fmo$year %in% c(2002:(DataYear + 1)),
    ], FUN = mean)

## Std. error of period 2002 - DataYear ----
rfmstdr <- aggregate(PropMat ~ Age, data = fmo[fmo$year %in% c(2002:(DataYear + 1)),
    ], FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
rfmstdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = rfmstdr$Age))
colnames(rfmstdr)[colnames(rfmstdr) %in% c("PropMat")] <- "StdErr"
rfmstdr$PropMat <- rfmprop$PropMat
rfmstdr$ymax <- rfmstdr$PropMat + 1.96 * rfmstdr$StdErr
rfmstdr$ymin <- rfmstdr$PropMat - 1.96 * rfmstdr$StdErr

## Combine with raw data df ----
rfmprop$year <- as.factor(rep("Running Mean", n = nrow(rfmprop)))
rownames(rfmstdr) <- NULL
fmo <- rbind(fmo, rfmprop)
fmo$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = fmo$Age))
fmo$yearF <- as.factor(as.character(fmo$year))


# saveRDS(fmo, file =
# 'Data/BiologicalData/Ple.27.21-32_MaturitiesFemaleLong_1999-AssYear.RDS')
# saveRDS(fmstdr,
# file('Data/BiologicalData/Ple.27.21-32_MaturitiesFemaleAveStdErr_15yr.RDS'))
# saveRDS(rfmstdr,
# file('Data/BiologicalData/Ple.27.21-32_MaturitiesFemaleAveStdErr_2002-AssYear.RDS'))
# =====

# === Male Only reshape and calculate means +/- 95%CI for plotting ---- ===
# Complete timeseries of annual maturity ogives ----
mmo <- reshape(mat_ogive_M, varying = colnames(mat_ogive_M)[-1], v.names = "PropMat",
    timevar = "Age", times = colnames(mat_ogive_M)[-1], idvar = "year", direction = "long")

## Mean of period 2002 - DataYear ----
rmmprop <- aggregate(PropMat ~ Age, data = mmo[mmo$year %in% c(2002:(DataYear + 1)),
    ], FUN = mean)

## Std. error of period 2002 - DataYear ----
rmmstdr <- aggregate(PropMat ~ Age, data = mmo[mmo$year %in% c(2002:(DataYear + 1)),
    ], FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
rmmstdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = rmmstdr$Age))
colnames(rmmstdr)[colnames(rmmstdr) %in% c("PropMat")] <- "StdErr"
rmmstdr$PropMat <- rmmprop$PropMat
rmmstdr$ymax <- rmmstdr$PropMat + 1.96 * rmmstdr$StdErr
rmmstdr$ymin <- rmmstdr$PropMat - 1.96 * rmmstdr$StdErr

## Combine with raw data df ----
rmmprop$year <- as.factor(rep("Running Mean", n = nrow(rmmprop)))
rownames(rmmstdr) <- NULL
mmo <- rbind(mmo, rmmprop)
mmo$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = mmo$Age))
mmo$yearF <- as.factor(as.character(mmo$year))


# saveRDS(mmo, file =
# 'Data/BiologicalData/Ple.27.21-32_MaturitiesMaleLong_1999-AssYear.RDS')
# saveRDS(mmstdr,
# file('Data/BiologicalData/Ple.27.21-32_MaturitiesMaleAveStdErr_15yr.RDS'))
# saveRDS(rmmstdr,
# file('Data/BiologicalData/Ple.27.21-32_MaturitiesMaleAveStdErr_2002-AssYear.RDS'))
# =====

## Calculate 3y sliding window average for whole timeseries ---- Calculate the
## mean ----
ada <- an(3, nrow(mat_ogive_combsex))
mo3sw <- frollmean(x = mat_ogive_combsex[, -1], n = ada, na.rm = T, align = "right",
    adaptive = TRUE)
mo3sw <- as.data.frame(do.call(cbind, mo3sw))
mo3sw$year <- mat_ogive_combsex$year

#### Wide to long format
mo3swL <- reshape(mo3sw, varying = colnames(mo3sw)[-11], v.names = "PropMat", timevar = "Age",
    times = colnames(mo3sw)[-11], idvar = "year", direction = "long")
mo3swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = mo3swL$Age))

### Calcualte the standard error ----
sw3stdr <- frollapply(mat_ogive_combsex[, -1], 3, FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
sw3stdr <- as.data.frame(do.call(cbind, sw3stdr))
sw3stdr$year <- mat_ogive_combsex$year

#### Wide to long format
sw3stdrL <- reshape(sw3stdr, varying = colnames(sw3stdr)[-11], v.names = "StdErrPropMat",
    timevar = "Age", times = colnames(sw3stdr)[-11], idvar = "year", direction = "long")
sw3stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw3stdrL$Age))

### Calculate 95% confidence intervals ----
mo3swL <- merge(x = mo3swL, y = sw3stdrL, by = c("year", "Age"), all.x = TRUE)
mo3swL$ymax <- mo3swL$PropMat + (1.96 * mo3swL$StdErrPropMat)
mo3swL$ymin <- mo3swL$PropMat - (1.96 * mo3swL$StdErrPropMat)
mo3swL$AgeN <- mo3swL$Age
mo3swL$Age <- as.character(mo3swL$Age)
mo3swL <- mo3swL[!mo3swL$year %in% c(1999:2001), ]

## Calculate 5y sliding window average for whole timeseries ---- Calculate the
## mean ----
ada <- an(5, nrow(mat_ogive_combsex))
mo5sw <- frollmean(x = mat_ogive_combsex[, -1], n = ada, na.rm = T, align = "right",
    adaptive = TRUE)
mo5sw <- as.data.frame(do.call(cbind, mo5sw))
#### Make the first year equal to the first calculable 5y average
mo5sw$year <- mat_ogive_combsex$year
# mo5sw[mo5sw$year == 2002, -ncol(mo5sw)] <- mo5sw[mo5sw$year == 2003,
# -ncol(mo5sw)]
mo5sw <- mo5sw[!mo5sw$year %in% c(1999:2001), ]


#### Wide to long format
mo5swL <- reshape(mo5sw, varying = colnames(mo5sw)[-11], v.names = "PropMat", timevar = "Age",
    times = colnames(mo5sw)[-11], idvar = "year", direction = "long")
mo5swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = mo5swL$Age))

### Calcualte the standard error ----
sw5stdr <- frollapply(mat_ogive_combsex[, -1], 5, FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
sw5stdr <- as.data.frame(do.call(cbind, sw5stdr))
sw5stdr$year <- mat_ogive_combsex$year

#### Make the first year equal to the first calculable 5y average
sw5stdr[sw5stdr$year == 2002, -ncol(sw5stdr)] <- sw5stdr[sw5stdr$year == 2003, -ncol(sw5stdr)]
sw5stdr <- sw5stdr[!sw5stdr$year %in% c(1999:2001), ]

#### Wide to long format
sw5stdrL <- reshape(sw5stdr, varying = colnames(sw5stdr)[-11], v.names = "StdErrPropMat",
    timevar = "Age", times = colnames(sw5stdr)[-11], idvar = "year", direction = "long")
sw5stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw5stdrL$Age))

### Calculate 95% confidence intervals ----
mo5swL <- merge(x = mo5swL, y = sw5stdrL, by = c("year", "Age"), all.x = TRUE)
mo5swL$ymax <- mo5swL$PropMat + (1.96 * mo5swL$StdErrPropMat)
mo5swL$ymin <- mo5swL$PropMat - (1.96 * mo5swL$StdErrPropMat)
mo5swL$AgeN <- mo5swL$Age
mo5swL$Age <- as.character(mo5swL$Age)
mo5swL <- mo5swL[!mo5swL$year %in% c(1999:2001), ]


## Calculate annual values from a smoothing spline ---- Build the spline
mo2 <- mo
mo2$Age <- as.factor(mo2$Age)
mo2$year <- as.numeric(mo2$year)
moss <- gam(formula = PropMat ~ s(year, bs = "cr", by = Age), data = mo2, family = gaussian(link = "identity"))

### Predict with the smoothed spline
predmo <- predict.gam(moss, newdata = mo2, type = "response", se.fit = TRUE)
mo2$smoothPropMat <- unname(predmo$fit)
mo2$seSmoothPropMat <- unname(predmo$se.fit)

# ====

# === Clean Data Environment ====
k <- append(k, c("mo", "mstdr", "rmstdr", "mat_ogive_F", "mat_ogive_M", "mat_ogive_combsex",
    "mo3swL", "mo5swL", "mo2", "sex_ratio_female"))
rm(list = ls()[!ls() %in% k])
# =====

There are various ways of looking a the Maturity Ogives. The previous Ple.27.21-23 stock used running means from the whole time-series to get single values of maturity at age, which were then applied to every year in the assessment.

# kable(mo[mo$year == "Running Mean", c("AgeN", "PropMat") ], 
rmstdrder <- rmstdr[order(rmstdr$AgeN), c("AgeN", "PropMat") ]
rownames(rmstdrder) <- NULL

### save_as_lowestoft Mean 2002-DataYear
mmA <- data.frame(lapply(colMeans(mat_ogive_combsex[mat_ogive_combsex$year %in% c(2002:DataYear), !colnames(mat_ogive_combsex) %in% ("year")], na.rm = TRUE), type.convert), stringsAsFactors=FALSE)

save_as_lowestoft(df = mmA, #[, !colnames(mWAA) %in% "Age"],
                  file_path = "Assessment Input/mo.dat",
                  title = "Stock weights at age for Ple.27.21-32. Mean values for combined sexes 2002 to Data year, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, DataYear), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"),
                  timeseries_type = 2)

kable(rmstdrder, 
      caption = paste0("Maturity Ogives of Ple.27.21-32, using the stock annex method from the previous Ple.27.21-23.  Values are timeseries means of both sexes for the period 2002-", DataYear),
      digits = 2)
(#tab:MOTable_rm)Maturity Ogives of Ple.27.21-32, using the stock annex method from the previous Ple.27.21-23. Values are timeseries means of both sexes for the period 2002-2023
AgeN PropMat
1 0.30
2 0.70
3 0.84
4 0.91
5 0.95
6 0.97
7 0.98
8 0.98
9 0.98
10 0.94

An alternate approach is to use smoothed or sliding window averages to allow for change in the age at maturity over time (different values for every year in the assessment), while smoothing out some of the noise introduced from annual observations of maturity. This noise can be significant due to the relatively low sample sizes of maturity level, relative to the population.

mo3order <- mo3swL[order(mo3swL$year, mo3swL$AgeN), c("year", "AgeN", "PropMat")]
rownames(mo3order) <- NULL
mo3orderw <- dcast(mo3order, year ~ AgeN, value.var = "PropMat")

## Save maturity data for assessment input ### Make 'NA's into '-9'
## mo3orderwSAM <- mo3orderw[mo3orderw$year %in% c(2002:(DataYear+1)), ] for(i
## in 1:ncol(mo3orderwSAM)){ for(j in 1:nrow(mo3orderwSAM)){ mo3orderwSAM[j, i]
## <- ifelse(is.na(mo3orderwSAM[j, i]), -9, mo3orderwSAM[j, i]) } }

### Make early timeseries 'NA's into plausible value
mo3orderwSAM <- mo3orderw[mo3orderw$year %in% c(2002:(DataYear + 1)), ]
for (i in 1:ncol(mo3orderwSAM)) {
    for (j in 1:nrow(mo3orderwSAM)) {
        mo3orderwSAM[j, i] <- ifelse(is.na(mo3orderwSAM[j, i]), median(c(mo3orderwSAM[,
            i]), na.rm = T), mo3orderwSAM[j, i])
    }
}

save_as_lowestoft(mo3orderwSAM[, !colnames(mo3orderwSAM) %in% "year"], file_path = "Assessment Input/AlternateModel_3ysw/mo.dat",
    title = paste0("Combined sex maturity ogives for ple.27.21-32. Three year sliding window means from 2002:",
        DataYear + 1), rando_numbers = paste(c("1", "6", "#I don't know what this information stands for, it's just made up."),
        collapse = "\t"), year_range = paste(c(2002, (DataYear + 1)), collapse = "\t"),
    age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = paste(c(1, "# 1 indicates annually varying, 2 indicates fixed values"),
        collapse = "\t"))

kable(mo3orderw, caption = paste0("Maturity Ogives of Ple.27.21-32, using a 3 year sliding window mean approach.  Values are timeseries means of the whole timeseries, 2002:",
    DataYear + 1), digits = 2)
(#tab:MOTable_sw3)Maturity Ogives of Ple.27.21-32, using a 3 year sliding window mean approach. Values are timeseries means of the whole timeseries, 2002:2024
year 1 2 3 4 5 6 7 8 9 10
2002 0.00 0.88 0.94 0.97 0.97 1.00 1.00 NaN NaN NaN
2003 0.37 0.80 0.88 0.96 0.97 1.00 1.00 NaN NaN NaN
2004 0.38 0.75 0.81 0.93 0.97 1.00 1.00 NaN NaN NaN
2005 0.38 0.59 0.74 0.91 0.96 0.99 1.00 1.00 NaN NaN
2006 0.22 0.61 0.71 0.90 0.96 0.94 0.91 1.00 1.00 NaN
2007 0.08 0.41 0.61 0.83 0.89 0.94 0.91 1.00 1.00 1.00
2008 0.17 0.53 0.66 0.83 0.89 0.93 0.89 0.98 0.98 1.00
2009 0.14 0.45 0.69 0.84 0.90 0.98 0.98 0.98 0.98 0.99
2010 0.39 0.63 0.82 0.89 0.95 0.98 0.98 0.98 0.97 0.99
2011 0.63 0.71 0.86 0.90 0.93 0.99 1.00 1.00 1.00 0.99
2012 0.52 0.82 0.91 0.91 0.94 0.99 1.00 1.00 1.00 1.00
2013 0.35 0.76 0.90 0.91 0.96 0.99 0.99 1.00 0.97 1.00
2014 0.16 0.70 0.83 0.89 0.98 0.99 0.99 1.00 0.97 1.00
2015 0.23 0.65 0.81 0.88 0.96 0.97 0.99 0.94 0.97 1.00
2016 0.40 0.75 0.83 0.89 0.93 0.94 0.99 0.92 0.97 0.94
2017 0.50 0.82 0.90 0.92 0.94 0.95 0.99 0.92 0.97 0.94
2018 0.46 0.86 0.94 0.95 0.96 0.97 0.99 0.97 0.97 0.94
2019 0.42 0.86 0.95 0.97 0.99 0.98 1.00 1.00 1.00 1.00
2020 0.32 0.76 0.95 0.98 0.99 0.99 1.00 1.00 1.00 1.00
2021 0.22 0.72 0.95 0.96 0.99 0.99 0.99 1.00 1.00 0.95
2022 0.16 0.71 0.95 0.95 0.98 0.98 0.98 1.00 0.98 0.73
2023 0.15 0.75 0.93 0.94 0.95 0.97 0.94 0.98 0.94 0.82
2024 0.18 0.74 0.92 0.94 0.94 0.95 0.95 0.96 0.94 0.75
mo5order <- mo5swL[order(mo5swL$year, mo5swL$AgeN), c("year", "AgeN", "PropMat")]
rownames(mo5order) <- NULL
mo5orderw <- dcast(mo5order, year ~ AgeN, value.var = "PropMat")

# ## Save maturity data for assessment input mo5orderwSAM <-
# mo5orderw[mo5orderw$year %in% c(2002:(DataYear+1)), ] for(i in
# 1:ncol(mo5orderwSAM)){ for(j in 1:nrow(mo5orderwSAM)){ mo5orderwSAM[j, i] <-
# ifelse(is.na(mo5orderwSAM[j, i]), -9, mo5orderwSAM[j, i]) } }

### Make early timeseries 'NA's into plausible value
mo5orderwSAM <- mo5orderw[mo5orderw$year %in% c(2002:(DataYear + 1)), ]
for (i in 1:ncol(mo5orderwSAM)) {
    for (j in 1:nrow(mo5orderwSAM)) {
        mo5orderwSAM[j, i] <- ifelse(is.na(mo5orderwSAM[j, i]), median(c(mo5orderwSAM[,
            i]), na.rm = T), mo5orderwSAM[j, i])
    }
}

save_as_lowestoft(mo5orderwSAM[, !colnames(mo5orderwSAM) %in% "year"], file_path = "Assessment Input/AlternateModel_5ysw/mo.dat",
    title = paste0("Combined sex maturity ogives for ple.27.21-32. Five year sliding window means from 2002:",
        DataYear + 1), rando_numbers = paste(c("1", "6", "#I don't know what this information stands for, it's just made up."),
        collapse = "\t"), year_range = paste(c(2002, (DataYear + 1)), collapse = "\t"),
    age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = paste(c(1, "# 1 indicates annually varying, 2 indicates fixed values"),
        collapse = "\t"))

kable(mo5orderw, caption = paste0("Maturity Ogives of Ple.27.21-32, using a 5 year sliding window mean approach.  Values are timeseries means of the whole timeseries, 2002:",
    DataYear + 1), digits = 2)
(#tab:MOTable_sw5)Maturity Ogives of Ple.27.21-32, using a 5 year sliding window mean approach. Values are timeseries means of the whole timeseries, 2002:2024
year 1 2 3 4 5 6 7 8 9 10
2002 0.00 0.88 0.94 0.97 0.97 1.00 1.00 NaN NaN NaN
2003 0.37 0.80 0.88 0.96 0.97 1.00 1.00 NaN NaN NaN
2004 0.38 0.80 0.86 0.95 0.98 1.00 1.00 NaN NaN NaN
2005 0.29 0.70 0.82 0.94 0.97 0.99 1.00 1.00 NaN NaN
2006 0.28 0.65 0.75 0.91 0.96 0.96 0.95 1.00 1.00 NaN
2007 0.28 0.54 0.68 0.87 0.92 0.96 0.95 1.00 1.00 1.00
2008 0.19 0.54 0.68 0.86 0.92 0.95 0.94 0.98 0.98 1.00
2009 0.13 0.47 0.68 0.86 0.92 0.95 0.94 0.99 0.99 0.99
2010 0.26 0.56 0.72 0.86 0.91 0.96 0.94 0.99 0.99 0.99
2011 0.38 0.60 0.78 0.86 0.90 0.98 0.99 0.99 0.99 0.99
2012 0.46 0.72 0.86 0.91 0.94 0.98 0.99 0.99 0.99 0.99
2013 0.39 0.70 0.87 0.90 0.95 1.00 0.99 1.00 0.98 0.99
2014 0.35 0.75 0.86 0.89 0.95 0.99 0.99 1.00 0.98 1.00
2015 0.35 0.73 0.86 0.90 0.95 0.98 0.99 0.97 0.98 1.00
2016 0.30 0.73 0.85 0.89 0.96 0.97 0.99 0.95 0.97 0.96
2017 0.34 0.75 0.86 0.90 0.95 0.96 0.99 0.95 0.97 0.96
2018 0.41 0.80 0.88 0.92 0.95 0.96 0.99 0.95 0.98 0.96
2019 0.45 0.82 0.92 0.94 0.96 0.96 0.99 0.95 0.98 0.96
2020 0.39 0.81 0.94 0.96 0.97 0.97 0.99 0.98 0.98 0.95
2021 0.31 0.78 0.95 0.97 0.99 0.99 1.00 1.00 1.00 0.97
2022 0.25 0.76 0.95 0.96 0.98 0.98 0.99 1.00 0.99 0.86
2023 0.20 0.74 0.94 0.95 0.97 0.98 0.97 0.99 0.96 0.86
2024 0.17 0.71 0.93 0.95 0.96 0.97 0.97 0.98 0.96 0.79

We could also attempt to fit smoothers to these data, in place of the sliding window means. However, instead of doing this in data prep, we can simply provide the raw annual estimates to SAM, and estimate this smoother during the model fit.

moRawOrder <- mat_ogive_combsex[mat_ogive_combsex$year %in% c(2002:(DataYear + 1)),
    ]
rownames(moRawOrder) <- NULL

# ## Save maturity data for assessment input moRawOrderSAM <-
# moRawOrder[moRawOrder$year %in% c(2002:(DataYear+1)), ] for(i in
# 1:ncol(moRawOrderSAM)){ for(j in 1:nrow(moRawOrderSAM)){ moRawOrderSAM[j, i]
# <- ifelse(is.na(moRawOrderSAM[j, i]), -9, moRawOrderSAM[j, i]) } }

### Make early timeseries 'NA's into plausible value
moRawOrderSAM <- moRawOrder[moRawOrder$year %in% c(2002:(DataYear + 1)), ]
for (i in 1:ncol(moRawOrderSAM)) {
    for (j in 1:nrow(moRawOrderSAM)) {
        moRawOrderSAM[j, i] <- ifelse(is.na(moRawOrderSAM[j, i]), median(c(moRawOrderSAM[,
            i]), na.rm = T), moRawOrderSAM[j, i])
    }
}

save_as_lowestoft(moRawOrderSAM[, !colnames(moRawOrderSAM) %in% "year"], file_path = "Assessment Input/AlternateModel_AnnualRawBio/mo.dat",
    title = paste0("Combined sex maturity ogives for ple.27.21-32. Annual estimates from 2002:",
        DataYear + 1), rando_numbers = paste(c("1", "6", "#I don't know what this information stands for, it's just made up."),
        collapse = "\t"), year_range = paste(c(2002, (DataYear + 1)), collapse = "\t"),
    age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = paste(c(1, "# 1 indicates annually varying, 2 indicates fixed values"),
        collapse = "\t"))

kable(moRawOrder, caption = paste0("Maturity Ogives of Ple.27.21-32, using annual estimates from surveys for the whole timeseries, 2002:",
    DataYear + 1), digits = 2)
(#tab:MOTable_AnnualEstimates)Maturity Ogives of Ple.27.21-32, using annual estimates from surveys for the whole timeseries, 2002:2024
year a1 a2 a3 a4 a5 a6 a7 a8 a9 a10
2002 0.00 0.80 0.87 0.94 0.94 1.00 1.00 NaN NaN NaN
2003 0.74 0.63 0.77 0.93 0.96 1.00 1.00 NaN NaN NaN
2004 0.41 0.82 0.78 0.92 1.00 1.00 1.00 NaN NaN NaN
2005 0.00 0.30 0.67 0.89 0.93 0.97 1.00 1.00 NaN NaN
2006 0.25 0.70 0.68 0.89 0.95 0.85 0.74 1.00 1.00 NaN
2007 0.00 0.23 0.49 0.71 0.78 1.00 1.00 1.00 1.00 1.00
2008 0.27 0.66 0.81 0.90 0.94 0.93 0.94 0.93 0.94 0.99
2009 NaN 0.46 0.77 0.91 0.98 1.00 1.00 1.00 1.00 0.97
2010 0.50 0.76 0.87 0.88 0.92 1.00 1.00 1.00 NaN 1.00
2011 0.76 0.90 0.94 0.91 0.89 0.98 1.00 1.00 1.00 1.00
2012 0.30 0.81 0.92 0.94 1.00 1.00 1.00 1.00 1.00 1.00
2013 0.00 0.57 0.84 0.87 0.99 1.00 0.97 1.00 0.92 1.00
2014 0.17 0.71 0.73 0.87 0.95 0.97 1.00 1.00 1.00 1.00
2015 0.53 0.68 0.86 0.89 0.93 0.94 0.99 0.83 1.00 1.00
2016 0.49 0.86 0.90 0.90 0.90 0.92 0.97 0.94 0.91 0.81
2017 0.49 0.91 0.95 0.96 0.98 0.98 1.00 1.00 1.00 1.00
2018 0.40 0.82 0.95 0.99 0.98 1.00 1.00 0.99 1.00 1.00
2019 0.37 0.85 0.95 0.96 0.99 0.98 1.00 1.00 1.00 1.00
2020 0.19 0.61 0.96 0.97 1.00 1.00 1.00 1.00 1.00 NaN
2021 0.11 0.70 0.94 0.95 0.98 1.00 0.98 1.00 1.00 0.89
2022 0.17 0.81 0.94 0.94 0.96 0.94 0.95 1.00 0.94 0.56
2023 0.18 0.73 0.92 0.94 0.91 0.98 0.89 0.94 0.87 1.00
2024 0.20 0.68 0.89 0.95 0.95 0.95 1.00 0.95 1.00 0.70
plt_mo_rm <- ggplot() +
  geom_line(data = mo[!mo$year %in% c("Running Mean", DataYear) & as.numeric(as.character(mo$year)) >= 2002 & as.numeric(as.character(mo$year)) != (DataYear+1), ],
            mapping = aes(x = AgeN,
                          y = PropMat,
                          group = yearF,
                          colour = yearF)) +
  geom_line(data = mo[mo$yearF == "Running Mean",],
            mapping = aes(x = AgeN,
                          y = PropMat,
                          group = yearF),
            colour = "Black",
            linetype = 3,
            size = 1.5) +
  geom_errorbar(data = rmstdr,
                mapping = aes(x = AgeN,
                              ymax = ymax,
                              ymin = ymin),
                colour = "Black",
                linetype = 3,
                size = 1) +
  geom_line(data = mo[mo$yearF == DataYear, ],
            mapping = aes(x = AgeN,
                          y = PropMat,
                          group = yearF),
            colour = "Black",
            # linetype = 9,
            size = 1.2) +
  theme_clean()+
  # scale_color_manual(values = ebpal) +
  scale_x_continuous(breaks = function(x) pretty(x, n = 5))

ggplotly(plt_mo_rm)

Figure 2.15: Maturity ogives for individual previous years (colours), the running mean based on Ple.27.21-23 stock annex (black dotted +/- 95% CI), and for 2023 (solid black)

Utilising an average of maturity ogives from the whole data series seems to mask any recent developments in rates of maturity. Therefore we were adivised by WGBFAS and by the ADG to consider switching to a sliding window approach. Below we see plots similar to the above, but this time we substitute in the results for annually varying, 3 and 5 year sliding window means.

# === Figure showing 3 year sliding window MO vs others ==== Make ordered
# mo3swL, with ymax max 1
mo3swLO <- mo3swL[order(mo3swL$year, mo3swL$AgeN), c("year", "AgeN", "PropMat", "ymax",
    "ymin")]
mo3swLO$ymax <- ifelse(mo3swLO$ymax > 1, 1, mo3swLO$ymax)
mo3swLO$ymin <- ifelse(mo3swLO$ymin < 0, 0, mo3swLO$ymin)
mo3swLO$yearF <- as.factor(as.character(mo3swLO$year))

plt_mo3swL <- ggplot() + geom_line(data = mo3swLO, mapping = aes(x = AgeN, y = PropMat,
    group = yearF, colour = yearF)) + geom_ribbon(data = mo3swLO, mapping = aes(x = AgeN,
    ymax = ymax, ymin = ymin, group = yearF, fill = yearF), alpha = 0.05) + geom_line(data = mo[mo$yearF ==
    "Running Mean", ], mapping = aes(x = AgeN, y = PropMat, group = yearF), colour = "Black",
    linetype = 3, size = 1.5) + geom_errorbar(data = rmstdr, mapping = aes(x = AgeN,
    ymax = ymax, ymin = ymin), colour = "Black", linetype = 3, size = 1) + theme_clean() +
    scale_x_continuous(breaks = function(x) pretty(x, n = 5))

ggplotly(plt_mo3swL)

Figure 2.16: Maturity ogives for three year sliding window means applied as annually varying maturity values. The running mean utilised in the Ple.27.21-23 annex is overlain for comparison (black dotted +/- 95% CI).

# =====
# === Figure showing 5 year sliding window MO vs others ==== Make ordered
# mo5swL, with ymax max 1
mo5swLO <- mo5swL[order(mo5swL$year, mo5swL$AgeN), c("year", "AgeN", "PropMat", "ymax",
    "ymin")]
mo5swLO$ymax <- ifelse(mo5swLO$ymax > 1, 1, mo5swLO$ymax)
mo5swLO$ymin <- ifelse(mo5swLO$ymin < 0, 0, mo5swLO$ymin)
mo5swLO$yearF <- as.factor(as.character(mo5swLO$year))

plt_mo5swL <- ggplot() + geom_line(data = mo5swLO, mapping = aes(x = AgeN, y = PropMat,
    group = yearF, colour = yearF)) + geom_ribbon(data = mo5swLO, mapping = aes(x = AgeN,
    ymax = ymax, ymin = ymin, group = yearF, fill = yearF), alpha = 0.05) + geom_line(data = mo[mo$yearF ==
    "Running Mean", ], mapping = aes(x = AgeN, y = PropMat, group = yearF), colour = "Black",
    linetype = 3, size = 1.5) + geom_errorbar(data = rmstdr, mapping = aes(x = AgeN,
    ymax = ymax, ymin = ymin), colour = "Black", linetype = 3, size = 1) + theme_clean() +
    scale_x_continuous(breaks = function(x) pretty(x, n = 5))

ggplotly(plt_mo5swL)

Figure 2.17: Maturity ogives for five year sliding window means applied as annually varying maturity values. The running mean utilised in the Ple.27.21-23 annex is overlain for comparison (black dotted +/- 95% CI).

# =====
mo2w <- reshape(mo2[, c("year", "Age", "smoothPropMat")], v.names = "smoothPropMat",
    timevar = "Age", idvar = "year", direction = "wide")

# for(i in 2:ncol(mo2w)){ for(j in 2:nrow(mo2w)){ mo2w[j, i] <-
# ifelse(is.na(mo2w[j, i]), -9, mo2w[j, i]) mo2w[j, i] <- ifelse((mo2w[j,
# i]>1), 1, mo2w[j, i]) } }

### Make early timeseries 'NA's into plausible value
mo2wSAM <- mo2w[mo2w$year %in% c(2002:(DataYear + 1)), ]
for (i in 1:ncol(mo2wSAM)) {
    for (j in 1:nrow(mo2wSAM)) {
        mo2wSAM[j, i] <- ifelse(is.na(mo2wSAM[j, i]), median(c(mo2wSAM[, i]), na.rm = T),
            mo2wSAM[j, i])
        mo2w[j, i] <- ifelse((mo2w[j, i] > 1), 1, mo2w[j, i])
    }
}

rownames(mo2w) <- NULL

save_as_lowestoft(df = mo2w[mo2w$year %in% c(2002:(DataYear + 1)), ], file_path = "Assessment Input/AlternateModel_SSbio/mo.dat",
    title = "Maturity Ogive for Ple.27.21-32. Smooth Spline for combined sexes, from survey data",
    rando_numbers = paste(c(1, 4), collapse = "\t"), year_range = paste(c(2002, (DataYear +
        1)), collapse = "\t"), age_range = paste(c(1, 10), collapse = "\t"))

kable(mo2w[mo2w$year >= 2002, ], caption = paste0("Maturity Ogives of Ple.27.21-32, using spline smoothed estimates from survey observations for the whole timeseries, 2002:",
    DataYear + 1), digits = 2)
(#tab:MOTable_AnnualSmoothedEstimates)Maturity Ogives of Ple.27.21-32, using spline smoothed estimates from survey observations for the whole timeseries, 2002:2024
year smoothPropMat.a1 smoothPropMat.a2 smoothPropMat.a3 smoothPropMat.a4 smoothPropMat.a5 smoothPropMat.a6 smoothPropMat.a7 smoothPropMat.a8 smoothPropMat.a9 smoothPropMat.a10
24 2022 0.6747897 0.9124604 0.9262226 0.8663733 0.8484428 0.8341142 0.8394752 0.8865159 0.9073891 0.7925157
25 2023 0.6922145 0.9190812 0.9344047 0.8677655 0.8478008 0.8318467 0.8378158 0.8901934 0.9131888 0.7712150
26 2024 0.7279639 0.9257020 0.9425868 0.8691578 0.8471588 0.8295791 0.8361565 0.8938708 0.9189848 0.7497751
NA NA NA NA NA NA NA NA NA NA NA NA
# swalba <- melt(setDT(WAA_combsex), id.vars = "year", variable.name = "Age", value.name = "MeanWeight")


ggplotly(ggplot() +
           geom_line(data = mo2,
                     mapping = aes(x = year,
                                   y = PropMat)) +
           geom_line(data = mo2,
                     mapping = aes(x = year,
                                   y = smoothPropMat,
                                   colour = Age)) +
           geom_ribbon(data = mo2,
                       mapping = aes(x = year,
                                     ymin = smoothPropMat-(1.96*seSmoothPropMat),
                                     ymax = smoothPropMat+(1.96*seSmoothPropMat),
                                     # colour = Age,
                                     fill = Age),
                       alpha = 0.15) + 
           facet_wrap(.~Age)+
           theme_few()+
           theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
           scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
           # scale_y_continuous(breaks = c(0, 0.2, 0.4, 0.6)) +
           # coord_cartesian(ylim = c(0,0.95)) +
    scale_color_manual(values = c(ebpal)) +
    scale_fill_manual(values = c(ebpal))
)

Figure 2.18: Maturity Ogives, actual values (black) and predicted from smoother (colours); ribbons = 95% CI.

In plenary at the Benchmark Workshop, it was decided that the levels of maturity in the early ages of the data do not look appropriate. This could be due to bias in teh sampling of the surveys, where larger fish from a given age group are more likely to be sampled in the deeper operating areas of the survey vessels. This may also be due to the difficulty in establishing the first winter ring when aging, leading to some larger two to three year olds being read as a year younger than they are.

Because of this we can produce some ogives with ages 1, or 1 & 2 set to zero, based on expert opinion.

mo5swL_1zero <- mo5swL
mo5swL_1zero[mo5swL_1zero$AgeN %in% c(1), c("PropMat", "StdErrPropMat", "ymax", "ymin")] <- 0
mo5swL_1zero$yearF <- as.factor(as.character(mo5swL_1zero$year))
# mo5swL_1zero$Age <- factor(as.character(mo5swL_1zero$AgeN), levels =
# as.character(sort(unique(mo5swL_1zero$AgeN))))

mo5swW_1zero <- reshape(mo5swL_1zero[, c("year", "Age", "PropMat")], timevar = "Age",
    idvar = "year", direction = "wide")
colnames(mo5swW_1zero) <- gsub(pattern = "PropMat.", replacement = "", x = colnames(mo5swW_1zero))


### Make early timeseries 'NA's into plausible value
mo5swW_1zeroSAM <- mo5swW_1zero[mo5swW_1zero$year %in% c(2002:(DataYear + 1)), c(-1)]
mo5swW_1zeroSAM <- mo5swW_1zeroSAM[, as.character(sort(as.numeric(names(mo5swW_1zeroSAM))))]
for (i in 1:ncol(mo5swW_1zeroSAM)) {
    for (j in 1:nrow(mo5swW_1zeroSAM)) {
        mo5swW_1zeroSAM[j, i] <- ifelse(is.na(mo5swW_1zeroSAM[j, i]), median(c(mo5swW_1zeroSAM[,
            i]), na.rm = T), mo5swW_1zeroSAM[j, i])
    }
}

save_as_lowestoft(df = mo5swW_1zeroSAM, file_path = "Assessment Input/MaturityVariants/5ysw_1zeromo.dat",
    title = "Maturity Ogive for Ple.27.21-32. Five year sliding window with age 1 set to 0, combined sexes, from survey data",
    rando_numbers = paste(c(1, 4), collapse = "\t"), year_range = paste(c(2002, (DataYear +
        1)), collapse = "\t"), age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = 1)

plt_mo5swL_1zero <- ggplot() + geom_line(data = mo5swL_1zero, mapping = aes(x = AgeN,
    y = PropMat, group = yearF, colour = yearF)) + geom_ribbon(data = mo5swL_1zero,
    mapping = aes(x = AgeN, ymax = ymax, ymin = ymin, group = yearF, fill = yearF),
    alpha = 0.05) + geom_line(data = mo[mo$yearF == "Running Mean", ], mapping = aes(x = AgeN,
    y = PropMat, group = yearF), colour = "Black", linetype = 3, size = 1.5) + geom_errorbar(data = rmstdr,
    mapping = aes(x = AgeN, ymax = ymax, ymin = ymin), colour = "Black", linetype = 3,
    size = 1) + theme_clean() + scale_x_continuous(breaks = function(x) pretty(x,
    n = 5))

ggplotly(plt_mo5swL_1zero)

Figure 2.19: Five-year sliding window mean of maturity at age, with age 1 set to 0, post-hoc.

mo5swL_2zero <- mo5swL
mo5swL_2zero[mo5swL_2zero$AgeN %in% c(1, 2), c("PropMat", "StdErrPropMat", "ymax",
    "ymin")] <- 0
mo5swL_2zero$yearF <- as.factor(as.character(mo5swL_2zero$year))

plt_mo5swL_2zero <- ggplot() + geom_line(data = mo5swL_2zero, mapping = aes(x = AgeN,
    y = PropMat, group = yearF, colour = yearF)) + geom_ribbon(data = mo5swL_2zero,
    mapping = aes(x = AgeN, ymax = ymax, ymin = ymin, group = yearF, fill = yearF),
    alpha = 0.05) + geom_line(data = mo[mo$yearF == "Running Mean", ], mapping = aes(x = AgeN,
    y = PropMat, group = yearF), colour = "Black", linetype = 3, size = 1.5) + geom_errorbar(data = rmstdr,
    mapping = aes(x = AgeN, ymax = ymax, ymin = ymin), colour = "Black", linetype = 3,
    size = 1) + theme_clean() + scale_x_continuous(breaks = function(x) pretty(x,
    n = 5))

ggplotly(plt_mo5swL_2zero)

Figure 2.20: Five-year sliding window mean of maturity at age, with ages 1 & 2 set to 0, post-hoc.

2.3.3 Sex Ratio

The sex ratio in the stock has

sr_lng <- reshape(sex_ratio_female, varying = colnames(sex_ratio_female)[-1], v.names = "PropFemale",
    timevar = "Age", times = colnames(sex_ratio_female)[-1], idvar = "year", direction = "long")
sr_lng$AgeN <- as.numeric(as.character(gsub(pattern = "a", replacement = "", x = sr_lng$Age)))

ggplotly(ggplot() + geom_line(data = sr_lng, mapping = aes(x = year, y = PropFemale,
    colour = Age)) + facet_wrap(. ~ AgeN) + theme_few() + theme(axis.text.x = element_text(angle = 45,
    hjust = 1, vjust = 1)) + scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
    scale_color_manual(values = c(ebpal)) + scale_fill_manual(values = c(ebpal)) +
    guides(colour = "none", fill = "none"))

Figure 2.21: Sex ratio over time, faceted by age.

ggplotly(ggplot(sr_lng) + geom_line(mapping = aes(x = AgeN, y = PropFemale)) + geom_hline(yintercept = 0.5,
    linetype = 2) + facet_wrap(facets = "year") + scale_x_continuous(breaks = function(x) pretty(x,
    n = 5)) + theme_few())

Figure 2.22: Sex ratios. Ages faceted by time.

2.3.4 Stock Weight At Age (SWAA)

The stock mean weights by age were calculated from the two first quarter surveys for each individual year. BITS data only exist for the period since 2008 and NS-IBTS only for the period since 2003. Therefore, prior to 2019 the BITS series was extended backwards to 2003 based on the average of 2008 to 2012. However, in 2019 it was found out that the procedure used for computing this average was erroneous, computing only a simple average across all length classes without weighting by the number of individuals within each length class. This lead to a very high estimate of the mean weight of the older fish, being driven up by very few observations. A more standard procedure with weighted average was implemented in 2019 (the same procedure as used for Western Baltic cod). The common series is finally extended backwards to 1999 based on the average of 2003 to 2007.

As for the maturity ogives, the SWAA must be calculated from the raw DATRAS Exchange products. These were read-in and cleaned in a previous section.

The below chunks (hidden) prepare the data, generate up-to-date SWAA for the assessment and plots a these out in figures for presentations/reporting. The fluctuating stock mean weights of the older age classes is caused by the small number of individuals caught at the surveys and the extremely high variability of weight for these age classes.

#===
# Subset processed exchange data ----
#===
# Select the SD and quarter
ca_q1<-subset(ca_hh_fin_bits_ibts,Quarter==1&Age!=-9&Age!=0&Age<15)
hl_q1<-subset(hl_hh_fin_bits_ibts,Quarter==1)
#=====

#===
# Summarise and aggregate data ----
#===
# Add 1 to all rows just to be able to count the fish
ca_q1$Nr_fish<-1

# Round the length class
ca_q1$RLngtClass<-round(ca_q1$LngtClass)

# How many fish we have
nr_fish<-aggregate(ca_q1$CANoAtLngt,
                   by=list(ca_q1$Country,ca_q1$Quarter,ca_q1$Year),
                   FUN="length")

nr_fish<- aggregate(ca_q1$Nr_fish,
                    by=list(ca_q1$Year,ca_q1$Sex,ca_q1$RLngtClass,ca_q1$Age),
                    FUN="sum",
                    na.rm=T)
names(nr_fish)<-c("year","sex","LngtClass","age","nr_fish")

# Aggregate number of fish and average weight in samples
weight<-aggregate(ca_q1$IndWgt,
                  by=list(ca_q1$Year,ca_q1$Sex,round(ca_q1$RLngtClass),
                          ca_q1$Age),
                  FUN="mean",na.rm=T)
names(weight)<-c("year","sex","LngtClass","age","weight")
#=====

#===
# Length Frequencies "at sea" ----
#===
# Set parameters for data
lencl<-c(4:60)
age<-c(1:10)
year<-c(1999:(DataYear+1))

# Make tables for length freq data
length_freq_tmp<-by(hl_q1,list(hl_q1$Year,round(hl_q1$LngtClass)),function (x){
  sum(x$HLNoAtLngt_1)
})
length_freq_tab<-t(as.table(length_freq_tmp))
Lfreq_sea<-data.frame(year=rep(year, each=length(lencl)),LngtClass=rep(lencl,length(year)),HLNoLngt=NA)

# Fill the table
for (i in c(1:nrow(Lfreq_sea))){
  year_i<-Lfreq_sea[i,names(Lfreq_sea)==as.character("year")]
  lencl_i<-Lfreq_sea[i,names(Lfreq_sea)==as.character("LngtClass")]
  
  if(lencl_i%in%c(as.numeric(dimnames(length_freq_tab)[[1]]))){
    
    data_i<-length_freq_tab[as.numeric(dimnames(length_freq_tab)[[1]])==lencl_i,dimnames(length_freq_tab)[[2]]==year_i]
    Lfreq_sea[i,names(Lfreq_sea)==as.character("HLNoLngt")]<-data_i
    
  }else{
    Lfreq_sea[i,names(Lfreq_sea)==as.character("HLNoLngt")]<-0       
  }
}

# replace NA with 0
Lfreq_sea[which(is.na(Lfreq_sea$HLNoLngt)),names(Lfreq_sea)==as.character("HLNoLngt")]<-0

#=====

#===
# Summary of sampled fish: weight by length and by age ----
#===
# Number of samples
## Make tables  
nr_fish_samp_F<-data.frame(year=rep(year, each=length(lencl)),LngtClass=rep(lencl,length(year)), a1=NA,a2=NA,a3=NA,a4=NA,a5=NA,a6=NA,a7=NA,a8=NA,a9=NA,a10=NA)
nr_fish_samp_M<-nr_fish_samp_F

wgt_samp_F<-nr_fish_samp_F
wgt_samp_M<-nr_fish_samp_M

## Filling the tables: 
### Female  
for (i in 1:nrow( nr_fish_samp_F)){
  for (j in 3:ncol( nr_fish_samp_F)){
    year_i<-nr_fish_samp_F[i,names(nr_fish_samp_F)==as.character("year")]
    lencl_i<-nr_fish_samp_F[i,names(nr_fish_samp_F)==as.character("LngtClass")]
    age_i<-j-2
    
    if(lencl_i%in% weight[which(weight$year==year_i&weight$sex==as.character("F")& weight$age==age_i),names(weight)==as.character("LngtClass")]){
      
      show_wgt<-weight[which(weight$year==year_i&weight$LngtClass==lencl_i&weight$sex==as.character("F")&weight$age==age_i),]
      show_nr<-nr_fish[which(nr_fish$year==year_i&nr_fish$LngtClass==lencl_i&nr_fish$sex==as.character("F")&nr_fish$age==age_i),]
      
      nr_fish_samp_F[i,j]<-sum(show_nr$nr_fish)
      wgt_samp_F[i,j]<-mean(show_wgt$weight, na.rm=T)
      
    } else{              
      nr_fish_samp_F[i,j]<-0
      wgt_samp_F[i,j]<-NA
    }
  }
}

### Male
for (i in 1:nrow( nr_fish_samp_M)){
  for (j in 3:ncol( nr_fish_samp_M)){
    year_i<-nr_fish_samp_M[i,names(nr_fish_samp_M)==as.character("year")]
    lencl_i<-nr_fish_samp_M[i,names(nr_fish_samp_M)==as.character("LngtClass")]
    age_i<-j-2
    
    if(lencl_i%in% weight[which(weight$year==year_i&weight$sex==as.character("M")& weight$age==age_i),names(weight)==as.character("LngtClass")]){
      
      show_wgt<-weight[which(weight$year==year_i&weight$LngtClass==lencl_i&weight$sex==as.character("M")&weight$age==age_i),]
      show_nr<-nr_fish[which(nr_fish$year==year_i&nr_fish$LngtClass==lencl_i&nr_fish$sex==as.character("M")&nr_fish$age==age_i),]
      
      nr_fish_samp_M[i,j]<-sum(show_nr$nr_fish)
      wgt_samp_M[i,j]<-mean(show_wgt$weight, na.rm=T)
      
    } else{              
      nr_fish_samp_M[i,j]<-0
      wgt_samp_M[i,j]<-NA
    }
  }
}

# Number of fish sampled by length class:
## Female
nr_fish_samp_F$tot<-NA

for (i in 1:nrow(nr_fish_samp_F)){
  nr_fish_samp_F[i,names(nr_fish_samp_F)==as.character("tot")]<-sum(nr_fish_samp_F[i,names(nr_fish_samp_F)%in%c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a10")])
}

##  Male        
nr_fish_samp_M$tot<-NA

for (i in 1:nrow(nr_fish_samp_M)){
  nr_fish_samp_M[i,names(nr_fish_samp_M)==as.character("tot")]<-sum(nr_fish_samp_M[i,names(nr_fish_samp_M)%in%c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a10")])
}

## F and M combined
Lfreq_samp<-data.frame(year=rep(year, each=length(lencl)),LngtClass=rep(lencl,length(year)), tot_samp=NA)

for (i in 1:nrow(Lfreq_samp)){
  year_i<-Lfreq_samp[i,names(Lfreq_samp)==as.character("year")]
  lencl_i<-Lfreq_samp[i,names(Lfreq_samp)==as.character("LngtClass")]
  
  F_sum<-nr_fish_samp_F[which(nr_fish_samp_F$year==year_i&nr_fish_samp_F$LngtClass==lencl_i),names(nr_fish_samp_F)==as.character("tot")]
  M_sum<-nr_fish_samp_M[which(nr_fish_samp_M$year==year_i&nr_fish_samp_M$LngtClass==lencl_i),names(nr_fish_samp_M)==as.character("tot")]
  
  Lfreq_samp[i,names(Lfreq_samp)==as.character("tot_samp")] <-F_sum+ M_sum 
}  

# Number of fish sampled by age:
## Make tables
tot_samp_age_F<-data.frame(year=year,a1=NA,a2=NA,a3=NA,a4=NA,a5=NA,a6=NA,a7=NA,a8=NA,a9=NA,a10=NA)
tot_samp_age_M<-data.frame(year=year,a1=NA,a2=NA,a3=NA,a4=NA,a5=NA,a6=NA,a7=NA,a8=NA,a9=NA,a10=NA)  

## Female
for (i in 1:nrow(tot_samp_age_F)){
  for (j in 2:ncol(tot_samp_age_F)){ 
    
    year_i<-tot_samp_age_F[i,names(tot_samp_age_F)==as.character("year")]
    show_data<- nr_fish_samp_F[which(nr_fish_samp_F$year==year_i),]
    
    tot_samp_age_F[i,j]<-sum(show_data[,names(show_data)==names(tot_samp_age_F)[j]])
  } 
}

## Male
for (i in 1:nrow(tot_samp_age_M)){
  for (j in 2:ncol(tot_samp_age_M)){ 
    
    year_i<-tot_samp_age_M[i,names(tot_samp_age_M)==as.character("year")]
    show_data<- nr_fish_samp_M[which(nr_fish_samp_M$year==year_i),]
    
    tot_samp_age_M[i,j]<-sum(show_data[,names(show_data)==names(tot_samp_age_M)[j]])
  } 
}
#=====

#===
# Sex Ratios ----
#===
# Make tables
sex_ratio_F<- tot_samp_age_F
sex_ratio_F[,-1]<-NA

# Fill tables
for (i in 1:nrow(sex_ratio_F)){
  for (j in 2:ncol(sex_ratio_F)){
    sex_ratio_F[i,j]<-tot_samp_age_F[i,j]/(tot_samp_age_F[i,j]+tot_samp_age_M[i,j])
  }
}
#=====

#===
# Full survey numbers for raising ----
#===
# Make Tables
nr_fish_sea_M<-nr_fish_samp_M
nr_fish_sea_M[,-(1:2)]<-NA
nr_fish_sea_F<-nr_fish_sea_M

## Female
for (i in 1:nrow(nr_fish_sea_F)){
  for (j in 3:(ncol(nr_fish_sea_F)-1)){
    if(nr_fish_samp_F$tot[i]>0&!is.na(Lfreq_sea$HLNoLngt[i])){
      
      pct_age_tot<-nr_fish_samp_F[i,j]/nr_fish_samp_F[i,names(nr_fish_samp_F)==as.character("tot")]   
      F_M_ratio<-nr_fish_samp_F[i,names(nr_fish_samp_F)==as.character("tot")]/Lfreq_samp$tot_samp[i]
      Lfreq<-Lfreq_sea$HLNoLngt[i]
      
      nr_fish_sea_F[i,j]<-pct_age_tot*Lfreq* F_M_ratio
    }else{
      nr_fish_sea_F[i,j]<-0 
    }
  }
}           

## Male
for (i in 1:nrow(nr_fish_sea_M)){
  for (j in 3:(ncol(nr_fish_sea_M)-1)){
    if(nr_fish_samp_M$tot[i]>0&!is.na(Lfreq_sea$HLNoLngt[i])){
      
      pct_age_tot<-nr_fish_samp_M[i,j]/nr_fish_samp_M[i,names(nr_fish_samp_M)==as.character("tot")]   
      M_F_ratio<-nr_fish_samp_M[i,names(nr_fish_samp_M)==as.character("tot")]/Lfreq_samp$tot_samp[i]
      Lfreq<-Lfreq_sea$HLNoLngt[i]
      
      nr_fish_sea_M[i,j]<-pct_age_tot*Lfreq* M_F_ratio
    }else{
      nr_fish_sea_M[i,j]<-0 
    }
  }
}           

# Sum of numbers over age-groups, by length
## Females
for (i in 1:nrow(nr_fish_sea_F)){
  nr_fish_sea_F[i,names(nr_fish_sea_F)==as.character("tot")]<-sum(nr_fish_sea_F[i,names(nr_fish_sea_F)%in%c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a10")])   
}    
## Males
for (i in 1:nrow(nr_fish_sea_M)){
  nr_fish_sea_M[i,names( nr_fish_sea_M)==as.character("tot")]<-sum(nr_fish_sea_M[i,names(nr_fish_sea_M)%in%c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a10")])   
}  

# Sum of numbers over length-groups, by age
## Make tables
sum_nr_fish_sea_F<-tot_samp_age_F
sum_nr_fish_sea_F[,-1]<-NA
sum_nr_fish_sea_M<-sum_nr_fish_sea_F

## Females
for (i in 1:nrow(sum_nr_fish_sea_F)){ 
  for (j in 2:ncol(sum_nr_fish_sea_F)){ 
    year_i<-sum_nr_fish_sea_F[i,names(sum_nr_fish_sea_F)==as.character("year")]
    sum_nr_fish_sea_F[i,j]<-sum(nr_fish_sea_F[which(nr_fish_sea_F$year==year_i),names(nr_fish_sea_F)==names(sum_nr_fish_sea_F)[j]]) 
  } 
}

## Males
for (i in 1:nrow(sum_nr_fish_sea_M)){ 
  for (j in 2:ncol(sum_nr_fish_sea_M)){ 
    year_i<-sum_nr_fish_sea_M[i,names(sum_nr_fish_sea_M)==as.character("year")]
    sum_nr_fish_sea_M[i,j]<-sum(nr_fish_sea_M[which(nr_fish_sea_M$year==year_i),names(nr_fish_sea_M)==names(sum_nr_fish_sea_M)[j]]) 
  } 
}

#=====

#===
# Raise proportions to full survey numbers ----
#===
# Make tables
wgt_nr_F<-nr_fish_sea_F
wgt_nr_F[,3:ncol(wgt_nr_F)]<-NA
wgt_nr_M<-wgt_nr_F

## Female
for (i in 1:nrow(wgt_nr_F)){
  for (j in 3:(ncol(wgt_nr_F)-1)) {
    if(nr_fish_sea_F[i,j]>0&!is.na(wgt_samp_F[i,j])){
      wgt<-wgt_samp_F[i,j]
      nr<-nr_fish_sea_F[i,j]
      wgt_nr_F[i,j]<-wgt*nr
    }else{
      wgt_nr_F[i,j]<-0
    }
  }
}   

## Male
for (i in 1:nrow(wgt_nr_M)){
  for (j in 3:(ncol(wgt_nr_M)-1)) {
    if(nr_fish_sea_M[i,j]>0&!is.na(wgt_samp_M[i,j])){
      wgt<-wgt_samp_M[i,j]
      nr<-nr_fish_sea_M[i,j]
      wgt_nr_M[i,j]<-wgt*nr
    }else{
      wgt_nr_M[i,j]<-0
    }
  }
} 

# Sum weights by age over length classes
## Make Tables
sum_wgt_nr_F<-tot_samp_age_F
sum_wgt_nr_F[,-1]<-NA
sum_wgt_nr_M<-sum_wgt_nr_F

## Females
for (i in 1:nrow(sum_wgt_nr_F)){ 
  for (j in 2:ncol(sum_wgt_nr_F)){ 
    year_i<-sum_wgt_nr_F[i,names(sum_wgt_nr_F)==as.character("year")]
    sum_wgt_nr_F[i,j]<-sum(wgt_nr_F[which(wgt_nr_F$year==year_i),names(wgt_nr_F)==names(sum_wgt_nr_F)[j]]) 
  } 
}

## Males
for (i in 1:nrow(sum_wgt_nr_M)){ 
  for (j in 2:ncol(sum_wgt_nr_M)){ 
    year_i<-sum_wgt_nr_M[i,names(sum_wgt_nr_M)==as.character("year")]
    sum_wgt_nr_M[i,j]<-sum(wgt_nr_M[which(wgt_nr_M$year==year_i),names(wgt_nr_M)==names(sum_wgt_nr_M)[j]]) 
  } 
}
#=====

#=== 
# Stock mean weight at age ----
#===
# Make Tables
WAA_F<-sum_wgt_nr_F
WAA_F[,-1]<-NA
WAA_M<-WAA_F
WAA_combsex<-WAA_M

## Females
for (i in 1:nrow(WAA_F)){
  for (j in 2:ncol(WAA_F)){
    WAA_F[i,j]<-sum_wgt_nr_F[i,j]/sum_nr_fish_sea_F[i,j]
  }
}

## Males
for (i in 1:nrow(WAA_M)){
  for (j in 2:ncol(WAA_M)){
    WAA_M[i,j]<-sum_wgt_nr_M[i,j]/sum_nr_fish_sea_M[i,j]
  }
}

## comb of F and M
for (i in 1:nrow(WAA_combsex)){ 
  for (j in 2:ncol(WAA_combsex)){ 
    if( !is.na(WAA_F[i,j])&!is.na(WAA_M[i,j])){
      WAA_combsex[i,j]<-(WAA_F[i,j]*sex_ratio_F[i,j])+(WAA_M[i,j]*(1-sex_ratio_F[i,j]))
    }
    if(is.na(WAA_F[i,j])&!is.na(WAA_M[i,j])){
      WAA_combsex[i,j]<-WAA_M[i,j]
    }
    if(is.na(WAA_M[i,j])&!is.na(WAA_F[i,j])){
      WAA_combsex[i,j]<-WAA_F[i,j]    
    }
  }
}

## Convert weights to kg, not grams
WAA_combsex <- WAA_combsex/1000
WAA_combsex$year <- WAA_combsex$year*1000
WAA_combsex$year <- as.integer(as.character(WAA_combsex$year))

#=====

#===
# Reshape WAA data and calculate means +/- 95%CI  for plotting  ----
#===
# Wide to long format
swaal <- reshape(WAA_combsex,
                 varying = colnames(WAA_combsex)[-1],
                 v.names = "MeanWeight",
                 timevar = "Age",
                 times = colnames(WAA_combsex)[-1],
                 idvar = "year",
                 direction = "long")



## Calculate mean swaa for 1999:2019 ----
m19WAA <- aggregate(MeanWeight ~ Age,
                    data = swaal[swaal$year %in% c(1999:2019),],
                    FUN = mean)

# Calculate std err around the above mean 1999:2019
mw19stdr <- aggregate(MeanWeight ~ Age,
                      data = swaal[swaal$year %in% c(1999:2019), ],
                      FUN = function(x){sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))})
mw19stdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = mw19stdr$Age))
colnames(mw19stdr)[colnames(mw19stdr) %in% c("MeanWeight")] <- "StdErr"
mw19stdr$MeanWeight <- m19WAA$MeanWeight
mw19stdr$ymax <- mw19stdr$MeanWeight + 1.96*mw19stdr$StdErr
mw19stdr$ymin <- mw19stdr$MeanWeight - 1.96*mw19stdr$StdErr
m19WAA$year <- as.factor(rep("Mean 1999-2019", n = nrow(m19WAA)))
mw19stdr <- mw19stdr[order(mw19stdr$AgeN), ]

## Calculate previous 3 year mean ----
m3WAA <- aggregate(MeanWeight ~ Age,
                   data = swaal[swaal$year %in% c(((DataYear+1)-2):(DataYear+1)),],
                   FUN = mean)

# Calculate std err around the above 3 year mean
m3wstdr <- aggregate(MeanWeight ~ Age,
                     data = swaal[swaal$year %in% c(((DataYear+1)-2):(DataYear+1)), ],
                     FUN = function(x){sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))})
m3wstdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = m3wstdr$Age))
colnames(m3wstdr)[colnames(m3wstdr) %in% c("MeanWeight")] <- "StdErr"
m3wstdr$MeanWeight <- m3WAA$MeanWeight
m3wstdr$ymax <- m3wstdr$MeanWeight + 1.96*m3wstdr$StdErr
m3wstdr$ymin <- m3wstdr$MeanWeight - 1.96*m3wstdr$StdErr
m3WAA$year <- as.factor(rep("3y Mean", n = nrow(m3WAA)))
m3wstdr <- m3wstdr[order(m3wstdr$AgeN), ]


## Calculate mean of 1999 to current year ----
rmWAA <- aggregate(MeanWeight ~ Age,
                   data = swaal[swaal$year %in% c(1999:(DataYear+1)),],
                   FUN = mean)

# Standard error of 1999 -> mean
rmwstdr <- aggregate(MeanWeight ~ Age,
                     data = swaal[swaal$year %in% c(1999:(DataYear+1)), ],
                     FUN = function(x){sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))})
rmwstdr$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = rmwstdr$Age))
colnames(rmwstdr)[colnames(rmwstdr) %in% c("MeanWeight")] <- "StdErr"
rmwstdr$MeanWeight <- rmWAA$MeanWeight
rmwstdr$ymax <- rmwstdr$MeanWeight + 1.96*rmwstdr$StdErr
rmwstdr$ymin <- rmwstdr$MeanWeight - 1.96*rmwstdr$StdErr
rmWAA$year <- as.factor(rep("Running Mean", n = nrow(rmWAA)))
rmwstdr <- rmwstdr[order(rmwstdr$AgeN), ]

# Combine all years, 2002 -> mean and 15 year mean into one object
swaal <- rbind(swaal, m19WAA, rmWAA, m3WAA)
swaal$AgeN <- as.numeric(sub(pattern = "a", replacement = "", x = swaal$Age))
swaal <- swaal[order(swaal$AgeN), ]
swaal$yearF <- as.factor(as.character(swaal$year))

## Calculate 3y sliding window average for whole timeseries ----
### Calculate the mean ----
ada <- an(3, nrow(WAA_combsex))
sw3sw <- frollmean(WAA_combsex[, -1], n=ada, na.rm = T, align = "right", adaptive = TRUE)
sw3sw <- as.data.frame(do.call(cbind, sw3sw))
sw3sw$year <- WAA_combsex$year

#### Wide to long format
sw3swL <- reshape(sw3sw,
                 varying = colnames(sw3sw)[-11],
                 v.names = "MeanWeight",
                 timevar = "Age",
                 times = colnames(sw3sw)[-11],
                 idvar = "year",
                 direction = "long")
sw3swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw3swL$Age))

### Calcualte the standard error ----
sw3stdr <- frollapply(WAA_combsex[, -1],
                      3,
                      FUN = function(x){sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))})
sw3stdr <- as.data.frame(do.call(cbind, sw3stdr))
sw3stdr$year <- WAA_combsex$year

#### Wide to long format
sw3stdrL <- reshape(sw3stdr,
                    varying = colnames(sw3stdr)[-11],
                    v.names = "StdErrWeight",
                    timevar = "Age",
                    times = colnames(sw3stdr)[-11],
                    idvar = "year",
                    direction = "long")
sw3stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw3stdrL$Age))

### Calculate 95% confidence intervals ----
sw3swL <- merge(x = sw3swL, y = sw3stdrL, by = c("year", "Age"), all.x = TRUE)
sw3swL$ymax <- sw3swL$MeanWeight + (1.96*sw3swL$StdErrWeight)
sw3swL$ymin <- sw3swL$MeanWeight - (1.96*sw3swL$StdErrWeight)
sw3swL$AgeN <- sw3swL$Age
sw3swL$Age <- as.character(sw3swL$Age)
sw3swL$year <- as.numeric(sw3swL$year)
sw3swL$yearF <- as.factor(as.character(sw3swL$year))


## Calculate 5y sliding window average for whole timeseries ----
### Calculate the mean ----
ada <- an(5, nrow(WAA_combsex))
sw5sw <- frollmean(WAA_combsex[, -1], n = ada, na.rm = T, align = "right", adaptive = TRUE)
sw5sw <- as.data.frame(do.call(cbind, sw5sw))
sw5sw$year <- WAA_combsex$year

#### Wide to long format
sw5swL <- reshape(sw5sw,
                  varying = colnames(sw5sw)[-11],
                  v.names = "MeanWeight",
                  timevar = "Age",
                  times = colnames(sw5sw)[-11],
                  idvar = "year",
                  direction = "long")
sw5swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw5swL$Age))

### Calcualte the standard error ----
sw5stdr <- frollapply(WAA_combsex[, -1],
                      5,
                      FUN = function(x){sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))})
sw5stdr <- as.data.frame(do.call(cbind, sw5stdr))
sw5stdr$year <- WAA_combsex$year
sw5stdr[sw5stdr$year == 2002, -ncol(sw5stdr)] <- sw5stdr[sw5stdr$year == 2003, -ncol(sw5stdr)]

#### Wide to long format
sw5stdrL <- reshape(sw5stdr,
                    varying = colnames(sw5stdr)[-11],
                    v.names = "StdErrWeight",
                    timevar = "Age",
                    times = colnames(sw5stdr)[-11],
                    idvar = "year",
                    direction = "long")
sw5stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = sw5stdrL$Age))

### Calculate 95% confidence intervals ----
sw5swL <- merge(x = sw5swL, y = sw5stdrL, by = c("year", "Age"), all.x = TRUE)
sw5swL$ymax <- sw5swL$MeanWeight + (1.96*sw5swL$StdErrWeight)
sw5swL$ymin <- sw5swL$MeanWeight - (1.96*sw5swL$StdErrWeight)
sw5swL$AgeN <- sw5swL$Age
sw5swL$Age <- as.character(sw5swL$Age)
sw5swL$year <- as.numeric(sw5swL$year)
sw5swL$yearF <- as.factor(as.character(sw5swL$year))

## Calculate annual values from a smoothing spline ----
### Build the spline
swaal2 <- swaal[!swaal$year %in% c("Mean 1999-2019", "Running Mean", "3y Mean"),]
swaal2$Age <- as.factor(swaal2$Age)
swaal2$year <- as.numeric(swaal2$year)
msw <- gam(formula = MeanWeight ~ s(year, bs = "cr", by = Age), data = swaal2, family = gaussian(link = "identity"))

### Predict with the smoothed spline
predweights <- predict.gam(msw, newdata = swaal2,type = "response", se.fit = TRUE)
swaal2$smoothMeanWeights <- unname(predweights$fit)
swaal2$seSmoothMeanWeights <- unname(predweights$se.fit)
#=====

#===
# save results
#====
write.csv(WAA_combsex,file="Data/BiologicalData/ple.27.21-32_StockWeightAtAge_1999-DataYear.csv")
# save_as_lowestoft Annaul Estimates
WAA_combsexSAM <- as.data.frame(WAA_combsex)

### save_as_lowestoft Mean 2002-DataYear
mWAA <- data.frame(lapply(colMeans(WAA_combsex[WAA_combsex$year %in% c(2002:(DataYear+1)), !colnames(WAA_combsex) %in% ("year")], na.rm = TRUE), type.convert), stringsAsFactors=FALSE)

save_as_lowestoft(df = mWAA, #[, !colnames(mWAA) %in% "Age"],
                  file_path = "Assessment Input/sw.dat",
                  title = "Stock weights at age for Ple.27.21-32. Mean values for combined sexes 2002 to data year, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"),
                  timeseries_type = 2)

### save_as_lowestoft Raw Annual Estimates

#### old removal of NAs
# for(i in 1:ncol(WAA_combsexSAM)){
#   for(j in 1:nrow(WAA_combsexSAM)){
#     WAA_combsexSAM[j, i] <- ifelse(is.na(WAA_combsexSAM[j, i]), -9, WAA_combsexSAM[j, i])
#   }
# }

#### Make early timeseries "NA"s into plausible value
for(i in 1:ncol(WAA_combsexSAM)){
  for(j in 1:nrow(WAA_combsexSAM)){
    WAA_combsexSAM[j, i] <- ifelse(is.na(WAA_combsexSAM[j, i]), median(c(WAA_combsexSAM[,i]), na.rm = T), WAA_combsexSAM[j, i])
  }
}

save_as_lowestoft(df = WAA_combsexSAM[WAA_combsexSAM$year %in% 2002:(DataYear+1), !colnames(WAA_combsexSAM) %in% "year"],
                  file_path = "Assessment Input/AlternateModel_AnnualRawBio/sw.dat",
                  title = "Stock weights at age for Ple.27.21-32. Annual values for combined sexes, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"))

### save_as_lowestoft Three Year Sliding Window
sw3swSAM <- as.data.frame(sw3sw)

# for(i in 1:ncol(sw3swSAM)){
#   for(j in 1:nrow(sw3swSAM)){
#     sw3swSAM[j, i] <- ifelse(is.na(sw3swSAM[j, i]), -9, sw3swSAM[j, i])
#   }
# }

#### Make early timeseries "NA"s into plausible value
for(i in 1:ncol(sw3swSAM)){
  for(j in 1:nrow(sw3swSAM)){
    sw3swSAM[j, i] <- ifelse(is.na(sw3swSAM[j, i]), median(c(sw3swSAM[,i]), na.rm = T), sw3swSAM[j, i])
  }
}

save_as_lowestoft(df = sw3swSAM[sw3swSAM$year %in% 2002:(DataYear+1), !colnames(sw3swSAM) %in% "year"],
                  file_path = "Assessment Input/AlternateModel_3ysw/sw.dat",
                  title = "Stock weights at age for Ple.27.21-32. Three year sliding window means for combined sexes, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"))

### save_as_lowestoft Five Year Sliding Window
sw5swSAM <- as.data.frame(sw5sw)

# for(i in 1:ncol(sw5swSAM)){
#   for(j in 1:nrow(sw5swSAM)){
#     sw5swSAM[j, i] <- ifelse(is.na(sw5swSAM[j, i]), -9, sw5swSAM[j, i])
#   }
# }

#### Make early timeseries "NA"s into plausible value
for(i in 1:ncol(sw5swSAM)){
  for(j in 1:nrow(sw5swSAM)){
    sw5swSAM[j, i] <- ifelse(is.na(sw5swSAM[j, i]), median(c(sw5swSAM[,i]), na.rm = T), sw5swSAM[j, i])
  }
}

save_as_lowestoft(df = sw5swSAM[sw5swSAM$year %in% 2002:(DataYear+1), !colnames(sw5swSAM) %in% "year"],
                  file_path = "Assessment Input/AlternateModel_5ysw/sw.dat",
                  title = "Stock weights at age for Ple.27.21-32. Five year sliding window means for combined sexes, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"))

### save_as_lowestoft spline-smoothed
swaa2 <- reshape(swaal2[, c("year", "Age", "smoothMeanWeights")],
                 varying = colnames(WAA_combsex)[-1],
                 v.names = "smoothMeanWeights",
                 timevar = "Age",
                 idvar = "year",
                 direction = "wide")

# for(i in 2:ncol(swaa2)){
#   for(j in 2:nrow(swaa2)){
#     swaa2[j, i] <- ifelse(is.na(swaa2[j, i]), -9, swaa2[j, i])
#     swaa2[j, i] <- ifelse((swaa2[j, i]>= 0), -9, swaa2[j, i])
#   }
# }

#### Make early timeseries "NA"s into plausible value
for(i in 1:ncol(swaa2)){
  for(j in 1:nrow(swaa2)){
    swaa2[j, i] <- ifelse(is.na(swaa2[j, i]), median(c(swaa2[,i]), na.rm = T), swaa2[j, i])
    swaa2[j, i] <- ifelse((swaa2[j, i]>1), 1, swaa2[j, i])
  }
}

save_as_lowestoft(df = swaa2[swaa2$year %in% c(2002:(DataYear+1)), ],
                  file_path = "Assessment Input/AlternateModel_SSbio/sw.dat",
                  title = "Stock weights at age for Ple.27.21-32. Smooth Spline for combined sexes, from survey data",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"))


# saveRDS(swaal, file = "Biological Data/Ple.27.21-23_swaal.RDS")
# saveRDS(mw19stdr, file("Biological Data/Ple.27.21-23_SWAA_AveStdErr_1999-2019.RDS"))
# saveRDS(rmwstdr, file("Biological Data/Ple.27.21-23_SWAA_AveStdErr_1999-DataYear.RDS"))
# saveRDS(m3wstdr, file("Biological Data/Ple.27.21-23_SWAA_AveStdErr_3yr.RDS"))
#=====

k <- append(k, c("WAA_combsex", "swaal", "swaal2", "mw19stdr", "rmwstdr", "m3wstdr", "sw3swL", "sw5swL", "sw_annual_raw", "sex_ratio_F"))
# rm(list = ls()[!ls() %in% k])

Similar to the maturity ogives, the stock mean weight at age (SWAA) in the assessment has historically, in the ple.27.21-23 stock, been an average of the whole time-series, namely from 1999 - 2023. However, because the weight at age has shifted from being relatively stable to being progressively lower since 2020 (probably due to density dependent competition) we can no longer use the mean of the time series. Over the last years of the ple.27.21-23 stock, WGBFAS agreed to, instead, use the mean for the period where it was stable, and sampling was low, and shift to the annual values for later years. This means the means for years 1999:2019 are applied to the years 1999:2019, while all years from 2020:2023 utilise the actual year’s estimated values from survey samples. Below we investigate what the SWAA values would be according to the stock annex compared to our new approach by first looking at the values in tables and then comparing them graphically.

# === Table of SWAA from stock annex ====
kable(swaal[swaal$year == "Running Mean", c("AgeN", "MeanWeight")], caption = "Static Stock Weight-at-age from mean of timeseries, according to ple.27.21-23 stock annex.")
Table 2.9: Static Stock Weight-at-age from mean of timeseries, according to ple.27.21-23 stock annex.
AgeN MeanWeight
11 1 0.0353194
31 2 0.0716080
41 3 0.1267258
51 4 0.1941207
61 5 0.2520088
71 6 0.3013635
81 7 0.3867862
91 8 0.4165005
101 9 0.4264940
21 10 0.5196663
# =====
# === Data Prep ====
mw19stdr$cat <- "mw1999_2019"
awCurrent <- swaal[swaal$year %in% c(2020:DataYear + 1), ]
awCurrent$cat <- as.character(awCurrent$year)
awCurrent$StdErr <- NA
awCurrent$ymax <- NA
awCurrent$ymin <- NA
years <- rep(1999:2019, 10)[order(rep(1999:2019, 10))]
mw19_19 <- data.frame(year = years, AgeN = rep(1:10, length(1999:2019)), MeanWeight = rep(mw19stdr$MeanWeight,
    length(1999:2019)), ymin = rep(mw19stdr$ymin, length(1999:2019)), ymax = rep(mw19stdr$ymax,
    length(1999:2019)), StdErr = rep(mw19stdr$StdErr, length(1999:2019)))
swaasepLong <- rbind(mw19_19, awCurrent[, colnames(awCurrent)[colnames(awCurrent) %in%
    colnames(mw19_19)]])

swaasepSAM <- dcast(data = swaasepLong[, c("year", "AgeN", "MeanWeight")], formula = year ~
    AgeN, value.var = "MeanWeight")
# write.csv(swaasepSAM, file = 'Biological
# Data/Ple.27.21-32_SWAA_Ave1999-2019_Value2020-Current.csv') ==== === Table of
# SWAA for Assessment ====
kable(swaasepSAM, caption = "Stock weight-at-age with mean values applied for 1999:2019 and observed values for 2020 onwards.")
Table 2.10: Stock weight-at-age with mean values applied for 1999:2019 and observed values for 2020 onwards.
year 1 2 3 4 5 6 7 8 9 10
1999 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2000 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2001 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2002 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2003 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2004 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2005 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2006 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2007 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2008 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2009 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2010 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2011 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2012 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2013 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2014 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2015 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2016 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2017 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2018 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2019 0.0398838 0.0777201 0.1363725 0.2100388 0.2728213 0.3256387 0.4220236 0.4487470 0.4495387 0.5637859
2021 0.0154406 0.0502570 0.0856119 0.1535145 0.1830782 0.2259203 0.2523265 0.3274388 0.3429285 0.3091177
2022 0.0175870 0.0442823 0.0906907 0.1190161 0.1552038 0.1841127 0.2715534 0.2746941 0.2639065 0.3422108
2023 0.0169497 0.0445842 0.0743983 0.1090106 0.1487086 0.2000505 0.2178145 0.2828484 0.3866234 0.3980744
2024 0.0129716 0.0364625 0.0626792 0.0902232 0.1123439 0.1461400 0.1640149 0.2214779 0.3267716 0.2532022
# =====
# === Figure stock weight at age (Calculated from DATRAS Exchange Data) ====
ggplotly(ggplot() + geom_line(data = rmwstdr, mapping = aes(x = AgeN, y = MeanWeight),
    size = 1.25, colour = ebpal[2]) + geom_ribbon(data = rmwstdr, mapping = aes(x = AgeN,
    ymin = ymin, ymax = ymax), fill = ebpal[2], alpha = 0.2) + geom_line(data = mw19stdr,
    mapping = aes(x = AgeN, y = MeanWeight), size = 1.25, colour = ebpal[1]) + geom_ribbon(data = mw19stdr,
    mapping = aes(x = AgeN, ymin = ymin, ymax = ymax), fill = ebpal[1], alpha = 0.2) +
    geom_line(data = swaal[swaal$year %in% c(2020:(DataYear + 1)), ], mapping = aes(x = AgeN,
        y = MeanWeight, colour = year)) + theme_clean() + scale_colour_manual(values = ebpal[3:length(ebpal)]) +
    scale_x_continuous(breaks = function(x) pretty(x, n = 10)))

Figure 2.23: Stock weight at age. The light green line and ribbon are the full time-series mean +/- 95%CI, to be used as fixed for all years according to the stock annex. The light blue line and ribbon is the 1999:2019 average (+/- 95%CI), which is applied to those years. Subsequent years, 2020 to 2024, are included independently in the assessment run and are shown in the remaining colours.

# =====
swalba <- melt(setDT(WAA_combsex), id.vars = "year", variable.name = "Age", value.name = "MeanWeight")


ggplotly(ggplot() + geom_line(data = swalba, mapping = aes(x = year, y = MeanWeight)) +
    facet_wrap(. ~ Age) + theme_few() + theme(axis.text.x = element_text(angle = 45,
    hjust = 1, vjust = 1)) + scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
    scale_y_continuous(breaks = c(0, 0.2, 0.4, 0.6)) + coord_cartesian(ylim = c(0,
    0.6)))

Figure 2.24: Stock weight at age by year, over time.

ggplotly(ggplot() + geom_line(data = swalba, mapping = aes(x = year, y = MeanWeight,
    colour = Age)) + theme_few() + theme(axis.text.x = element_text(angle = 45, hjust = 1,
    vjust = 1)) + scale_x_continuous(breaks = function(x) pretty(x, n = 5)) + scale_y_continuous(breaks = c(0,
    0.2, 0.4, 0.6, 0.8)) + coord_cartesian(ylim = c(0, 0.8)) + scale_color_manual(values = c("#000000",
    ebpal)))

Figure 2.25: Stock weight at age by year, over time, all in one panel (FOR JESPER).

ggplotly(ggplot() +
  geom_line(data = swaal2,
            mapping = aes(x = year,
                          y = smoothMeanWeights,
                          colour = Age)) +
  geom_ribbon(data = swaal2,
              mapping = aes(x = year,
                            ymin = smoothMeanWeights-(1.96*seSmoothMeanWeights),
                            ymax = smoothMeanWeights+(1.96*seSmoothMeanWeights),
                            # colour = Age,
                            fill = Age),
              alpha = 0.15) + 
  theme_few()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
  scale_y_continuous(breaks = c(0, 0.2, 0.4, 0.6, 0.8)) +
  coord_cartesian(ylim = c(0,0.95))+
    scale_color_manual(values = c(ebpal)) +
    scale_fill_manual(values = c(ebpal))
)

Figure 2.26: Stock weight at age by year, over time, estimated from smoothed splines by age.

swalba <- melt(setDT(WAA_combsex), id.vars = "year", variable.name = "Age", value.name = "MeanWeight")


ggplotly(ggplot() +
           geom_line(data = swalba,
                     mapping = aes(x = year,
                                   y = MeanWeight)) +
           geom_line(data = swaal2,
                     mapping = aes(x = year,
                                   y = smoothMeanWeights,
                                   colour = Age)) +
           geom_ribbon(data = swaal2,
                       mapping = aes(x = year,
                                     ymin = smoothMeanWeights-(1.96*seSmoothMeanWeights),
                                     ymax = smoothMeanWeights+(1.96*seSmoothMeanWeights),
                                     # colour = Age,
                                     fill = Age),
                       alpha = 0.15) + 
           facet_wrap(.~Age)+
           theme_few()+
           theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
           scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
           # scale_y_continuous(breaks = c(0, 0.2, 0.4, 0.6)) +
           coord_cartesian(ylim = c(0,0.95)) +
    scale_color_manual(values = c(ebpal)) +
    scale_fill_manual(values = c(ebpal))
)

Figure 2.27: Stock weight at age by year, over time, actual values (black) and predicted from smoother (colours); ribbons = 95% CI.

2.3.5 Stock Length at Age

While not necessary for the assessment, we can use the above aggregations to also get the stock mean length at age.

# === Get numbers of length samples ==== Make tables
len_nr_F <- wgt_nr_F
len_nr_F[, 3:ncol(len_nr_F)] <- NA
len_nr_M <- len_nr_F

# Females
for (i in 1:nrow(len_nr_F)) {
    for (j in 3:(ncol(len_nr_F) - 1)) {

        if (nr_fish_sea_F[i, j] > 0) {
            len_nr_F[i, j] <- nr_fish_sea_F[i, j] * nr_fish_sea_F[i, names(nr_fish_sea_F) ==
                as.character("LngtClass")]
        } else {
            len_nr_F[i, j] <- 0
        }
    }
}

# Males
for (i in 1:nrow(len_nr_M)) {
    for (j in 3:(ncol(len_nr_M) - 1)) {

        if (nr_fish_sea_M[i, j] > 0) {
            len_nr_M[i, j] <- nr_fish_sea_M[i, j] * nr_fish_sea_M[i, names(nr_fish_sea_M) ==
                as.character("LngtClass")]
        } else {
            len_nr_M[i, j] <- 0
        }
    }
}

# === Sum of these values over lenghtclasses, by age ==== Make Tables
sum_len_nr_F <- sum_wgt_nr_F
sum_len_nr_F[, -1] <- NA
sum_len_nr_M <- sum_len_nr_F

# Females
for (i in 1:nrow(sum_len_nr_F)) {
    for (j in 2:ncol(sum_len_nr_F)) {
        year_i <- sum_len_nr_F[i, names(sum_len_nr_F) == as.character("year")]
        sum_len_nr_F[i, j] <- sum(len_nr_F[which(len_nr_F$year == year_i), names(len_nr_F) ==
            names(sum_len_nr_F)[j]])
    }
}

# Males
for (i in 1:nrow(sum_len_nr_M)) {
    for (j in 2:ncol(sum_len_nr_M)) {
        year_i <- sum_len_nr_M[i, names(sum_len_nr_M) == as.character("year")]
        sum_len_nr_M[i, j] <- sum(len_nr_M[which(len_nr_M$year == year_i), names(len_nr_M) ==
            names(sum_len_nr_M)[j]])
    }
}
# =====

# === Calculate mean length at age ==== Make tables
LAA_F <- WAA_F
LAA_F[, -1] <- NA
LAA_M <- LAA_F
LAA_combsex <- LAA_M

# Females
for (i in 1:nrow(LAA_F)) {
    for (j in 2:ncol(LAA_F)) {
        LAA_F[i, j] <- sum_len_nr_F[i, j]/sum_nr_fish_sea_F[i, j]
    }
}

# Males
for (i in 1:nrow(LAA_M)) {
    for (j in 2:ncol(LAA_M)) {
        LAA_M[i, j] <- sum_len_nr_M[i, j]/sum_nr_fish_sea_M[i, j]
    }
}

# comb of F and M
for (i in 1:nrow(LAA_combsex)) {
    for (j in 2:ncol(LAA_combsex)) {
        if (!is.na(LAA_F[i, j]) & !is.na(LAA_M[i, j])) {
            LAA_combsex[i, j] <- (LAA_F[i, j] * sex_ratio_F[i, j]) + (LAA_M[i, j] *
                (1 - sex_ratio_F[i, j]))
        }
        if (is.na(LAA_F[i, j]) & !is.na(LAA_M[i, j])) {
            LAA_combsex[i, j] <- LAA_M[i, j]
        }
        if (is.na(LAA_M[i, j]) & !is.na(LAA_F[i, j])) {
            LAA_combsex[i, j] <- LAA_F[i, j]
        }
    }
}

# === Clean Data Environment ====
k <- append(k, c("LAA_combsex", "LAA_F", "LAA_M", "WAA_combsex", "WAA_F", "WAA_M",
    "swaal", "m19WAA", "rm19WAA"))
rm(list = ls()[!ls() %in% k])
# =====

2.3.5.1 Stock Lengths at age

slalba <- melt(setDT(LAA_combsex), id.vars = "year", variable.name = "Age", value.name = "MeanLength")


ggplotly(ggplot() + geom_line(data = slalba, mapping = aes(x = year, y = MeanLength,
    colour = Age)) + facet_wrap(. ~ Age) + theme_few() + theme(axis.text.x = element_text(angle = 45,
    hjust = 1, vjust = 1)) + scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
    scale_color_manual(values = ebpal))

Figure 2.28: Stock lengths at age by year, over time.

2.3.5.2 Raw lengths at age observations

ca_hh_fin_bits_ibts$AgeN <- ca_hh_fin_bits_ibts$Age
ca_hh_fin_bits_ibts$AgeF <- factor(as.character(ca_hh_fin_bits_ibts$AgeN), levels = as.character(c(1:max(ca_hh_fin_bits_ibts$AgeN,
    na.rm = T))))

ggplot() + geom_point(data = ca_hh_fin_bits_ibts[!is.na(ca_hh_fin_bits_ibts$AgeF) &
    ca_hh_fin_bits_ibts$LngtClass < 110 & ca_hh_fin_bits_ibts$Quarter == 1 & ca_hh_fin_bits_ibts$AgeN <
    26, ], mapping = aes(x = AgeF, y = LngtClass)) + theme_few() + scale_color_manual(values = c(ebpal)) +
    scale_fill_manual(values = c(ebpal)) + guides(colour = "none", fill = "none")
Raw lengths at age from survey

Figure 2.29: Raw lengths at age from survey

ggplot() + geom_point(data = ca_hh_fin_bits_ibts[!is.na(ca_hh_fin_bits_ibts$Age) &
    ca_hh_fin_bits_ibts$LngtClass < 110 & ca_hh_fin_bits_ibts$Quarter == 1, ], mapping = aes(x = Year,
    y = LngtClass)) + facet_wrap(facets = "AgeF") + theme_few() + scale_x_continuous(breaks = function(x) pretty(x,
    n = 5)) + scale_color_manual(values = c(ebpal)) + scale_fill_manual(values = c(ebpal)) +
    guides(colour = "none", fill = "none")
Lengths at age, over time.

Figure 2.30: Lengths at age, over time.

2.3.6 Natural Mortality Estimates

To try and improve upon the magic numbers that are currently the basis of the assumed natural mortality across ages, we can use the Gislason (et al. 2010) method for estimating natural mortality based on length, \(L_{\infty}\), and \(K\). \[ ln(M) = 0.55 - 1.61ln(L) + 1.44ln(L_{\infty}) + ln(K) \] Where M is natural mortality, \(L\) is length at a given age (and/or age*year), \(L_{\infty}\) is the asymptotal length of the stock, and \(K\) is the shape parameter of the Von Bertalanffy growth curve.

To estimate \(L_{\infty}\) and \(K\), we can fit a linear model to the 1-year staggered lengths (Ford-Walford method) and derive these values from the slope and intercept parameters.

## Create staggered length at age data
LAA_long <- reshape(data = LAA_combsex, varying = colnames(LAA_combsex)[-1], v.names = "MeanLength",
    timevar = "Age", times = colnames(LAA_combsex)[-1], idvar = "year", direction = "long")
LAA_long$AgeN <- as.numeric(gsub(pattern = "a", replacement = "", x = LAA_long$Age))

tempshift <- LAA_long
tempshift$AgeN <- tempshift$AgeN + 1
tempshift$year <- tempshift$year + 1
names(tempshift)[3] <- "FirstMeanLength"

temp_df <- merge(LAA_long, tempshift, by = c("AgeN", "year"), all.x = TRUE)

m1 <- lm(MeanLength ~ FirstMeanLength, data = temp_df[!is.na(temp_df$MeanLength) &
    !is.na(temp_df$FirstMeanLength), ])

plt_fw <- ggplot(temp_df[!is.na(temp_df$MeanLength) & !is.na(temp_df$FirstMeanLength),
    ]) + geom_point(mapping = aes(x = FirstMeanLength, y = MeanLength, colour = Age.x)) +
    geom_smooth(mapping = aes(x = FirstMeanLength, y = MeanLength), method = "lm") +
    scale_colour_manual(values = ebpal) + theme_few()

ggplotly(plt_fw)
## `geom_smooth()` using formula = 'y ~ x'

From this linear model we can calculate that \(L_{\infty} =\) 34.0148381, and \(K =\) 0.3041184. Now we can calculate the natural mortality estimates for each age across time.

Alternately, we can estimate and from raw survey data using maximum likelihood estimation. we can look at the length at age plots to propose some good starting points for this estimation.

## Initialising values for linf, k and t0
theta <- c(unname(m1$coefficients[1]/(1 - m1$coefficients[2])), unname(-log(m1$coefficients[2])),
    0)

## Explicit ages and lengths to be used in optimisation
tempdf <- ca_hh_fin_bits_ibts[!is.na(ca_hh_fin_bits_ibts$Age) & ca_hh_fin_bits_ibts$LngtClass <
    110 & ca_hh_fin_bits_ibts$Quarter == 1 & ca_hh_fin_bits_ibts$AgeN < 26, ]

age <- tempdf[, "AgeN"]
lt <- tempdf[, "LngtClass"]

## Optimisation function
SSQ <- function(theta, x) {
    Linf <- theta[1]
    K <- theta[2]
    t0 <- theta[3]
    epsilon <- rep(0, length(age))
    lpred <- rep(0, length(age))
    for (i in 1:length(age)) {
        lpred[i] <- Linf * (1 - exp(-K * (age[i] - t0)))
        epsilon[i] <- (lt[i] - lpred[i])^2
    }
    ssq <- sum(epsilon)
    return(ssq)
}
out <- optim(theta, fn = SSQ, method = "BFGS", x = age, hessian = TRUE)
out$V <- solve(out$hessian)  #solve the hessian
out$S <- sqrt(diag(out$V))  #Standard Error
out$R <- out$V/(out$S %o% out$S)  #Correlation
L_inf <- unname(m1$coefficients[1]/(1-m1$coefficients[2]))
K <- unname(-log(m1$coefficients[2]))
t0 <- 0
sd <- 1

vbg <- bbmle::mle2(log(LngtClass) ~ #response variable
        dnorm(mean = log(L_inf)+log(1-exp(-K*(AgeN-t0))), sd=sd), 
        data=tempdf, #data frame
        start=list(L_inf=L_inf , K=K, t0=t0, sd=sd))

coef <- data.frame(coeff = names(vbg@fullcoef),
                   mech = c(L_inf, K, t0, sd),
                   est = as.numeric(vbg@fullcoef))

Now by utilising the raw input data we arrive at similar values for L and k as we acheived with the Ford-Walford method.

tempdf$est_sv <- out$par[1] * (1 - exp(-out$par[2] * (tempdf$AgeN - out$par[3])))
tdf <- data.frame(AgeN = seq(from = 0, to = max(tempdf$AgeN), by = 0.1))
tdf$est_sv <- out$par[1] * (1 - exp(-out$par[2] * (tdf$AgeN - out$par[3])))

ggplot() + geom_point(data = tempdf, mapping = aes(x = AgeF, y = LngtClass)) + geom_line(data = tdf,
    mapping = aes(x = AgeN, y = est_sv), colour = ebpal[1], size = 2) + theme_few() +
    scale_color_manual(values = c(ebpal)) + scale_fill_manual(values = c(ebpal)) +
    guides(colour = "none", fill = "none")
Plot estimated growth parameters over lengths at age.

Figure 2.31: Plot estimated growth parameters over lengths at age.

After all of this, these life history parameters do not look acceptable for this species. Therefore we take values from fishbase.se, such that: \(L_{\infty} =\) 52cm and \(K =\) 0.168 (\(t0 =\) -0.72, in this case).

## Select life history parameters
Linf <- 52  #Fishbase for Baltic
K <- 0.168  #Fishbase for Baltic
t0 <- -0.72  #Fishbase for Baltic
tdf <- data.frame(AgeN = seq(from = 0, to = max(tempdf$AgeN), by = 0.1))
tdf$vbgf <- Linf * (1 - exp(-K * (tdf$AgeN - t0)))
ggplot() + geom_line(data = tdf, mapping = aes(x = AgeN, y = vbgf), colour = ebpal[1],
    size = 2) + theme_few() + scale_color_manual(values = c(ebpal)) + scale_fill_manual(values = c(ebpal)) +
    guides(colour = "none", fill = "none")
Plot of Selected VBGF.

Figure 2.32: Plot of Selected VBGF.

## Calculate annually varying natural mortality
LAA_long$nm <- exp(0.55 - 1.61 * log(LAA_long$MeanLength) + 1.44 * log(Linf) + log(K))
nm_var <- LAA_long[!is.na(LAA_long$nm), ]

## Aggregate to time invariant natural mortality
nm_fix <- aggregate(nm ~ AgeN, data = nm_var, FUN = "mean")

nm_stdr <- aggregate(nm ~ AgeN, data = nm_var, FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})

names(nm_stdr)[2] <- "StdErr"
nm_stdr <- merge(nm_stdr, nm_fix, by = "AgeN", all.y = T)
nm_stdr$ymax <- nm_stdr$nm + 1.96 * nm_stdr$StdErr
nm_stdr$ymin <- nm_stdr$nm - 1.96 * nm_stdr$StdErr

nm_var$Year <- as.factor(as.character(nm_var$year))
nm_var$Age <- factor(as.character(nm_var$AgeN), levels = unique(as.character(nm_var$AgeN)))
plt_nmvar_age <- ggplot(nm_var) + geom_line(mapping = aes(x = year, y = nm, group = Age,
    colour = Age)) + facet_wrap(facets = "Age", scales = "free_y") + scale_color_manual(values = ebpal) +
    theme_few() + theme(axis.text.x = element_text(angle = 45))

ggplotly(plt_nmvar_age)

Figure 2.33: Time and age varying natural mortality based on Gislason. Time faceted by age.

plt_nmvar_year <- ggplot(nm_var) + geom_line(mapping = aes(x = AgeN, y = nm)) + facet_wrap(facets = "Year") +
    theme_few()

ggplotly(plt_nmvar_year)

Figure 2.34: Time and age varying natural mortality based on Gislason. Ages faceted by time.

nm_sam <- as.data.frame(nm_var[, c("AgeN", "year", "nm")])
nm_sam <- reshape(nm_sam, v.names = "nm", timevar = "AgeN", idvar = "year", direction = "wide")


# Raw annual estimates
nm_SAM <- nm_sam
# for(i in 1:ncol(nm_SAM)){ for(j in 1:nrow(nm_SAM)){ nm_SAM[j, i] <-
# ifelse(is.na(nm_SAM[j, i]), -9, nm_SAM[j, i]) } }

#### Make early 'NA' Values plausible
for (i in 1:ncol(nm_SAM)) {
    for (j in 1:nrow(nm_SAM)) {
        nm_SAM[j, i] <- ifelse(is.na(nm_SAM[j, i]), median(c(nm_SAM[, i]), na.rm = T),
            nm_SAM[j, i])
    }
}

save_as_lowestoft(df = nm_SAM[nm_SAM$year %in% c(2002:(DataYear + 1)), colnames(nm_SAM)[-1]],
    file_path = "Assessment Input/NaturalMortalityVariants/timeVariantGislasonRaw_nm.dat",
    title = "Natural mortality estimates from Gislason method, annual estimations by age and year.",
    rando_numbers = paste(c(1, 4), collapse = "\t"), year_range = paste(c(2002, (DataYear +
        1)), collapse = "\t"), age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = 1)

## Calculate 3y sliding window average for whole timeseries ---- Calculate the
## mean ----
ada <- an(3, nrow(nm_sam))
nmG3sw <- frollmean(x = nm_sam[, -1], n = ada, na.rm = T, align = "right", adaptive = TRUE)
nmG3sw <- as.data.frame(do.call(cbind, nmG3sw))
#### Retain only the correct years
nmG3sw$year <- nm_sam$year
nmG3sw <- nmG3sw[nmG3sw$year %in% c(2002:(DataYear + 1)), ]



#### Wide to long format
nmG3swL <- reshape(nmG3sw, varying = colnames(nmG3sw)[-11], v.names = "nm", timevar = "Age",
    times = colnames(nmG3sw)[-11], idvar = "year", direction = "long")
nmG3swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = nmG3swL$Age))

### Calcualte the standard error ----
nmG3stdr <- frollapply(nm_sam[, -1], 3, FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
nmG3stdr <- as.data.frame(do.call(cbind, nmG3stdr))
nmG3stdr$year <- nm_sam$year

#### Retain only the correct years
nmG3stdr <- nmG3stdr[nmG3stdr$year %in% c(2002:(DataYear + 1)), ]

#### Wide to long format
nmG3stdrL <- reshape(nmG3stdr, varying = colnames(nmG3stdr)[-11], v.names = "StdErrnm",
    timevar = "Age", times = colnames(nmG3stdr)[-11], idvar = "year", direction = "long")
nmG3stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = nmG3stdrL$Age))

### Calculate 93% confidence intervals ----
nmG3swL <- merge(x = nmG3swL, y = nmG3stdrL, by = c("year", "Age"), all.x = TRUE)
nmG3swL$ymax <- nmG3swL$nm + (1.96 * nmG3swL$StdErrnm)
nmG3swL$ymin <- nmG3swL$nm - (1.96 * nmG3swL$StdErrnm)
nmG3swL$AgeN <- nmG3swL$Age
nmG3swL$Age <- as.character(nmG3swL$Age)
nmG3swL <- nmG3swL[nmG3swL$year %in% c(2002:(DataYear + 1)), ]

nm_SAM <- nmG3sw
# for(i in 1:ncol(nm_SAM)){ for(j in 1:nrow(nm_SAM)){ nm_SAM[j, i] <-
# ifelse(is.na(nm_SAM[j, i]), -9, nm_SAM[j, i]) } }

#### Make early 'NA' Values plausible
for (i in 1:ncol(nm_SAM)) {
    for (j in 1:nrow(nm_SAM)) {
        nm_SAM[j, i] <- ifelse(is.na(nm_SAM[j, i]), median(c(nm_SAM[, i]), na.rm = T),
            nm_SAM[j, i])
    }
}

save_as_lowestoft(df = nm_SAM[nm_SAM$year %in% c(2002:(DataYear + 1)), colnames(nm_SAM)[-11]],
    file_path = "Assessment Input/NaturalMortalityVariants/timeVariantGislason3ysw_nm.dat",
    title = "Natural mortality estimates from Gislason method, five year sliding window means, by age and year.",
    rando_numbers = paste(c(1, 4), collapse = "\t"), year_range = paste(c(2002, (DataYear +
        1)), collapse = "\t"), age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = 1)



## Calculate 5y sliding window average for whole timeseries ---- Calculate the
## mean ----
ada <- an(5, nrow(nm_sam))
nmG5sw <- frollmean(x = nm_sam[, -1], n = ada, na.rm = T, align = "right", adaptive = TRUE)
nmG5sw <- as.data.frame(do.call(cbind, nmG5sw))
#### Make the first year equal to the first calculable 5y average
nmG5sw$year <- nm_sam$year
# mo5sw[mo5sw$year == 2002, -ncol(mo5sw)] <- mo5sw[mo5sw$year == 2003,
# -ncol(mo5sw)]
nmG5sw <- nmG5sw[nmG5sw$year %in% c(2002:(DataYear + 1)), ]


#### Wide to long format
nmG5swL <- reshape(nmG5sw, varying = colnames(nmG5sw)[-11], v.names = "nm", timevar = "Age",
    times = colnames(nmG5sw)[-11], idvar = "year", direction = "long")
nmG5swL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = nmG5swL$Age))

### Calcualte the standard error ----
nmG5stdr <- frollapply(nm_sam[, -1], 5, FUN = function(x) {
    sd(x, na.rm = TRUE)/sqrt(length(na.omit(x)))
})
nmG5stdr <- as.data.frame(do.call(cbind, nmG5stdr))
nmG5stdr$year <- nm_sam$year

#### Make the first year equal to the first calculable 5y average
nmG5stdr[nmG5stdr$year == 2002, -ncol(nmG5stdr)] <- nmG5stdr[nmG5stdr$year == 2003,
    -ncol(nmG5stdr)]
nmG5stdr <- nmG5stdr[nmG5stdr$year %in% c(2002:(DataYear + 1)), ]

#### Wide to long format
nmG5stdrL <- reshape(nmG5stdr, varying = colnames(nmG5stdr)[-11], v.names = "StdErrnm",
    timevar = "Age", times = colnames(nmG5stdr)[-11], idvar = "year", direction = "long")
nmG5stdrL$Age <- as.numeric(gsub(pattern = "V", replacement = "", x = nmG5stdrL$Age))

### Calculate 95% confidence intervals ----
nmG5swL <- merge(x = nmG5swL, y = nmG5stdrL, by = c("year", "Age"), all.x = TRUE)
nmG5swL$ymax <- nmG5swL$nm + (1.96 * nmG5swL$StdErrnm)
nmG5swL$ymin <- nmG5swL$nm - (1.96 * nmG5swL$StdErrnm)
nmG5swL$AgeN <- nmG5swL$Age
nmG5swL$Age <- as.character(nmG5swL$Age)
nmG5swL <- nmG5swL[nmG5swL$year %in% c(2002:(DataYear + 1)), ]

nm_SAM <- nmG5sw
# for(i in 1:ncol(nm_SAM)){ for(j in 1:nrow(nm_SAM)){ nm_SAM[j, i] <-
# ifelse(is.na(nm_SAM[j, i]), -9, nm_SAM[j, i]) } }

#### Make early 'NA' Values plausible
for (i in 1:ncol(nm_SAM)) {
    for (j in 1:nrow(nm_SAM)) {
        nm_SAM[j, i] <- ifelse(is.na(nm_SAM[j, i]), median(c(nm_SAM[, i]), na.rm = T),
            nm_SAM[j, i])
    }
}

save_as_lowestoft(df = nm_SAM[nm_SAM$year %in% c(2002:(DataYear + 1)), colnames(nm_SAM)[-11]],
    file_path = "Assessment Input/NaturalMortalityVariants/timeVariantGislason5ysw_nm.dat",
    title = "Natural mortality estimates from Gislason method, five year sliding window means, by age and year.",
    rando_numbers = paste(c(1, 4), collapse = "\t"), year_range = paste(c(2002, (DataYear +
        1)), collapse = "\t"), age_range = paste(c(1, 10), collapse = "\t"), timeseries_type = 1)
plt_nmfix <- ggplot(nm_stdr) + geom_line(mapping = aes(x = AgeN, y = nm)) + geom_ribbon(mapping = aes(x = AgeN,
    ymax = ymax, ymin = ymin), alpha = 0.3) + theme_few()

ggplotly(plt_nmfix)

Figure 2.35: Age varying natural mortality based on Gislason (mean values from above time series +/- 95% confidence intervals.

### save_as_lowestoft Five Year Sliding Window
nm_SAM <- nm_stdr
nm_SAM$year <- rep("all", nrow(nm_SAM))
nm_SAM <- reshape(nm_SAM[, c("AgeN", "nm", "year")],
                 # varying = as.factor(as.character(nm_stdr$AgeN)),
                 v.names = "nm",
                 timevar = "AgeN",
                 idvar = "year",
                 direction = "wide")

# for(i in 1:ncol(nm_SAM)){
#   for(j in 1:nrow(nm_SAM)){
#     nm_SAM[j, i] <- ifelse(is.na(nm_SAM[j, i]), -9, nm_SAM[j, i])
#   }
# }

#### Make early "NA" Values plausible
for(i in 1:ncol(nm_SAM)){
  for(j in 1:nrow(nm_SAM)){
    nm_SAM[j, i] <- ifelse(is.na(nm_SAM[j, i]), median(c(nm_SAM[,i]), na.rm = T), nm_SAM[j, i])
  }
}

save_as_lowestoft(df = nm_SAM[, colnames(nm_SAM)[-1]],
                  file_path = "Assessment Input/NaturalMortalityVariants/timeInvariantGislason_nm.dat",
                  title = "Natural mortality estimates from Gislason method, timeseries means by age for time-invariant profile.",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"),
                  timeseries_type = 2)

#Table for HTML
kable(nm_stdr,
      caption = "Mean mortalities by age for time invariant natural mortality in SAM.")
Table 2.11: Mean mortalities by age for time invariant natural mortality in SAM.
AgeN StdErr nm ymax ymin
1 0.0679126 1.3259716 1.4590803 1.1928628
2 0.0203356 0.7813209 0.8211788 0.7414631
3 0.0134688 0.5691832 0.5955820 0.5427844
4 0.0117310 0.4549878 0.4779807 0.4319950
5 0.0106549 0.3967858 0.4176693 0.3759022
6 0.0099764 0.3642710 0.3838248 0.3447172
7 0.0124551 0.3313319 0.3557438 0.3069200
8 0.0148525 0.3312037 0.3603146 0.3020929
9 0.0121269 0.3077322 0.3315010 0.2839635
10 0.0182600 0.3071420 0.3429317 0.2713523

Based on scaling these time-invariant natural mortalities up an down, an optimised likelihood profile found that scaling all ages by a factor of 1.2 produced the best model fit. To see the details of this please see the working report, or script in the appendix.

### save_as_lowestoft Five Year Sliding Window
nm_scaled <- nm_stdr
nm_scaled$year <- rep("all", nrow(nm_scaled))
nm_scaled$nm <- nm_scaled$nm*1.2
nm_scaled <- reshape(nm_scaled[, c("AgeN", "nm", "year")],
                 # varying = as.factor(as.character(nm_stdr$AgeN)),
                 v.names = "nm",
                 timevar = "AgeN",
                 idvar = "year",
                 direction = "wide")

# for(i in 1:ncol(nm_scaled)){
#   for(j in 1:nrow(nm_scaled)){
#     nm_scaled[j, i] <- ifelse(is.na(nm_scaled[j, i]), -9, nm_scaled[j, i])
#   }
# }

#### Make early "NA" Values plausible
for(i in 1:ncol(nm_scaled)){
  for(j in 1:nrow(nm_scaled)){
    nm_scaled[j, i] <- ifelse(is.na(nm_scaled[j, i]), median(c(nm_scaled[,i]), nm_scaled = T), nm_scaled[j, i])
  }
}

save_as_lowestoft(df = nm_scaled[, colnames(nm_scaled)[-1]],
                  file_path = "Assessment Input/NaturalMortalityVariants/scaledTimeInvariantGislason_nm.dat",
                  title = "Time invariant natural mortality estimates from Gislason method scaled according to optimised likelihood profile runs.",
                  rando_numbers = paste(c(1, 4), collapse = "\t"),
                  year_range = paste(c(2002, (DataYear+1)), collapse = "\t"),
                  age_range = paste(c(1, 10), collapse = "\t"),
                  timeseries_type = 2)

#Table for HTML
kable(nm_stdr,
      caption = "Time invariant natural mortality estimates from Gislason method scaled according to optimised likelihood profile runs.")
Table 2.12: Time invariant natural mortality estimates from Gislason method scaled according to optimised likelihood profile runs.
AgeN StdErr nm ymax ymin
1 0.0679126 1.3259716 1.4590803 1.1928628
2 0.0203356 0.7813209 0.8211788 0.7414631
3 0.0134688 0.5691832 0.5955820 0.5427844
4 0.0117310 0.4549878 0.4779807 0.4319950
5 0.0106549 0.3967858 0.4176693 0.3759022
6 0.0099764 0.3642710 0.3838248 0.3447172
7 0.0124551 0.3313319 0.3557438 0.3069200
8 0.0148525 0.3312037 0.3603146 0.3020929
9 0.0121269 0.3077322 0.3315010 0.2839635
10 0.0182600 0.3071420 0.3429317 0.2713523

2.3.7 Catch weight at age (CWAA)

This section is currently a work in progress - need to figure out the appropriate method to raise intercatch data according to the allocations, manually, to be able to automatically update the section each year (instead of copy-pasting intercatch ouput for multiple tables every year).

cw_df <- cw

2.4 Cohort Tracking

We can track the progression of different cohorts through time from both commercial and survey data.

Let’s start with catches.

# === Data Prep ====
catchNumLng <- reshape(data = catchNum, varying = list(colnames(catchNum)[2:length((colnames(catchNum)))]),
    v.names = c("Number"), timevar = "Age", direction = "long")
# catchNumLng$Age <- as.factor(as.character(catchNumLng$Age)) catchNumLng$Age
# <- factor(catchNumLng$Age, levels = c('1', '2', '3', '4', '5', '6', '7', '8',
# '9', '10')) catchNumLng$Year <- as.factor(as.character(catchNumLng$Year))
catchNumLng$Year <- as.numeric(as.character(catchNumLng$Year))

catchcohortsLng <- reshape(data = catchcohorts, varying = list(colnames(catchcohorts)[2:length((colnames(catchcohorts)))]),
    v.names = c("Age"), timevar = "Cohort", direction = "long")
# catchcohortsLng$Age <- factor(catchcohortsLng$Age, levels = c('1', '2', '3',
# '4', '5', '6', '7', '8', '9', '10')) catchcohortsLng$Age <-
# as.factor(as.character(catchcohortsLng$Age), levels = c('1', '2', '3', '4',
# '5', '6', '7', '8', '9', '10')) catchcohortsLng$Year <-
# as.factor(as.character(catchcohortsLng$Year))
catchcohortsLng$Year <- as.numeric(as.character(catchcohortsLng$Year))
# =====

# === Figure Cohorts over time from catches ====
plt_catchCohorts <- ggplot() + geom_line(data = catchcohortsLng, mapping = aes(x = Year,
    y = Age, group = Cohort), linetype = "dotted") + geom_point(data = catchNumLng,
    mapping = aes(x = Year, y = Age, size = Number)) + theme_clean() + coord_cartesian(xlim = c(1999,
    DataYear)) + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

ggplotly(plt_catchCohorts)

Figure 2.36: Bubble plot showing numbers (size of bubble) at age (y-axis), over time (x-axis) in catches. The dotted lines show the progression of co-horts where large and small numbers at age can be tracked year to year.

# ====
# === Figure Numbers per age group over time (less intuitive than above cohort
# plot) ====
plt_catchTime <- ggplot() + geom_line(data = catchNumLng, mapping = aes(x = Year,
    y = Number/1e+06, group = Age)) + facet_grid(rows = vars(Age), scales = "free_y") +
    ylab("Number (millions)") + theme_few() + theme(axis.text.x = element_text(angle = 90,
    hjust = 1, vjust = 0.5))

ggplotly(plt_catchTime)

Figure 2.37: Numbers per age over time.

# =====

Now, let’s do the same with survey estimations of numbers at age.

# === Data Prep ====
survcohorts <- read.csv(file = "Data/ple.27.21-32_CohortMatrix_1998-WorkingYear.csv",
    header = T)
survcohorts$Year <- as.factor(as.character(survcohorts$Year))

survcohortsLng <- reshape(data = survcohorts, varying = list(colnames(survcohorts)[2:length((colnames(survcohorts)))]),
    v.names = c("Age"), timevar = "Cohort", direction = "long")
# survcohortsLng$Age <- as.factor(as.character(survcohortsLng$Age))
survcohortsLng$Year <- as.factor(as.character(survcohortsLng$Year))
survcohortsLng <- survcohortsLng[survcohortsLng$Age <= 6, ]
# =====

# === Plot =====
plt_survCohorts <- ggplot() + geom_point(data = survTunLng, mapping = aes(x = Year,
    y = Age, size = Index)) + geom_line(data = survcohortsLng, mapping = aes(x = Year,
    y = Age, group = Cohort), linetype = "dotted") + theme_classic() + facet_grid(rows = vars(Survey)) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

ggplotly(plt_survCohorts)

Figure 2.38: Bubble plot showing numbers (size of bubble) at age (y-axis), over time (x-axis) estimated from surveys. The dotted lines show the progression of co-horts where large and small numbers at age can be tracked year to year.

k <- append(k, "survcohortsLng")
rm(list = ls()[!ls() %in% k])
# ======
LS0tDQp0aXRsZTogIlBsZS4yNy4zYS4yMS0zMiBCZW5jaG1hcmsgRGF0YSBJbnZlc3RpZ2F0aW9uIg0KYXV0aG9yOg0KICAtIG5hbWU6ICJFbGxpb3QgSi4gQnJvd24iDQogIC0gbmFtZTogIkNhc3BlciBXLiBCZXJnIg0KICAtIG5hbWU6ICJTdmVuIFN0w7Z0ZXJhIg0KZGF0ZTogIjE2LzA5LzIwMjQiDQpvdXRwdXQ6IA0KICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoubWFpbi1jb250YWluZXIgew0KICBtYXgtd2lkdGg6IDkwJSAhaW1wb3J0YW50Ow0KICBtYXJnaW46IGF1dG87DQp9DQpwLmNhcHRpb24gew0KICBmb250LXNpemU6IDAuOGVtOw0KICBmb250LXN0eWxlOiBpdGFsaWM7DQp9DQo8L3N0eWxlPg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgZXZhbCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgIHRpZHkgPSAnZm9ybWF0UicsDQogICAgICAgICAgICAgICAgICAgICAgb3V0LndpZHRoID0gIjkwJSIpDQoNCiM9PT0NCiMgTWFudWFsIHNldHRpbmdzIGZvciBmaWd1cmUgZm9ybWF0dGluZw0KIz09PT0NCiMgZWJwYWwgPC0gYygiIzJGM0VFQSIsICIjMUZEMDgyIiwgIiMwMzBGNEYiLCAiI0Y2RDA0RCIsICIjRkM3NjM0IiwgIiNGN0JCQjEiLCAiI0U4M0Y0OCIsICIjMDA4ODM1IiwgIiM3OTIzOEUiKQ0KZWJwYWwgPC0gYygiIzgwMDA4MCIsICIjMDA2NDAwIiwgIiNENTVFMDAiLCAiIzAwNzJCMiIsICIjRjBFNDQyIiwgIiMwMDlFNzMiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiNDQzc5QTciLCAiIzVEQTVEQSIsICIjRkY4MDAwIiwgIiM4OUNGRjAiLCAiI0E1MkEyQSIsICIjNzdERDc3IiwgIiNGRkZBQ0QiKQ0KIz09PT09DQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCiMjIENvbnRlbnRzDQpUaGlzIHNjcmlwdCBnZW5lcmF0ZXMgYSB3b3JraW5nIGRvY3VtZW50IGRlc2NyaWJpbmcgdGhlIGRhdGEgYXZhaWxhYmxlIGZvciBhbiBhc3Nlc3NtZW50IG9mIHBsZS4yNy4zYS4yMS0zMjsgUGxhaWNlIGluIHRoZSBLYXR0ZWdhdCwgVGhlIEJlbHQgU2VhcyBhbmQgdGhlIEJhbHRpYyBTZWEuICBUaGUgcmVwb3J0IGdlbmVyYXRlZCBjb3ZlcnMgdGhlIGZvbGxvd2luZyB0b3BpY3M6DQoNCi0gQXNzZXNzbWVudCBJbnB1dCBEYXRhDQogIC0gQ2F0Y2hlcyBhbmQgTGFuZGluZ3MNCiAgLSBTdXJ2ZXkgSW5kaWNlcw0KICAtIEJpb2xvZ2ljYWwgRGF0YQ0KICAtIFJlZmVyZW5jZSBQb2ludHMNCi0gQmFja2dyb3VuZCBEYXRhIGFuZCBfYWQtaG9jXyBSZXF1ZXN0cyBhcmUgZGVhbHQgd2l0aCBpbiB0aGUgcmVsZXZhbnQgc2VjdGlvbnMuDQogIA0KTW9zdCBvZiB0aGUgY29kZSB1c2VkIHRvIHByb2Nlc3MgZGF0YSBhbmQgY3JlYXRlIHZpc3VhbGlzYXRpb25zIGFyZSBoaWRkZW4gaW4gdGhpcyBIVE1MLiAgVG8gdmlldyBlYWNoIGNodW5rLCBzaW1wbHkgY2xpY2sgb24gdGhlIGJ1dHRvbiB0byB0aGUgcmlnaHQgb2YgdGhlIHJlbGV2YW50IHNlY3Rpb24uICBUbyBkb3dubG9hZCB0aGUgZW50aXJlIFItbWFya2Rvd24gKC5ybWQpIGZpbGUgaW5jbHVkaW5nIGFsbCB0ZXh0IGFuZCBjb2RlIGNodW5rcywgdXNlIHRoZSBfY29kZV8gYnV0dG9uIGF0IHRoZSB0b3Agb2YgdGhlIHBhZ2UsIHdpdGggdGhlIGRyb3Bkb3duIGFycm93LiAgDQoNCiMjIFByZXBhcmF0aW9uDQpUbyBydW4gdGhpcyBzY3JpcHQgeW91IHJlcXVpcmUgdGhlIGZvbGxvd2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSJoaWRlIn0NCnJlcXVpcmUobWdjdikNCnJlcXVpcmUoZGF0YS50YWJsZSkNCnJlcXVpcmUocmVzaGFwZTIpDQpyZXF1aXJlKGtuaXRyKQ0KcmVxdWlyZShzY2FsZXMpDQpyZXF1aXJlKGJvb2tkb3duKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShnZ3RoZW1lcykNCnJlcXVpcmUoc3RyaW5ncikNCnJlcXVpcmUobGF0dGljZSkNCnJlcXVpcmUocGx5cikNCnJlcXVpcmUocGxvdGx5KQ0KcmVxdWlyZShpY2VzQWR2aWNlKQ0KcmVxdWlyZSgic3RvY2thc3Nlc3NtZW50IikgIyBhdmFpbGFibGUgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vZmlzaGZvbGxvd2VyL1NBTQ0KcmVxdWlyZShwYXJhbGxlbCkNCnJlcXVpcmUoc2YpDQoNCm15cHJvcCA8LSBmdW5jdGlvbihkZiwgbm9tbyA9ICJub21vIiwgTm9BdExuZ3QgPSAiQ0FOb0F0TG5ndCIpew0KICB0IDwtIHN1bShkZiRub21vKS9zdW0oZGYkQ0FOb0F0TG5ndCkNCn0NCg0KY2F0Y2hGcmFjIDwtIGZ1bmN0aW9uKHgsIG5tLCB3LCBmcmFjKXsNCiAgRiA8LSBnZXRGKHgpDQogIFogPC0gRitubQ0KICBOIDwtIGdldE4oeCkNCiAgQyA8LSBGL1oqKDEtZXhwKC1aKSkqTg0KICByZXR1cm4oc3VtKGZyYWMqdypDKSkNCn0NCg0Kc2F2ZV9hc19sb3dlc3RvZnQgPC0gZnVuY3Rpb24oZGYsIGZpbGVfcGF0aCwgdGl0bGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygiMSIsICI2IiksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCBEYXRhWWVhcisxKSwgY29sbGFwc2UgPSAiXHQiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfcmFuZ2UgPSBwYXN0ZShjKDEsIDEwKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVzZXJpZXNfdHlwZSA9IHBhc3RlKGMoMSwgIiMgMSBpbmRpY2F0ZXMgYW5udWFsbHkgdmFyeWluZywgMiBpbmRpY2F0ZXMgZml4ZWQgdmFsdWVzIiksIGNvbGxhcHNlID0gIlx0IikpIHsNCiAgIyBPcGVuIGEgY29ubmVjdGlvbiB0byB0aGUgZmlsZQ0KICBjb24gPC0gZmlsZShmaWxlX3BhdGgsIG9wZW4gPSAid3QiKQ0KICANCiAgIyBXcml0ZSB0aGUgaGVhZGVyIChjdXN0b21pemUgYXMgbmVlZGVkKQ0KICB3cml0ZUxpbmVzKHBhc3RlMCh0aXRsZSksIGNvbikNCiAgd3JpdGVMaW5lcyhwYXN0ZTAocmFuZG9fbnVtYmVycyksIGNvbikNCiAgd3JpdGVMaW5lcyhwYXN0ZTAoeWVhcl9yYW5nZSksIGNvbikNCiAgd3JpdGVMaW5lcyhwYXN0ZTAoYWdlX3JhbmdlKSwgY29uKQ0KICB3cml0ZUxpbmVzKHBhc3RlMCh0aW1lc2VyaWVzX3R5cGUpLCBjb24pDQogIA0KICAjIFdyaXRlIHRoZSBkYXRhZnJhbWUgdG8gdGhlIGZpbGUNCiAgd3JpdGUudGFibGUoZGYsIGNvbiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQ0KICANCiAgIyBDbG9zZSB0aGUgY29ubmVjdGlvbg0KICBjbG9zZShjb24pDQp9DQoNCiMjIENyZWF0ZSBzZXF1ZW5jZXMgZm9yIG1vdmluZyB3aW5kb3cgYXZlcmFnZToNCmFuID0gZnVuY3Rpb24obiwgbGVuKSBjKHNlcS5pbnQobiksIHJlcChuLCBsZW4tbikpDQoNCmBgYA0KDQpXZSBhbHNvIG5lZWQgdG8gc2V0IGEgZmV3IHZhcmlhYmxlcyBtYW51YWxseS4gIA0KVGhlIGZpcnN0IGlzIHRoZSAqRGF0YVllYXIqLCB3aGljaCBpcyB0aGUgeWVhciBpbW1lZGlhdGVseSBwcmVjZWVkaW5nIHRoZSBhc3Nlc3NtZW50IHllYXIgb3IgdGhlIHllYXIgZm9yIHdoaWNoIHRoZSBtb3N0IHJlY2VudCBkYXRhIGlzIGF2YWlsYWJsZS4gIA0KVGhlIHNlY29uZCBpcyB0aGUgY2F0Y2ggd2UgKElDRVMpIGFkdmlzZWQgYXMgVEFDIGZvciB0aGUgbGFzdCBhc3Nlc3NtZW50ICpMYXN0SWNlc0FkdmljZSosIGluIHRvbm5lcy4gX19OT1RFX18gdGhpcyB2YWx1ZSBpcyB0YWtlbiBmcm9tIHRoZSBhZHZpY2Ugc2hlZXQsIHRvIGNvbXBhcmUgY2hhbmdlcyBpbiBhZHZpY2UsIG5vdCBjaGFuZ2VzIGluIGFkdmljZSByZWxhdGl2ZSB0byBhY3R1YWwgQWxsb3dhYmxlIENhdGNoZXMuDQpUaGUgdGhpcmQgaXMgd2hldGhlciB0aGlzIHJ1biBpcyBleHBsb3JhdG9yeSwgb3IgdG8gYmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgZmluYWwgYWR2aWNlLiBUaGlzIG9wdGlvbiB3aWxsIGRldGVybWluZSB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgdXNlZCB0byBkZXRlcm1pbmUgdGhlIHNob3J0LXRlcm0gZm9yZWNhc3RzLiANCg0KYGBge3J9DQpEYXRhWWVhciA8LSAyMDIzDQpMYXN0SWNlc0FkdmljZSA8LSAyMTczNSAjIEFkdmlzZWQgY2F0Y2ggZm9yIGFyZWFzIDIxLTMyIChmcm9tIHN0b2NrIHNwbGl0dGluZyB0YWJsZSBpbiBhZHZpY2UpDQppc0ZpbmFsIDwtIEZBTFNFDQojIGlzRmluYWwgPC0gVFJVRQ0KYGBgDQoNCiMgQXNzZXNzbWVudCBJbnB1dCBEYXRhDQojIyBMYW5kaW5ncyBhbmQgQ2F0Y2hlcw0KQ2F0Y2ggZGF0YSwgaW5jbHVkaW5nIGJyZWFrIGRvd25zIGJ5IGxhbmRpbmdzL2Rpc2NhcmRzLCBhcmUgdGFrZW4gZGlyZWN0bHkgZnJvbSBpbnRlci1jYXRjaCBmb3IgZWFjaCBvZiB0aGUgaGlzdG9yaWMgc3RvY2tzIChuYW1lbHkgcGxlLjI3LjIxLTIzIGFuZCBwbGUuMjcuMjQtMzIpLCB3aGVyZSBkaXNjYXJkcyBhbmQgc2FtcGxlZCBtZWFzdXJlcyBhcmUgcmFpc2VkIGFjY29yZGluZyB0byB0aGUgcHJpb3JpdGlzYXRpb24gZGVzY3JpYmVkIGluIHRoZSBjb3JyZXNwb25kaW5nIHN0b2NrIGFubmV4ZXMsIGJlZm9yZSB0aGUgcmVzdWx0YW50IGNhdGNoIGRhdGEgYXJlIGNvbWJpbmVkLiBUaGUgaW1wb3J0ZWQgdGFibGUgaXMgdGhlIGN1bXVsYXRpdmUgZXh0cmFjdHMgZnJvbSBJbnRlckNhdGNoLCBzcGVjaWZpY2FsbHkgX1RhYmxlIDFfIGZyb20gdGhlIF9BbGxDYXRjaGVzXyBleHRyYWN0aW9uIGFuZCBmaWxlIF9DYXRjaEFuZFNhbXBsZURhdGFUYWJsZXMudHh0Xy4NCg0KRnVydGhlcm1vcmUsIHJlY3JlYXRpb25hbCBjYXRjaGVzIGZyb20gR2VybWFueSBoYXZlIGJlZW4gaW50cm9kdWNlZCBsYXRlIGluIHRoZSBwcm9jZXNzLiAgSGVyZSB3ZSBkZXNjcmliZSB0aGUgZGF0YSB0aGF0IGFyZSBhdmFpbGFibGUgZm9yIGluY29ycG9yYXRpb24gaW50byBhbiBhc3Nlc3NtZW50IG1vZGVsLCBidXQgYWxzbyBkZXNjcmliZSBob3cgdGhlc2UgZGF0YSB3aWxsIGJlIGZ1cnRoZXIgaW50ZWdyYXRlZCB0byB0aGUgd2hvbGUgYXNzZXNzbWVudCBwcm9jZWR1cmUgaW4gdGhlIG5lYXIgZnV0dXJlLiANCg0KYGBge3J9DQojIyBSZWFkIGluIHRoZSBjb21iaW5lZCBJbnRlcmNhdGNoIG91dHB1dCBmcm9tIHRoZSB0d28gb2xkIHN0b2Nrcy4NCmljX3JhdyA8LSByZWFkLmNzdihmaWxlID0gIkRhdGEvQ2F0Y2hEYXRhL1BsZS4yNy4yMS0zMl9JbnRlcmNhdGNoVGFibGUxXzIwMDItMjAyMy5jc3YiLCBoZWFkZXIgPSBUKQ0KDQojIyBSZWFkIGluIGhpc3RvcmljIFRBQyB2YWx1ZXMgYnkgYXJlYQ0KdGFjX3JhdyA8LSByZWFkLmNzdihmaWxlID0gIkRhdGEvcGxlLjI3LjIxXzIyLTMyX1RBQy1IaXN0b3JpZXNfMjAwMC1EYXRhWWVhci5jc3YiLCBoZWFkZXIgPSBUKQ0KYGBgDQoNClRoZXNlIGRhdGEgYXJlIGNsZWFuZWQgYWNjb3JkaW5nIHRvIGRhdGEgZm9ybWF0cyBhbmQgbmFtaW5nIGNvbnZlbnRpb25zIChoaWRkZW4gY2h1bmspLg0KYGBge3J9DQppY19yYXckWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGljX3JhdyRZZWFyKSkNCiMgaWNfcmF3JENhdGNoQ2F0ZWdvcnkgPC0gYXMuZmFjdG9yKGdzdWIocGF0dGVybiA9ICJCTVMgbGFuZGluZyIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkJNUyIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBpY19yYXckQ2F0Y2hDYXRlZ29yeSkpDQppY19yYXckU2Vhc29uIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoaWNfcmF3JFNlYXNvbikpDQpuYW1lcyhpY19yYXcpW25hbWVzKGljX3JhdykgPT0gIkNBVE9OLi5Ub25zLiJdIDwtICJDQVRPTiINCmljX3JhdyRGbGVldCA8LSBnc3ViKHBhdHRlcm4gPSAnICcsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBpY19yYXckRmxlZXQsIGZpeGVkID0gVFJVRSkNCiMjIyBBbGxvY2F0ZSBzb21lIHN0cmFuZ2UgZmxlZXQgdHlwZXMgYWNjb3JkaW5nIHRvIGxvZ2ljLCBvciAiQWxsIiB0byAiQWN0aXZlIiBhcyB0aGUgbW9zdCBsaWtlbHkuDQppY19yYXdbaWNfcmF3JEZsZWV0ICVpbiUgYygiT1RCX0NSVV85MC0xMTlfMF8wX2FsbCIsICJNSVNfTUlTXzBfMF8wX0hDIiwgIkFjaXR2ZSAiLCAiVHJhd2wiLCAiQWxsIiwgIkZsZWV0LUFsbCIpLCAiRmxlZXQiXSA8LSAiQWN0aXZlIg0KaWNfcmF3W2ljX3JhdyRGbGVldCAlaW4lIGMoIkdOU19ERUZfYWxsXzBfMF9hbGwiLCAiUGFzc2l2ZSAiLCAiR2lsbG5ldCIsICJUcmFwbmV0IiwgIkxvbmdsaW5lIiksICJGbGVldCJdIDwtICJQYXNzaXZlIg0KaWNfY2xlYW4gPC0gZHJvcGxldmVscyhpY19yYXcpDQoNCiMjIENyZWF0ZSBub3ZlbCBmbGVldCBieSBtYW5hZ2VtZW50IGFyZWENCmljX2NsZWFuJEZsZWV0MiA8LSBpZmVsc2UoaWNfY2xlYW4kQXJlYSA9PSAiMjcuMy5hLjIxIiAmIGljX2NsZWFuJEZsZWV0ID09ICJBY3RpdmUiLCAiTlNfQWN0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGljX2NsZWFuJEFyZWEgPT0gIjI3LjMuYS4yMSIgJiBpY19jbGVhbiRGbGVldCA9PSAiUGFzc2l2ZSIsICJOU19QYXNzaXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShpY19jbGVhbiRBcmVhICE9ICIyNy4zLmEuMjEiICYgaWNfY2xlYW4kRmxlZXQgPT0gIkFjdGl2ZSIsICJCU19BY3RpdmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShpY19jbGVhbiRBcmVhICE9ICIyNy4zLmEuMjEiICYgaWNfY2xlYW4kRmxlZXQgPT0gIlBhc3NpdmUiLCAiQlNfUGFzc2l2ZSIsIE5BKSkpKQ0KDQojIyMgQ2xlYW4gVEFDIGRhdGENCnRhY19yYXckWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHRhY19yYXckWWVhcikpDQoNCmsgPC0gYygiayIsICJpY19jbGVhbiIsICJteXByb3AiLCAiRGF0YVllYXIiLCAiZWJwYWwiLCAiaXNGaW5hbCIsICJMYXN0SWNlc0FkdmljZSIsICJzYXZlX2FzX2xvd2VzdG9mdCIsICJhbiIsICJ0YWNfcmF3IikNCnJtKGljX3JhdykNCmBgYA0KDQpIaXN0b3JpYyBsYW5kaW5ncyBhbmQgVEFDIHZhbHVlcyBhcmUgaW1wb3J0ZWQgZnJvbSBsZWdhY3kgcmVjb3JkcyAoaGlkZGVuIGNodW5rKS4gX1RoZXNlIG5lZWQgdG8gYmUgY29sbGF0ZWQgZm9yIHRoZSBuZXcgInN1cGVyIHN0b2NrIl8uDQpgYGB7ciBldmFsPUZBTFNFfQ0KSGlzdExhbmRfcmF3IDwtIHJlYWQuY3N2KGZpbGUgPSAiRGF0YS9wbGUuMjcuMjEtMjNfSGlzdG9yaWNMYW5kaW5nc18xOTcwLTIwMTcuY3N2IiwgaGVhZGVyID0gVCkNCkhpc3RMYW5kX3JhdyRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoSGlzdExhbmRfcmF3JFllYXIpKQ0KDQoNCg0KIz09PQ0KIyBVcGRhdGUgSGlzdExhbmQNCiM9PT09DQpsYW5kaW5ncyA8LSBhZ2dyZWdhdGUoQ0FUT05+QXJlYStDb3VudHJ5K1llYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhblthcy5udW1lcmljKGFzLmNoYXJhY3RlcihpY19jbGVhbiRZZWFyKSkgPj0gMjAxOCAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgIT0gIkRpc2NhcmRzIiwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KY29sbmFtZXMobGFuZGluZ3MpW2NvbG5hbWVzKGxhbmRpbmdzKSA9PSAiQ0FUT04iXSA8LSAiTGFuZGluZ3MiDQoNCiMgbGFuZGluZ3MyMDE4IDwtIGFnZ3JlZ2F0ZShDQVRPTn5BcmVhK0NvdW50cnkrWWVhciwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gIjIwMTgiICYgaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAhPSAiRGlzY2FyZHMiLCBdLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCiMgbGFuZGluZ3MyMDE4JFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcigyMDE4KSkNCiMgbmFtZXMobGFuZGluZ3MyMDE4KVtuYW1lcyhsYW5kaW5nczIwMTgpID09ICJDQVRPTiJdIDwtICJMYW5kaW5ncyINCiMgIyBsYW5kaW5nczIwMTgkTGFuZGluZ3MgPC0gbGFuZGluZ3MyMDE4JExhbmRpbmdzLzEwMDANCiMgDQojIA0KIyBsYW5kaW5nczIwMTkgPC0gYWdncmVnYXRlKENBVE9OfkFyZWErQ291bnRyeSwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gIjIwMTkiICYgaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAhPSAiRGlzY2FyZHMiLCBdLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCiMgbGFuZGluZ3MyMDE5JFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcigyMDE5KSkNCiMgbmFtZXMobGFuZGluZ3MyMDE5KVtuYW1lcyhsYW5kaW5nczIwMTkpID09ICJDQVRPTiJdIDwtICJMYW5kaW5ncyINCiMgIyBsYW5kaW5nczIwMTkkTGFuZGluZ3MgPC0gbGFuZGluZ3MyMDE5JExhbmRpbmdzLzEwMDANCiMgDQojIGxhbmRpbmdzMjAyMCA8LSBhZ2dyZWdhdGUoQ0FUT05+QXJlYStDb3VudHJ5LCANCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSAiMjAyMCIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ICE9ICJEaXNjYXJkcyIsIF0sDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KIyBsYW5kaW5nczIwMjAkWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKDIwMjApKQ0KIyBuYW1lcyhsYW5kaW5nczIwMjApW25hbWVzKGxhbmRpbmdzMjAyMCkgPT0gIkNBVE9OIl0gPC0gIkxhbmRpbmdzIg0KIyANCiMgbGFuZGluZ3MyMDIxIDwtIGFnZ3JlZ2F0ZShDQVRPTn5BcmVhK0NvdW50cnksIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRZZWFyID09ICIyMDIxIiAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgIT0gIkRpc2NhcmRzIiwgXSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQojIGxhbmRpbmdzMjAyMSRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoMjAyMSkpDQojIG5hbWVzKGxhbmRpbmdzMjAyMSlbbmFtZXMobGFuZGluZ3MyMDIxKSA9PSAiQ0FUT04iXSA8LSAiTGFuZGluZ3MiDQoNCiMgSGlzdExhbmQgPC0gcmJpbmQoSGlzdExhbmRfcmF3LCBsYW5kaW5nczIwMTgsIGxhbmRpbmdzMjAxOSwgbGFuZGluZ3MyMDIwLCBsYW5kaW5nczIwMjEpDQpIaXN0TGFuZCA8LSByYmluZChIaXN0TGFuZF9yYXcsIGxhbmRpbmdzKQ0KZ2V0d2QoKQ0KDQpybShsaXN0ID0gYygiSGlzdExhbmRfcmF3IiwgImxhbmRpbmdzIikpDQojPT09PT0NCg0KayA8LSBhcHBlbmQoaywgYygiSGlzdExhbmQiKSkNCmBgYA0KDQpDYXRjaCBjb2hvcnQgbWF0cmljZXMgYXJlIHNldCB1cCBleHRlcm5hbGx5IGluIGV4Y2VsLCBhY2NvcmRpbmcgdG8gdGhlIGFubnVhbGx5IHVwZGF0ZWQgaW50ZXJjYXRjaCBvdXRwdXQgKGhpZGRlbiBjaHVuaykuDQoqVGhpcyBzZWN0aW9uIG5lZWRzIHRvIGJlIHVwZGF0ZWQgc28gdGhhdCB0aGUgY29ob3J0IG1hdHJpY2VzIHVzZWQgdG8gc3RydWN0dXJlIHRoZSBmaWd1cmVzIGFyZSAgZ2VuZXJhdGVkIGF1dG9tYWdpY2FsbHkgd2l0aCBSLCB0byByZW1vdmUgdGhlIGV4Y2VsIHN0ZXAqDQpgYGB7cn0NCmNhdGNoY29ob3J0cyA8LSByZWFkLmNzdihmaWxlID0gIkRhdGEvcGxlLjI3LjIxLTMyX0NvaG9ydE1hdHJpeF8xOTk4LVdvcmtpbmdZZWFyLmNzdiIsIGhlYWRlciA9IFQpDQpjYXRjaGNvaG9ydHMkWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGNhdGNoY29ob3J0cyRZZWFyKSkNCg0KIyAjPT09DQojICMgQXR0ZW1wdHMgdG8gY3JlYXRlIGNvaG9ydCBtYXRyaXggaW4gUg0KIyAjPT09PQ0KIyBmb3IoaSBpbiAxOihsZW5ndGgoMTk5MjpEYXRhWWVhcikrMSkpew0KIyAgIGFzc2lnbih4ID0gcGFzdGUwKCJjb2hvcnRfIixpKSwNCiMgICAgICAgICAgdmFsdWUgPSBjKHJlcChOQSwgaS0xKSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgYygxOjEwKSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgYyhyZXAoTkEsKChsZW5ndGgoMTk5MjpEYXRhWWVhcikrMSktbWluKDEwKyhpLTEpLDIzKSkpKQ0KIyAgICAgICAgICAgICAgICAgICAgKQ0KIyAgICAgICAgICApDQojIH0NCiMgY2F0Y2hjb2hvcnRzIDwtIGRvLmNhbGwoY2JpbmQsIG1nZXQobHMocGF0dGVybiA9ICJjb2hvcnRfIikpKQ0KIyBjYXRjaGNvaG9ydHMkWWVhciA8LSAxOTkyOihEYXRhWWVhcisxKQ0KIyAjPT09PQ0KDQpjYXRjaE51bSA8LSByZWFkLmNzdihmaWxlID0gIkRhdGEvcGxlLjI3LjIxLTMyX0NhdGNoTnVtQWdlXzIwMDJfRGF0YVllYXIuY3N2IiwgaGVhZGVyID0gVCkgDQpjYXRjaE51bSRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoY2F0Y2hOdW0kWWVhcikpDQprIDwtIGFwcGVuZChrLCBjKCJjYXRjaGNvaG9ydHMiLCAiY2F0Y2hOdW0iKSkNCmBgYA0KICANCg0KIyMjIExhbmRpbmdzIC0gUmVzdWx0cyANCiAgSW4gbW9yZSByZWNlbnQgaGlzdG9yeSwgb2JzZXJ2ZXJzIGFuZCBvdGhlciBzYW1wbGluZyBwcm9ncmFtbWVzIGhhdmUgYmVlbiBhYmxlIHRvIHByb3ZpZGUgZXN0aW1hdGVzIG9mIGRpc2NhcmRlZCBwb3J0aW9ucyBvZiBjYXRjaC4gIEJlbG93IHdlIGNvbnNpZGVyIG9ubHkgdGhlIGxhbmRpbmdzIGZvciB0aGUgcGVyaW9kIHdoZW4gY2F0Y2ggd2FzIGRpdmlkZWQgaW50byBsYW5kaW5ncyAmIGRpc2NhcmRzLg0KYGBge3IgZmlnLmNhcD0gIlJlY2VudCBoaXN0b3J5IGxhbmRpbmdzIGJ5IGNvdW50cnkifQ0KIz09PQ0KIyBGaWd1cmUgMyBTaG9ydCB0ZXJtIExhbmRpbmdzIGJ5IGNvdW50cnkNCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhcitDb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiwgXSwNCiAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCklDX2FnZ190ZW1wJENvdW50cnkgPC0gZmFjdG9yKElDX2FnZ190ZW1wJENvdW50cnksIGxldmVscyA9IGMoIlN3ZWRlbiIsICJHZXJtYW55IiwgIkRlbm1hcmsiLCAiUG9sYW5kIiwgIkxhdHZpYSIsICJMaXRodWFuaWEiLCAiRXN0b25pYSIsICJGaW5sYW5kIikpDQojIElDX2FnZ190ZW1wJENBVE9OIDwtIElDX2FnZ190ZW1wJENBVE9OLmtnLzEwMDANCg0KcGx0X2xhbmRfY3RyeSA8LSBnZ3Bsb3QoZGF0YSA9IElDX2FnZ190ZW1wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IENBVE9OLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IENvdW50cnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBDb3VudHJ5KSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBzdW0sIGdlb20gPSAiYXJlYSIsIHBvc2l0aW9uID0gInN0YWNrIiwgbmEucm0gPSBUUlVFKSArDQogIHlsYWIoIkxhbmRpbmdzICh0KSIpICsNCiAgdGhlbWVfY2xlYW4oKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzAwNEI4NyIsIiMwMDAwMDAiLCAiI0M2MEMzMCIsIGVicGFsKSkNCmdncGxvdGx5KHBsdF9sYW5kX2N0cnkpDQojPT09PQ0KYGBgDQoNCldlIGNhbiBhbHNvIGludGVycm9nYXRlIHRoZSBsYW5kaW5ncyByZWxhdGl2ZSB0byB0aGUgVEFDcyBmb3IgdGhlIHJlc3BlY3RpdmUgbWFuYWdlbWVudCBhcmVhcyB0aGF0IHRoaXMgc3RvY2sgc3RyYWRkbGVzLiBOYW1lbHkgdGhlIE5vcnRoIFNlYSBtYW5hZ2VtZW50IGFyZWEgaW4gU0QyMSAoS2F0dGVnYXQpLCBhbmQgdGhlIEJhbHRpYyBTZWEgbWFuYWdlbWVudCBhcmVhIGNvdmVyaW5nIHRoZSByZW1haW5kZXIgb2YgdGhlIHN0b2NrOyBTRDIyLTMyLg0KYGBge3IgZXZhbD1UUlVFLCBmaWcuY2FwPSAiUmVjZW50IGhpc3RvcnkgbGFuZGluZ3MgZm9yIHRoZSBOb3J0aCBTZWEgTWFuYWdlbWVudCBhcmVhIGluIHN1YmRpdmlzaW9uIDIxIn0NCiM9PT0NCiMgRmlndXJlIDQgTGFuZGluZ3MgaW4gMjENCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhcitDb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ID09ICJMYW5kaW5ncyIgJiBpY19jbGVhbiRBcmVhID09ICIyNy4zLmEuMjEiLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCklDX2FnZ190ZW1wJENvdW50cnkgPC0gZmFjdG9yKElDX2FnZ190ZW1wJENvdW50cnksIGxldmVscyA9IGMoIlN3ZWRlbiIsICJHZXJtYW55IiwgIkRlbm1hcmsiKSkNCiMgSUNfYWdnX3RlbXAkQ0FUT04gPC0gSUNfYWdnX3RlbXAkQ0FUT04ua2cvMTAwMA0KVEFDMjEgPC0gdGFjX3Jhd1t0YWNfcmF3JEFyZWE9PSAiMjcuMy5hLjIxIiAmIHRhY19yYXckWWVhciAlaW4lIGMoMjAwMjpEYXRhWWVhciksIF0NCg0KcGx0X2xhbmRfMjEgPC0gZ2dwbG90KCkgKw0KICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBzdW0sDQogICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLA0KICAgICAgICAgICAgICAgcG9zaXRpb24gPSAic3RhY2siLA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLA0KICAgICAgICAgICAgICAgZGF0YSA9IElDX2FnZ190ZW1wLA0KICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IENBVE9OLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IENvdW50cnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBDb3VudHJ5KSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFRBQzIxLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFRBQywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBBcmVhLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBBcmVhKSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHlsYWIoIkxhbmRpbmdzIChrZykiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKSArDQogIHRoZW1lX2NsZWFuKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA0Qjg3IiwiIzAwMDAwMCIsICIjQzYwQzMwIikpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKG5hbWUgPSAiVEFDIiwgdmFsdWVzID0gIiM3NTcwYjMiLCApDQoNCnN0eWxlKGdncGxvdGx5KHBsdF9sYW5kXzIxKSwgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KIz09PT09DQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRSwgZmlnLmNhcD0gIlJlY2VudCBoaXN0b3J5IGxhbmRpbmdzIGZvciBzdWJkaXZpc2lvbiAyMiJ9DQojPT09DQojIEZpZ3VyZSA1IExhbmRpbmdzIGluIDIyDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ291bnRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAhPSAiRGlzY2FyZHMiICYgaWNfY2xlYW4kQXJlYSA9PSAiMjcuMy5jLjIyIiwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQpJQ19hZ2dfdGVtcCRDb3VudHJ5IDwtIGZhY3RvcihJQ19hZ2dfdGVtcCRDb3VudHJ5LCBsZXZlbHMgPSBjKCJTd2VkZW4iLCAiR2VybWFueSIsICJEZW5tYXJrIikpDQojIElDX2FnZ190ZW1wJENBVE9OIDwtIElDX2FnZ190ZW1wJENBVE9OLmtnLzEwMDANClRBQzIyIDwtIHRhY19yYXdbdGFjX3JhdyRBcmVhPT0gIjI3LjMuYy4yMiIgJiB0YWNfcmF3JFllYXIgJWluJSBjKDIwMDI6RGF0YVllYXIpLCBdDQoNCnBsdF9sYW5kXzIyIDwtIGdncGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gc3VtLA0KICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwNCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gInN0YWNrIiwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwNCiAgICAgICAgICAgICAgIGRhdGEgPSBJQ19hZ2dfdGVtcCwNCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBDQVRPTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gQ291bnRyeSkpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBUQUMyMiwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBUQUMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQXJlYSksDQogICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgIGNvbG91ciA9ICIjNzU3MGIzIikgKw0KICB5bGFiKCJMYW5kaW5ncyAoa2cpIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA0Qjg3IiwiIzAwMDAwMCIsICIjQzYwQzMwIikpDQoNCiM9PT09DQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRSwgZmlnLmNhcD0gIlJlY2VudCBoaXN0b3J5IGxhbmRpbmdzIGZvciBzdWJkaXZpc2lvbiAyMyJ9DQojPT09DQojIEZpZ3VyZSA2IExhbmRpbmdzIGluIDIzDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ291bnRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAhPSAiRGlzY2FyZHMiICYgaWNfY2xlYW4kQXJlYSA9PSAiMjcuMy5iLjIzIiwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQpJQ19hZ2dfdGVtcCRDb3VudHJ5IDwtIGZhY3RvcihJQ19hZ2dfdGVtcCRDb3VudHJ5LCBsZXZlbHMgPSBjKCJTd2VkZW4iLCAiR2VybWFueSIsICJEZW5tYXJrIikpDQojIElDX2FnZ190ZW1wJENBVE9OIDwtIElDX2FnZ190ZW1wJENBVE9OLmtnLzEwMDANClRBQzIzIDwtIHRhY19yYXdbdGFjX3JhdyRBcmVhPT0gIjI3LjMuYi4yMyIgJiB0YWNfcmF3JFllYXIgJWluJSBjKDIwMDI6RGF0YVllYXIpLCBdDQoNCnBsdF9sYW5kXzIzIDwtIGdncGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gc3VtLA0KICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwNCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gInN0YWNrIiwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwNCiAgICAgICAgICAgICAgIGRhdGEgPSBJQ19hZ2dfdGVtcCwNCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBDQVRPTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gQ291bnRyeSkpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBUQUMyMywNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBUQUMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQXJlYSksDQogICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgIGNvbG91ciA9ICIjNzU3MGIzIikgKw0KICB5bGFiKCJMYW5kaW5ncyAoa2cpIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA0Qjg3IiwgIiNDNjBDMzAiKSkNCg0KIz09PT0NCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGZpZy5jYXA9ICJSZWNlbnQgaGlzdG9yeSBsYW5kaW5ncyBmb3IgdGhlIEJhbHRpYyBTZWEgTWFuYWdlbWVudCBhcmVhIGluIHN1YmRpdmlzaW9ucyAyMi0zMiJ9DQojPT09DQojIEZpZ3VyZSA1IExhbmRpbmdzIGluIDIyOjMyDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ291bnRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSA9PSAiTGFuZGluZ3MiICYgaWNfY2xlYW4kQXJlYSAhPSAiMjcuMy5hLjIxIiwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQpJQ19hZ2dfdGVtcCRDb3VudHJ5IDwtIGZhY3RvcihJQ19hZ2dfdGVtcCRDb3VudHJ5LCBsZXZlbHMgPSBjKCJTd2VkZW4iLCAiR2VybWFueSIsICJEZW5tYXJrIiwgIlBvbGFuZCIsICJMYXR2aWEiLCAiTGl0aHVhbmlhIiwgIkVzdG9uaWEiLCAiRmlubGFuZCIpKQ0KIyBJQ19hZ2dfdGVtcCRDQVRPTiA8LSBJQ19hZ2dfdGVtcCRDQVRPTi5rZy8xMDAwDQpUQUMyMiA8LSB0YWNfcmF3W3RhY19yYXckQXJlYT09ICJwbGUuMjcuMjItMzIiICYgdGFjX3JhdyRZZWFyICVpbiUgYygyMDAyOkRhdGFZZWFyKSwgXQ0KDQpwbHRfbGFuZF8yMl8zMiA8LSBnZ3Bsb3QoKSArDQogIHN0YXRfc3VtbWFyeShmdW4ueSA9IHN1bSwNCiAgICAgICAgICAgICAgIGdlb20gPSAiYXJlYSIsDQogICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsDQogICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsDQogICAgICAgICAgICAgICBkYXRhID0gSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQ0FUT04sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ291bnRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IENvdW50cnkpKSArDQogIGdlb21fbGluZShkYXRhID0gVEFDMjIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gVEFDLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IEFyZWEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFyZWEpLA0KICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgeWxhYigiTGFuZGluZ3MgKGtnKSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsNCiAgdGhlbWVfY2xlYW4oKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDRCODciLCIjMDAwMDAwIiwgIiNDNjBDMzAiLCBlYnBhbCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSAiIzc1NzBiMyIpDQogIA0Kc3R5bGUoZ2dwbG90bHkocGx0X2xhbmRfMjJfMzIpLCBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiM9PT09DQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRSwgZmlnLmNhcD0gIkxhbmRpbmdzIGluIHNlbGVjdCBzdWJkaXZpc2lvbnMsIGJ5IGNvdW50cnkuICBTRDIxIGhhcyBpdCdzIG93biBUQUMsIHdoaWNoIGlzIHNob3duIGluIHB1cnBsZSwgd2hpbGUgU0RzIDIyIGFuZCBhYm92ZSBzaGFyZSBhIFRBQyBhY3Jvc3MgYWxsIFNEcyAoMjI6MzIpLiJ9DQojPT09DQojIEZpZ3VyZSA3IExhbmRpbmdzIGluIGFsbCBhcmVhcyBieSBjb3VudHJ5DQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ291bnRyeStBcmVhLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICE9ICJEaXNjYXJkcyIsIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KSUNfYWdnX3RlbXAkQ291bnRyeSA8LSBmYWN0b3IoSUNfYWdnX3RlbXAkQ291bnRyeSwgbGV2ZWxzID0gYygiU3dlZGVuIiwgIkdlcm1hbnkiLCAiRGVubWFyayIsICJQb2xhbmQiLCAiTGF0dmlhIiwgIkxpdGh1YW5pYSIsICJFc3RvbmlhIiwgIkZpbmxhbmQiKSkNCiMgSUNfYWdnX3RlbXAkQ0FUT04gPC0gSUNfYWdnX3RlbXAkQ0FUT04ua2cvMTAwMA0KIyBUQUNhbGwgPC0gdGFjX3Jhd1t0YWNfcmF3JFllYXIgJWluJSBjKDIwMDI6RGF0YVllYXIpLF0NClRBQzIxIDwtIHRhY19yYXdbdGFjX3JhdyRBcmVhPT0gIjI3LjMuYS4yMSIgJiB0YWNfcmF3JFllYXIgJWluJSBjKDIwMDI6RGF0YVllYXIrMiksIF0NClRBQzIyIDwtIHRhY19yYXdbdGFjX3JhdyRBcmVhID09ICJwbGUuMjcuMjItMzIiICYgdGFjX3JhdyRZZWFyICVpbiUgYygyMDAyOkRhdGFZZWFyKzIpLCBdDQoNCg0KcGx0X2xhbmRfYWxsIDwtIGdncGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gc3VtLA0KICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwNCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gInN0YWNrIiwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwNCiAgICAgICAgICAgICAgIGRhdGEgPSBJQ19hZ2dfdGVtcFtJQ19hZ2dfdGVtcCRBcmVhICVpbiUgYygiMjcuMy5hLjIxIiwgIjI3LjMuYi4yMyIsICIyNy4zLmMuMjIiLCAiMjcuMy5kLjI0IiwgIjI3LjMuZC4yNSIpLF0sDQogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQ0FUT04sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ291bnRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IENvdW50cnkpKSArDQogIGdlb21fbGluZShkYXRhID0gVEFDMjFbVEFDMjEkQXJlYSAlaW4lIGMoIjI3LjMuYS4yMSIsICIyNy4zLmIuMjMiLCAiMjcuMy5jLjIyIiwgIjI3LjMuZC4yNCIsICIyNy4zLmQuMjUiKSxdLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFRBQyksDQogICAgICAgICAgICAjIHNpemUgPSAyLA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbbGVuZ3RoKGVicGFsKS0xXSkgKw0KICAjIGdlb21fbGluZShkYXRhID0gVEFDMjIsDQogICMgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFRBQyksDQogICMgICAgICAgICAgICMgc2l6ZSA9IDIsDQogICMgICAgICAgICAgIGNvbG91ciA9IGVicGFsW2xlbmd0aChlYnBhbCktMl0pICsNCiAgeWxhYigiTGFuZGluZ3MgKHQpIikgKw0KICB0aGVtZV9jbGVhbigpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA0Qjg3IiwiIzAwMDAwMCIsICIjQzYwQzMwIiwgZWJwYWwpKSArDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoQXJlYSkpIywgc2NhbGVzID0gImZyZWVfeSIpDQpnZ3Bsb3RseShwbHRfbGFuZF9hbGwpDQojPT09PQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9ICJSZWNlbnQgaGlzdG9yeSBsYW5kaW5ncyBzcGxpdCBieSBhY3RpdmUgYW5kIHBhc3NpdmUgZ2VhcnMifQ0KIz09PQ0KIyBGaWd1cmUgb2YgbGFuZGluZ3MgYnkgZ2VhciB0eXBlDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OfkNhdGNoQ2F0ZWdvcnkrRmxlZXQrWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KDQpwbHRfbGFuZF9nZWFyIDwtIGdncGxvdChkYXRhID0gSUNfYWdnX3RlbXBbSUNfYWdnX3RlbXAkQ2F0Y2hDYXRlZ29yeSA9PSAiTGFuZGluZ3MiLF0sDQogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBDQVRPTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gRmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gRmxlZXQpKSArDQogIHN0YXRfc3VtbWFyeShmdW4ueSA9IHN1bSwgZ2VvbSA9ICJhcmVhIiwgcG9zaXRpb24gPSAic3RhY2siLCBuYS5ybSA9IFRSVUUpICsNCiAgeWxhYigiTGFuZGluZ3MgKFRvbnMpIikgKw0KICB0aGVtZV9jbGVhbigpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBlYnBhbFsxOmxlbmd0aCh1bmlxdWUoSUNfYWdnX3RlbXAkRmxlZXQpKV0pDQpnZ3Bsb3RseShwbHRfbGFuZF9nZWFyKQ0KDQoNCmBgYA0KDQojIyMgQ29tbWVyY2lhbCBDYXRjaGVzIC0gUmVzdWx0cw0KIyMjIyBDYXRjaCBWb2x1bWUgKE1hc3MpDQpDYXRjaGVzIGZvciB0aGUgeWVhciBgciBEYXRhWWVhcmAgYXJlIHN1bW1hcmlzZWQgYWNyb3NzIGRpZmZlcmVudCBmYWN0b3JzIGJlbG93IGFuZCBhcmUgZ2l2ZW4gaW4gdG9ubmVzLg0KDQpgYGB7ciBUb3RhbENhdGNoQW5kUHJvcFBlckFyZWF9DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+QXJlYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KDQpQcm9wb3J0aW9uIDwtIG51bWVyaWMoKQ0KZm9yKGkgaW4gSUNfYWdnX3RlbXAkQXJlYSl7DQogIFByb3BvcnRpb24gPC0gYXBwZW5kKHggPSBQcm9wb3J0aW9uLCB2YWx1ZXMgPSBJQ19hZ2dfdGVtcFtJQ19hZ2dfdGVtcCRBcmVhID09IGksICJDQVRPTiJdL3N1bShJQ19hZ2dfdGVtcFssICJDQVRPTiJdKSkNCn0NCklDX2FnZ190ZW1wIDwtIGNiaW5kKElDX2FnZ190ZW1wLCBQcm9wb3J0aW9uKQ0KDQprYWJsZShJQ19hZ2dfdGVtcCwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIlRvdGFsIGNvbW1lcmNpYWwgY2F0Y2ggYW5kIHByb3BvcnRpb24gb2YgY2F0Y2ggb2YgcGxhaWNlLCBwZXIgYXJlYSBpbiAiLCBEYXRhWWVhciwgIiAodG9ubmVzKS4iKSwNCiAgICAgIGRpZ2l0cyA9IDIpDQpgYGANCg0KYGBge3IgVG90YWxDYXRjaFBlckFyZWFBbmRGbGVldH0NCmthYmxlKGFnZ3JlZ2F0ZShDQVRPTiB+IEFyZWErRmxlZXQsDQogICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSxdLA0KICAgICAgICAgICAgICAgIEZVTiA9IHN1bSksDQogICAgICBjYXB0aW9uID0gcGFzdGUwKCJUb3RhbCBjb21tZXJjaWFsIGNhdGNoIG9mIHBsYWljZSwgcGVyIGFyZWEgYW5kIGJ5IGZsZWV0LCBpbiAiLCBEYXRhWWVhciwgIiAodG9ubmVzKS4iKSwNCiAgICAgIGRpZ2l0cyA9IDIpIA0KYGBgDQoNCmBgYHtyIFRvdGFsQ2F0Y2hQZXJGbGVldDJ9DQprYWJsZShhZ2dyZWdhdGUoQ0FUT04gfiBGbGVldDIsDQogICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSxdLA0KICAgICAgICAgICAgICAgIEZVTiA9IHN1bSksDQogICAgICBjYXB0aW9uID0gcGFzdGUwKCJUb3RhbCBjb21tZXJjaWFsIGNhdGNoIG9mIHBsYWljZSwgYnkgbmV3IGZsZWV0IGNvbmNlcHQgKG1hbmFnZW1lbnQgYXJlYSAqIGZsZWV0KSwgaW4gIiwgRGF0YVllYXIsICIgKHRvbm5lcykuIiksDQogICAgICBkaWdpdHMgPSAyKSANCmBgYA0KDQpgYGB7ciBUb3RhbENhdGNoUGVyQXJlYUFuZEZsZWV0Mn0NCmthYmxlKGFnZ3JlZ2F0ZShDQVRPTiB+IEFyZWErRmxlZXQyLA0KICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRZZWFyID09IERhdGFZZWFyICYgaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksXSwNCiAgICAgICAgICAgICAgICBGVU4gPSBzdW0pLA0KICAgICAgY2FwdGlvbiA9IHBhc3RlMCgiVG90YWwgY29tbWVyY2lhbCBjYXRjaCBvZiBwbGFpY2UsIHBlciBhcmVhIGFuZCBuZXcgZmxlZXQgY29uY2VwdCAobWFuYWdlbWVudCBhcmVhICogZmxlZXQpLCBpbiAiLCBEYXRhWWVhciwgIiAodG9ubmVzKS4iKSwNCiAgICAgIGRpZ2l0cyA9IDIpIA0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9ICJDb21tZXJjaWFsIGNhdGNoIGJ5IGNhdGNoIGNhdGVnb3J5IGZvciBhbGwgYXJlYXMgYW5kIGFsbCBjb3VudHJpZXMgKHRvbm5lcykuIn0NCiM9PT0NCiMgRmlndXJlIENhdGNoIGJ5IGNhdGNoIGNhdGVnb3J5IChhbGwgYXJlYXMsIGFsbCBjb3VudHJpZXMpDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ2F0Y2hDYXRlZ29yeStBcmVhLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhblshaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkJNUyIsICJCTVMgbGFuZGluZyIsIkxvZ2Jvb2sgUmVnaXN0ZXJlZCBEaXNjYXJkIiwgIkNhdGNoIiksXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQoNCnBsdF9jYXRjaGNhdCA8LSBnZ3Bsb3QoKSArDQogIHN0YXRfc3VtbWFyeShmdW4ueSA9IHN1bSwNCiAgICAgICAgICAgICAgIGdlb20gPSAiYXJlYSIsDQogICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsDQogICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsDQogICAgICAgICAgICAgICBkYXRhID0gSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQ0FUT04sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ2F0Y2hDYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IENhdGNoQ2F0ZWdvcnkpKSArDQogIHlsYWIoIkNhdGNoIChUb25zKSIpICsgDQogIHRoZW1lX2NsZWFuKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gcmVsKDAuNzUpKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxYjllNzciLCIjZDk1ZjAyIiwgIiM3NTcwYjMiLCAiZ3JleSIpKSArDQogIHlsYWIoIkNhdGNoICh0KSIpICsNCiAgZmFjZXRfd3JhcChmYWNldHMgPSB2YXJzKEFyZWEpLCBuY29sID0gMikgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgDQpzdHlsZShnZ3Bsb3RseShwbHRfY2F0Y2hjYXQpLCBzaG93bGVnZW5kID0gRkFMU0UpDQojPT09PQ0KYGBgDQojIyMjIENhdGNoIE51bWJlcnMNCldlIGNhbiBhbHNvIGludmVzdGlnYXRlIHN0b2NrIHN0cnVjdHVyZSBieSBsb29raW5nIGF0IG51bWJlcnMgYXQgYWdlLiANCg0KYGBge3IgZmlnQ2FudW0sIGV2YWw9RkFMU0V9DQpjYXRjaE51bUxuZyA8LSByZXNoYXBlKGRhdGEgPSBjYXRjaE51bSwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGxpc3QoY29sbmFtZXMoY2F0Y2hOdW0pWzI6bGVuZ3RoKChjb2xuYW1lcyhjYXRjaE51bSkpKV0pLA0KICAgICAgICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gYygiTnVtYmVyIiksDQogICAgICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0KY2F0Y2hOdW1MbmckQWdlIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoY2F0Y2hOdW1MbmckQWdlKSkNCmNhdGNoTnVtTG5nJEFnZSA8LSBmYWN0b3IoY2F0Y2hOdW1MbmckQWdlLCBsZXZlbHMgPSBjKCIxIiwgIjIiLCAiMyIsICI0IiwgIjUiLCAiNiIsICI3IiwgIjgiLCAiOSIsICIxMCIpKQ0KIyBjYXRjaE51bUxuZyRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoY2F0Y2hOdW1MbmckWWVhcikpDQpjYXRjaE51bUxuZyRZZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNhdGNoTnVtTG5nJFllYXIpKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoY2F0Y2hOdW1MbmcpKw0KICAgICAgICAgICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IE51bWJlciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IEFnZSkpKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gZWJwYWwpKQ0KDQpgYGANCg0KIyMjIyBEaXNjYXJkcw0KTGFuZGluZ3MgYmVsb3cgbWluaW11bSBzaXplIChCTVMgbGFuZGluZykgYXJlIGVzdGltYXRlZCBhcyBwYXJ0IG9mIHRoZSBkaXNjYXJkcywgZHVlIHRvIGV4cGVjdGVkIHBvb3IgcmVwb3J0aW5nIG9mIG9mZmljaWFsIEJNUyBsYW5kaW5ncy4gIFRoaXMgbWVhbnMgdGhhdCBpbiB0aGUgYXNzZXNzbWVudCwgd2UgZG8gbm90IHVzZSByZXBvcnRzIG9mIEJNUy4gICBIb3dldmVyLCB3aGVuIHJlcG9ydGluZyBvbiBCTVMgY2F0Y2ggY29tcG9uZW50cywgd2UgbXVzdCBzdWJ0cmFjdCBvZmZpY2lhbCBCTVMgbGFuZGluZ3MgZnJvbSBEaXNjYXJkcy4gIFByaW9yIHRvIDIwMTkgKDw9MjAxOCksIEJNUyBsYW5kaW5ncyB3ZXJlIHJlcG9ydGVkIGFzIHBhcnQgb2YgbGFuZGluZ3MuICAgDQoNCiAgDQpgYGB7cn0NCiMjIEFnZ3JlZ2F0ZSBjYXRjaGVzIGJ5IHllYXIgYW5kIGFyZWENCklDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyK0NhdGNoQ2F0ZWdvcnkrQXJlYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQoNCmRpc3JhdCA8LSBhcy5kYXRhLmZyYW1lKHJlc2hhcGUoSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiWWVhciIsIkFyZWEiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJDYXRjaENhdGVnb3J5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIndpZGUiKSkNCmRpc3JhdCREaXNjYXJkUmF0aW8gPC0gZGlzcmF0JENBVE9OLkRpc2NhcmRzLyhkaXNyYXQkQ0FUT04uTGFuZGluZ3MrZGlzcmF0JENBVE9OLkRpc2NhcmRzKQ0KZGlzcmF0JEFyZWEgPC0gZmFjdG9yKGRpc3JhdCRBcmVhLCBsZXZlbHMgPSBjKCIyNy4zLmEuMjEiLCAiMjcuMy5iLjIzIiwgIjI3LjMuYy4yMiIsICIyNy4zLmQuMjQiLCAiMjcuMy5kLjI1IiwgIjI3LjMuZC4yNiIsICIyNy4zLmQuMjciLCAiMjcuMy5kLjI4IiwgIjI3LjMuZC4yOC4yIiwgIjI3LjMuZC4yOSIsICIyNy4zLmQuMzAiLCAiMjcuMy5kLjMxIiwgIjI3LjMuZC4zMiIpKQ0KDQojIyBBZ2dyZWdhdGUgY2F0Y2hlcyBieSB5ZWFyIGFuZCBmbGVldA0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ2F0Y2hDYXRlZ29yeStGbGVldDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKQ0KDQpkaXNyYXRGbGVldCA8LSBhcy5kYXRhLmZyYW1lKHJlc2hhcGUoSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiWWVhciIsIkZsZWV0MiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkNhdGNoQ2F0ZWdvcnkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpKQ0KZGlzcmF0RmxlZXQkRGlzY2FyZFJhdGlvIDwtIGRpc3JhdEZsZWV0JENBVE9OLkRpc2NhcmRzLyhkaXNyYXRGbGVldCRDQVRPTi5MYW5kaW5ncytkaXNyYXRGbGVldCRDQVRPTi5EaXNjYXJkcykNCg0KDQpyb3duYW1lcyhkaXNyYXQpIDwtIE5VTEwNCmBgYA0KDQoNCmBgYHtyIERpc2NhcmRzQnlBcmVhfQ0Ka2FibGUoZGlzcmF0W2Rpc3JhdCRZZWFyID09IERhdGFZZWFyLCBjKCJBcmVhIiwiRGlzY2FyZFJhdGlvIildLA0KICAgICAgY2FwdGlvbiA9IHBhc3RlMCgiRGlzY2FyZCByYXRpb3MgYnkgc3ViZGl2aXNpb24gZm9yICIsIERhdGFZZWFyLCAiLiIpLA0KICAgICAgZGlnaXRzID0gMykNCmBgYA0KDQoNCmBgYHtyIGZpZy5jYXA9IHBhc3RlMCgiRGlzY2FyZCByYXRpb3MgKHByb3BvcnRpb24gb2YgdG90YWwgY29tbWVyY2lhbCBjYXRjaCBkaXNjYXJkZWQpIGJ5IHN1YmRpdmlzaW9uIG92ZXIgdGltZS4iKX0NCiM9PT0NCiMgRmlndXJlcyBvZiBkaXNjYXJkIHJhdGlvcw0KIz09PT0NCiMgIyMgQmFyIGNoYXJ0DQojIHBsdF9kaXNyYXRfYXJlYSA8LSBnZ3Bsb3QoKSArDQojICAgZ2VvbV9jb2woZGF0YSA9IGRpc3JhdCwNCiMgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IERpc2NhcmRSYXRpbywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBBcmVhKSwNCiMgICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiMgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KIyAgIHRoZW1lX2J3KCkgKw0KIyAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAwLjUpKQ0KDQojIyBMaW5lIENoYXJ0DQpkaXNyYXQkWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkaXNyYXQkWWVhcikpDQpwbHRfZGlzcmF0X2FyZWEgPC0gZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRpc3JhdCwNCiAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gRGlzY2FyZFJhdGlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFyZWEpLA0KICAgICAgICAgICBzaXplID0gMS41LA0KICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KICB0aGVtZV9jbGVhbigpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSkpDQoNCmdncGxvdGx5KHBsdF9kaXNyYXRfYXJlYSkNCiM9PT09PQ0KYGBgDQoNClBsYWljZSBpcyBjb25zaWRlcmVkIGEgYnljYXRjaCBzcGVjaWVzIGluIHRoZSBCYWx0aWMgU2VhIE1hbmFnZW1lbnQgcGxhbi4gSW4gU0QyMSBhbmQgMjIgdGhpcyByZW1haW5zIHRvIGJlIHRoZSBjYXNlIHdoZXJlIHBsYWljZSBhcmUgYXBwYXJlbnRseSBjYXVnaHQgaW4gbmVwaHJvcHMgKFNEMjEpIGFuZCBjb2QgKFNEMjEmMjIpIGZpc2hlcmllcywgd2l0aCBzb21lIHRhcmdldGVkIGNvYXN0YWwgZmlzaGVyaWVzIChlc3BlY2lhbGx5IGluIFNEMjImMjMpLiAgVG8gZnVydGhlciBpbnZlc3RpZ2F0ZSB0aGUgZGlzY2FyZCByYXRlcyByZWxhdGl2ZSB0byBsYW5kaW5ncyBieSBkaWZmZXJlbnQgZmxlZXRzIGluIHRoZSBkaWZmZXJlbnQgbWFuYWdtZW50IGFyZWFzLCB3ZSBjYW4gcGxvdCB0aGUgdHdvIGZpZ3VyZXMgdG9nZXRoZXIuICBJbiBkb2luZyBzbyB3ZSBtYWtlIHRoZSBkaXNjYXJkIHJhdGlvcyByZWxhdGl2ZSB0byB0aGUgbGFuZGluZ3Mgc2NhbGUsIHRodXMgdGhlIGxpbmVzIGluIHRoZSBiZWxvdyBmaWd1cmUgc2hvdyB0aGUgcmVsYXRpdmUgY29udHJpYnV0aW9uIG9mIGRpc2NhcmRzIHRvIHRoZSBjYXRjaCBjb21wYXJlZCB0byB0aGUgbWF4aW11bSB2YWx1ZSAoaS5lLiBub3QgYWJzb2x1dGUgZGlzY2FyZCByYXRpb3MsIG5vciBsaW5rZWQgdG8gdGhlIHktYXhpcyB1bml0cykuDQpgYGB7ciBmaWcuY2FwPSAiQ29tbWVyY2lhbCBjYXRjaCBhcyBMYW5kaW5ncyAoYmFycykgYW5kIERpc2NhcmQgUmF0aW9zIGFzIHJlbGF0aXZlIHByb3BvcnRpb25zIChsaW5lcykgb3ZlciB0aW1lIGJ5IGZsZWV0IGFuZCBtYW5hZ2VtZW50IGFyZWEifQ0KIz09PQ0KIyBQcmVwYXJlIGRhdGENCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBkcm9wbGV2ZWxzKGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyK0NhdGNoQ2F0ZWdvcnkrRmxlZXQyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIixdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKSkNCiMgZGlzcmF0JFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihkaXNyYXQkWWVhcikpDQpkaXNyYXRGbGVldCRZZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRpc3JhdEZsZWV0JFllYXIpKQ0KSUNfYWdnX3RlbXAkWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihJQ19hZ2dfdGVtcCRZZWFyKSkNCg0KeWxpbS5wcmltIDwtIGMoMCwgbWF4KHJhbmdlKElDX2FnZ190ZW1wJENBVE9OKSkpDQp5bGltLnNlYyA8LSBjKDAsIG1heChyYW5nZShkaXNyYXRGbGVldCREaXNjYXJkUmF0aW8sIG5hLnJtID0gVCkpKQ0KYiA8LSBkaWZmKHlsaW0ucHJpbSkvZGlmZih5bGltLnNlYykNCmEgPC0geWxpbS5wcmltWzFdIC0gKGIqeWxpbS5zZWNbMV0pDQojPT09PT0NCg0KIz09PQ0KIyBGaWd1cmUgZm9yIGFkdmljZSBhZnRlciAyMDIxOiBEaXNjYXJkIFJhdGlvcyBhbmQgTGFuZGluZ3Mgb3ZlciB0aW1lDQojPT09PQ0KcGx0X2NhdGNoY2F0IDwtIGdncGxvdCgpICsNCiAgZ2VvbV9jb2woZGF0YSA9IElDX2FnZ190ZW1wLA0KICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBDQVRPTiksDQogICAgICAgICAgIGZpbGwgPSAiIzAwMmI1ZiIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkaXNyYXRGbGVldCwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhICsgRGlzY2FyZFJhdGlvKmIpLA0KICAgICAgICAgICAgY29sb3VyID0gIiNlZDVmMjYiLA0KICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkxhbmRpbmdzICh0b25uZXMpIiwgc2VjLmF4aXMgPSBzZWNfYXhpcyh+ICguIC0gYSkvYiwgbmFtZSA9ICJEaXNjYXJkIFJhdGlvIikpICsNCiAgdGhlbWVfY2xlYW4oKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpLA0KICAgICAgICBheGlzLmxpbmUueS5yaWdodCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjZWQ1ZjI2IiksIA0KICAgICAgICBheGlzLnRpY2tzLnkucmlnaHQgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiI2VkNWYyNiIpLA0KICAgICAgICBheGlzLnRleHQueS5yaWdodCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjZWQ1ZjI2IiksIA0KICAgICAgICBheGlzLnRpdGxlLnkucmlnaHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiI2VkNWYyNiIpLA0KICAgICAgICBheGlzLmxpbmUueS5sZWZ0ID0gZWxlbWVudF9saW5lKGNvbG9yID0gIiMwMDJiNWYiKSwgDQogICAgICAgIGF4aXMudGlja3MueS5sZWZ0ID0gZWxlbWVudF9saW5lKGNvbG9yID0gIiMwMDJiNWYiKSwNCiAgICAgICAgYXhpcy50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjMDAyYjVmIiksIA0KICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjMDAyYjVmIikpICsNCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhGbGVldDIpKQ0KZ2dwbG90bHkocGx0X2NhdGNoY2F0KQ0KIz09PT09DQoNCmBgYA0KICANCkluIHN1YmRpdmlzaW9uIDIyLCB0aGUgY29sbGFwc2Ugb2YgdGhlIGNvZCBmaXNoZXJ5IGZyb20gdGhlIHBlcmlvZCAyMDE1IG9ud2FyZCwgYXBwZWFycyB0byBzaG93IGEgZ3JlYXRlciByZXRlbnRpb24gb2YgUGxhaWNlLCB3aGlsZSBmaXNoZXJzIHdlcmUgc3RpbGwgdGFyZ2V0dGluZyBjb2QuIFN1YnNlcXVlbnRseSwgYXMgZmlzaGluZyBvcHBvcnR1bml0aWVzIGZvciBjb2QgY29sbGFwc2VkLCB0aGUgZmlzaGVyIGZvciBwbGFpY2UgYWxzbyBjb2xsYXBzZWQuICBUaGlzIGNvdWxkIGJlIGR1ZSB0byB0aGUgbG93ZXIgb3ZlcmFsbCBlZmZvcnQsIHdpdGggYSBzcGVjaWZpYyBpbnRlcmVzdCBpbiB3aGF0IGNvZCBpcyBhdmFpbGFibGUsIG9yIGl0IGNvdWxkIGJlIGR1ZSB0byB0aGUgZXhwbG9zaW9uIGluIHRoZSBwbGFpY2UgcG9wdWxhdGlvbi4gSW4gdGhlIGxhdHRlciBjYXNlLCBwbGFpY2UgYXJlIGJvdGggY2F1Z2h0IG1vcmUgZWFzaWx5LCB3aGlsZSByZW1haW5pbmcgdW53YW50ZWQsIGFuZCB0aGVpciBjb25kaXRpb24gaGFzIGJlZW4gZGV0ZXJpb3JhdGluZywgbWVhbmluZyBhIGhpZ2hlciBwcm9wb3J0aW9uIG9mIHRoZSBjYXRjaCBpcyBub3QgbWFya2V0YWJsZS4gQmVsb3cgd2UgZm9jdXMgb24gU0QyMiBhbmQgaG93IGNhdGNoZXMgYW5kIGRpc2NhcmQgcmF0aW9zIGhhdmUgZGV2ZWxvcGVkIHRvZ2V0aGVyIG92ZXIgdGltZS4NCmBgYHtyIGZpZy5jYXA9ICJEaXNjYXJkIFJhdGlvcyAobGluZXMpIGFuZCBMYW5kaW5ncyAoYmFycykgb3ZlciB0aW1lIGluIFNEMjIgLSB0aGUgU1cgQmFsdGljIn0NCiM9PT0NCiMgUHJlcGFyZSBkYXRhDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gZHJvcGxldmVscyhhZ2dyZWdhdGUoQ0FUT05+WWVhcitDYXRjaENhdGVnb3J5K0FyZWEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQXJlYSA9PSAiMjcuMy5jLjIyIiAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIixdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKSkNCiMgZGlzcmF0JFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihkaXNyYXQkWWVhcikpDQpkaXNyYXQkWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkaXNyYXQkWWVhcikpDQpJQ19hZ2dfdGVtcCRZZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKElDX2FnZ190ZW1wJFllYXIpKQ0KDQpkaXNyYXQgPC0gZGlzcmF0W2Rpc3JhdCRBcmVhID09ICIyNy4zLmMuMjIiLF0NCg0KeWxpbS5wcmltIDwtIGMoMCwgbWF4KHJhbmdlKElDX2FnZ190ZW1wJENBVE9OKSkpDQp5bGltLnNlYyA8LSBjKDAsIG1heChyYW5nZShkaXNyYXQkRGlzY2FyZFJhdGlvKSkpDQpiIDwtIGRpZmYoeWxpbS5wcmltKS9kaWZmKHlsaW0uc2VjKQ0KYSA8LSB5bGltLnByaW1bMV0gLSAoYip5bGltLnNlY1sxXSkNCiM9PT09PQ0KDQojPT09DQojIEZpZ3VyZSBvZiBsYW5kaW5ncyBhbmQgZGlzY2FyZCByYXRpb3Mgb3ZlciB0aW1lDQojPT09PQ0KcGx0X2NhdGNoY2F0IDwtIGdncGxvdCgpICsNCiAgZ2VvbV9jb2woZGF0YSA9IElDX2FnZ190ZW1wLA0KICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBDQVRPTiksDQogICAgICAgICAgIGZpbGwgPSAiIzAwMmI1ZiIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkaXNyYXQsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYSArIERpc2NhcmRSYXRpbypiKSwNCiAgICAgICAgICAgIGNvbG91ciA9ICIjZWQ1ZjI2IiwNCiAgICAgICAgICAgIHNpemUgPSAxLjUpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJMYW5kaW5ncyAodG9ubmVzKSIsIHNlYy5heGlzID0gc2VjX2F4aXMofiAoLiAtIGEpL2IsIG5hbWUgPSAiRGlzY2FyZCBSYXRpbyIpKSArDQogIHRoZW1lX2NsZWFuKCkgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSksDQogICAgICAgIGF4aXMubGluZS55LnJpZ2h0ID0gZWxlbWVudF9saW5lKGNvbG9yID0gIiNlZDVmMjYiKSwgDQogICAgICAgIGF4aXMudGlja3MueS5yaWdodCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjZWQ1ZjI2IiksDQogICAgICAgIGF4aXMudGV4dC55LnJpZ2h0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiNlZDVmMjYiKSwgDQogICAgICAgIGF4aXMudGl0bGUueS5yaWdodCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjZWQ1ZjI2IiksDQogICAgICAgIGF4aXMubGluZS55LmxlZnQgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiIzAwMmI1ZiIpLCANCiAgICAgICAgYXhpcy50aWNrcy55LmxlZnQgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiIzAwMmI1ZiIpLA0KICAgICAgICBheGlzLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMwMDJiNWYiKSwgDQogICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMwMDJiNWYiKSkNCg0KZ2dwbG90bHkocGx0X2NhdGNoY2F0KQ0KIz09PT09DQpgYGANCg0KVGhlc2Ugc2FtZSB0cmVuZHMgYXJlIG1pcnJvcmVkIGluIHRoZSBkaXNjYXJkIHJhdGVzIGJ5IGNvdW50cnksIHdoZXJlIHZlc3NlbHMgbWFpbmx5IG9wZXJhdGluZyBpbiAyMSAoaS5lLiBTd2VkZW4pIGhhdmUgdGhlIGhpZ2hlc3QgcmF0ZXMsIHRob3NlIG9wZXJhdGluZyBtYWlubHkgaW4gdGhlIEJhbHRpYyAoaS5lLiBQb2xhbmQgYW5kIEdlcm1hbnkpIHRoZSBsb3dlc3QsIGFuZCB0aG9zZSBvcGVyYXRpbmcgaW4gYm90aCBoYXZlIGFuIGludGVybWVkaWF0ZSBsZXZlbCBvZiBkaXNjYXJkcyAoaS5lLiBEZW5tYXJrKS4NCmBgYHtyIGZpZy5jYXA9ICJEaXNjYXJkIHJhdGlvcyAocHJvcG9ydGlvbiBvZiB0b3RhbCBjYXRjaCBkaXNjYXJkZWQpIGJ5IGNvdW50cnkgb3ZlciB0aW1lIn0NCiM9PT0NCiMgUHJlcCBkYXRhDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIrQ2F0Y2hDYXRlZ29yeStDb3VudHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSxdLA0KICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCg0KZGlzcmF0IDwtIGFzLmRhdGEuZnJhbWUocmVzaGFwZShJQ19hZ2dfdGVtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWR2YXIgPSBjKCJZZWFyIiwiQ291bnRyeSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkNhdGNoQ2F0ZWdvcnkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpKQ0KIyBkaXNyYXRbaXMubmEoZGlzcmF0JENBVE9OLkJNUyksICJDQVRPTi5CTVMiXSA8LSAwDQpkaXNyYXQkRGlzY2FyZFJhdGlvIDwtIGRpc3JhdCRDQVRPTi5EaXNjYXJkcy8oZGlzcmF0JENBVE9OLkxhbmRpbmdzK2Rpc3JhdCRDQVRPTi5EaXNjYXJkcykNCmRpc3JhdCRDb3VudHJ5IDwtIGZhY3RvcihkaXNyYXQkQ291bnRyeSwgbGV2ZWxzID0gYygiU3dlZGVuIiwgIkdlcm1hbnkiLCAiRGVubWFyayIsICJQb2xhbmQiLCAiTGF0dmlhIiwgIkxpdGh1YW5pYSIsICJFc3RvbmlhIiwgIkZpbmxhbmQiKSkNCmRpc3JhdCRZZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRpc3JhdCRZZWFyKSkNCiM9PT09PQ0KDQojPT09DQojIEZpZ3VyZSBEaXNjYXJkIFJhdGlvcyBieSBDb3VudHJ5DQojPT09PQ0KcGx0X2Rpc3JhdF9jb3VudHJ5IDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkaXNyYXQsDQogICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IERpc2NhcmRSYXRpbywNCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBDb3VudHJ5KSwNCiAgICAgICAgICAgc2l6ZSA9IDEuNSwNCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHRoZW1lX2NsZWFuKCkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDRCODciLCIjMDAwMDAwIiwgIiNDNjBDMzAiLCBlYnBhbCkpDQpnZ3Bsb3RseShwbHRfZGlzcmF0X2NvdW50cnkpDQojPT09PQ0KYGBgDQoNCkRyaWxsaW5nIGRvd24gaW50byBhIGJpdCBtb3JlIGRldGFpbCB3ZSBjYW4gc2VlIHdoZXJlIChzdWJkaXZpc2lvbiksIHdoZW4gKHF1YXJ0ZXIpIGFuZCBieSB3aGljaCBnZW5lcmFsIGdlYXIgdHlwZXMgdGhlIG1ham9yaXR5IG9mIGNhdGNoZXMgKGRpc2NhcmRzICYgbGFuZGluZ3MpIGFyZSB0YWtlbi4gDQpgYGB7ciBmaWcuY2FwPSAiRGlzY2FyZHMgYW5kIGxhbmRpbmdzIGZyb20gQ3VycmVudCB5ZWFyIGJ5IHF1YXJ0ZXIgYW5kIGdlYXIiLCBvdXQuaGVpZ2h0PSc4MCUnfQ0KIz09PQ0KIyBGaWd1cmUgRGlzY2FyZHMvbGFuZGluZ3Mgb2YgRGF0YVllYXIgYnkgcXVhcnRlciBhbmQgZ2Vhcg0KIz09PT0NCklDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5TZWFzb24rQ2F0Y2hDYXRlZ29yeStBcmVhK0ZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICMgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRGbGVldCAlaW4lIGMoIkFjdGl2ZSIsICJQYXNzaXZlIiksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiRGlzY2FyZHMiLCAiTGFuZGluZ3MiKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQpJQ19hZ2dfdGVtcCA8LSBkcm9wbGV2ZWxzKElDX2FnZ190ZW1wKQ0KIz09PT09DQoNCiM9PT0NCiMgRmlndXJlIERpc2NhcmRzL2xhbmRpbmdzIG9mIERhdGFZZWFyIGJ5IHF1YXJ0ZXIgYW5kIGdlYXINCiM9PT09DQpwbHRfZGlzcmF0X1FfYXJlYSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fY29sKGRhdGEgPSBJQ19hZ2dfdGVtcCwNCiAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gU2Vhc29uLCANCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQ0FUT04sDQogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IENhdGNoQ2F0ZWdvcnkpKSArIA0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKEFyZWEpLA0KICAgICAgICAgICAgIGNvbHMgPSB2YXJzKEZsZWV0KSwNCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZV95IikgKw0KICB0aGVtZV9jbGVhbigpICsNCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNzUpKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KICB4bGFiKCJRdWFydGVyIikgKw0KICB5bGFiKCJDYXRjaCAodCkiKQ0KDQpzdHlsZShnZ3Bsb3RseShwbHRfZGlzcmF0X1FfYXJlYSksIHNob3dsZWdlbmQgPSBGQUxTRSkNCiM9PT09DQpgYGANCg0KYGBge3IgY2F0Y2hlc0J5Q2F0ZWdvcnlCeUZsZWV0T3ZlclF1YXJ0ZXJzfQ0KIz09PQ0KIyBGaWd1cmUgRGlzY2FyZHMvbGFuZGluZ3Mgb2YgRGF0YVllYXIgYnkgcXVhcnRlciBhbmQgZ2Vhcg0KIz09PT0NCklDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5BcmVhK0NhdGNoQ2F0ZWdvcnkrRmxlZXQrU2Vhc29uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICMgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRGbGVldCAlaW4lIGMoIkFjdGl2ZSIsICJQYXNzaXZlIiksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiRGlzY2FyZHMiLCAiTGFuZGluZ3MiKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQpJQ19hZ2dfdGVtcCA8LSBkcm9wbGV2ZWxzKElDX2FnZ190ZW1wKQ0KIz09PT09DQoNCiM9PT0NCiMgUmVzaGFwZSB0byBtYWtlIFF1YXJ0ZXJzIHdpZGUNCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSByZXNoYXBlKElDX2FnZ190ZW1wLA0KICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIsDQogICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiQXJlYSIsICJDYXRjaENhdGVnb3J5IiwgIkZsZWV0IiksDQogICAgICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiU2Vhc29uIikNCmNvbG5hbWVzKElDX2FnZ190ZW1wKSA8LSBjKCJTdWJkaXZpc2lvbiIsICJDYXRjaENhdGVnb3J5IiwgIkZsZWV0IiwgIlExIiwgIlEyIiwgIlEzIiwgIlE0IikNCklDX2FnZ190ZW1wIDwtIElDX2FnZ190ZW1wW29yZGVyKElDX2FnZ190ZW1wJFN1YmRpdmlzaW9uLCBJQ19hZ2dfdGVtcCRDYXRjaENhdGVnb3J5LCBJQ19hZ2dfdGVtcCRGbGVldCksIF0NCiM9PT09PQ0KDQprYWJsZShJQ19hZ2dfdGVtcCwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIkNvbW1lcmNpYWwgY2F0Y2ggZnJvbSBwbGUuMjcuMjEtMjMgaW4gIiwgRGF0YVllYXIsICIgYnkgY2F0Y2ggY2F0ZWdvcnksIGJ5IGZsZWV0IGFuZCBvdmVyIHF1YXJ0ZXJzICh0b25uZXMpLiIpLA0KICAgICAgZGlnaXRzID0gMCkNCg0KYGBgDQoNCkZ1cnRoZXJtb3JlLCB3ZSBjYW4gc3BsaXQgdGhlIGRpc2NhcmQgcmF0ZXMgYnkgb3VyIG5ldyBmbGVldCBjb25jZXB0LCB0aGF0IG9mIGZsZWV0cyBieSBtYW5hZ2VtZW50IGFyZWEuICBUaGlzIHdheSBkaWZmZXJlbnQgZGlzY2FyZCByYXRlcyBpbiBkaWZmZXJlbnQgbWFuYWdlbWV0biBhcmVhcyBjYW4gYmUgdGFrZW4gaW50byBjb25zaWRlcmF0aW9uIHdoZW4gc2V0dGluZyBUQUNzIGFuZCBvdGhlciBtYW5hZ2VtZW50IGRldmljZXMuIA0KYGBge3IgZmlnLmNhcD0gIkRpc2NhcmQgcmF0aW9zIChwcm9wb3J0aW9uIG9mIHRvdGFsIGNvbW1lcmNpYWwgY2F0Y2ggZGlzY2FyZGVkKSBieSBtYW5hZ2VtZW50IGFyZWEgYW5kIGZsZWV0LCBvdmVyIHRpbWUifQ0KIz09PQ0KIyBQcmVwIGRhdGENCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhcitDYXRjaENhdGVnb3J5K0ZsZWV0MiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQoNCmRpc3JhdCA8LSBhcy5kYXRhLmZyYW1lKHJlc2hhcGUoSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiWWVhciIsIkZsZWV0MiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkNhdGNoQ2F0ZWdvcnkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpKQ0KIyBkaXNyYXRbaXMubmEoZGlzcmF0JENBVE9OLkJNUyksICJDQVRPTi5CTVMiXSA8LSAwDQpkaXNyYXQkRGlzY2FyZFJhdGlvIDwtIGRpc3JhdCRDQVRPTi5EaXNjYXJkcy8oZGlzcmF0JENBVE9OLkxhbmRpbmdzK2Rpc3JhdCRDQVRPTi5EaXNjYXJkcykNCmRpc3JhdCRGbGVldDIgPC0gZmFjdG9yKGRpc3JhdCRGbGVldDIsIGxldmVscyA9IGMoIk5TX0FjdGl2ZSIsICJOU19QYXNzaXZlIiwgIkJTX0FjdGl2ZSIsICJCU19QYXNzaXZlIikpDQpkaXNyYXQkWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkaXNyYXQkWWVhcikpDQojPT09PT0NCg0KIz09PQ0KIyBGaWd1cmUgRGlzY2FyZCBSYXRpb3MgYnkgQ291bnRyeQ0KIz09PT0NCnBsdF9kaXNyYXRfY291bnRyeSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gZGlzcmF0LA0KICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBEaXNjYXJkUmF0aW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gRmxlZXQyKSwNCiAgICAgICAgICAgc2l6ZSA9IDEuNSwNCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHRoZW1lX2NsZWFuKCkgKw0KICAjIGZhY2V0X2dyaWQoQ291bnRyeX4uKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gZWJwYWwpDQpnZ3Bsb3RseShwbHRfZGlzcmF0X2NvdW50cnkpDQojPT09PQ0KYGBgDQoNCmBgYHtyIHRvdGFsZGlzY2FyZHN9DQojPT09DQojIERhdGEgYWdyZWdnYXRpb24NCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhcitDYXRjaENhdGVnb3J5LA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pDQoNCmRpc3JhdCA8LSBhcy5kYXRhLmZyYW1lKHJlc2hhcGUoSUNfYWdnX3RlbXAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiWWVhciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkNhdGNoQ2F0ZWdvcnkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpKQ0KZGlzcmF0W2lzLm5hKGRpc3JhdCRDQVRPTi5CTVMpLCAiQ0FUT04uQk1TIl0gPC0gMA0KZGlzcmF0JERpc2NhcmRSYXRpbyA8LSBkaXNyYXQkQ0FUT04uRGlzY2FyZHMvKGRpc3JhdCRDQVRPTi5MYW5kaW5ncytkaXNyYXQkQ0FUT04uRGlzY2FyZHMpDQptZHIgPC0gbWVkaWFuKGRpc3JhdCREaXNjYXJkUmF0aW8sIG5hLnJtID0gVCkNCm1kcjMgPC0gbWVhbihkaXNyYXRbZGlzcmF0JFllYXIgJWluJSBjKChEYXRhWWVhci0yKTooRGF0YVllYXIpKSwgIkRpc2NhcmRSYXRpbyJdLCBuYS5ybSA9IFQpDQojPT09PT0NCg0KDQpgYGANCiAgDQpUaGUgZ2VuZXJhbCB0aW1lIHRyZW5kcyBmb3IgdGhlIHdob2xlIHN0b2NrIGFyZSBvZiBsZXNzIGludGVyZXN0IGJ1dCBhcmUgaW5jbHVkZWQgaW4gdGhlIHJlcG9ydCBhcyBhIHRpbWUgc2VyaWVzLiAgVGhlIG1lZGlhbiBvZiB0aGUgdGltZSBzZXJpZXMgaXMgYHIgbWRyYC4gIFRoZSBtZWFuIGRpc2NhcmQgcmF0ZSBmb3IgdGhlIHByaW9yIHRocmVlIHllYXJzIGlzIGByIG1kcjNgLg0KDQpgYGB7ciBmaWcuY2FwPSAiQW5udWFsIGRpc2NhcmQgcmF0aW8gZm9yIHRoZSB0b3RhbCBzdG9jayBvdmVyIHRpbWUuIE9yYW5nZSBsaW5lIHJlcHJlc2VudHMgbWVkaWFuIG9mIHRoZSB0aW1lIHNlcmllcy4ifQ0KIz09PQ0KIyBEaXNjYXJkIFJhdGlvcyBhbGwgdG9nZXRoZXINCiM9PT09DQpwbHRfZGlzcmF0IDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gZGlzcmF0LA0KICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBEaXNjYXJkUmF0aW8pLA0KICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRpc3JhdCwNCiAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gRGlzY2FyZFJhdGlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gMSksDQogICAgICAgICAgIGNvbG91ciA9IGVicGFsWzJdKSArDQogIGdlb21faGxpbmUobWFwcGluZyA9IGFlcyh5aW50ZXJjZXB0ID0gbWRyKSwNCiAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFszXSkgKw0KICB0aGVtZV9jbGVhbigpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSkpDQpnZ3Bsb3RseShwbHRfZGlzcmF0KQ0KDQojPT09PQ0KYGBgDQoNCg0KIyMjIENhdGNoZXMgLSBhZHZpY2Ugc2hlZXQgcmVxdWlyZW1lbnRzDQpUaGUgYWR2aWNlIHNoZWV0cyByZXF1aXJlIHNwZWNpZmljIGluZm9ybWF0aW9uIHdoaWNoIGlzIHByZXNlbnRlZCBiZWxvdw0KYGBge3IgQ2F0Y2hMYW5kaW5nRGlzY2FyZERhdGFZZWFyLCBldmFsPUZBTFNFfQ0KIz09PQ0KIyBBZ2dyZWdhdGUgY2F0Y2hlcyBpbiBhIGZvcm1hdCBmb3IgdXNlIGluIHRoZSBzdG9jayBzcGxpdHRpbmcgdGFibGUNCiM9PT09DQpJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+Q2F0Y2hDYXRlZ29yeStBcmVhLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRZZWFyID09IERhdGFZZWFyICYgaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSAic3VtIikNCklDX2FnZ190ZW1wIDwtIHJlc2hhcGUoSUNfYWdnX3RlbXAsIGRpcmVjdGlvbiA9ICJ3aWRlIiwgaWR2YXIgPSAiQXJlYSIsIHRpbWV2YXIgPSAiQ2F0Y2hDYXRlZ29yeSIpDQpJQ19hZ2dfdGVtcFtpcy5uYShJQ19hZ2dfdGVtcCRDQVRPTi5EaXNjYXJkcyksICJDQVRPTi5EaXNjYXJkcyJdIDwtIDANCklDX2FnZ190ZW1wJENhdGNoIDwtIElDX2FnZ190ZW1wJENBVE9OLkRpc2NhcmRzICsgSUNfYWdnX3RlbXAkQ0FUT04uTGFuZGluZ3MNCiM9PT09PQ0KDQprYWJsZShJQ19hZ2dfdGVtcCwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIkNhdGNoZXMgYnkgY2F0Y2ggY2F0ZWdvcnkgYW5kIHN1YmRpdmlzaW9uIGluICIsIERhdGFZZWFyLCAiICh0b25uZXMpLiBfVXNlZCBmb3IgdGhlIHN0b2NrIHNwbGl0dGluZyB0YWJsZV8uIiksDQogICAgICBkaWdpdHMgPSAyKQ0KYGBgDQoNCi0gVGhlIGNhdGNoIGZyb20gc3ViZGl2aXNpb25zIDIxLCAyMiAmIDIzIGNvbWJpbmVkIGluIGByIChEYXRhWWVhcilgIHdhcyBgciBzdW0oaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciwgIkNBVE9OIl0pYCB0b25uZXMuICANCi0gVGhlIGxhbmRpbmdzIGZyb20gc3ViZGl2aXNpb25zIDIxLCAyMiAmIDIzIGNvbWJpbmVkIGluIGByIChEYXRhWWVhcilgIHdhcyBgciBzdW0oaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiwgIkNBVE9OIl0pYCB0b25uZXMuICANCiAgLSBUaGUgcGVyY2VudGFnZSBvZiBsYW5kaW5ncyB0aGF0IHdlcmUgdGFrZW4gaW4gX2FjdGl2ZV8gZ2VhcnMgd2FzIGByICgoc3VtKGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ID09ICJMYW5kaW5ncyIgJiBpY19jbGVhbiRGbGVldCA9PSAiQWN0aXZlIiwgIkNBVE9OIl0pKS8oc3VtKGljX2NsZWFuW2ljX2NsZWFuJFllYXIgPT0gRGF0YVllYXIgJiBpY19jbGVhbiRDYXRjaENhdGVnb3J5ID09ICJMYW5kaW5ncyIsICJDQVRPTiJdKSkpKjEwMGAlLiANCiAgLSBUaGUgcGVyY2VudGFnZSBvZiBsYW5kaW5ncyB0aGF0IHdlcmUgdGFrZW4gaW4gX3Bhc3NpdmVfIGdlYXJzIHdhcyBgciAoKHN1bShpY19jbGVhbltpY19jbGVhbiRZZWFyID09IERhdGFZZWFyICYgaWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSA9PSAiTGFuZGluZ3MiICYgaWNfY2xlYW4kRmxlZXQgPT0gIlBhc3NpdmUiLCAiQ0FUT04iXSkpLyhzdW0oaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiwgIkNBVE9OIl0pKSkqMTAwYCUuICANCi0gVGhlIGRpc2NhcmRzIGZyb20gc3ViZGl2aXNpb25zIDIxLCAyMiAmIDIzIGNvbWJpbmVkIGluIGByIChEYXRhWWVhcilgIHdhcyBgciBzdW0oaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgPT0gIkRpc2NhcmRzIiwgIkNBVE9OIl0pYCB0b25uZXMuICANCg0KDQpUaGUgX0hpc3Rvcnkgb2YgY29tbWVyY2lhbCBjYXRjaCBhbmQgbGFuZGluZ3NfIHRhYmxlIGluIHRoZSBhZHZpY2Ugc2hlZXQgcmVxdWlyZXMgdGhhdCBCTVMgb2ZmaWNpYWwgbGFuZGluZ3MgYXJlIHN1YnRyYWN0ZWQgZnJvbSB0aGUgZGlzY2FyZCB2YWx1ZXMuIF9OZWVkIHRvIGRldGVybWluZSB0aGUgYWR2aWNlIHNoZWV0IHJlc29sdXRpb24gcmVxdWlyZW1lbnRzIChieSBzdG9jaywgYnkgbWFuYWdlbWVudCBhcmVhLCBieSBzdWJkaXZpc2lvbiBldGMuKSBiZWZvcmUgcmV3b3JraW5nIHRoaXMgY29kZSB0byBmaXQuXw0KYGBge3IgbWFudWFsQ2F0Y2hDYWxjcywgZXZhbD1GQUxTRX0NCiM9PT0NCiMgQWdncmVnYXRlIGFuZCBmb3JtYXQgTGFuZGluZ3MgYW5kIERpc2NhcmRzDQojPT09PQ0KSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OfkFyZWErQ2F0Y2hDYXRlZ29yeStDb3VudHJ5LCBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciwgXSwgRlVOID0gInN1bSIpDQphZGN0Y2h0YmxlIDwtIHJlc2hhcGUoZGF0YSA9IElDX2FnZ190ZW1wW0lDX2FnZ190ZW1wJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLF0sIGRpcmVjdGlvbiA9ICJ3aWRlIiwNCiAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFyZWEiLA0KICAgICAgICAgICAgICAgICAgICAgIGlkdmFyID0gYygiQ2F0Y2hDYXRlZ29yeSIsICJDb3VudHJ5IikpDQojIGFkY3RjaHRibGVbaXMubmEoYWRjdGNodGJsZSRDQVRPTi4yNy4zLmEuMjEpLCAiQ0FUT04uMjcuMy5hLjIxIl0gPC0gMA0KIyBhZGN0Y2h0YmxlW2lzLm5hKGFkY3RjaHRibGUkQ0FUT04uMjcuMy5iLjIzKSwgIkNBVE9OLjI3LjMuYi4yMyJdIDwtIDANCiMgYWRjdGNodGJsZVtpcy5uYShhZGN0Y2h0YmxlJENBVE9OLjI3LjMuYy4yMiksICJDQVRPTi4yNy4zLmMuMjIiXSA8LSAwDQphZGN0Y2h0YmxlIDwtIGRhdGEudGFibGU6OnRyYW5zcG9zZShhZGN0Y2h0YmxlKQ0KY29sbmFtZXMoYWRjdGNodGJsZSkgPC0gYygiREtfRGlzY2FyZHMiLCAiREtfTGFuZGluZ3MiLCAiREVfRGlzY2FyZHMiLCAiREVfTGFuZGluZ3MiLCAiU0tfRGlzY2FyZHMiLCAiU0tfTGFuZGluZ3MiKQ0KYWRjdGNodGJsZSA8LSBhZGN0Y2h0YmxlWzM6NSwgXQ0KYWRjdGNodGJsZSA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShhZGN0Y2h0YmxlLCBGVU4gPSAiYXMubnVtZXJpYyIpKQ0KIz09PT0NCg0KIz09PQ0KIyBBZ2dyZWdhdGUgYW5kIGZvcm1hdCBCTVMgTGFuZGluZ3MNCiM9PT09DQpJQ19hZ2dfdGVtcDEgPC0gYWdncmVnYXRlKE9mZmljaWFsTGFuZGluZ3Mua2d+QXJlYStDYXRjaENhdGVnb3J5K0NvdW50cnksIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRZZWFyID09IERhdGFZZWFyLCBdLCBGVU4gPSAic3VtIikNCmFkYm1zdGJsZSA8LSByZXNoYXBlKGRhdGEgPSBJQ19hZ2dfdGVtcDFbSUNfYWdnX3RlbXAxJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJCTVMgbGFuZGluZyIpLCBdLCBkaXJlY3Rpb24gPSAid2lkZSIsDQogICAgICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBcmVhIiwNCiAgICAgICAgICAgICAgICAgICAgICBpZHZhciA9IGMoIkNhdGNoQ2F0ZWdvcnkiLCAiQ291bnRyeSIpKQ0KDQojIGFkYm1zdGJsZVtpcy5uYShhZGJtc3RibGUkT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmEuMjEpLCAiT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmEuMjEiXSA8LSAwDQojIGFkYm1zdGJsZVtpcy5uYShhZGJtc3RibGUkT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmIuMjMpLCAiT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmIuMjMiXSA8LSAwDQojIGFkYm1zdGJsZVtpcy5uYShhZGJtc3RibGUkT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmMuMjIpLCAiT2ZmaWNpYWxMYW5kaW5ncy5rZy4yNy4zLmMuMjIiXSA8LSAwDQphZGJtc3RibGUgPC0gZGF0YS50YWJsZTo6dHJhbnNwb3NlKGFkYm1zdGJsZSkNCmNvbG5hbWVzKGFkYm1zdGJsZSkgPC0gYygiREtfQk1TIiwgIkRFX0JNUyIsICJTS19CTVMiKQ0KYWRibXN0YmxlIDwtIGFkYm1zdGJsZVszOjUsIF0NCmFkYm1zdGJsZSA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShhZGJtc3RibGUsIEZVTiA9ICJhcy5udW1lcmljIikpDQoNCiMjIENvbnZlcnQgZnJvbSBrZyB0byB0b25uZXMNCmFkYm1zdGJsZSA8LSBhZGJtc3RibGUvMTAwMA0KIz09PT09DQojPT09DQojIENvbWJpbmUsIHN1YnRyYWN0IEJNUyBmcm9tIERpc2NhcmRzICYgUmVzdHJ1Y3R1cmUNCiM9PT09DQojIyBDb21iaW5lDQphZGN0Y2h0YmxlIDwtIGNiaW5kKGFkY3RjaHRibGUsIGFkYm1zdGJsZSkNCg0KIyMgUmVwbGFjZSBOQXMgd2l0aCB6ZXJvcyBmb3IgYWNjdXJhdGUgYXJpdGhtZXRpYw0KYWRjdGNodGJsZVtpcy5uYShhZGN0Y2h0YmxlKV0gPC0gMA0KDQojIyBTdWJ0cmFjdCBCTVMgZnJvbSBkaXNjYXJkcw0KYWRjdGNodGJsZSRES19EaXNjYXJkcyA8LSBhZGN0Y2h0YmxlJERLX0Rpc2NhcmRzIC0gYWRjdGNodGJsZSRES19CTVMNCmFkY3RjaHRibGUkREVfRGlzY2FyZHMgPC0gYWRjdGNodGJsZSRERV9EaXNjYXJkcyAtIGFkY3RjaHRibGUkREVfQk1TDQphZGN0Y2h0YmxlJFNLX0Rpc2NhcmRzIDwtIGFkY3RjaHRibGUkU0tfRGlzY2FyZHMgLSBhZGN0Y2h0YmxlJFNLX0JNUw0KDQojIyBDYWxjdWxhdGUgdG90YWwgY2F0Y2gNCklDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5BcmVhLCBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kWWVhciA9PSBEYXRhWWVhciAmIGljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFkY3RjaHRibGUkVG90YWxDYXRjaCA8LSBJQ19hZ2dfdGVtcCRDQVRPTg0KDQojIyBBZGQgc3ViZGl2aXNpb24gaW5mb3JtYXRpb24NCmFkY3RjaHRibGUkU3ViZGl2aXNpb24gPC0gdW5pcXVlKElDX2FnZ190ZW1wJEFyZWEpDQoNCiMjIEFnZ3JlZ2F0ZSBCTVMgYWNyb3NzIGFsbCBjb3VudHJpZXMNCmFkY3RjaHRibGUkQk1TIDwtIHJvd1N1bXMoYWRjdGNodGJsZVssIGMoIkRLX0JNUyIsICJERV9CTVMiLCAiU0tfQk1TIildLCBuYS5ybSA9IFRSVUUpDQoNCiMjIFJlZm9ybWF0DQphZGN0Y2h0YmxlIDwtIGFkY3RjaHRibGVbLCBjKCJTdWJkaXZpc2lvbiIsICJES19EaXNjYXJkcyIsICJES19MYW5kaW5ncyIsICJERV9EaXNjYXJkcyIsICJERV9MYW5kaW5ncyIsICAiU0tfRGlzY2FyZHMiLCAiU0tfTGFuZGluZ3MiLCAiQk1TIiwgIlRvdGFsQ2F0Y2giKV0NCiM9PT09PQ0KDQojPT09DQojIEFkZCBBbm51YWwgVG90YWxzDQojPT09PQ0KdG90cyA8LSBhZGN0Y2h0YmxlWzAsXQ0KZm9yKGkgaW4gMjpuY29sKHRvdHMpKXsNCiAgdG90c1sxLGldIDwtIHN1bShhZGN0Y2h0YmxlWywgaV0sIG5hLnJtID0gVFJVRSkNCn0NCnRvdHMkU3ViZGl2aXNpb24gPC0gYXMuY2hhcmFjdGVyKERhdGFZZWFyKQ0KDQphZGN0Y2h0YmxlIDwtIHJiaW5kKHRvdHMsIGFkY3RjaHRibGUpDQojPT09PT0NCg0KDQoNCmthYmxlKGFkY3RjaHRibGUsDQogICAgICBjYXB0aW9uID0gcGFzdGUwKCJPZmZpY2lhbCBjYXRjaCBudW1iZXJzIGJ5IGNvdW50cnkgYW5kIHN1YmRpdmlzaW9uIGZvciAiLCBEYXRhWWVhciwgIi4gIE9mZmljaWFsIGxhbmRpbmdzIG9mIEJNUyBoYXZlIGJlZW4gc3VidHJhY3RlZCBmcm9tIERpc2NhcmRzLiBfY2FuIGJlIGNvcHktcGFzdGVkIGludG8gdGhlIGFkdmljZSBzaGVldF8uIiksDQogICAgICBkaWdpdHMgPSAwKQ0KDQpgYGANCg0KIyMjIENvbW1lcmNpYWwgU2FtcGxpbmcgQ292ZXJhZ2UNCk5vdCBhbGwgdHJpcHMgaGF2ZSBvYnNlcnZlcnMgb3IgZWxlY3Ryb25pYyBtb25pdG9yaW5nIHRvIGVuYWJsZSBtZWFzdXJlbWVudHMgb2YgZGlzY2FyZCByYXRlcywgb3IgdGhlIHNhbXBsaW5nIG9mIGFsbCBzdHJhdGEgb2YgZmlzaGVyaWVzIGZvciBiaW9sb2dpY2FsIGluZm9ybWF0aW9uLiAgVGhlcmVmb3JlLCByYWlzaW5nIGlzIGNhcnJpZWQgb3V0IHRvIG1hdGNoIHVuc2FtcGxlZCBzdHJhdGEgd2l0aCB0aG9zZSB3aGVyZSB3ZSBoYXZlIG9ic2VydmF0aW9ucyAodGhpcyBpcyBjdXJyZW50bHkgZG9uZSBpbiBpbnRlcmNhdGNoKS4gRWFjaCB5ZWFyLCBkaWZmZXJlbnQgcG9ydGlvbnMgb2YgdGhlIGZpc2hlcnkgYXJlIHNhbXBsZWQgYW5kIHRvIHZhcnlpbmcgZGVncmVlcywgdGhlcmVmb3JlIHRoZXJlIGlzIG5vIGhhcmQgYW5kIGZhc3QgcnVsZSBhYm91dCB3aGljaCBzdHJhdGEgc2hvdWxkIGJlIG1hdGNoZWQuIFJhdGhlciwgdGhlcmUgYXJlIGEgc2V0IG9mIHByaW9yaXRpZXMgYnkgd2hpY2ggd2UgdHJ5IHRvIG1hdGNoIHVuc2FtcGxlZCBzdHJhdGEgdG8gc2FtcGxlZCBzdHJhdGEuICBUaGVzZSBjYW4gYmUgZm91bmQgaW4gdGhlIHN0b2NrIGFubmV4LiBCZWxvdyB3ZSBleHBsb3JlIHRoZSBsZXZlbCBvZiBzYW1wbGluZyBjb3ZlcmFnZSBhY3Jvc3MgdGhlIGRpZmZlcmVudCBzdHJhdGEgZm9yIGByIERhdGFZZWFyYCAodXNpbmcgdG9ubmFnZSBwZXIgY2F0ZWdvcnkgdG8gZGVyaXZlIHByb3BvcnRpb25zKS4gIEdlbmVyYWxseSwgdGhpcyBwbGFpY2Ugc3RvY2sgaXMgd2VsbCBjb3ZlcmVkIGJ5IHNhbXBsaW5nIGFuZCB0aGVyZSBhcmUgYSBtaW5vcml0eSBvZiBjYXRjaGVzIGZvciB3aGljaCBkYXRhIGFyZSBtYXRjaGVkIGFuZCBhc3N1bXB0aW9ucyBhcmUgbWFkZS4gIA0KDQpgYGB7ciBTYW1wbGluZ0NvdmVyYWdlQ2FsY3N9DQojPT09DQojIERhdGEgd3JhbmdsaW5nIGFuZCBjYWxjdWxhdGlvbiBvZiBSYWlzZWQvaW1wb3J0ZWQgc2FtcGxlZC9Fc3RpbWF0ZWQgY2F0Y2hlcyBmb3IgQ3VycmVudCBZZWFyDQojPT09PQ0KZGF0YWNvdmVyYWdlX0RZIDwtIGFnZ3JlZ2F0ZShDQVRPTn5DYXRjaENhdGVnb3J5K0NBVE9OUmFpc2VkT3JJbXBvcnRlZCtTYW1wbGVkT3JFc3RpbWF0ZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBpY19jbGVhbltpY19jbGVhbiRZZWFyID09IERhdGFZZWFyLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkNCmxuZF9EWSA8LSBzdW0oZGF0YWNvdmVyYWdlX0RZW2RhdGFjb3ZlcmFnZV9EWSRDYXRjaENhdGVnb3J5ID09ICJMYW5kaW5ncyIsICJDQVRPTiJdKQ0KZGlzY19EWSA8LSBzdW0oZGF0YWNvdmVyYWdlX0RZW2RhdGFjb3ZlcmFnZV9EWSRDYXRjaENhdGVnb3J5ICVpbiUgYygiRGlzY2FyZHMiKSwgIkNBVE9OIl0pDQoNCmRhdGFjb3ZlcmFnZV9EWSRQcm9wb3J0aW9uIDwtIE5BDQpkYXRhY292ZXJhZ2VfRFlbZGF0YWNvdmVyYWdlX0RZJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiAmIGRhdGFjb3ZlcmFnZV9EWSRTYW1wbGVkT3JFc3RpbWF0ZWQgPT0gIlNhbXBsZWRfRGlzdHJpYnV0aW9uIiwgIlByb3BvcnRpb24iXSA8LSBkYXRhY292ZXJhZ2VfRFlbZGF0YWNvdmVyYWdlX0RZJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiAmIGRhdGFjb3ZlcmFnZV9EWSRTYW1wbGVkT3JFc3RpbWF0ZWQgPT0gIlNhbXBsZWRfRGlzdHJpYnV0aW9uIiwgIkNBVE9OIl0vbG5kX0RZDQpkYXRhY292ZXJhZ2VfRFlbZGF0YWNvdmVyYWdlX0RZJENhdGNoQ2F0ZWdvcnkgPT0gIkxhbmRpbmdzIiAmIGRhdGFjb3ZlcmFnZV9EWSRTYW1wbGVkT3JFc3RpbWF0ZWQgPT0gIkVzdGltYXRlZF9EaXN0cmlidXRpb24iLCAiUHJvcG9ydGlvbiJdIDwtIGRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSA9PSAiTGFuZGluZ3MiICYgZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCA9PSAiRXN0aW1hdGVkX0Rpc3RyaWJ1dGlvbiIsICJDQVRPTiJdL2xuZF9EWQ0KDQpkYXRhY292ZXJhZ2VfRFlbZGF0YWNvdmVyYWdlX0RZJENhdGNoQ2F0ZWdvcnkgPT0gIkRpc2NhcmRzIiAmIGRhdGFjb3ZlcmFnZV9EWSRTYW1wbGVkT3JFc3RpbWF0ZWQgPT0gIlNhbXBsZWRfRGlzdHJpYnV0aW9uIiAmIGRhdGFjb3ZlcmFnZV9EWSRDQVRPTlJhaXNlZE9ySW1wb3J0ZWQgPT0gIkltcG9ydGVkX0RhdGEiLCAiUHJvcG9ydGlvbiJdIDwtIGRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSA9PSAiRGlzY2FyZHMiICYgZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCA9PSAiU2FtcGxlZF9EaXN0cmlidXRpb24iICYgZGF0YWNvdmVyYWdlX0RZJENBVE9OUmFpc2VkT3JJbXBvcnRlZCA9PSAiSW1wb3J0ZWRfRGF0YSIsICJDQVRPTiJdL2Rpc2NfRFkNCmRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSA9PSAiRGlzY2FyZHMiICYgZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCA9PSAiRXN0aW1hdGVkX0Rpc3RyaWJ1dGlvbiIgJiBkYXRhY292ZXJhZ2VfRFkkQ0FUT05SYWlzZWRPckltcG9ydGVkID09ICJJbXBvcnRlZF9EYXRhIiwgIlByb3BvcnRpb24iXSA8LSBkYXRhY292ZXJhZ2VfRFlbZGF0YWNvdmVyYWdlX0RZJENhdGNoQ2F0ZWdvcnkgPT0gIkRpc2NhcmRzIiAmIGRhdGFjb3ZlcmFnZV9EWSRTYW1wbGVkT3JFc3RpbWF0ZWQgPT0gIkVzdGltYXRlZF9EaXN0cmlidXRpb24iICYgZGF0YWNvdmVyYWdlX0RZJENBVE9OUmFpc2VkT3JJbXBvcnRlZCA9PSAiSW1wb3J0ZWRfRGF0YSIsICJDQVRPTiJdL2Rpc2NfRFkNCmRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSA9PSAiRGlzY2FyZHMiICYgZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCA9PSAiRXN0aW1hdGVkX0Rpc3RyaWJ1dGlvbiIgJiBkYXRhY292ZXJhZ2VfRFkkQ0FUT05SYWlzZWRPckltcG9ydGVkID09ICJSYWlzZWRfRGlzY2FyZHMiLCAiUHJvcG9ydGlvbiJdIDwtIGRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSA9PSAiRGlzY2FyZHMiICYgZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCA9PSAiRXN0aW1hdGVkX0Rpc3RyaWJ1dGlvbiIgJiBkYXRhY292ZXJhZ2VfRFkkQ0FUT05SYWlzZWRPckltcG9ydGVkID09ICJSYWlzZWRfRGlzY2FyZHMiLCAiQ0FUT04iXS9kaXNjX0RZDQoNCmRhdGFjb3ZlcmFnZV9EWSRTb3VyY2UgPC0gcGFzdGUoZGF0YWNvdmVyYWdlX0RZJFNhbXBsZWRPckVzdGltYXRlZCwgZGF0YWNvdmVyYWdlX0RZJENBVE9OUmFpc2VkT3JJbXBvcnRlZCwgc2VwID0gIlxuIikNCmRhdGFjb3ZlcmFnZV9EWSRTb3VyY2UgPC0gYXMuZmFjdG9yKGRhdGFjb3ZlcmFnZV9EWSRTb3VyY2UpDQpkYXRhY292ZXJhZ2VfRFkkU291cmNlIDwtIGZhY3RvcihkYXRhY292ZXJhZ2VfRFkkU291cmNlLCBsZXZlbHMgPSBjKCJFc3RpbWF0ZWRfRGlzdHJpYnV0aW9uXG5SYWlzZWRfRGlzY2FyZHMiLCAiRXN0aW1hdGVkX0Rpc3RyaWJ1dGlvblxuSW1wb3J0ZWRfRGF0YSIsICJTYW1wbGVkX0Rpc3RyaWJ1dGlvblxuSW1wb3J0ZWRfRGF0YSIpKQ0KZGF0YWNvdmVyYWdlX0RZIDwtIGRyb3BsZXZlbHMoZGF0YWNvdmVyYWdlX0RZKQ0KIz09PT09DQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIlByb3BvcnRpb25zIG9mIGNhdGNoIGNvbXBvbmVudHMgdGhhdCB3ZXJlIHNhbXBsZWQgZm9yIGJpb2xvZ2ljYWwgZGF0YSwgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGRpc2NhcmRzIHRoYXQgd2VyZSByYWlzZWQgYnkgcGFpcmluZyB3aXRoIHJlcG9ydGVkIGRpc2NhcmQgZGF0YS4gIFByb3BvcnRpb25zIGFyZSBtYWRlIHdpdGggY2F0Y2ggdG9ubmFnZSBieSBzdHJhdGEgKGZsZWV0LCBhcmVhLCBjb3VudHJ5LCBxdWFydGVyKSBmb3IgdGhlIHllYXIgIiwgRGF0YVllYXIpIH0NCg0KIz09PQ0KIyBGaWd1cmUgb2Ygc2FtcGxpbmcgY292ZXJhZ2UgZm9yIERhdGFZZWFyDQojPT09PQ0KcGx0X2RhdGFDb3ZlciA8LSBnZ3Bsb3QoKSArDQogIGdlb21fY29sKGRhdGEgPSBkYXRhY292ZXJhZ2VfRFlbIWRhdGFjb3ZlcmFnZV9EWSRDYXRjaENhdGVnb3J5ICVpbiUgYygiQk1TIiwgIkJNUyBsYW5kaW5nIiwgIkxvZ2Jvb2sgUmVnaXN0ZXJlZCBEaXNjYXJkIiwgIkNhdGNoIiksIF0sDQogICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IENhdGNoQ2F0ZWdvcnksDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BvcnRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFNvdXJjZSkpICsNCiAgdGhlbWVfY2xlYW4oKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxYjllNzciLCIjZDk1ZjAyIiwgIiM3NTcwYjMiKSkNCmdncGxvdGx5KHBsdF9kYXRhQ292ZXIpDQojPT09PT0NCmBgYA0KDQpgYGB7ciBkYXRhQ292ZXJhZ2VUYWJ9DQojPT09DQojIFRhYnVsYXRlIGZvciBwcmVzZW50YXRpb24NCiM9PT09DQpkY0RZdGFiIDwtIGRhdGFjb3ZlcmFnZV9EWVtkYXRhY292ZXJhZ2VfRFkkQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksIGMoIkNhdGNoQ2F0ZWdvcnkiLCAiU291cmNlIiwgIkNBVE9OIiwgIlByb3BvcnRpb24iKV0NCmRjRFl0YWIkSW5mb1NvdXJjZSA8LSBnc3ViKHBhdHRlcm4gPSAiXFxcbiIsIHJlcGxhY2VtZW50ID0gIiBhbmQgIiwgZGNEWXRhYiRTb3VyY2UpDQpkY0RZdGFiIDwtIGRjRFl0YWJbZGNEWXRhYiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgYygiQ2F0Y2hDYXRlZ29yeSIsICJJbmZvU291cmNlIiwgIkNBVE9OIiwgIlByb3BvcnRpb24iKV0NCnJvd25hbWVzKGRjRFl0YWIpIDwtIE5VTEwNCmRjRFl0YWIkQ0FUT04gPC0gcm91bmQoZGNEWXRhYiRDQVRPTiwgZGlnaXRzID0gMCkNCmRjRFl0YWIkUHJvcG9ydGlvbiA8LSBpY2VzUm91bmQoZGNEWXRhYiRQcm9wb3J0aW9uKjEwMCwgcGVyY2VudCA9IFRSVUUsIHNpZ24gPSBGQUxTRSkNCg0Ka2FibGUoZGNEWXRhYiwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIlByb3BvcnRpb25zIG9mIGNhdGNoIGNvbXBvbmVudHMgdGhhdCB3ZXJlIHNhbXBsZWQgZm9yIGJpb2xvZ2ljYWwgZGF0YSwgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGRpc2NhcmRzIHRoYXQgd2VyZSByYWlzZWQgYnkgcGFpcmluZyB3aXRoIHJlcG9ydGVkIGRpc2NhcmQgZGF0YS4gIFByb3BvcnRpb25zIGFyZSBtYWRlIHdpdGggY2F0Y2ggdG9ubmFnZSBieSBzdHJhdGEgKGZsZWV0LCBhcmVhLCBjb3VudHJ5LCBxdWFydGVyKSBmb3IgdGhlIHllYXIgIiwgRGF0YVllYXIpKQ0KIz09PT09DQpgYGANCg0KYGBge3IgRGV0YWlsZWRTYW1wbGluZ0NvdmVyYWdlVGFifQ0KIz09PQ0KIyBEYXRhIHdyYW5nbGluZw0KIz09PT0NCklDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShjYmluZChDQVRPTiwgTm8ub2YubGVuZ3RoLnNhbnBsZXMsIE5vLmxlbmd0aC5tZXN1cmVzLCBOby5vZi5hZ2Uuc2FtcGxlcywgTm8ub2YuYWdlLnJlYWRpbmdzKX5BcmVhK0NhdGNoQ2F0ZWdvcnkrQ291bnRyeStGbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIikgJiBpY19jbGVhbiRZZWFyID09IERhdGFZZWFyLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gInN1bSIpDQpjb2xuYW1lcyhJQ19hZ2dfdGVtcCkgPC0gYygiU3ViZGl2aXNpb24iLCAiQ2F0Y2hDYXRlZ29yeSIsICJDb3VudHJ5IiwgIkZsZWV0IiwgIkNhdGNoKHRvbm5lcykiLCAiTGVuZ3RoU2FtcGxlcyIsICJMZW5ndGhzTWVhc3VyZWQiLCAiQWdlU2FtcGxlcyIsICJBZ2VzUmVhZCIpDQpzYW1wdGFibGUgPC0gSUNfYWdnX3RlbXBbb3JkZXIoSUNfYWdnX3RlbXAkU3ViZGl2aXNpb24sIElDX2FnZ190ZW1wJENhdGNoQ2F0ZWdvcnksIElDX2FnZ190ZW1wJENvdW50cnksIElDX2FnZ190ZW1wJEZsZWV0KSwgXQ0Kc2FtcHRhYmxlJGBDYXRjaCh0b25uZXMpYCA8LSByb3VuZChzYW1wdGFibGUkYENhdGNoKHRvbm5lcylgLCBkaWdpdHMgPSAzKQ0KIz09PT09DQoNCiM9PT0NCiMNCiM9PT09DQpyb3duYW1lcyhzYW1wdGFibGUpIDwtIE5VTEwNCmthYmxlKHNhbXB0YWJsZSwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIlNhbXBsaW5nIGVmZm9ydCBpbiAiLCBEYXRhWWVhciwgIiBieSBzdHJhdGEuIikpDQoNCmBgYA0KDQoNCiMjIFN1cnZleSBJbmRpY2VzDQpUaGlzIHN0b2NrIHV0aWxpc2VzIGRhdGEgZnJvbSBmb3VyIHN1cnZleXMuICBBIGNvbWJpbmF0aW9uIG9mIDFzdCBxdWFydGVyIE5TLUlCVFMgYW5kIHRoZSAxc3QgcXVhcnRlciBCSVRTIG9uIHRoZSBvbmUgaGFuZCwgYW5kIHRoZSBjb21iaW5hdGlvbiBvZiAzcmQgcXVhcnRlciBOUy1JQlRTIGFuZCA0dGggcXVhcnRlciBCSVRTIG9uIHRoZSBvdGhlci4gDQoNCkN1cnJlbnRseSwgdGhlc2UgaW5kaWNlcyBhcmUgZ2VuZXJhdGVkIGJ5IENhc3BlciBCZXJnIGZyb20gRFRVIEFxdWEsIHVzaW5nIGEgbWV0aG9kIGhlIHB1Ymxpc2hlZCBpbiAyMDE0LiBBbiBhZGFwdGF0aW9uIG9mIENhc3BlcidzIG1ldGhvZCBpcyBpbiBwcm9ncmVzcy4NCl9EZXNjcmlwdGlvbiBvZiBuZXcgbW9kZWwgYW5kIHVwZGF0ZWQgaW5kaWNlcyBuZWVkIHRvIGJlIHByb3ZpZGVkIGluIHRoaXMgc2VjdGlvbiBvbmNlIHJlYWR5Ll8NCg0KDQpgYGB7cn0NCiMgIyMgMjAxOSBRMy80IGRhdGEgZXhjbHVkZWQgZnJvbSBjYWxjdWxhdGlvbiBvZiBpbmRpY2VzDQpzdXJ2VHVuIDwtIHJlYWQuY3N2KGZpbGUgPSAiRGF0YS9wbGUuMjcuMjEtMjNfU3VydmV5VHVuaW5nX0lCVFMtQklUU18xOTkyLURhdGFZZWFyXzIwMTlRMzRFeGNsdWRlZC5jc3YiLCBoZWFkZXIgPSBUKQ0KayA8LSBhcHBlbmQoaywgInN1cnZUdW4iKQ0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZmlnLmNhcD0gIk5TLUlCVFMgJiBCSVRTIGRlcml2ZWQgdHVuaW5nIGluZGljZXMgZm9yIHBsZS4yNy4yMS0yMyBRMSBhbmQgUTMvNC4ifQ0KIz09PQ0KIyBEYXRhIHByZXANCiM9PT09DQpzdXJ2VHVuTG5nIDwtIHJlc2hhcGUoZGF0YSA9IHN1cnZUdW4sDQogICAgICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGxpc3QoY29sbmFtZXMoc3VydlR1bilbMzpsZW5ndGgoKGNvbG5hbWVzKHN1cnZUdW4pKSldKSwNCiAgICAgICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gYygiSW5kZXgiKSwNCiAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0Kc3VydlR1bkxuZyRBZ2UgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihzdXJ2VHVuTG5nJEFnZSkpDQpzdXJ2VHVuTG5nJFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihzdXJ2VHVuTG5nJFllYXIpKQ0KayA8LSBhcHBlbmQoaywgInN1cnZUdW5MbmciKQ0KIz09PT09DQoNCiM9PT0NCiMgRmlndXJlIDEyIFN1cnZleSBUdW5pbmcgSW5kaWNlcyBvdmVyIHRpbWUNCiM9PT09DQpzZXQuc2VlZCg1KQ0KcGx0X3N1cnZUdW4gPC0gZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHN1cnZUdW5MbmcsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gSW5kZXgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBBZ2UpLA0KICAgICAgICAgICAgc2l6ZSA9IDEuMjUpICsNCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhTdXJ2ZXkpLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICB0aGVtZV9jbGVhbigpICsNCiAgIyBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNhbXBsZShlYnBhbCwgc2l6ZSA9IGxlbmd0aChsZXZlbHMoc3VydlR1bkxuZyRBZ2UpKSkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDEpKQ0KDQpnZ3Bsb3RseShwbHRfc3VydlR1bikNCiM9PT09DQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRSwgZmlnLmNhcD0iSW50ZXJuYWwgY29uc2lzdGVuY3kgcGxvdCBmb3IgYW5kIG1hcHMgb2YgdGhlIGNvbWJpbmVkIFExIHN1cnZleXMuICBHZW5lcmF0ZWQgYnkgQ2FzcGVyIEJlcmciLCBvdXQud2lkdGg9ICI4NSUifQ0KIyBpbmNsdWRlX2dyYXBoaWNzKHBhdGggPSBwYXN0ZTAoIi4uLyIsIERhdGFZZWFyKzEsICIvU3VydmV5SW5kaWNlcy9DYXNwZXJDYWxjdWxhdGlvbnMvSUNRMS5wbmciKSkNCg0KIz09PQ0KIyBBbHRlcm5hdGUgY29kZSBmb3IgaW5jbHVkaW5nIG11bHRpcGxlIHBsb3RzDQojPT09PQ0KaW5jbHVkZV9ncmFwaGljcyhwYXRoID0gcGFzdGUwKCIuLi8iLCBEYXRhWWVhcisxLCAiL1N1cnZleUluZGljZXMvQ2FzcGVyQ2FsY3VsYXRpb25zLyIsIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlMCgiLi4vIiwgRGF0YVllYXIrMSwgIi9TdXJ2ZXlJbmRpY2VzL0Nhc3BlckNhbGN1bGF0aW9ucyIpLCBwYXR0ZXJuID0gIlExLnBuZyIpKSkNCiM9PT09PQ0KYGBgDQoNCmBgYHtyIGV2YWw9RkFMU0UsIGZpZy5jYXA9IkludGVybmFsIGNvbnNpc3RlbmN5IHBsb3QgZm9yLCBhbmQgbWFwcyBvZiB0aGUgY29tYmluZWQgUTMgJiBRNCBzdXJ2ZXlzLiAgR2VuZXJhdGVkIGJ5IENhc3BlciBCZXJnIiwgb3V0LndpZHRoPSAiODUlIn0NCiM9PT0NCiMgQWx0ZXJuYXRlIGNvZGUgZm9yIGluY2x1ZGluZyBtdWx0aXBsZSBncmFwaGljcw0KIz09PT0NCnhtYXRjaGVzIDwtIGludGVyc2VjdChncmVwKHBhdHRlcm4gPSAiLnBuZyIsIHggPSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZTAoIi4uLyIsIERhdGFZZWFyKzEsICIvU3VydmV5SW5kaWNlcy9DYXNwZXJDYWxjdWxhdGlvbnMiKSkpLA0KICAgICAgICAgICAgICAgICAgICAgIGdyZXAocGF0dGVybiA9ICIyMDE5IiwgeCA9IGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlMCgiLi4vIiwgRGF0YVllYXIrMSwgIi9TdXJ2ZXlJbmRpY2VzL0Nhc3BlckNhbGN1bGF0aW9ucyIpKSkpDQppbmNsdWRlX2dyYXBoaWNzKHBhdGggPSBwYXN0ZTAoIi4uLyIsIERhdGFZZWFyKzEsICIvU3VydmV5SW5kaWNlcy9DYXNwZXJDYWxjdWxhdGlvbnMvIiwgbGlzdC5maWxlcyhwYXRoID0gcGFzdGUwKCIuLi8iLCBEYXRhWWVhcisxLCAiL1N1cnZleUluZGljZXMvQ2FzcGVyQ2FsY3VsYXRpb25zIikpW3htYXRjaGVzXSkpDQojPT09PT0NCg0KYGBgDQogIA0KDQojIyBCaW9sb2dpY2FsIERhdGENClRvIGJlZ2luIHdpdGggd2UgbmVlZCBzdXJ2ZXkgZGF0YS4gIFRoZXNlIGNhbiBiZSBkb3dubG9hZGVkIG11bGlwbGUgd2F5cyBmcm9tIERBVFJBUyBidXQgd2UgbmVlZCB0aGUgIERBVFJBUyBFeGNoYW5nZSBmaWxlcyAoSEgsIENBLCBITCkuICBUaGUgc2NyaXB0ICowMV9EYXRyYXNEb3dubG9hZHMuUiogZG93bmxvYWRzIGFsbCBleGNoYW5nZSBkYXRhIGZvciBOUy1JQlRTIGFuZCBCSVRTIHN1cnZleXMgYW5kIHNhdmVzIHRoZSByZXN1bHRzIGFzIC5DU1YgZmlsZXMgd2hpY2ggd2UgY2FuIHVzZSBoZXJlLg0KDQojIyMgUmVhZGluZywgU3Vic2V0dGluZyBhbmQgQ2xlYW5pbmcNCmBgYHtyIENhbGNzRm9yU3VydmV5QmlvbG9naWNhbERhdGEsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPVRSVUV9DQoNCiMjIFJlYWQgaW4gSUNFUyBhcmVhIC8gc3ViZGl2aXNpb24gbGF5ZXJzDQpTRHMgPC0gc3RfcmVhZChkc24gPSAiRGF0YS9JQ0VTX2FyZWFzLyIsIGxheWVyID0gIklDRVNfQXJlYXNfMjAxNjA2MDFfY3V0X2RlbnNlXzM4NTciKQ0KDQojICM9PT0NCiMgIyBPUFRJT05BTDogVXBkYXRlIGRhdHJhcyBkYXRhIGJ5IHJlLWRvd25sb2FkaW5nIC0gVEFLRVMgTE9ORyBUSU1FIC0tLS0NCiMgIz09PQ0KIyBzb3VyY2UoZmlsZSA9ICJEYXRhL1N1cnZleXMvMDFfRGF0cmFzRG93bmxvYWRzLlIiKQ0KIyAjPT09PQ0KDQppZigoZmlsZS5leGlzdHMoIkRhdGEvU3VydmV5cy9leGNoYW5nZS9QbGUuMjcuMjEtMzJfY2EtaGguUkRTIikgJiBmaWxlLmV4aXN0cygiRGF0YS9TdXJ2ZXlzL2V4Y2hhbmdlL1BsZS4yNy4yMS0zMl9obC1oaC5SRFMiKSkpew0KICBjYV9oaF9maW5fYml0c19pYnRzIDwtIHJlYWRSRFMoZmlsZSA9ICJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvUGxlLjI3LjIxLTMyX2NhLWhoLlJEUyIpDQogIGhsX2hoX2Zpbl9iaXRzX2lidHMgPC0gcmVhZFJEUyhmaWxlID0gIkRhdGEvU3VydmV5cy9leGNoYW5nZS9QbGUuMjcuMjEtMzJfaGwtaGguUkRTIikNCn1lbHNlew0KICAjPT09DQogICMgUmVhZCBpbiBEYXRhIC0tLS0NCiAgIz09PQ0KICAjIFJlYWQgaW4gRGF0cmFzIGZpbGVzDQogIGhoX2lidHM8LXJlYWQuY3N2KCJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvSUJUU19ISF8xOTY1X0Fzc1llYXIuY3N2IixzZXA9IiwiLHN0cmluZ3NBc0ZhY3RvcnM9RikNCiAgY2FfaWJ0czwtcmVhZC5jc3YoIkRhdGEvU3VydmV5cy9leGNoYW5nZS9JQlRTX0NBXzE5NjVfQXNzWWVhci5jc3YiLHNlcD0iLCIsc3RyaW5nc0FzRmFjdG9ycz1GKQ0KICBobF9pYnRzPC1yZWFkLmNzdigiRGF0YS9TdXJ2ZXlzL2V4Y2hhbmdlL0lCVFNfSExfMTk2NV9Bc3NZZWFyLmNzdiIsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzPUYpDQogIA0KICBoaF9iaXRzPC1yZWFkLmNzdigiRGF0YS9TdXJ2ZXlzL2V4Y2hhbmdlL0JJVFNfSEhfMTk5MV9Bc3NZZWFyLmNzdiIsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzPUYpDQogIGNhX2JpdHM8LXJlYWQuY3N2KCJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvQklUU19DQV8xOTkxX0Fzc1llYXIuY3N2IixzZXA9IiwiLHN0cmluZ3NBc0ZhY3RvcnM9RikNCiAgaGxfYml0czwtcmVhZC5jc3YoIkRhdGEvU3VydmV5cy9leGNoYW5nZS9CSVRTX0hMXzE5OTFfQXNzWWVhci5jc3YiLHNlcD0iLCIsc3RyaW5nc0FzRmFjdG9ycz1GKQ0KICAjPT09PQ0KICANCiAgIz09PQ0KICAjIFNlbGVjdCBQbGFpY2UgaW4gY2EgYW5kIGhsIGZpbGVzIC0tLS0NCiAgIz09PQ0KICBjYTFfaWJ0czwtc3Vic2V0KGNhX2lidHMsU3BlY0NvZGVUeXBlPT0iVCImU3BlY0NvZGU9PTE3MjkwMikNCiAgY2EyX2lidHM8LXN1YnNldChjYV9pYnRzLFNwZWNDb2RlVHlwZT09IlciJlNwZWNDb2RlPT0xMjcxNDMpDQogIGNhX2lidHM8LXJiaW5kKGNhMV9pYnRzLGNhMl9pYnRzKQ0KICANCiAgaGwxX2lidHM8LXN1YnNldChobF9pYnRzLFNwZWNDb2RlVHlwZT09IlQiJlNwZWNDb2RlPT0xNzI5MDIpDQogIGhsMl9pYnRzPC1zdWJzZXQoaGxfaWJ0cyxTcGVjQ29kZVR5cGU9PSJXIiZTcGVjQ29kZT09MTI3MTQzKQ0KICBobF9pYnRzPC1yYmluZChobDFfaWJ0cyxobDJfaWJ0cykNCiAgDQogIGNhMTwtc3Vic2V0KGNhX2JpdHMsU3BlY0NvZGVUeXBlPT0iVCImU3BlY0NvZGU9PTE3MjkwMikNCiAgY2EyPC1zdWJzZXQoY2FfYml0cyxTcGVjQ29kZVR5cGU9PSJXIiZTcGVjQ29kZT09MTI3MTQzKQ0KICBjYTwtcmJpbmQoY2ExLGNhMikNCiAgDQogIGhsMTwtc3Vic2V0KGhsX2JpdHMsU3BlY0NvZGVUeXBlPT0iVCImU3BlY0NvZGU9PTE3MjkwMikNCiAgaGwyPC1zdWJzZXQoaGxfYml0cyxTcGVjQ29kZVR5cGU9PSJXIiZTcGVjQ29kZT09MTI3MTQzKQ0KICBobDwtcmJpbmQoaGwxLGhsMikNCiAgIz09PT0NCiAgDQogICM9PT0NCiAgIyBBZGQgU0QgYW5kIFN0YXRpb24gaW5mbyB0byBJQlRTIC0tLS0gIA0KICAjPT09DQogICMgTWFrZSBOUy1JQlRTIGhhdWwgZGF0YSBzcGF0aWFsIG9iamVjdA0KICBoaF9pYnRzX3NmIDwtIHN0X2FzX3NmKGhoX2lidHMsIGNvb3JkcyA9IGMoIlNob290TG9uZyIsICJTaG9vdExhdCIpLCBjcnMgPSA0MzI2KQ0KICANCiAgIyBNYXRjaCBwcm9qZWN0aW9ucyBiZXR3ZWVuIElDRVMgYXJlYXMgYW5kIEhhdWwgZGF0YSANCiAgU0RzIDwtIHN0X21ha2VfdmFsaWQoc3RfdHJhbnNmb3JtKFNEcywgY3JzID0gc3RfY3JzKGhoX2lidHNfc2YpKSkNCiAgDQogICMgSm9pbiAvIG1lcmdlIHRoZSBJQ0VTIHNwYXRpYWwgaW5mb3JtYXRpb24gd2l0aCB0aGUgREFUUkFTIGhhdWxzIGJ5IGdlb21ldHJpZXMNCiAgaGhfaWJ0c19zZiA8LSBzdF9qb2luKHggPSBoaF9pYnRzX3NmLCB5ID0gU0RzLCBqb2luID0gc3RfbmVhcmVzdF9mZWF0dXJlLCBsZWZ0ID0gVCkNCiAgDQogICMgcmVkdWNlIGRhdGEgdG8gZGF0YWZyYW1lDQogIGhoX2lidHMgPC0gc3RfZHJvcF9nZW9tZXRyeShoaF9pYnRzX3NmKQ0KDQogICMgU2VsZWN0IHRoZSByb3dzIHdpdGhpbiB0aGUgcmVsZXZhbnQgc3ViZGl2aXNpb25zDQogIGhoX2lidHMxIDwtIGhoX2lidHNbaGhfaWJ0cyRTdWJEaXZpc2lvICVpbiUgYXMuY2hhcmFjdGVyKGMoMjE6MzIpKSwgXQ0KICANCiAgIyBBZGQgc3RhdGlvbiBpbmZvcm1hdGlvbiB0byBjYSBmaWxlDQogIGNhX3NlbF9pYnRzPC1jYV9pYnRzWyxuYW1lcyhjYV9pYnRzKSVpbiVjKCJTdXJ2ZXkiLCJRdWFydGVyIiwiQ291bnRyeSIsIlNoaXAiLCJHZWFyIiwiU3RObyIsIkhhdWxObyIsIlllYXIiLCJBcmVhQ29kZSIsIkxuZ3RDb2RlIiwiTG5ndENsYXNzIiwiU2V4IiwiTWF0dXJpdHkiLCJQbHVzR3IiLCJBZ2UiLCJDQU5vQXRMbmd0IiwiSW5kV2d0IildDQogIGhoX3NlbF9pYnRzPC1oaF9pYnRzMVssbmFtZXMoaGhfaWJ0czEpJWluJWMoIlN1cnZleSIsIlF1YXJ0ZXIiLCJDb3VudHJ5IiwiU2hpcCIsIkdlYXIiLCJTdE5vIiwiSGF1bE5vIiwiWWVhciIsIk1vbnRoIiwiRGF5IiwiU3RyYXR1bSIsIkhhdWxEdXIiLCJTaG9vdExhdCIsIlNob290TG9uZyIsIkhhdWxMYXQiLCJIYXVsTG9uZyIsIlN0YXRSZWMiLCJEZXB0aCIsIkhhdWxWYWwiLCJEYXRhVHlwZSIsIlN1YkRpdmlzaW8iKV0NCiAgDQogIGNhX3NlbF9pYnRzPC1jYV9zZWxfaWJ0c1tvcmRlcihjYV9zZWxfaWJ0cyRZZWFyLGNhX3NlbF9pYnRzJFF1YXJ0ZXIsY2Ffc2VsX2lidHMkQ291bnRyeSxjYV9zZWxfaWJ0cyRTaGlwLGNhX3NlbF9pYnRzJEdlYXIsY2Ffc2VsX2lidHMkU3RObyxjYV9zZWxfaWJ0cyRIYXVsTm8pLF0NCiAgaGhfc2VsX2lidHM8LWhoX3NlbF9pYnRzW29yZGVyKGhoX3NlbF9pYnRzJFllYXIsaGhfc2VsX2lidHMkUXVhcnRlcixoaF9zZWxfaWJ0cyRDb3VudHJ5LGhoX3NlbF9pYnRzJFNoaXAsaGhfc2VsX2lidHMkR2VhcixoaF9zZWxfaWJ0cyRTdE5vLGhoX3NlbF9pYnRzJEhhdWxObyksXQ0KICANCiAgY2FfaGhfaWJ0czwtbWVyZ2UoaGhfc2VsX2lidHMsY2Ffc2VsX2lidHMsYnk9YygiU3VydmV5IiwiUXVhcnRlciIsIkNvdW50cnkiLCJTaGlwIiwiR2VhciIsIlN0Tm8iLCJIYXVsTm8iLCJZZWFyIiksYWxsPUYpDQogIA0KICAjIHdyaXRlLmNzdihjYV9oaF9pYnRzLGZpbGU9IkRhdGEvU3VydmV5cy9leGNoYW5nZS9jYV9oaF9pYnRzLmNzdiIpDQogIA0KICAjIEFkZCBTRCBpbmZvIHRvIGhsIGZpbGUNCiAgaGxfc2VsX2lidHM8LWhsX2lidHNbLG5hbWVzKGhsX2lidHMpJWluJWMoIlllYXIiLCJDb3VudHJ5IiwiUXVhcnRlciIsIlNoaXAiLCJHZWFyIiwiU3RObyIsIkhhdWxObyIsIlNleCIsIlRvdGFsTm8iLCJTdWJGYWN0b3IiLCJMbmd0Q29kZSIsIkxuZ3RDbGFzcyIsIkhMTm9BdExuZ3QiKV0NCiAgaGxfc2VsX2lidHM8LWhsX3NlbF9pYnRzW29yZGVyKGhsX3NlbF9pYnRzJFllYXIsaGxfc2VsX2lidHMkUXVhcnRlcixobF9zZWxfaWJ0cyRDb3VudHJ5LGhsX3NlbF9pYnRzJFNoaXAsaGxfc2VsX2lidHMkR2VhcixobF9zZWxfaWJ0cyRTdE5vLGhsX3NlbF9pYnRzJEhhdWxObyksXQ0KICANCiAgaGxfaGhfaWJ0czwtbWVyZ2UoaGhfc2VsX2lidHMsaGxfc2VsX2lidHMsYnk9YygiUXVhcnRlciIsIkNvdW50cnkiLCJTaGlwIiwiR2VhciIsIlN0Tm8iLCJIYXVsTm8iLCJZZWFyIiksYWxsPUYpDQogIA0KICAjIHdyaXRlLmNzdihobF9oaCxmaWxlPSJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvaGxfaGguY3N2IikNCiAgIz09PT0NCiAgDQogICM9PT0NCiAgIyBBZGQgU0QgYW5kIFN0YXRpb24gaW5mbyB0byBCSVRTIC0tLS0gIA0KICAjPT09DQogICMgTWFrZSBCSVRTIGhhdWwgZGF0YSBzcGF0aWFsIG9iamVjdA0KICBoaF9iaXRzX3NmIDwtIHN0X2FzX3NmKGhoX2JpdHMsIGNvb3JkcyA9IGMoIlNob290TG9uZyIsICJTaG9vdExhdCIpLCBjcnMgPSA0MzI2KQ0KICANCiAgIyBNYXRjaCBwcm9qZWN0aW9ucyBiZXR3ZWVuIElDRVMgYXJlYXMgYW5kIEhhdWwgZGF0YSANCiAgIyBTRHMgPC0gaWZlbHNlKHN0X2NycyhTRHMpID09IHN0X2NycyhoaF9iaXRzX3NmKSwgDQogICMgICAgICAgICAgICAgICBTRHMsDQogICMgICAgICAgICAgICAgICBzdF9tYWtlX3ZhbGlkKHN0X3RyYW5zZm9ybShTRHMsIGNycyA9IHN0X2NycyhoaF9iaXRzX3NmKSkpKQ0KICBTRHMgPC0gc3RfbWFrZV92YWxpZChzdF90cmFuc2Zvcm0oU0RzLCBjcnMgPSBzdF9jcnMoaGhfYml0c19zZikpKQ0KICANCiAgIyBKb2luIC8gbWVyZ2UgdGhlIElDRVMgc3BhdGlhbCBpbmZvcm1hdGlvbiB3aXRoIHRoZSBEQVRSQVMgaGF1bHMgYnkgZ2VvbWV0cmllcw0KICBoaF9iaXRzX3NmIDwtIHN0X2pvaW4oeCA9IGhoX2JpdHNfc2YsIHkgPSBTRHMsIGpvaW4gPSBzdF9uZWFyZXN0X2ZlYXR1cmUsIGxlZnQgPSBUKQ0KICANCiAgIyByZWR1Y2UgZGF0YSB0byBkYXRhZnJhbWUNCiAgaGhfYml0cyA8LSBzdF9kcm9wX2dlb21ldHJ5KGhoX2JpdHNfc2YpDQogIA0KICAjIyBTZWxlY3QgdGhlIHJvd3Mgd2l0aGluIHRoZSByZWxldmFudCBzdWJkaXZpc2lvbnMNCiAgaGhfYml0czEgPC0gaGhfYml0c1toaF9iaXRzJFN1YkRpdmlzaW8gJWluJSBhcy5jaGFyYWN0ZXIoYygyMTozMikpLCBdDQogIA0KICAjIEFkZCBzdGF0aW9uIGluZm9ybWF0aW9uIHRvIGNhIGZpbGUNCiAgY2Ffc2VsPC1jYVssbmFtZXMoY2EpJWluJWMoIlN1cnZleSIsIlF1YXJ0ZXIiLCJDb3VudHJ5IiwiU2hpcCIsIkdlYXIiLCJTdE5vIiwiSGF1bE5vIiwiWWVhciIsIkFyZWFDb2RlIiwiTG5ndENvZGUiLCJMbmd0Q2xhc3MiLCJTZXgiLCJNYXR1cml0eSIsIlBsdXNHciIsIkFnZSIsIkNBTm9BdExuZ3QiLCJJbmRXZ3QiKV0NCiAgaGhfc2VsPC1oaF9iaXRzMVssbmFtZXMoaGhfYml0czEpJWluJWMoIlN1cnZleSIsIlF1YXJ0ZXIiLCJDb3VudHJ5IiwiU2hpcCIsIkdlYXIiLCJTdE5vIiwiSGF1bE5vIiwiWWVhciIsIk1vbnRoIiwiRGF5IiwiU3RyYXR1bSIsIkhhdWxEdXIiLCJTaG9vdExhdCIsIlNob290TG9uZyIsIkhhdWxMYXQiLCJIYXVsTG9uZyIsIlN0YXRSZWMiLCJEZXB0aCIsIkhhdWxWYWwiLCJEYXRhVHlwZSIsIlN1YkRpdmlzaW8iKV0NCiAgDQogIGNhX3NlbDwtY2Ffc2VsW29yZGVyKGNhX3NlbCRZZWFyLGNhX3NlbCRRdWFydGVyLGNhX3NlbCRDb3VudHJ5LGNhX3NlbCRTaGlwLGNhX3NlbCRHZWFyLGNhX3NlbCRTdE5vLGNhX3NlbCRIYXVsTm8pLF0NCiAgaGhfc2VsPC1oaF9zZWxbb3JkZXIoaGhfc2VsJFllYXIsaGhfc2VsJFF1YXJ0ZXIsaGhfc2VsJENvdW50cnksaGhfc2VsJFNoaXAsaGhfc2VsJEdlYXIsaGhfc2VsJFN0Tm8saGhfc2VsJEhhdWxObyksXQ0KICANCiAgY2FfaGg8LW1lcmdlKGhoX3NlbCxjYV9zZWwsYnk9YygiU3VydmV5IiwiUXVhcnRlciIsIkNvdW50cnkiLCJTaGlwIiwiR2VhciIsIlN0Tm8iLCJIYXVsTm8iLCJZZWFyIiksYWxsPUYpDQogIA0KICAjIHdyaXRlLmNzdihjYV9oaCxmaWxlPSJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvY2FfaGguY3N2IikNCiAgDQogICMgQWRkIFNEIGluZm8gdG8gaGwgZmlsZQ0KICBobF9zZWw8LWhsWyxuYW1lcyhobCklaW4lYygiWWVhciIsIkNvdW50cnkiLCJRdWFydGVyIiwiU2hpcCIsIkdlYXIiLCJTdE5vIiwiSGF1bE5vIiwiU2V4IiwiVG90YWxObyIsIlN1YkZhY3RvciIsIkxuZ3RDb2RlIiwiTG5ndENsYXNzIiwiSExOb0F0TG5ndCIpXQ0KICBobF9zZWw8LWhsX3NlbFtvcmRlcihobF9zZWwkWWVhcixobF9zZWwkUXVhcnRlcixobF9zZWwkQ291bnRyeSxobF9zZWwkU2hpcCxobF9zZWwkR2VhcixobF9zZWwkU3RObyxobF9zZWwkSGF1bE5vKSxdDQogIA0KICBobF9oaDwtbWVyZ2UoaGhfc2VsLGhsX3NlbCxieT1jKCJRdWFydGVyIiwiQ291bnRyeSIsIlNoaXAiLCJHZWFyIiwiU3RObyIsIkhhdWxObyIsIlllYXIiKSxhbGw9RikNCiAgDQogICMgd3JpdGUuY3N2KGhsX2hoLGZpbGU9IkRhdGEvU3VydmV5cy9leGNoYW5nZS9obF9oaC5jc3YiKQ0KICAjPT09PQ0KICANCiAgIz09PQ0KICAjIEFESlVTVCBVTklUUyBBTkQgQ0xFQU4gREFUQSAtLS0tDQogICM9PT0NCiAgIyMgU3RhcnQgd2l0aCBOUy1JQlRTDQogICMgZ2V0IExuZ3RDbGFzcyBpbiB0aGUgc2FtZSB1bml0cy4gIi4iIG9yICIwIiBpbiBMbmd0Q29kZSBtZWFucyBpdCBpcyBpbiBtbSwgIjEiIG1lYW5zIGl0IGlzIGluIGNtDQogICMgTWFrZSBhbGwgaW4gY20NCiAgbW1fY2FfaWJ0czwtc3Vic2V0KGNhX2hoX2lidHMsTG5ndENvZGUlaW4lYygiLiIsIjAiKSkNCiAgY21fY2FfaWJ0czwtc3Vic2V0KGNhX2hoX2lidHMsTG5ndENvZGUlaW4lYygiMSIpKQ0KICANCiAgbW1fY2FfaWJ0cyRMbmd0Q2xhc3M8LW1tX2NhX2lidHMkTG5ndENsYXNzLzEwDQogIGNhX3RtcDFfaWJ0czwtcmJpbmQobW1fY2FfaWJ0cyxjbV9jYV9pYnRzKQ0KICANCiAgbW1faGxfaWJ0czwtc3Vic2V0KGhsX2hoX2lidHMsTG5ndENvZGUlaW4lYygiLiIsIjAiKSkNCiAgY21faGxfaWJ0czwtc3Vic2V0KGhsX2hoX2lidHMsTG5ndENvZGUlaW4lYygiMSIpKQ0KICANCiAgbW1faGxfaWJ0cyRMbmd0Q2xhc3M8LW1tX2hsX2lidHMkTG5ndENsYXNzLzEwDQogIGhsX3RtcDFfaWJ0czwtcmJpbmQobW1faGxfaWJ0cyxjbV9obF9pYnRzKSAgICAgICAgICAgICAgICAgICAgICAgICAjIGhhcyBsZXNzIHJvd3MgdGhhbiBobF9oaCBiZWNhdXNlIHNvbWUgTG5ndENvZGUgLTkNCiAgDQogICMgY2hlY2sgd2hldGhlciBITCBuZWVkcyBjbGVhbmluZw0KICAjIHVuaXF1ZShobF90bXAxX2lidHMkTG5ndENsYXNzKQ0KICBobF9oaF9maW5faWJ0czwtaGxfdG1wMV9pYnRzDQogIA0KICAjIHdyaXRlLmNzdihobF9oaF9maW5faWJ0cyxmaWxlPSJEYXRhL1N1cnZleXMvZXhjaGFuZ2UvaGxfaGhfZmluX2lidHMuY3N2Iixyb3cubmFtZXM9RikNCiAgDQogICMjIEJJVFMnIFR1cm4hDQogICMgZ2V0IExuZ3RDbGFzcyBpbiB0aGUgc2FtZSB1bml0cy4gIi4iIG9yICIwIiBpbiBMbmd0Q29kZSBtZWFucyBpdCBpcyBpbiBtbSwgIjEiIG1lYW5zIGl0IGlzIGluIGNtDQogICMgTWFrZSBhbGwgaW4gY20NCiAgbW1fY2E8LXN1YnNldChjYV9oaCxMbmd0Q29kZSVpbiVjKCIuIiwiMCIpKQ0KICBjbV9jYTwtc3Vic2V0KGNhX2hoLExuZ3RDb2RlJWluJWMoIjEiKSkNCiAgDQogIG1tX2NhJExuZ3RDbGFzczwtbW1fY2EkTG5ndENsYXNzLzEwDQogIGNhX3RtcDE8LXJiaW5kKG1tX2NhLGNtX2NhKQ0KICANCiAgbW1faGw8LXN1YnNldChobF9oaCxMbmd0Q29kZSVpbiVjKCIuIiwiMCIpKQ0KICBjbV9obDwtc3Vic2V0KGhsX2hoLExuZ3RDb2RlJWluJWMoIjEiKSkNCiAgDQogIG1tX2hsJExuZ3RDbGFzczwtbW1faGwkTG5ndENsYXNzLzEwDQogIGhsX3RtcDE8LXJiaW5kKG1tX2hsLGNtX2hsKSAgICAgICAgICAgICAgICAgICAgICAgICAjIGhhcyBsZXNzIHJvd3MgdGhhbiBobF9oaCBiZWNhdXNlIHNvbWUgTG5ndENvZGUgLTkNCiAgDQogICMgY2hlY2sgd2hldGhlciBITCBuZWVkcyBjbGVhbmluZw0KICAjIHVuaXF1ZShobF90bXAxJExuZ3RDbGFzcykNCiAgaGxfaGhfZmluPC1obF90bXAxDQogIA0KICAjIHdyaXRlLmNzdihobF9oaF9maW4sZmlsZT0iRGF0YS9TdXJ2ZXlzL2V4Y2hhbmdlL2hsX2hoX2Zpbi5jc3YiLHJvdy5uYW1lcz1GKQ0KICAjPT09PQ0KICANCiAgIz09PQ0KICAjIENhbGN1bGF0ZSBDUFVFIGZvciByZWNvcmRzIG5vdCBhbHJlYWR5IHJlcG9ydGVkIGFzIHN1Y2ggLS0tLQ0KICAjIyBUYWtlIGludG8gYWNjb3VudCBEYXRhVHlwZSAobXVsdGlwbHkgd2l0aCBzdWJGYWN0b3IpIGluIEhMOiANCiAgIz09PQ0KICAjIyBTdGFydCB3aXRoIE5TLUlCVFMuDQogICNDSEVDSyBXSElDSCBUWVBFUyBZT1UgSEFWRToNCiAgIyB1bmlxdWUoaGxfaGhfZmluX2lidHMkRGF0YVR5cGUpDQogIA0KICBobF9oaF9maW5faWJ0cyRITE5vQXRMbmd0XzE8LU5BDQogIA0KICBmb3IgKGkgaW4gYygxOm5yb3coaGxfaGhfZmluX2lidHMpKSl7DQogICAgaWYoaGxfaGhfZmluX2lidHMkRGF0YVR5cGVbaV09PWFzLmNoYXJhY3RlcigiQyIpKXsNCiAgICAgIGhsX2hoX2Zpbl9pYnRzJEhMTm9BdExuZ3RfMVtpXTwtaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndFtpXQ0KICAgIH0NCiAgICBpZihobF9oaF9maW5faWJ0cyREYXRhVHlwZVtpXT09YXMuY2hhcmFjdGVyKCJSIikpew0KICAgICAgaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndF8xW2ldPC0oaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndFtpXSpobF9oaF9maW5faWJ0cyRTdWJGYWN0b3JbaV0pKig2MC9obF9oaF9maW5faWJ0cyRIYXVsRHVyW2ldKQ0KICAgIH0NCiAgICBpZihobF9oaF9maW5faWJ0cyREYXRhVHlwZVtpXT09YXMuY2hhcmFjdGVyKCJTIikpew0KICAgICAgaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndF8xW2ldPC0oaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndFtpXSpobF9oaF9maW5faWJ0cyRTdWJGYWN0b3JbaV0pKig2MC9obF9oaF9maW5faWJ0cyRIYXVsRHVyW2ldKQ0KICAgIH0NCiAgICBpZihpcy5uYShobF9oaF9maW5faWJ0cyREYXRhVHlwZVtpXSkpew0KICAgICAgaGxfaGhfZmluX2lidHMkSExOb0F0TG5ndF8xW2ldPC1obF9oaF9maW5faWJ0cyRITE5vQXRMbmd0W2ldICANCiAgICB9DQogIH0NCiAgDQogICMjIEJJVFMnIFR1cm4hDQogICMgI0NIRUNLIFdISUNIIFRZUEVTIFlPVSBIQVZFOg0KICAjIHVuaXF1ZShobF9oaF9maW4kRGF0YVR5cGUpDQogIA0KICBobF9oaF9maW4kSExOb0F0TG5ndF8xPC1OQQ0KICANCiAgZm9yIChpIGluIGMoMTpucm93KGhsX2hoX2ZpbikpKXsNCiAgICBpZihobF9oaF9maW4kRGF0YVR5cGVbaV09PWFzLmNoYXJhY3RlcigiQyIpKXsgICAjIEMgPSBSZXBvcnRlZCBhcyBDUFVFDQogICAgICBobF9oaF9maW4kSExOb0F0TG5ndF8xW2ldPC1obF9oaF9maW4kSExOb0F0TG5ndFtpXQ0KICAgIH0NCiAgICBpZihobF9oaF9maW4kRGF0YVR5cGVbaV09PWFzLmNoYXJhY3RlcigiUiIpKXsgICAjIFIgPSBEYXRhIGJ5IEhhdWwgKGNvdWxkIGJlIGNwdWUgb3Igbm90IGRlcGVuZGluZyBvbiBzcGVjaWVzL3N1cnZleSAtIGlmIENQVUUgdGhlbiBTdWJGYWN0b3IgPT0gMSkNCiAgICAgIGhsX2hoX2ZpbiRITE5vQXRMbmd0XzFbaV08LShobF9oaF9maW4kSExOb0F0TG5ndFtpXSpobF9oaF9maW4kU3ViRmFjdG9yW2ldKSooNjAvaGxfaGhfZmluJEhhdWxEdXJbaV0pDQogICAgfQ0KICAgIGlmKGhsX2hoX2ZpbiREYXRhVHlwZVtpXT09YXMuY2hhcmFjdGVyKCJTIikpeyAgICMgUyA9IFN1YnNhbXBsZWQgaGF1bCwgbXVsdGlwbHkgYnkgU3ViRmFjdG9yIHdoaWNoIHNob3VsZCBiZSA+MSkNCiAgICAgIGhsX2hoX2ZpbiRITE5vQXRMbmd0XzFbaV08LShobF9oaF9maW4kSExOb0F0TG5ndFtpXSpobF9oaF9maW4kU3ViRmFjdG9yW2ldKSooNjAvaGxfaGhfZmluJEhhdWxEdXJbaV0pDQogICAgfQ0KICAgIGlmKGlzLm5hKGhsX2hoX2ZpbiREYXRhVHlwZVtpXSkpew0KICAgICAgaGxfaGhfZmluJEhMTm9BdExuZ3RfMVtpXTwtaGxfaGhfZmluJEhMTm9BdExuZ3RbaV0gIA0KICAgIH0NCiAgfQ0KICAjPT09PQ0KICANCiAgIz09PQ0KICAjIENsZWFuIGFuZCByZXNoYXBlIENBIGRhdGE6IA0KICAjPT09DQogICMjIFN0YXJ0IHdpdGggTlMtSUJUUy4NCiAgIyBDbGVhbiBDQSBkYXRhOiANCiAgbWlzc2luZ19jYV9pYnRzIDwtIGNhX3RtcDFfaWJ0c1t3aGljaChjYV90bXAxX2lidHMkTG5ndENsYXNzPT0tOXxjYV90bXAxX2lidHMkSW5kV2d0PT0tOXxjYV90bXAxX2lidHMkSW5kV2d0PT0wfGNhX3RtcDFfaWJ0cyRBZ2U9PS05NSksXQ0KICBtaXNzaW5nX3Jvd3NfY2FfaWJ0cyA8LSB3aGljaChjYV90bXAxX2lidHMkTG5ndENsYXNzPT0tOXxjYV90bXAxX2lidHMkSW5kV2d0PT0tOXxjYV90bXAxX2lidHMkSW5kV2d0PT0wfGNhX3RtcDFfaWJ0cyRBZ2U9PS05NSkNCiAgY2FfdG1wMl9pYnRzPC1jYV90bXAxX2lidHNbLShtaXNzaW5nX3Jvd3NfY2FfaWJ0cyksXSAgDQogIA0KICAjIENBIGRhdGE6IGFkZCByb3dzIHdoZXJlIENhTm9Mbmd0IGlzIGxhcmdlciB0aGFuIDEsIHNvIGVhY2ggcm93IHdpbGwgcmVwcmVzZW50IG9uZSBmaXNoDQogIGNhX3RtcDJfMV9pYnRzPC1zdWJzZXQoY2FfdG1wMl9pYnRzLENBTm9BdExuZ3Q9PTEpDQogIGNhX3RtcDJfMl9pYnRzPC1zdWJzZXQoY2FfdG1wMl9pYnRzLENBTm9BdExuZ3Q+MSkNCiAgDQogIG5fdGltZXNfaWJ0czwtYyhjYV90bXAyXzJfaWJ0cyRDQU5vQXRMbmd0KQ0KICBjYV90bXAyXzJfYWRqX2lidHM8LWNhX3RtcDJfMl9pYnRzW3JlcChzZXFfbGVuKG5yb3coY2FfdG1wMl8yX2lidHMpKSwgbl90aW1lc19pYnRzKSxdDQogIA0KICBjYV9oaF9maW5faWJ0czwtcmJpbmQoY2FfdG1wMl8xX2lidHMsY2FfdG1wMl8yX2Fkal9pYnRzKQ0KICANCiAgIyAjIENoZWNrIHRoZSBkYXRhDQogICMgcGxvdChjYV9oaF9maW5faWJ0cyRMbmd0Q2xhc3MsY2FfaGhfZmluX2lidHMkSW5kV2d0KQ0KICANCiAgIyMgQklUUycgVHVybiENCiAgbWlzc2luZ19jYTwtY2FfdG1wMVt3aGljaChjYV90bXAxJExuZ3RDbGFzcz09LTl8Y2FfdG1wMSRJbmRXZ3Q9PS05fGNhX3RtcDEkSW5kV2d0PT0wfGNhX3RtcDEkQWdlPT0tOTUpLF0NCiAgbWlzc2luZ19yb3dzX2NhPC13aGljaChjYV90bXAxJExuZ3RDbGFzcz09LTl8Y2FfdG1wMSRJbmRXZ3Q9PS05fGNhX3RtcDEkSW5kV2d0PT0wfGNhX3RtcDEkQWdlPT0tOTUpDQogIGNhX3RtcDI8LWNhX3RtcDFbLShtaXNzaW5nX3Jvd3NfY2EpLF0gIA0KICANCiAgIyBDQSBkYXRhOiBhZGQgcm93cyB3aGVyZSBDYU5vTG5ndCBpcyBsYXJnZXIgdGhhbiAxLCBzbyBlYWNoIHJvdyB3aWxsIHJlcHJlc2VudCBvbmUgZmlzaA0KICBjYV90bXAyXzE8LXN1YnNldChjYV90bXAyLENBTm9BdExuZ3Q9PTEpDQogIGNhX3RtcDJfMjwtc3Vic2V0KGNhX3RtcDIsQ0FOb0F0TG5ndD4xKQ0KICANCiAgbl90aW1lczwtYyhjYV90bXAyXzIkQ0FOb0F0TG5ndCkNCiAgY2FfdG1wMl8yX2FkajwtY2FfdG1wMl8yW3JlcChzZXFfbGVuKG5yb3coY2FfdG1wMl8yKSksIG5fdGltZXMpLF0NCiAgDQogIGNhX2hoX2ZpbjwtcmJpbmQoY2FfdG1wMl8xLGNhX3RtcDJfMl9hZGopDQogIA0KICAjICMgTnVtYmVyIG9mIGZpc2ggaW4gQ0EgcGVyIHllYXIsIHFydCwgU0QNCiAgIyBucl9maXNoX2NhPC1hZ2dyZWdhdGUoY2FfaGhfZmluJENBTm9BdExuZ3QsYnk9bGlzdChjYV9oaF9maW4kU0QsY2FfaGhfZmluJENvdW50cnksY2FfaGhfZmluJFF1YXJ0ZXIsY2FfaGhfZmluJFllYXIpLEZVTj0ibGVuZ3RoIikNCiAgDQogICMgI2NoZWNrIHRoZSBkYXRhDQogICAjIHBsb3QoY2FfaGhfZmluJExuZ3RDbGFzcyxjYV9oaF9maW4kSW5kV2d0KQ0KICAjPT09PQ0KICANCiAgIz09PQ0KICAjIE1lcmdlIE5TLUlCVFMgJiBCSVRTDQogICM9PT0NCiAgY2FfaGhfZmluX2JpdHNfaWJ0cyA8LSByYmluZChjYV9oaF9maW4sIGNhX2hoX2Zpbl9pYnRzKQ0KICBobF9oaF9maW5fYml0c19pYnRzIDwtIHJiaW5kKGhsX2hoX2ZpbiwgaGxfaGhfZmluX2lidHMpDQogIA0KICAjIE9wdGlvbmFsIHNhdmUgZm9yIGxhdGVyOiANCiAgc2F2ZVJEUyhjYV9oaF9maW5fYml0c19pYnRzLCBmaWxlID0gIkRhdGEvU3VydmV5cy9leGNoYW5nZS9QbGUuMjcuMjEtMzJfY2EtaGguUkRTIikNCiAgc2F2ZVJEUyhobF9oaF9maW5fYml0c19pYnRzLCBmaWxlID0gIkRhdGEvU3VydmV5cy9leGNoYW5nZS9QbGUuMjcuMjEtMzJfaGwtaGguUkRTIikNCiAgIz09PT0NCn0NCg0KIz09PQ0KIyBDbGVhbiB1cCBkYXRhIGVudmlyb25tZW50DQojPT09DQprIDwtIGFwcGVuZChrLCBjKCJjYV9oaF9maW5fYml0c19pYnRzIiwgImhsX2hoX2Zpbl9iaXRzX2lidHMiLCAiY2F0Y2hOdW0iLCAiY2F0Y2hjb2hvcnRzIikpDQpyIDwtIGxzKHBhdHRlcm4gPSAiY2F8aGx8aGgiKVshbHMocGF0dGVybiA9ICJjYXxobHxoaCIpICVpbiUga10NCg0Kcm0obGlzdCA9IHIpDQojPT09PT0NCmBgYA0KDQojIyMgTWF0dXJpdHkgT2dpdmVzIChNTykNClRoZSBtYXR1cml0eSBvZ2l2ZXMgdXRpbGlzZWQgaW4gdGhlIGFzc2Vzc21lbnQgYXJlIHRoZSBtZWFuIG1hdHVyaXR5IGF0IGFnZSBmcm9tIDIwMDIgdW50aWwgdGhlIHByZXNlbnQgZGF0YSB5ZWFyLiAgVmFsdWVzIGFyZSBtZWFuIHByb3BvcnRpb24gbWF0dXJlIGF0IGFnZXMgb25lIHRocm91Z2ggdGVuLiANCg0KVGhlIGRhdGEgdXNlZCB0byBkZXJpdmUgdGhlc2UgbWF0dXJpdHkgb2dpdmVzIGNvbWUgZnJvbSBxdWFydGVyIG9uZSBvZiB0aGUgTlMtSUJUUyBhbmQgQklUUyBzdXJ2ZXlzLCB3aGVyZSB0aGUgc3Vic2V0dGluZyBvZiByZWxldmFudCBhcmVhcyBhbmQgc3BlY2llcywgYXMgd2VsbCBhcyB0aGUgbWVyZ2luZyBvZiB0aGUgdHdvIGRhdGEgc2VyaWVzIGlzIGNhcnJpZWQgb3V0IGluIHRoZSBhYm92ZSBzZWN0aW9uLiAgVGhlc2UgZGF0YSBjb21lIGZyb20gdGhlIHJhdyBEQVRSQVMgRXhjaGFuZ2UgcHJvZHVjdHMsIG5vdCB0aGUgU01BTEsgcHJvZHVjdHMuICBUaGlzIGlzIGltcG9ydGFudCBiZWNhdXNlIHdlIGFyZSBzdWJzZXR0aW5nIGFuZCBjb21iaW5pbmcgZGF0YSBzb3VyY2VzLCBzbyB0aGUgcmFpc2luZyBwcm9jZWR1cmUgbmVlZHMgdG8gYmUgZG9uZSBpbmRlcGVuZGVudGx5LiANCg0KVGhpcyBzZWN0aW9uIGNvbnRhaW5zIGhpZGRlbiBjaHVua3Mgb2YgY29kZSB0aGF0IHByZXBhcmUgdGhlIGRhdGEsIGdlbmVyYXRlIHRoZSBjdXJyZW50IG9naXZlcyBmb3IgdGhlIGFzc2Vzc21lbnQgYW5kIHBsb3QgdGhlc2Ugb3V0IGluIGEgZmlndXJlIGZvciBwcmVzZW50YXRpb25zL3JlcG9ydGluZy4gDQpgYGB7ciBNT0NhbGNzfQ0KIz09PQ0KIyBGaXJzdCBwcmVwYXJlIG1hdHVyaXR5IGRhdGEgZm9yIGNhbGN1bGF0aW5nIE1PcyAtLS0tDQojPT09DQojIFNlbGVjdCBkYXRhIGZvciB1c2UgaW4gdGhpcyBzY3JpcHQgYnkgcmVtb3Zpbmcgcm93cyB3aXRob3V0IHJlbGV2YW50IG9ic2VydmF0aW9ucw0KY2E8LXN1YnNldChjYV9oaF9maW5fYml0c19pYnRzLCBRdWFydGVyPT0xICYgQWdlIT0tOSAmIEFnZSE9MCkNCmhsPC1zdWJzZXQoaGxfaGhfZmluX2JpdHNfaWJ0cywgUXVhcnRlcj09MSkNCg0KIyBSZS1jb2RlIHRoZSBzcGF3bmluZyBzdGF0dXMgc28gdGhhdCB0aGV5IGFyZSBhbGwgdW5pZm9ybSBhbmQgc2ltcGxpZmllZCBmcm9tIG1hdHVyaXR5IHN0YWdlIHRvIGJpbmFyeQ0KY2Ekc3Bhd25lcjwtTkENCmNhJG5vbnNwYXduZXI8LU5BDQoNCmNhJHNwYXduZXIgPC0gaWZlbHNlKGNhJE1hdHVyaXR5ICVpbiUgYygiNjEiLCAiSSIsICIxIiwgIkEiLCAiQiIsICJCYiIpLCAwLA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNhJE1hdHVyaXR5ICVpbiUgYygiSUkiLCAiSUlJIiwgIklWIiwgIklYIiwgIk0iLCAiNjIiLCAiNjMiLCAiNjQiLCAiNjUiLCAiMiIsICIzIiwgIjQiLCAiNSIsICJCYSIsICJDIiwgIkNhIiwgIkNiIiwgIkQiLCAiRGEiLCAiRGIiLCAiRSIpLCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQSIpKQ0KDQpjYSRub25zcGF3bmVyIDwtIGlmZWxzZShjYSRNYXR1cml0eSAlaW4lIGMoIjYxIiwgIkkiLCAiMSIsICJBIiwgIkIiLCAiQmIiKSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjYSRNYXR1cml0eSAlaW4lIGMoIklJIiwgIklJSSIsICJJViIsICJJWCIsICJNIiwgIjYyIiwgIjYzIiwgIjY0IiwgIjY1IiwgIjIiLCAiMyIsICI0IiwgIjUiLCAiQmEiLCAiQyIsICJDYSIsICJDYiIsICJEIiwgIkRhIiwgIkRiIiwgIkUiKSwgMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTkEiKSkNCmNhJHNwYXduZXIgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY2Ekc3Bhd25lcikpDQpjYSRub25zcGF3bmVyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNhJG5vbnNwYXduZXIpKQ0KDQojIFNvcnQgdGhlIGRhdGENCmNhPC1jYVtvcmRlcihjYSRZZWFyLGNhJFN1YkRpdmlzaW8sY2EkU2V4LGNhJEFnZSxjYSRMbmd0Q2xhc3MsIGNhJHNwYXduZXIsY2Ekbm9uc3Bhd25lciksIF0NCg0KY2F4IDwtIGNhW2lzLm5hKGNhJHNwYXduZXIpICYgaXMubmEoY2Ekbm9uc3Bhd25lciksIF0NCg0KIyBDYWxjdWxhdGUgbnVtYmVyIG9mIGZpc2ggKG1hdHVyZSBvciBpbW1hdHVyZSkgYnkgeWVhcitzZXgrYWdlK0xuZ3RDbGFzcw0KbWF0dXJpdHlfbG5ndCA8LSBhZ2dyZWdhdGUoY2JpbmQoc3Bhd25lciwgbm9uc3Bhd25lcikgfiBZZWFyK1NleCtBZ2UrTG5ndENsYXNzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGNhLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOPXN1bSkNCiM9PT09DQoNCiM9PT0NCiMgQ2FsY3VsYXRlIGxlbmd0aCBmcmVxdWVuY2llcyBmcm9tIGF0IHNlYSBvYnNlcnZhdGlvbnMgLS0tLQ0KIz09PQ0KIyBFc3RhYmxpc2ggcGFyYW1ldGVycyBmb3IgY2FsY3VsYXRpb25zDQpsZW5jbDwtYyg0OjYwKQ0KYWdlPC1jKDE6MTApDQp5ZWFyPC1jKDE5OTk6KERhdGFZZWFyKzEpKQ0KDQojIE1ha2UgdGFibGUgZm9yIGxlbmd0aCBmcmVxIGRhdGENCmxlbmd0aF9mcmVxX3RtcDwtYnkoaGwsbGlzdChobCRZZWFyLHJvdW5kKGhsJExuZ3RDbGFzcykpLGZ1bmN0aW9uICh4KXsNCiAgc3VtKHgkSExOb0F0TG5ndF8xKQ0KfSkNCmxlbmd0aF9mcmVxX3RhYjwtdChhcy50YWJsZShsZW5ndGhfZnJlcV90bXApKQ0KDQpMZnJlcV9zZWE8LWRhdGEuZnJhbWUoeWVhcj1yZXAoeWVhciwgZWFjaD1sZW5ndGgobGVuY2wpKSxMbmd0Q2xhc3M9cmVwKGxlbmNsLGxlbmd0aCh5ZWFyKSksSExOb0xuZ3Q9TkEpDQoNCiMgRmlsbCB0aGUgdGFibGUNCmZvciAoaSBpbiBjKDE6bnJvdyhMZnJlcV9zZWEpKSl7DQogIHllYXJfaTwtTGZyZXFfc2VhW2ksbmFtZXMoTGZyZXFfc2VhKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogIGxlbmNsX2k8LUxmcmVxX3NlYVtpLG5hbWVzKExmcmVxX3NlYSk9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogIA0KICBpZihsZW5jbF9pJWluJWMoYXMubnVtZXJpYyhkaW1uYW1lcyhsZW5ndGhfZnJlcV90YWIpW1sxXV0pKSl7DQogICAgDQogICAgZGF0YV9pPC1sZW5ndGhfZnJlcV90YWJbYXMubnVtZXJpYyhkaW1uYW1lcyhsZW5ndGhfZnJlcV90YWIpW1sxXV0pPT1sZW5jbF9pLGRpbW5hbWVzKGxlbmd0aF9mcmVxX3RhYilbWzJdXT09eWVhcl9pXQ0KICAgIExmcmVxX3NlYVtpLG5hbWVzKExmcmVxX3NlYSk9PWFzLmNoYXJhY3RlcigiSExOb0xuZ3QiKV08LWRhdGFfaQ0KICAgIA0KICB9ZWxzZXsNCiAgICBMZnJlcV9zZWFbaSxuYW1lcyhMZnJlcV9zZWEpPT1hcy5jaGFyYWN0ZXIoIkhMTm9Mbmd0IildPC0wICAgICAgIA0KICB9DQp9DQoNCiMgUmVwbGFjZSBOQSB3aXRoIDANCkxmcmVxX3NlYVt3aGljaChpcy5uYShMZnJlcV9zZWEkSExOb0xuZ3QpKSxuYW1lcyhMZnJlcV9zZWEpPT1hcy5jaGFyYWN0ZXIoIkhMTm9Mbmd0IildPC0wDQojPT09PQ0KDQojPT09DQojIENhbGN1bGF0ZSBwcm9wb3J0aW9ucyBmcm9tIHNhbXBsZWQgZGF0YSAob2JzZXJ2YXRpb25zKSAtLS0tDQojPT09DQojIE1ha2UgYSB0YWJsZSBmb3IgbnVtYmVyIG9mIGZpc2ggc2FtcGxlZCwgZm9yIHNwYXduZXIgYW5kIG5vbi1zcGF3bmVyDQpucl9maXNoX3NhbXBfc3BfRjwtZGF0YS5mcmFtZSh5ZWFyPXJlcCh5ZWFyLGVhY2g9bGVuZ3RoKGxlbmNsKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5jbD1yZXAobGVuY2wsdGltZXM9bGVuZ3RoKHllYXIpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGExPU5BLGEyPU5BLGEzPU5BLGE0PU5BLGE1PU5BLGE2PU5BLGE3PU5BLGE4PU5BLGE5PU5BLGExMD1OQSkNCm5yX2Zpc2hfc2FtcF9ub25zcF9GPC1ucl9maXNoX3NhbXBfc3BfRg0KbnJfZmlzaF9zYW1wX3NwX008LW5yX2Zpc2hfc2FtcF9zcF9GDQpucl9maXNoX3NhbXBfbm9uc3BfTTwtbnJfZmlzaF9zYW1wX3NwX0YNCg0KIyBGaWxsIHRoZSB0YWJsZSB3aXRoIGhvdyBtYW55IGZpc2ggaGF2ZSBiZWVuIHNhbXBsZWQgKG1hdHVyZSwgaW1tYXR1cmUpDQojIyBGZW1hbGUNCmZvciAoaSBpbiAxOm5yb3cobnJfZmlzaF9zYW1wX3NwX0YpKXsNCiAgZm9yIChqIGluIDM6bmNvbChucl9maXNoX3NhbXBfc3BfRikpew0KICAgIGxlbmNsX2k8LW5yX2Zpc2hfc2FtcF9zcF9GW2ksbmFtZXMobnJfZmlzaF9zYW1wX3NwX0YpPT1hcy5jaGFyYWN0ZXIoImxlbmNsIildDQogICAgYWdlX2k8LSBqLTINCiAgICB5ZWFyX2k8LW5yX2Zpc2hfc2FtcF9zcF9GW2ksbmFtZXMobnJfZmlzaF9zYW1wX3NwX0YpPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICANCiAgICBpZihsZW5jbF9pICVpbiUgbWF0dXJpdHlfbG5ndFt3aGljaChtYXR1cml0eV9sbmd0JFllYXIgPT0geWVhcl9pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBtYXR1cml0eV9sbmd0JFNleCA9PSBhcy5jaGFyYWN0ZXIoIkYiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgbWF0dXJpdHlfbG5ndCRBZ2UgPT0gYWdlX2kpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKG1hdHVyaXR5X2xuZ3QpPT1hcy5jaGFyYWN0ZXIoIkxuZ3RDbGFzcyIpXSl7DQogICAgICANCiAgICAgIHNob3dfZGF0YTwtbWF0dXJpdHlfbG5ndFt3aGljaChtYXR1cml0eV9sbmd0JFllYXI9PXllYXJfaQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZtYXR1cml0eV9sbmd0JExuZ3RDbGFzcz09bGVuY2xfaQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZtYXR1cml0eV9sbmd0JFNleD09YXMuY2hhcmFjdGVyKCJGIikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmbWF0dXJpdHlfbG5ndCRBZ2U9PWFnZV9pKSxdDQogICAgICANCiAgICAgIG5yX2Zpc2hfc2FtcF9zcF9GW2ksal08LXN1bShzaG93X2RhdGEkc3Bhd25lcikNCiAgICAgIG5yX2Zpc2hfc2FtcF9ub25zcF9GW2ksal08LXN1bShzaG93X2RhdGEkbm9uc3Bhd25lcikNCiAgICAgIA0KICAgIH0gZWxzZXsNCiAgICAgIA0KICAgICAgbnJfZmlzaF9zYW1wX3NwX0ZbaSxqXTwtMA0KICAgICAgbnJfZmlzaF9zYW1wX25vbnNwX0ZbaSxqXTwtMA0KICAgIH0NCiAgfQ0KfQ0KDQojIyBNYWxlDQpmb3IgKGkgaW4gMTpucm93KG5yX2Zpc2hfc2FtcF9zcF9NKSl7DQogIGZvciAoaiBpbiAzOm5jb2wobnJfZmlzaF9zYW1wX3NwX00pKXsNCiAgICANCiAgICBsZW5jbF9pPC1ucl9maXNoX3NhbXBfc3BfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9zcF9NKT09YXMuY2hhcmFjdGVyKCJsZW5jbCIpXQ0KICAgIGFnZV9pPC0gai0yDQogICAgeWVhcl9pPC1ucl9maXNoX3NhbXBfc3BfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9zcF9NKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgDQogICAgaWYobGVuY2xfaSVpbiVtYXR1cml0eV9sbmd0W3doaWNoKG1hdHVyaXR5X2xuZ3QkWWVhcj09eWVhcl9pJm1hdHVyaXR5X2xuZ3QkU2V4PT1hcy5jaGFyYWN0ZXIoIk0iKSZtYXR1cml0eV9sbmd0JEFnZT09YWdlX2kpLG5hbWVzKG1hdHVyaXR5X2xuZ3QpPT1hcy5jaGFyYWN0ZXIoIkxuZ3RDbGFzcyIpXSl7DQogICAgICANCiAgICAgIHNob3dfZGF0YTwtbWF0dXJpdHlfbG5ndFt3aGljaChtYXR1cml0eV9sbmd0JFllYXI9PXllYXJfaSZtYXR1cml0eV9sbmd0JExuZ3RDbGFzcz09bGVuY2xfaSZtYXR1cml0eV9sbmd0JFNleD09YXMuY2hhcmFjdGVyKCJNIikmbWF0dXJpdHlfbG5ndCRBZ2U9PWFnZV9pKSxdDQogICAgICANCiAgICAgIG5yX2Zpc2hfc2FtcF9zcF9NW2ksal08LXN1bShzaG93X2RhdGEkc3Bhd25lcikNCiAgICAgIG5yX2Zpc2hfc2FtcF9ub25zcF9NW2ksal08LXN1bShzaG93X2RhdGEkbm9uc3Bhd25lcikNCiAgICAgIA0KICAgIH0gZWxzZXsNCiAgICAgIA0KICAgICAgbnJfZmlzaF9zYW1wX3NwX01baSxqXTwtMA0KICAgICAgbnJfZmlzaF9zYW1wX25vbnNwX01baSxqXTwtMA0KICAgIH0NCiAgfQ0KfQ0KDQojIFRvdGFsIG51bWJlciBvZiBmaXNoIHNhbXBsZWQgKGltbWF0dXJlK21hdHVyZSkgIGJ5IGxlbmd0aA0KbnJfZmlzaF9zYW1wbGVkX3RvdDwtbnJfZmlzaF9zYW1wX3NwX0ZbLDE6NV0NCm5yX2Zpc2hfc2FtcGxlZF90b3RbLDM6bmNvbChucl9maXNoX3NhbXBsZWRfdG90KV08LU5BDQpuYW1lcyhucl9maXNoX3NhbXBsZWRfdG90KVszOm5jb2wobnJfZmlzaF9zYW1wbGVkX3RvdCldPC1jKCJGX3NwX25vbnNwIiwiTV9zcF9ub25zcCIsIkZfTV90b3QiKQ0KDQpmb3IgKGkgaW4gMTpucm93KG5yX2Zpc2hfc2FtcGxlZF90b3QpKXsNCiAgZl9zcDwtc3VtKG5yX2Zpc2hfc2FtcF9zcF9GW2ksMzogbmNvbChucl9maXNoX3NhbXBfc3BfRildKQ0KICBmX25vbnNwPC1zdW0obnJfZmlzaF9zYW1wX25vbnNwX0ZbaSwzOiBuY29sKG5yX2Zpc2hfc2FtcF9ub25zcF9GKV0pDQogIA0KICBtX3NwPC1zdW0obnJfZmlzaF9zYW1wX3NwX01baSwzOiBuY29sKG5yX2Zpc2hfc2FtcF9zcF9NKV0pDQogIG1fbm9uc3A8LXN1bShucl9maXNoX3NhbXBfbm9uc3BfTVtpLDM6IG5jb2wobnJfZmlzaF9zYW1wX25vbnNwX00pXSkNCiAgDQogIG5yX2Zpc2hfc2FtcGxlZF90b3RbaSxuYW1lcyggbnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiRl9zcF9ub25zcCIpXSA8LWZfc3ArIGZfbm9uc3ANCiAgbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKCBucl9maXNoX3NhbXBsZWRfdG90KT09YXMuY2hhcmFjdGVyKCJNX3NwX25vbnNwIildIDwtIG1fc3ArIG1fbm9uc3ANCiAgbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKCBucl9maXNoX3NhbXBsZWRfdG90KT09YXMuY2hhcmFjdGVyKCJGX01fdG90IildIDwtIGZfc3ArIGZfbm9uc3ArIG1fc3ArIG1fbm9uc3ANCn0NCg0KIyBUb3RhbCBudW1iZXIgb2YgZmlzaCBzYW1wbGVkLCBieSBhZ2UNCnN1bV9ucl9zYW1wbF9hZ2Vfc3BfRjwtIGRhdGEuZnJhbWUoeWVhcj15ZWFyLGExPU5BLGEyPU5BLGEzPU5BLGE0PU5BLGE1PU5BLGE2PU5BLGE3PU5BLGE4PU5BLGE5PU5BLGExMD1OQSkNCnN1bV9ucl9zYW1wbF9hZ2Vfbm9uc3BfRjwtc3VtX25yX3NhbXBsX2FnZV9zcF9GDQpzdW1fbnJfc2FtcGxfYWdlX3NwX008LXN1bV9ucl9zYW1wbF9hZ2Vfc3BfRg0Kc3VtX25yX3NhbXBsX2FnZV9ub25zcF9NPC1zdW1fbnJfc2FtcGxfYWdlX3NwX0YNCg0KIyMgRmVtYWxlDQpmb3IgKGkgaW4gMTpucm93KHN1bV9ucl9zYW1wbF9hZ2Vfc3BfRikpew0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9ucl9zYW1wbF9hZ2Vfc3BfRikpew0KICAgIA0KICAgIGlfeWVhcjwtc3VtX25yX3NhbXBsX2FnZV9zcF9GW2ksbmFtZXMoc3VtX25yX3NhbXBsX2FnZV9zcF9GKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc3VtX25yX3NhbXBsX2FnZV9zcF9GW2ksal08LXN1bShucl9maXNoX3NhbXBfc3BfRlt3aGljaChucl9maXNoX3NhbXBfc3BfRiR5ZWFyPT1pX3llYXIpLG5hbWVzKG5yX2Zpc2hfc2FtcF9zcF9GKT09bmFtZXMoc3VtX25yX3NhbXBsX2FnZV9zcF9GKVtqXV0pDQogIH0NCn0NCiMNCmZvciAoaSBpbiAxOm5yb3coc3VtX25yX3NhbXBsX2FnZV9ub25zcF9GKSl7DQogIGZvciAoaiBpbiAyOm5jb2woc3VtX25yX3NhbXBsX2FnZV9ub25zcF9GKSl7DQogICAgDQogICAgaV95ZWFyPC1zdW1fbnJfc2FtcGxfYWdlX25vbnNwX0ZbaSxuYW1lcyhzdW1fbnJfc2FtcGxfYWdlX25vbnNwX0YpPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fbnJfc2FtcGxfYWdlX25vbnNwX0ZbaSxqXTwtc3VtKG5yX2Zpc2hfc2FtcF9ub25zcF9GW3doaWNoKG5yX2Zpc2hfc2FtcF9ub25zcF9GJHllYXI9PWlfeWVhciksbmFtZXMobnJfZmlzaF9zYW1wX25vbnNwX0YpPT1uYW1lcyhzdW1fbnJfc2FtcGxfYWdlX25vbnNwX0YpW2pdXSkNCiAgfQ0KfQ0KDQojIyBNYWxlDQpmb3IgKGkgaW4gMTpucm93KHN1bV9ucl9zYW1wbF9hZ2Vfc3BfTSkpew0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9ucl9zYW1wbF9hZ2Vfc3BfTSkpew0KICAgIA0KICAgIGlfeWVhcjwtc3VtX25yX3NhbXBsX2FnZV9zcF9NW2ksbmFtZXMoc3VtX25yX3NhbXBsX2FnZV9zcF9NKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc3VtX25yX3NhbXBsX2FnZV9zcF9NW2ksal08LXN1bShucl9maXNoX3NhbXBfc3BfTVt3aGljaChucl9maXNoX3NhbXBfc3BfTSR5ZWFyPT1pX3llYXIpLG5hbWVzKG5yX2Zpc2hfc2FtcF9zcF9NKT09bmFtZXMoc3VtX25yX3NhbXBsX2FnZV9zcF9NKVtqXV0pDQogIH0NCn0NCiMNCmZvciAoaSBpbiAxOm5yb3coc3VtX25yX3NhbXBsX2FnZV9ub25zcF9NKSl7DQogIGZvciAoaiBpbiAyOm5jb2woc3VtX25yX3NhbXBsX2FnZV9ub25zcF9NKSl7DQogICAgDQogICAgaV95ZWFyPC1zdW1fbnJfc2FtcGxfYWdlX25vbnNwX01baSxuYW1lcyhzdW1fbnJfc2FtcGxfYWdlX25vbnNwX00pPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fbnJfc2FtcGxfYWdlX25vbnNwX01baSxqXTwtc3VtKG5yX2Zpc2hfc2FtcF9ub25zcF9NW3doaWNoKG5yX2Zpc2hfc2FtcF9ub25zcF9NJHllYXI9PWlfeWVhciksbmFtZXMobnJfZmlzaF9zYW1wX25vbnNwX00pPT1uYW1lcyhzdW1fbnJfc2FtcGxfYWdlX25vbnNwX00pW2pdXSkNCiAgfQ0KfQ0KIz09PT0NCg0KIz09PQ0KIyBSYWlzZSBwcm9wb3J0aW9ucyB0byB1bnNhbXBsZWQgc3RyYXRhIC0tLS0NCiM9PT0NCiMgTWFrZSB0YWJsZXMgDQpucl9maXNoX3NlYV9zcF9GPC1ucl9maXNoX3NhbXBfc3BfRg0KbnJfZmlzaF9zZWFfc3BfRlssMzpuY29sKG5yX2Zpc2hfc2VhX3NwX0YpXTwtTkENCg0KbnJfZmlzaF9zZWFfbm9uc3BfRjwtbnJfZmlzaF9zZWFfc3BfRg0KbnJfZmlzaF9zZWFfc3BfTTwtbnJfZmlzaF9zZWFfc3BfRg0KbnJfZmlzaF9zZWFfbm9uc3BfTTwtbnJfZmlzaF9zZWFfc3BfRg0KDQojIE51bWJlcnMgYXQgc2VhIGJ5IG1hdHVyaXR5IGNsYXNzIGJ5IGxlbmd0aA0KIyMgRmVtYWxlIHNwYXduZXIgDQpmb3IgKGkgaW4gMTpucm93KG5yX2Zpc2hfc2VhX3NwX0YpKXsNCiAgZm9yIChqIGluIDM6bmNvbChucl9maXNoX3NlYV9zcF9GKSl7DQogICAgDQogICAgaWYobnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIkZfc3Bfbm9uc3AiKV0+MCl7IA0KICAgICAgbWF0X3RvdF9yYXRpbzwtbnJfZmlzaF9zYW1wX3NwX0ZbaSxqXS9ucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiRl9zcF9ub25zcCIpXQ0KICAgICAgZmVtYWxlX3RvdF9yYXRpbzwtbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIkZfc3Bfbm9uc3AiKV0vbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIkZfTV90b3QiKV0NCiAgICAgIA0KICAgICAgdG90X2xlbjwtTGZyZXFfc2VhW2ksbmFtZXMoTGZyZXFfc2VhKT09YXMuY2hhcmFjdGVyKCJITE5vTG5ndCIpXQ0KICAgICAgbnJfZmlzaF9zZWFfc3BfRltpLGpdPC1tYXRfdG90X3JhdGlvKiBmZW1hbGVfdG90X3JhdGlvKnRvdF9sZW4NCiAgICB9ZWxzZXsNCiAgICAgIG5yX2Zpc2hfc2VhX3NwX0ZbaSxqXTwtMA0KICAgIH0NCiAgfQ0KfSANCg0KIyMgRmVtYWxlIG5vbnNwYXduZXINCmZvciAoaSBpbiAxOm5yb3cobnJfZmlzaF9zZWFfbm9uc3BfRikpew0KICBmb3IgKGogaW4gMzpuY29sKG5yX2Zpc2hfc2VhX25vbnNwX0YpKXsNCiAgICANCiAgICBpZihucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiRl9zcF9ub25zcCIpXT4wKXsgDQogICAgICBtYXRfdG90X3JhdGlvPC1ucl9maXNoX3NhbXBfbm9uc3BfRltpLGpdL25yX2Zpc2hfc2FtcGxlZF90b3RbaSxuYW1lcyhucl9maXNoX3NhbXBsZWRfdG90KT09YXMuY2hhcmFjdGVyKCJGX3NwX25vbnNwIildDQogICAgICBmZW1hbGVfdG90X3JhdGlvPC1ucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiRl9zcF9ub25zcCIpXS9ucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiRl9NX3RvdCIpXQ0KICAgICAgDQogICAgICB0b3RfbGVuPC1MZnJlcV9zZWFbaSxuYW1lcyhMZnJlcV9zZWEpPT1hcy5jaGFyYWN0ZXIoIkhMTm9Mbmd0IildDQogICAgICBucl9maXNoX3NlYV9ub25zcF9GW2ksal08LW1hdF90b3RfcmF0aW8qIGZlbWFsZV90b3RfcmF0aW8qdG90X2xlbg0KICAgIH1lbHNlew0KICAgICAgbnJfZmlzaF9zZWFfbm9uc3BfRltpLGpdPC0wDQogICAgfQ0KICB9DQp9IA0KDQojIyBNYWxlIHNwYXduZXINCmZvciAoaSBpbiAxOm5yb3cobnJfZmlzaF9zZWFfc3BfTSkpew0KICBmb3IgKGogaW4gMzpuY29sKG5yX2Zpc2hfc2VhX3NwX00pKXsNCiAgICANCiAgICBpZihucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiTV9zcF9ub25zcCIpXT4wKXsgDQogICAgICBtYXRfdG90X3JhdGlvPC1ucl9maXNoX3NhbXBfc3BfTVtpLGpdL25yX2Zpc2hfc2FtcGxlZF90b3RbaSxuYW1lcyhucl9maXNoX3NhbXBsZWRfdG90KT09YXMuY2hhcmFjdGVyKCJNX3NwX25vbnNwIildDQogICAgICBtYWxlX3RvdF9yYXRpbzwtbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIk1fc3Bfbm9uc3AiKV0vbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIkZfTV90b3QiKV0NCiAgICAgIA0KICAgICAgdG90X2xlbjwtTGZyZXFfc2VhW2ksbmFtZXMoTGZyZXFfc2VhKT09YXMuY2hhcmFjdGVyKCJITE5vTG5ndCIpXQ0KICAgICAgbnJfZmlzaF9zZWFfc3BfTVtpLGpdPC1tYXRfdG90X3JhdGlvKiBtYWxlX3RvdF9yYXRpbyp0b3RfbGVuDQogICAgfWVsc2V7DQogICAgICBucl9maXNoX3NlYV9zcF9NW2ksal08LTANCiAgICB9DQogIH0NCn0gDQoNCiMjIE1hbGUgbm9uLXNwYXduZXINCmZvciAoaSBpbiAxOm5yb3cobnJfZmlzaF9zZWFfbm9uc3BfTSkpew0KICBmb3IgKGogaW4gMzpuY29sKG5yX2Zpc2hfc2VhX25vbnNwX00pKXsNCiAgICANCiAgICBpZihucl9maXNoX3NhbXBsZWRfdG90W2ksbmFtZXMobnJfZmlzaF9zYW1wbGVkX3RvdCk9PWFzLmNoYXJhY3RlcigiTV9zcF9ub25zcCIpXT4wKXsgDQogICAgICBtYXRfdG90X3JhdGlvPC1ucl9maXNoX3NhbXBfbm9uc3BfTVtpLGpdL25yX2Zpc2hfc2FtcGxlZF90b3RbaSxuYW1lcyhucl9maXNoX3NhbXBsZWRfdG90KT09YXMuY2hhcmFjdGVyKCJNX3NwX25vbnNwIildDQogICAgICBtYWxlX3RvdF9yYXRpbzwtbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIk1fc3Bfbm9uc3AiKV0vbnJfZmlzaF9zYW1wbGVkX3RvdFtpLG5hbWVzKG5yX2Zpc2hfc2FtcGxlZF90b3QpPT1hcy5jaGFyYWN0ZXIoIkZfTV90b3QiKV0NCiAgICAgIA0KICAgICAgdG90X2xlbjwtTGZyZXFfc2VhW2ksbmFtZXMoTGZyZXFfc2VhKT09YXMuY2hhcmFjdGVyKCJITE5vTG5ndCIpXQ0KICAgICAgbnJfZmlzaF9zZWFfbm9uc3BfTVtpLGpdPC1tYXRfdG90X3JhdGlvKiBtYWxlX3RvdF9yYXRpbyp0b3RfbGVuDQogICAgfWVsc2V7DQogICAgICBucl9maXNoX3NlYV9ub25zcF9NW2ksal08LTANCiAgICB9DQogIH0NCn0gDQoNCiMgU3VtIG9mIG51bWJlcnMgYXQgc2VhLCBieSBtYXR1cml0eSBjbGFzcywgYnkgYWdlcyAoc3VtIG92ZXIgbGVuZ3RoLWdyb3VwcykgLSBnZW5lcmF0ZSB0YWJsZXMNCnN1bV9ucl9zZWFfYWdlX3NwX0Y8LXN1bV9ucl9zYW1wbF9hZ2Vfc3BfRg0Kc3VtX25yX3NlYV9hZ2Vfc3BfRlssLTFdPC1OQSANCg0Kc3VtX25yX3NlYV9hZ2Vfbm9uc3BfRjwtIHN1bV9ucl9zZWFfYWdlX3NwX0YNCnN1bV9ucl9zZWFfYWdlX3NwX008LXN1bV9ucl9zZWFfYWdlX3NwX0YNCnN1bV9ucl9zZWFfYWdlX25vbnNwX008LXN1bV9ucl9zZWFfYWdlX3NwX0YNCg0KIyMgRmVtYWxlIHNwYXduZXINCmZvciAoaSBpbiAxOm5yb3coc3VtX25yX3NlYV9hZ2Vfc3BfRikpew0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9ucl9zZWFfYWdlX3NwX0YpKXsNCiAgICANCiAgICBpX3llYXI8LXN1bV9ucl9zZWFfYWdlX3NwX0ZbaSxuYW1lcyhzdW1fbnJfc2VhX2FnZV9zcF9GKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc3VtX25yX3NlYV9hZ2Vfc3BfRltpLGpdPC1zdW0obnJfZmlzaF9zZWFfc3BfRlt3aGljaChucl9maXNoX3NlYV9zcF9GJHllYXI9PWlfeWVhciksbmFtZXMobnJfZmlzaF9zZWFfc3BfRik9PW5hbWVzKHN1bV9ucl9zZWFfYWdlX3NwX0YpW2pdXSkNCiAgfQ0KfQ0KDQojIyBGZW1hbGUgbm9uLXNwYXduZXINCmZvciAoaSBpbiAxOm5yb3coc3VtX25yX3NlYV9hZ2Vfbm9uc3BfRikpew0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9ucl9zZWFfYWdlX25vbnNwX0YpKXsNCiAgICANCiAgICBpX3llYXI8LXN1bV9ucl9zZWFfYWdlX25vbnNwX0ZbaSxuYW1lcyhzdW1fbnJfc2VhX2FnZV9ub25zcF9GKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc3VtX25yX3NlYV9hZ2Vfbm9uc3BfRltpLGpdPC1zdW0obnJfZmlzaF9zZWFfbm9uc3BfRlt3aGljaChucl9maXNoX3NlYV9ub25zcF9GJHllYXI9PWlfeWVhciksbmFtZXMobnJfZmlzaF9zZWFfbm9uc3BfRik9PW5hbWVzKHN1bV9ucl9zZWFfYWdlX25vbnNwX0YpW2pdXSkNCiAgfQ0KfQ0KDQojIyBNYWxlIHNwYXduZXINCmZvciAoaSBpbiAxOm5yb3coc3VtX25yX3NlYV9hZ2Vfc3BfTSkpew0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9ucl9zZWFfYWdlX3NwX00pKXsNCiAgICANCiAgICBpX3llYXI8LXN1bV9ucl9zZWFfYWdlX3NwX01baSxuYW1lcyhzdW1fbnJfc2VhX2FnZV9zcF9NKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc3VtX25yX3NlYV9hZ2Vfc3BfTVtpLGpdPC1zdW0obnJfZmlzaF9zZWFfc3BfTVt3aGljaChucl9maXNoX3NlYV9zcF9NJHllYXI9PWlfeWVhciksbmFtZXMobnJfZmlzaF9zZWFfc3BfTSk9PW5hbWVzKHN1bV9ucl9zZWFfYWdlX3NwX00pW2pdXSkNCiAgfQ0KfQ0KDQojIyBNYWxlIG5vbi1zcGF3bmVyDQpmb3IgKGkgaW4gMTpucm93KHN1bV9ucl9zZWFfYWdlX25vbnNwX00pKXsNCiAgZm9yIChqIGluIDI6bmNvbChzdW1fbnJfc2VhX2FnZV9ub25zcF9NKSl7DQogICAgDQogICAgaV95ZWFyPC1zdW1fbnJfc2VhX2FnZV9ub25zcF9NW2ksbmFtZXMoc3VtX25yX3NlYV9hZ2Vfbm9uc3BfTSk9PWFzLmNoYXJhY3RlcigieWVhciIpXQ0KICAgIHN1bV9ucl9zZWFfYWdlX25vbnNwX01baSxqXTwtc3VtKG5yX2Zpc2hfc2VhX25vbnNwX01bd2hpY2gobnJfZmlzaF9zZWFfbm9uc3BfTSR5ZWFyPT1pX3llYXIpLG5hbWVzKG5yX2Zpc2hfc2VhX25vbnNwX00pPT1uYW1lcyhzdW1fbnJfc2VhX2FnZV9ub25zcF9NKVtqXV0pDQogIH0NCn0NCiM9PT09DQoNCiM9PT0NCiMgQ2FsY3VsYXRlIHRoZSBzZXggcmF0aW8gLS0tLQ0KIz09PQ0Kc2V4X3JhdGlvX2ZlbWFsZTwtc3VtX25yX3NlYV9hZ2Vfc3BfRg0Kc2V4X3JhdGlvX2ZlbWFsZVssLTFdPC1OQQ0KDQpmb3IgKGogaW4gMjpuY29sKHNleF9yYXRpb19mZW1hbGUpKXsNCiAgc2V4X3JhdGlvX2ZlbWFsZVssal08LShzdW1fbnJfc2VhX2FnZV9ub25zcF9GWyxqXStzdW1fbnJfc2VhX2FnZV9zcF9GWyxqXSkvKHN1bV9ucl9zZWFfYWdlX25vbnNwX0ZbLGpdK3N1bV9ucl9zZWFfYWdlX3NwX0ZbLGpdK3N1bV9ucl9zZWFfYWdlX25vbnNwX01bLGpdK3N1bV9ucl9zZWFfYWdlX3NwX01bLGpdKQ0KfQ0KIz09PT0NCg0KIz09PQ0KIyBDYWxjdWxhdGUgTWF0dXJpdHkgT2dpdmVzIC0tLS0NCiM9PT0NCiMgR2VuZXJhdGUgdGFibGVzIGZvciBmZW1hbGUsIG1hbGUgYW5kIGNvbWJpbmVkIG9naXZlcw0KbWF0X29naXZlX0Y8LXN1bV9ucl9zYW1wbF9hZ2Vfc3BfRg0KbWF0X29naXZlX0ZbLC0xXTwtTkENCm1hdF9vZ2l2ZV9NPC0gbWF0X29naXZlX0YNCm1hdF9vZ2l2ZV9jb21ic2V4PC0gbWF0X29naXZlX0YNCg0KIyBGZW1hbGUgbWF0dXJlDQpmb3IgKGkgaW4gMTpucm93IChtYXRfb2dpdmVfRikpew0KICBmb3IgKGogaW4gMjpuY29sKG1hdF9vZ2l2ZV9GKSl7DQogICAgbWF0X29naXZlX0ZbaSxqXTwtIHN1bV9ucl9zZWFfYWdlX3NwX0ZbaSxqXS8oc3VtX25yX3NlYV9hZ2Vfc3BfRltpLGpdK3N1bV9ucl9zZWFfYWdlX25vbnNwX0ZbaSxqXSkgDQogIH0NCn0gIA0KIyBNYWxlIG1hdHVyZQ0KZm9yIChpIGluIDE6bnJvdyAobWF0X29naXZlX00pKXsNCiAgZm9yIChqIGluIDI6bmNvbChtYXRfb2dpdmVfTSkpew0KICAgIG1hdF9vZ2l2ZV9NW2ksal08LSBzdW1fbnJfc2VhX2FnZV9zcF9NW2ksal0vKHN1bV9ucl9zZWFfYWdlX3NwX01baSxqXStzdW1fbnJfc2VhX2FnZV9ub25zcF9NW2ksal0pIA0KICB9DQp9ICANCg0KIyBDb21ic2V4IG1hdHVyZSAgICAgICAgICAgICAgICAgIA0KZm9yIChpIGluIDE6bnJvdyAobWF0X29naXZlX2NvbWJzZXgpKXsNCiAgZm9yIChqIGluIDI6bmNvbChtYXRfb2dpdmVfY29tYnNleCkpew0KICAgIG1hdF9vZ2l2ZV9jb21ic2V4W2ksal08LShtYXRfb2dpdmVfRltpLGpdKnNleF9yYXRpb19mZW1hbGVbaSxqXSkrKG1hdF9vZ2l2ZV9NW2ksal0qKDEtc2V4X3JhdGlvX2ZlbWFsZVtpLGpdKSkgDQogIH0gIA0KfQ0KIz09PT0NCg0KIz09PQ0KIyBDb21iaW5lZCBTZXhlcyByZXNoYXBlIGFuZCBjYWxjdWxhdGUgbWVhbnMgKy8tIDk1JUNJIGZvciBwbG90dGluZyAtLS0tDQojPT09DQojIyBDb21wbGV0ZSB0aW1lc2VyaWVzIG9mIGFubnVhbCBtYXR1cml0eSBvZ2l2ZXMgLS0tLQ0KbW8gPC0gcmVzaGFwZShtYXRfb2dpdmVfY29tYnNleCwNCiAgICAgICAgICAgICAgdmFyeWluZyA9IGNvbG5hbWVzKG1hdF9vZ2l2ZV9jb21ic2V4KVstMV0sDQogICAgICAgICAgICAgIHYubmFtZXMgPSAiUHJvcE1hdCIsDQogICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgdGltZXMgPSBjb2xuYW1lcyhtYXRfb2dpdmVfY29tYnNleClbLTFdLA0KICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0KDQojIyBNZWFuIG9mIHBlcmlvZCAyMDAyIC0gRGF0YVllYXINCnJtcHJvcCA8LSBhZ2dyZWdhdGUoUHJvcE1hdCB+IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1vW21vJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSxdLA0KICAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQ0KDQojIyBTdGQuIGVycm9yIG9mIHBlcmlvZCAyMDAyIC0gRGF0YVllYXINCnJtc3RkciA8LSBhZ2dyZWdhdGUoUHJvcE1hdCB+IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1vW21vJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0Kcm1zdGRyJEFnZU4gPC0gYXMubnVtZXJpYyhzdWIocGF0dGVybiA9ICJhIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJtc3RkciRBZ2UpKQ0KY29sbmFtZXMocm1zdGRyKVtjb2xuYW1lcyhybXN0ZHIpICVpbiUgYygiUHJvcE1hdCIpXSA8LSAiU3RkRXJyIg0Kcm1zdGRyJFByb3BNYXQgPC0gcm1wcm9wJFByb3BNYXQNCnJtc3RkciR5bWF4IDwtIHJtc3RkciRQcm9wTWF0ICsgMS45NipybXN0ZHIkU3RkRXJyDQpybXN0ZHIkeW1pbiA8LSBybXN0ZHIkUHJvcE1hdCAtIDEuOTYqcm1zdGRyJFN0ZEVycg0KDQojIyBDb21iaW5lIHdpdGggcmF3IGRhdGEgZGYNCnJtcHJvcCR5ZWFyIDwtIGFzLmZhY3RvcihyZXAoIlJ1bm5pbmcgTWVhbiIsIG4gPSBucm93KHJtcHJvcCkpKQ0Kcm93bmFtZXMocm1zdGRyKSA8LSBOVUxMDQptbyA8LSByYmluZChtbywgcm1wcm9wKQ0KbW8kQWdlTiA8LSBhcy5udW1lcmljKHN1YihwYXR0ZXJuID0gImEiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gbW8kQWdlKSkNCm1vJHllYXJGIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobW8keWVhcikpDQojPT09PT0NCg0KDQojPT09DQojIEZlbWFsZSBPbmx5IHJlc2hhcGUgYW5kIGNhbGN1bGF0ZSBtZWFucyArLy0gOTUlQ0kgZm9yIHBsb3R0aW5nIC0tLS0NCiM9PT0NCiMjIENvbXBsZXRlIHRpbWVzZXJpZXMgb2YgYW5udWFsIG1hdHVyaXR5IG9naXZlcyAtLS0tDQpmbW8gPC0gcmVzaGFwZShtYXRfb2dpdmVfRiwNCiAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhtYXRfb2dpdmVfRilbLTFdLA0KICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJQcm9wTWF0IiwNCiAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMobWF0X29naXZlX0YpWy0xXSwNCiAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0KDQojIyBNZWFuIG9mIHBlcmlvZCAyMDAyIC0gRGF0YVllYXIgIC0tLS0NCnJmbXByb3AgPC0gYWdncmVnYXRlKFByb3BNYXQgfiBBZ2UsDQogICAgICAgICAgICAgICAgICAgICBkYXRhID0gZm1vW2ZtbyR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksXSwNCiAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4pDQoNCiMjIFN0ZC4gZXJyb3Igb2YgcGVyaW9kIDIwMDIgLSBEYXRhWWVhciAgLS0tLQ0KcmZtc3RkciA8LSBhZ2dyZWdhdGUoUHJvcE1hdCB+IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBmbW9bZm1vJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpe3NkKHgsIG5hLnJtID0gVFJVRSkvc3FydChsZW5ndGgobmEub21pdCh4KSkpfSkNCnJmbXN0ZHIkQWdlTiA8LSBhcy5udW1lcmljKHN1YihwYXR0ZXJuID0gImEiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gcmZtc3RkciRBZ2UpKQ0KY29sbmFtZXMocmZtc3RkcilbY29sbmFtZXMocmZtc3RkcikgJWluJSBjKCJQcm9wTWF0IildIDwtICJTdGRFcnIiDQpyZm1zdGRyJFByb3BNYXQgPC0gcmZtcHJvcCRQcm9wTWF0DQpyZm1zdGRyJHltYXggPC0gcmZtc3RkciRQcm9wTWF0ICsgMS45NipyZm1zdGRyJFN0ZEVycg0KcmZtc3RkciR5bWluIDwtIHJmbXN0ZHIkUHJvcE1hdCAtIDEuOTYqcmZtc3RkciRTdGRFcnINCg0KIyMgQ29tYmluZSB3aXRoIHJhdyBkYXRhIGRmICAtLS0tDQpyZm1wcm9wJHllYXIgPC0gYXMuZmFjdG9yKHJlcCgiUnVubmluZyBNZWFuIiwgbiA9IG5yb3cocmZtcHJvcCkpKQ0Kcm93bmFtZXMocmZtc3RkcikgPC0gTlVMTA0KZm1vIDwtIHJiaW5kKGZtbywgcmZtcHJvcCkNCmZtbyRBZ2VOIDwtIGFzLm51bWVyaWMoc3ViKHBhdHRlcm4gPSAiYSIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBmbW8kQWdlKSkNCmZtbyR5ZWFyRiA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGZtbyR5ZWFyKSkNCg0KDQojIHNhdmVSRFMoZm1vLCBmaWxlID0gIkRhdGEvQmlvbG9naWNhbERhdGEvUGxlLjI3LjIxLTMyX01hdHVyaXRpZXNGZW1hbGVMb25nXzE5OTktQXNzWWVhci5SRFMiKQ0KIyBzYXZlUkRTKGZtc3RkciwgZmlsZSgiRGF0YS9CaW9sb2dpY2FsRGF0YS9QbGUuMjcuMjEtMzJfTWF0dXJpdGllc0ZlbWFsZUF2ZVN0ZEVycl8xNXlyLlJEUyIpKQ0KIyBzYXZlUkRTKHJmbXN0ZHIsIGZpbGUoIkRhdGEvQmlvbG9naWNhbERhdGEvUGxlLjI3LjIxLTMyX01hdHVyaXRpZXNGZW1hbGVBdmVTdGRFcnJfMjAwMi1Bc3NZZWFyLlJEUyIpKQ0KIz09PT09DQoNCiM9PT0NCiMgTWFsZSBPbmx5IHJlc2hhcGUgYW5kIGNhbGN1bGF0ZSBtZWFucyArLy0gOTUlQ0kgZm9yIHBsb3R0aW5nIC0tLS0NCiM9PT0NCiMjIENvbXBsZXRlIHRpbWVzZXJpZXMgb2YgYW5udWFsIG1hdHVyaXR5IG9naXZlcyAtLS0tDQptbW8gPC0gcmVzaGFwZShtYXRfb2dpdmVfTSwNCiAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhtYXRfb2dpdmVfTSlbLTFdLA0KICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJQcm9wTWF0IiwNCiAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMobWF0X29naXZlX00pWy0xXSwNCiAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0KDQojIyBNZWFuIG9mIHBlcmlvZCAyMDAyIC0gRGF0YVllYXIgLS0tLQ0Kcm1tcHJvcCA8LSBhZ2dyZWdhdGUoUHJvcE1hdCB+IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBtbW9bbW1vJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSxdLA0KICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWVhbikNCg0KIyMgU3RkLiBlcnJvciBvZiBwZXJpb2QgMjAwMiAtIERhdGFZZWFyICAtLS0tDQpybW1zdGRyIDwtIGFnZ3JlZ2F0ZShQcm9wTWF0IH4gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1tb1ttbW8keWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0Kcm1tc3RkciRBZ2VOIDwtIGFzLm51bWVyaWMoc3ViKHBhdHRlcm4gPSAiYSIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBybW1zdGRyJEFnZSkpDQpjb2xuYW1lcyhybW1zdGRyKVtjb2xuYW1lcyhybW1zdGRyKSAlaW4lIGMoIlByb3BNYXQiKV0gPC0gIlN0ZEVyciINCnJtbXN0ZHIkUHJvcE1hdCA8LSBybW1wcm9wJFByb3BNYXQNCnJtbXN0ZHIkeW1heCA8LSBybW1zdGRyJFByb3BNYXQgKyAxLjk2KnJtbXN0ZHIkU3RkRXJyDQpybW1zdGRyJHltaW4gPC0gcm1tc3RkciRQcm9wTWF0IC0gMS45NipybW1zdGRyJFN0ZEVycg0KDQojIyBDb21iaW5lIHdpdGggcmF3IGRhdGEgZGYgIC0tLS0NCnJtbXByb3AkeWVhciA8LSBhcy5mYWN0b3IocmVwKCJSdW5uaW5nIE1lYW4iLCBuID0gbnJvdyhybW1wcm9wKSkpDQpyb3duYW1lcyhybW1zdGRyKSA8LSBOVUxMDQptbW8gPC0gcmJpbmQobW1vLCBybW1wcm9wKQ0KbW1vJEFnZU4gPC0gYXMubnVtZXJpYyhzdWIocGF0dGVybiA9ICJhIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IG1tbyRBZ2UpKQ0KbW1vJHllYXJGIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobW1vJHllYXIpKQ0KDQoNCiMgc2F2ZVJEUyhtbW8sIGZpbGUgPSAiRGF0YS9CaW9sb2dpY2FsRGF0YS9QbGUuMjcuMjEtMzJfTWF0dXJpdGllc01hbGVMb25nXzE5OTktQXNzWWVhci5SRFMiKQ0KIyBzYXZlUkRTKG1tc3RkciwgZmlsZSgiRGF0YS9CaW9sb2dpY2FsRGF0YS9QbGUuMjcuMjEtMzJfTWF0dXJpdGllc01hbGVBdmVTdGRFcnJfMTV5ci5SRFMiKSkNCiMgc2F2ZVJEUyhybW1zdGRyLCBmaWxlKCJEYXRhL0Jpb2xvZ2ljYWxEYXRhL1BsZS4yNy4yMS0zMl9NYXR1cml0aWVzTWFsZUF2ZVN0ZEVycl8yMDAyLUFzc1llYXIuUkRTIikpDQojPT09PT0NCg0KIyMgQ2FsY3VsYXRlIDN5IHNsaWRpbmcgd2luZG93IGF2ZXJhZ2UgZm9yIHdob2xlIHRpbWVzZXJpZXMgLS0tLQ0KIyMjIENhbGN1bGF0ZSB0aGUgbWVhbiAtLS0tDQphZGEgPC0gYW4oMywgbnJvdyhtYXRfb2dpdmVfY29tYnNleCkpDQptbzNzdyA8LSBmcm9sbG1lYW4oeCA9IG1hdF9vZ2l2ZV9jb21ic2V4WywgLTFdLCBuID0gYWRhLCBuYS5ybSA9IFQsIGFsaWduID0gInJpZ2h0IiwgYWRhcHRpdmUgPSBUUlVFKQ0KbW8zc3cgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBtbzNzdykpDQptbzNzdyR5ZWFyIDwtIG1hdF9vZ2l2ZV9jb21ic2V4JHllYXINCg0KIyMjIyBXaWRlIHRvIGxvbmcgZm9ybWF0DQptbzNzd0wgPC0gcmVzaGFwZShtbzNzdywNCiAgICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhtbzNzdylbLTExXSwNCiAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiUHJvcE1hdCIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKG1vM3N3KVstMTFdLA0KICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQptbzNzd0wkQWdlIDwtIGFzLm51bWVyaWMoZ3N1YihwYXR0ZXJuID0gIlYiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gbW8zc3dMJEFnZSkpDQoNCiMjIyBDYWxjdWFsdGUgdGhlIHN0YW5kYXJkIGVycm9yIC0tLS0NCnN3M3N0ZHIgPC0gZnJvbGxhcHBseShtYXRfb2dpdmVfY29tYnNleFssIC0xXSwNCiAgICAgICAgICAgICAgICAgICAgICAzLA0KICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpe3NkKHgsIG5hLnJtID0gVFJVRSkvc3FydChsZW5ndGgobmEub21pdCh4KSkpfSkNCnN3M3N0ZHIgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBzdzNzdGRyKSkNCnN3M3N0ZHIkeWVhciA8LSBtYXRfb2dpdmVfY29tYnNleCR5ZWFyDQoNCiMjIyMgV2lkZSB0byBsb25nIGZvcm1hdA0Kc3czc3RkckwgPC0gcmVzaGFwZShzdzNzdGRyLA0KICAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMoc3czc3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJTdGRFcnJQcm9wTWF0IiwNCiAgICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKHN3M3N0ZHIpWy0xMV0sDQogICAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQpzdzNzdGRyTCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBzdzNzdGRyTCRBZ2UpKQ0KDQojIyMgQ2FsY3VsYXRlIDk1JSBjb25maWRlbmNlIGludGVydmFscyAtLS0tDQptbzNzd0wgPC0gbWVyZ2UoeCA9IG1vM3N3TCwgeSA9IHN3M3N0ZHJMLCBieSA9IGMoInllYXIiLCAiQWdlIiksIGFsbC54ID0gVFJVRSkNCm1vM3N3TCR5bWF4IDwtIG1vM3N3TCRQcm9wTWF0ICsgKDEuOTYqbW8zc3dMJFN0ZEVyclByb3BNYXQpDQptbzNzd0wkeW1pbiA8LSBtbzNzd0wkUHJvcE1hdCAtICgxLjk2Km1vM3N3TCRTdGRFcnJQcm9wTWF0KQ0KbW8zc3dMJEFnZU4gPC0gbW8zc3dMJEFnZQ0KbW8zc3dMJEFnZSA8LSBhcy5jaGFyYWN0ZXIobW8zc3dMJEFnZSkNCm1vM3N3TCA8LSBtbzNzd0xbIW1vM3N3TCR5ZWFyICVpbiUgYygxOTk5OjIwMDEpLF0NCg0KIyMgQ2FsY3VsYXRlIDV5IHNsaWRpbmcgd2luZG93IGF2ZXJhZ2UgZm9yIHdob2xlIHRpbWVzZXJpZXMgLS0tLQ0KIyMjIENhbGN1bGF0ZSB0aGUgbWVhbiAtLS0tDQphZGEgPC0gYW4oNSwgbnJvdyhtYXRfb2dpdmVfY29tYnNleCkpDQptbzVzdyA8LSBmcm9sbG1lYW4oeCA9IG1hdF9vZ2l2ZV9jb21ic2V4WywgLTFdLCBuID0gYWRhLCBuYS5ybSA9IFQsIGFsaWduID0gInJpZ2h0IiwgYWRhcHRpdmUgPSBUUlVFKQ0KbW81c3cgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBtbzVzdykpDQojIyMjIE1ha2UgdGhlIGZpcnN0IHllYXIgZXF1YWwgdG8gdGhlIGZpcnN0IGNhbGN1bGFibGUgNXkgYXZlcmFnZQ0KbW81c3ckeWVhciA8LSBtYXRfb2dpdmVfY29tYnNleCR5ZWFyDQojIG1vNXN3W21vNXN3JHllYXIgPT0gMjAwMiwgLW5jb2wobW81c3cpXSA8LSBtbzVzd1ttbzVzdyR5ZWFyID09IDIwMDMsIC1uY29sKG1vNXN3KV0NCm1vNXN3IDwtIG1vNXN3WyFtbzVzdyR5ZWFyICVpbiUgYygxOTk5OjIwMDEpLF0NCg0KDQojIyMjIFdpZGUgdG8gbG9uZyBmb3JtYXQNCm1vNXN3TCA8LSByZXNoYXBlKG1vNXN3LA0KICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGNvbG5hbWVzKG1vNXN3KVstMTFdLA0KICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJQcm9wTWF0IiwNCiAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMobW81c3cpWy0xMV0sDQogICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCm1vNXN3TCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBtbzVzd0wkQWdlKSkNCg0KIyMjIENhbGN1YWx0ZSB0aGUgc3RhbmRhcmQgZXJyb3IgLS0tLQ0Kc3c1c3RkciA8LSBmcm9sbGFwcGx5KG1hdF9vZ2l2ZV9jb21ic2V4WywgLTFdLA0KICAgICAgICAgICAgICAgICAgICAgIDUsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0Kc3c1c3RkciA8LSBhcy5kYXRhLmZyYW1lKGRvLmNhbGwoY2JpbmQsIHN3NXN0ZHIpKQ0Kc3c1c3RkciR5ZWFyIDwtIG1hdF9vZ2l2ZV9jb21ic2V4JHllYXINCg0KIyMjIyBNYWtlIHRoZSBmaXJzdCB5ZWFyIGVxdWFsIHRvIHRoZSBmaXJzdCBjYWxjdWxhYmxlIDV5IGF2ZXJhZ2UNCnN3NXN0ZHJbc3c1c3RkciR5ZWFyID09IDIwMDIsIC1uY29sKHN3NXN0ZHIpXSA8LSBzdzVzdGRyW3N3NXN0ZHIkeWVhciA9PSAyMDAzLCAtbmNvbChzdzVzdGRyKV0NCnN3NXN0ZHIgPC0gc3c1c3Rkclshc3c1c3RkciR5ZWFyICVpbiUgYygxOTk5OjIwMDEpLF0NCg0KIyMjIyBXaWRlIHRvIGxvbmcgZm9ybWF0DQpzdzVzdGRyTCA8LSByZXNoYXBlKHN3NXN0ZHIsDQogICAgICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhzdzVzdGRyKVstMTFdLA0KICAgICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gIlN0ZEVyclByb3BNYXQiLA0KICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMoc3c1c3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCnN3NXN0ZHJMJEFnZSA8LSBhcy5udW1lcmljKGdzdWIocGF0dGVybiA9ICJWIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHN3NXN0ZHJMJEFnZSkpDQoNCiMjIyBDYWxjdWxhdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIC0tLS0NCm1vNXN3TCA8LSBtZXJnZSh4ID0gbW81c3dMLCB5ID0gc3c1c3RkckwsIGJ5ID0gYygieWVhciIsICJBZ2UiKSwgYWxsLnggPSBUUlVFKQ0KbW81c3dMJHltYXggPC0gbW81c3dMJFByb3BNYXQgKyAoMS45NiptbzVzd0wkU3RkRXJyUHJvcE1hdCkNCm1vNXN3TCR5bWluIDwtIG1vNXN3TCRQcm9wTWF0IC0gKDEuOTYqbW81c3dMJFN0ZEVyclByb3BNYXQpDQptbzVzd0wkQWdlTiA8LSBtbzVzd0wkQWdlDQptbzVzd0wkQWdlIDwtIGFzLmNoYXJhY3RlcihtbzVzd0wkQWdlKQ0KbW81c3dMIDwtIG1vNXN3TFshbW81c3dMJHllYXIgJWluJSBjKDE5OTk6MjAwMSksXQ0KDQoNCiMjIENhbGN1bGF0ZSBhbm51YWwgdmFsdWVzIGZyb20gYSBzbW9vdGhpbmcgc3BsaW5lIC0tLS0NCiMjIyBCdWlsZCB0aGUgc3BsaW5lDQptbzIgPC0gbW8NCm1vMiRBZ2UgPC0gYXMuZmFjdG9yKG1vMiRBZ2UpDQptbzIkeWVhciA8LSBhcy5udW1lcmljKG1vMiR5ZWFyKQ0KbW9zcyA8LSBnYW0oZm9ybXVsYSA9IFByb3BNYXQgfiBzKHllYXIsIGJzID0gImNyIiwgYnkgPSBBZ2UpLCBkYXRhID0gbW8yLCBmYW1pbHkgPSBnYXVzc2lhbihsaW5rID0gImlkZW50aXR5IikpDQoNCiMjIyBQcmVkaWN0IHdpdGggdGhlIHNtb290aGVkIHNwbGluZQ0KcHJlZG1vPC0gcHJlZGljdC5nYW0obW9zcywgbmV3ZGF0YSA9IG1vMiwgdHlwZSA9ICJyZXNwb25zZSIsIHNlLmZpdCA9IFRSVUUpDQptbzIkc21vb3RoUHJvcE1hdCA8LSB1bm5hbWUocHJlZG1vJGZpdCkNCm1vMiRzZVNtb290aFByb3BNYXQgPC0gdW5uYW1lKHByZWRtbyRzZS5maXQpDQoNCiM9PT09DQoNCiM9PT0NCiMgQ2xlYW4gRGF0YSBFbnZpcm9ubWVudA0KIz09PT0NCmsgPC0gYXBwZW5kKGssIGMoIm1vIiwgIm1zdGRyIiwgInJtc3RkciIsICJtYXRfb2dpdmVfRiIsICJtYXRfb2dpdmVfTSIsICJtYXRfb2dpdmVfY29tYnNleCIsICJtbzNzd0wiLCAibW81c3dMIiwgIm1vMiIsICJzZXhfcmF0aW9fZmVtYWxlIikpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGtdKQ0KIz09PT09DQpgYGANCg0KVGhlcmUgYXJlIHZhcmlvdXMgd2F5cyBvZiBsb29raW5nIGEgdGhlIE1hdHVyaXR5IE9naXZlcy4gIFRoZSBwcmV2aW91cyBQbGUuMjcuMjEtMjMgc3RvY2sgdXNlZCBydW5uaW5nIG1lYW5zIGZyb20gdGhlIHdob2xlIHRpbWUtc2VyaWVzIHRvIGdldCBzaW5nbGUgdmFsdWVzIG9mIG1hdHVyaXR5IGF0IGFnZSwgd2hpY2ggd2VyZSB0aGVuIGFwcGxpZWQgdG8gZXZlcnkgeWVhciBpbiB0aGUgYXNzZXNzbWVudC4NCmBgYHtyIE1PVGFibGVfcm19DQojIGthYmxlKG1vW21vJHllYXIgPT0gIlJ1bm5pbmcgTWVhbiIsIGMoIkFnZU4iLCAiUHJvcE1hdCIpIF0sIA0Kcm1zdGRyZGVyIDwtIHJtc3RkcltvcmRlcihybXN0ZHIkQWdlTiksIGMoIkFnZU4iLCAiUHJvcE1hdCIpIF0NCnJvd25hbWVzKHJtc3RkcmRlcikgPC0gTlVMTA0KDQojIyMgc2F2ZV9hc19sb3dlc3RvZnQgTWVhbiAyMDAyLURhdGFZZWFyDQptbUEgPC0gZGF0YS5mcmFtZShsYXBwbHkoY29sTWVhbnMobWF0X29naXZlX2NvbWJzZXhbbWF0X29naXZlX2NvbWJzZXgkeWVhciAlaW4lIGMoMjAwMjpEYXRhWWVhciksICFjb2xuYW1lcyhtYXRfb2dpdmVfY29tYnNleCkgJWluJSAoInllYXIiKV0sIG5hLnJtID0gVFJVRSksIHR5cGUuY29udmVydCksIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gbW1BLCAjWywgIWNvbG5hbWVzKG1XQUEpICVpbiUgIkFnZSJdLA0KICAgICAgICAgICAgICAgICAgZmlsZV9wYXRoID0gIkFzc2Vzc21lbnQgSW5wdXQvbW8uZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlN0b2NrIHdlaWdodHMgYXQgYWdlIGZvciBQbGUuMjcuMjEtMzIuIE1lYW4gdmFsdWVzIGZvciBjb21iaW5lZCBzZXhlcyAyMDAyIHRvIERhdGEgeWVhciwgZnJvbSBzdXJ2ZXkgZGF0YSIsDQogICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygxLCA0KSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHllYXJfcmFuZ2UgPSBwYXN0ZShjKDIwMDIsIERhdGFZZWFyKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gMikNCg0Ka2FibGUocm1zdGRyZGVyLCANCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIk1hdHVyaXR5IE9naXZlcyBvZiBQbGUuMjcuMjEtMzIsIHVzaW5nIHRoZSBzdG9jayBhbm5leCBtZXRob2QgZnJvbSB0aGUgcHJldmlvdXMgUGxlLjI3LjIxLTIzLiAgVmFsdWVzIGFyZSB0aW1lc2VyaWVzIG1lYW5zIG9mIGJvdGggc2V4ZXMgZm9yIHRoZSBwZXJpb2QgMjAwMi0iLCBEYXRhWWVhciksDQogICAgICBkaWdpdHMgPSAyKQ0KYGBgDQoNCkFuIGFsdGVybmF0ZSBhcHByb2FjaCBpcyB0byB1c2Ugc21vb3RoZWQgb3Igc2xpZGluZyB3aW5kb3cgYXZlcmFnZXMgdG8gYWxsb3cgZm9yIGNoYW5nZSBpbiB0aGUgYWdlIGF0IG1hdHVyaXR5IG92ZXIgdGltZSAoZGlmZmVyZW50IHZhbHVlcyBmb3IgZXZlcnkgeWVhciBpbiB0aGUgYXNzZXNzbWVudCksIHdoaWxlIHNtb290aGluZyBvdXQgc29tZSBvZiB0aGUgbm9pc2UgaW50cm9kdWNlZCBmcm9tIGFubnVhbCBvYnNlcnZhdGlvbnMgb2YgbWF0dXJpdHkuICBUaGlzIG5vaXNlIGNhbiBiZSBzaWduaWZpY2FudCBkdWUgdG8gdGhlIHJlbGF0aXZlbHkgbG93IHNhbXBsZSBzaXplcyBvZiBtYXR1cml0eSBsZXZlbCwgcmVsYXRpdmUgdG8gdGhlIHBvcHVsYXRpb24uDQoNCmBgYHtyIE1PVGFibGVfc3czfQ0KbW8zb3JkZXIgPC0gbW8zc3dMW29yZGVyKG1vM3N3TCR5ZWFyLCBtbzNzd0wkQWdlTiksIGMoInllYXIiLCAiQWdlTiIsICJQcm9wTWF0IikgXQ0Kcm93bmFtZXMobW8zb3JkZXIpIDwtIE5VTEwNCm1vM29yZGVydyA8LSBkY2FzdChtbzNvcmRlciwgeWVhciB+IEFnZU4sIHZhbHVlLnZhciA9ICJQcm9wTWF0IikNCg0KIyMgU2F2ZSBtYXR1cml0eSBkYXRhIGZvciBhc3Nlc3NtZW50IGlucHV0DQojICMjIyBNYWtlICJOQSJzIGludG8gIi05Ig0KIyBtbzNvcmRlcndTQU0gPC0gbW8zb3JkZXJ3W21vM29yZGVydyR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksIF0NCiMgZm9yKGkgaW4gMTpuY29sKG1vM29yZGVyd1NBTSkpew0KIyAgIGZvcihqIGluIDE6bnJvdyhtbzNvcmRlcndTQU0pKXsNCiMgICAgIG1vM29yZGVyd1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobW8zb3JkZXJ3U0FNW2osIGldKSwgLTksIG1vM29yZGVyd1NBTVtqLCBpXSkNCiMgICB9DQojIH0NCg0KIyMjIE1ha2UgZWFybHkgdGltZXNlcmllcyAiTkEicyBpbnRvIHBsYXVzaWJsZSB2YWx1ZQ0KbW8zb3JkZXJ3U0FNIDwtIG1vM29yZGVyd1ttbzNvcmRlcnckeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdDQpmb3IoaSBpbiAxOm5jb2wobW8zb3JkZXJ3U0FNKSl7DQogIGZvcihqIGluIDE6bnJvdyhtbzNvcmRlcndTQU0pKXsNCiAgICBtbzNvcmRlcndTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG1vM29yZGVyd1NBTVtqLCBpXSksIG1lZGlhbihjKG1vM29yZGVyd1NBTVssaV0pLCBuYS5ybSA9IFQpLCBtbzNvcmRlcndTQU1baiwgaV0pDQogIH0NCn0NCg0Kc2F2ZV9hc19sb3dlc3RvZnQobW8zb3JkZXJ3U0FNWywgIWNvbG5hbWVzKG1vM29yZGVyd1NBTSkgJWluJSAieWVhciJdLA0KICAgICAgICAgICAgICAgICAgZmlsZV9wYXRoID0gIkFzc2Vzc21lbnQgSW5wdXQvQWx0ZXJuYXRlTW9kZWxfM3lzdy9tby5kYXQiLCB0aXRsZSA9IHBhc3RlMCgiQ29tYmluZWQgc2V4IG1hdHVyaXR5IG9naXZlcyBmb3IgcGxlLjI3LjIxLTMyLiBUaHJlZSB5ZWFyIHNsaWRpbmcgd2luZG93IG1lYW5zIGZyb20gMjAwMjoiLCBEYXRhWWVhcisxKSwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKCIxIiwgIjYiLCAiI0kgZG9uJ3Qga25vdyB3aGF0IHRoaXMgaW5mb3JtYXRpb24gc3RhbmRzIGZvciwgaXQncyBqdXN0IG1hZGUgdXAuIiksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLCANCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gcGFzdGUoYygxLCAiIyAxIGluZGljYXRlcyBhbm51YWxseSB2YXJ5aW5nLCAyIGluZGljYXRlcyBmaXhlZCB2YWx1ZXMiKSwgY29sbGFwc2UgPSAiXHQiKSkNCg0Ka2FibGUobW8zb3JkZXJ3LCANCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIk1hdHVyaXR5IE9naXZlcyBvZiBQbGUuMjcuMjEtMzIsIHVzaW5nIGEgMyB5ZWFyIHNsaWRpbmcgd2luZG93IG1lYW4gYXBwcm9hY2guICBWYWx1ZXMgYXJlIHRpbWVzZXJpZXMgbWVhbnMgb2YgdGhlIHdob2xlIHRpbWVzZXJpZXMsIDIwMDI6IiwgRGF0YVllYXIrMSksDQogICAgICBkaWdpdHMgPSAyKQ0KYGBgDQoNCmBgYHtyIE1PVGFibGVfc3c1fQ0KbW81b3JkZXIgPC0gbW81c3dMW29yZGVyKG1vNXN3TCR5ZWFyLCBtbzVzd0wkQWdlTiksIGMoInllYXIiLCAiQWdlTiIsICJQcm9wTWF0IikgXQ0Kcm93bmFtZXMobW81b3JkZXIpIDwtIE5VTEwNCm1vNW9yZGVydyA8LSBkY2FzdChtbzVvcmRlciwgeWVhciB+IEFnZU4sIHZhbHVlLnZhciA9ICJQcm9wTWF0IikNCg0KIyAjIyBTYXZlIG1hdHVyaXR5IGRhdGEgZm9yIGFzc2Vzc21lbnQgaW5wdXQNCiMgbW81b3JkZXJ3U0FNIDwtIG1vNW9yZGVyd1ttbzVvcmRlcnckeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdDQojIGZvcihpIGluIDE6bmNvbChtbzVvcmRlcndTQU0pKXsNCiMgICBmb3IoaiBpbiAxOm5yb3cobW81b3JkZXJ3U0FNKSl7DQojICAgICBtbzVvcmRlcndTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG1vNW9yZGVyd1NBTVtqLCBpXSksIC05LCBtbzVvcmRlcndTQU1baiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyBNYWtlIGVhcmx5IHRpbWVzZXJpZXMgIk5BInMgaW50byBwbGF1c2libGUgdmFsdWUNCm1vNW9yZGVyd1NBTSA8LSBtbzVvcmRlcndbbW81b3JkZXJ3JHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSwgXQ0KZm9yKGkgaW4gMTpuY29sKG1vNW9yZGVyd1NBTSkpew0KICBmb3IoaiBpbiAxOm5yb3cobW81b3JkZXJ3U0FNKSl7DQogICAgbW81b3JkZXJ3U0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShtbzVvcmRlcndTQU1baiwgaV0pLCBtZWRpYW4oYyhtbzVvcmRlcndTQU1bLGldKSwgbmEucm0gPSBUKSwgbW81b3JkZXJ3U0FNW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KG1vNW9yZGVyd1NBTVssICFjb2xuYW1lcyhtbzVvcmRlcndTQU0pICVpbiUgInllYXIiXSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L0FsdGVybmF0ZU1vZGVsXzV5c3cvbW8uZGF0IiwgdGl0bGUgPSBwYXN0ZTAoIkNvbWJpbmVkIHNleCBtYXR1cml0eSBvZ2l2ZXMgZm9yIHBsZS4yNy4yMS0zMi4gRml2ZSB5ZWFyIHNsaWRpbmcgd2luZG93IG1lYW5zIGZyb20gMjAwMjoiLCBEYXRhWWVhcisxKSwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKCIxIiwgIjYiLCAiI0kgZG9uJ3Qga25vdyB3aGF0IHRoaXMgaW5mb3JtYXRpb24gc3RhbmRzIGZvciwgaXQncyBqdXN0IG1hZGUgdXAuIiksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLCANCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gcGFzdGUoYygxLCAiIyAxIGluZGljYXRlcyBhbm51YWxseSB2YXJ5aW5nLCAyIGluZGljYXRlcyBmaXhlZCB2YWx1ZXMiKSwgY29sbGFwc2UgPSAiXHQiKSkNCg0Ka2FibGUobW81b3JkZXJ3LCANCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIk1hdHVyaXR5IE9naXZlcyBvZiBQbGUuMjcuMjEtMzIsIHVzaW5nIGEgNSB5ZWFyIHNsaWRpbmcgd2luZG93IG1lYW4gYXBwcm9hY2guICBWYWx1ZXMgYXJlIHRpbWVzZXJpZXMgbWVhbnMgb2YgdGhlIHdob2xlIHRpbWVzZXJpZXMsIDIwMDI6IiwgRGF0YVllYXIrMSksDQogICAgICBkaWdpdHMgPSAyKQ0KYGBgDQpXZSBjb3VsZCBhbHNvIGF0dGVtcHQgdG8gZml0IHNtb290aGVycyB0byB0aGVzZSBkYXRhLCBpbiBwbGFjZSBvZiB0aGUgc2xpZGluZyB3aW5kb3cgbWVhbnMuICBIb3dldmVyLCBpbnN0ZWFkIG9mIGRvaW5nIHRoaXMgaW4gZGF0YSBwcmVwLCB3ZSBjYW4gc2ltcGx5IHByb3ZpZGUgdGhlIHJhdyBhbm51YWwgZXN0aW1hdGVzIHRvIFNBTSwgYW5kIGVzdGltYXRlIHRoaXMgc21vb3RoZXIgZHVyaW5nIHRoZSBtb2RlbCBmaXQuDQoNCmBgYHtyIE1PVGFibGVfQW5udWFsRXN0aW1hdGVzfQ0KbW9SYXdPcmRlciA8LSBtYXRfb2dpdmVfY29tYnNleFttYXRfb2dpdmVfY29tYnNleCR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksIF0NCnJvd25hbWVzKG1vUmF3T3JkZXIpIDwtIE5VTEwNCg0KIyAjIyBTYXZlIG1hdHVyaXR5IGRhdGEgZm9yIGFzc2Vzc21lbnQgaW5wdXQNCiMgbW9SYXdPcmRlclNBTSA8LSBtb1Jhd09yZGVyW21vUmF3T3JkZXIkeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdDQojIGZvcihpIGluIDE6bmNvbChtb1Jhd09yZGVyU0FNKSl7DQojICAgZm9yKGogaW4gMTpucm93KG1vUmF3T3JkZXJTQU0pKXsNCiMgICAgIG1vUmF3T3JkZXJTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG1vUmF3T3JkZXJTQU1baiwgaV0pLCAtOSwgbW9SYXdPcmRlclNBTVtqLCBpXSkNCiMgICB9DQojIH0NCg0KIyMjIE1ha2UgZWFybHkgdGltZXNlcmllcyAiTkEicyBpbnRvIHBsYXVzaWJsZSB2YWx1ZQ0KbW9SYXdPcmRlclNBTSA8LSBtb1Jhd09yZGVyW21vUmF3T3JkZXIkeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdDQpmb3IoaSBpbiAxOm5jb2wobW9SYXdPcmRlclNBTSkpew0KICBmb3IoaiBpbiAxOm5yb3cobW9SYXdPcmRlclNBTSkpew0KICAgIG1vUmF3T3JkZXJTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG1vUmF3T3JkZXJTQU1baiwgaV0pLCBtZWRpYW4oYyhtb1Jhd09yZGVyU0FNWyxpXSksIG5hLnJtID0gVCksIG1vUmF3T3JkZXJTQU1baiwgaV0pDQogIH0NCn0NCg0Kc2F2ZV9hc19sb3dlc3RvZnQobW9SYXdPcmRlclNBTVssICFjb2xuYW1lcyhtb1Jhd09yZGVyU0FNKSAlaW4lICJ5ZWFyIl0sDQogICAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSAiQXNzZXNzbWVudCBJbnB1dC9BbHRlcm5hdGVNb2RlbF9Bbm51YWxSYXdCaW8vbW8uZGF0IiwgdGl0bGUgPSBwYXN0ZTAoIkNvbWJpbmVkIHNleCBtYXR1cml0eSBvZ2l2ZXMgZm9yIHBsZS4yNy4yMS0zMi4gQW5udWFsIGVzdGltYXRlcyBmcm9tIDIwMDI6IiwgRGF0YVllYXIrMSksDQogICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygiMSIsICI2IiwgIiNJIGRvbid0IGtub3cgd2hhdCB0aGlzIGluZm9ybWF0aW9uIHN0YW5kcyBmb3IsIGl0J3MganVzdCBtYWRlIHVwLiIpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwgDQogICAgICAgICAgICAgICAgICBhZ2VfcmFuZ2UgPSBwYXN0ZShjKDEsIDEwKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHRpbWVzZXJpZXNfdHlwZSA9IHBhc3RlKGMoMSwgIiMgMSBpbmRpY2F0ZXMgYW5udWFsbHkgdmFyeWluZywgMiBpbmRpY2F0ZXMgZml4ZWQgdmFsdWVzIiksIGNvbGxhcHNlID0gIlx0IikpDQoNCmthYmxlKG1vUmF3T3JkZXIsIA0KICAgICAgY2FwdGlvbiA9IHBhc3RlMCgiTWF0dXJpdHkgT2dpdmVzIG9mIFBsZS4yNy4yMS0zMiwgdXNpbmcgYW5udWFsIGVzdGltYXRlcyBmcm9tIHN1cnZleXMgZm9yIHRoZSB3aG9sZSB0aW1lc2VyaWVzLCAyMDAyOiIsIERhdGFZZWFyKzEpLA0KICAgICAgZGlnaXRzID0gMikNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIk1hdHVyaXR5IG9naXZlcyBmb3IgaW5kaXZpZHVhbCBwcmV2aW91cyB5ZWFycyAoY29sb3VycyksIHRoZSBydW5uaW5nIG1lYW4gYmFzZWQgb24gUGxlLjI3LjIxLTIzIHN0b2NrIGFubmV4IChibGFjayBkb3R0ZWQgKy8tIDk1JSBDSSksIGFuZCBmb3IgIiwgRGF0YVllYXIsICIgKHNvbGlkIGJsYWNrKSIpfQ0KcGx0X21vX3JtIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtb1shbW8keWVhciAlaW4lIGMoIlJ1bm5pbmcgTWVhbiIsIERhdGFZZWFyKSAmIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKG1vJHllYXIpKSA+PSAyMDAyICYgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobW8keWVhcikpICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBQcm9wTWF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IHllYXJGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSB5ZWFyRikpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtb1ttbyR5ZWFyRiA9PSAiUnVubmluZyBNZWFuIixdLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYpLA0KICAgICAgICAgICAgY29sb3VyID0gIkJsYWNrIiwNCiAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gcm1zdGRyLA0KICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSB5bWluKSwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgICAgICBzaXplID0gMSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IG1vW21vJHllYXJGID09IERhdGFZZWFyLCBdLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYpLA0KICAgICAgICAgICAgY29sb3VyID0gIkJsYWNrIiwNCiAgICAgICAgICAgICMgbGluZXR5cGUgPSA5LA0KICAgICAgICAgICAgc2l6ZSA9IDEuMikgKw0KICB0aGVtZV9jbGVhbigpKw0KICAjIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gZnVuY3Rpb24oeCkgcHJldHR5KHgsIG4gPSA1KSkNCg0KZ2dwbG90bHkocGx0X21vX3JtKQ0KYGBgDQoNClV0aWxpc2luZyBhbiBhdmVyYWdlIG9mIG1hdHVyaXR5IG9naXZlcyBmcm9tIHRoZSB3aG9sZSBkYXRhIHNlcmllcyBzZWVtcyB0byBtYXNrIGFueSByZWNlbnQgZGV2ZWxvcG1lbnRzIGluIHJhdGVzIG9mIG1hdHVyaXR5LiBUaGVyZWZvcmUgd2Ugd2VyZSBhZGl2aXNlZCBieSBXR0JGQVMgYW5kIGJ5IHRoZSBBREcgdG8gIGNvbnNpZGVyIHN3aXRjaGluZyB0byBhIHNsaWRpbmcgd2luZG93IGFwcHJvYWNoLiAgQmVsb3cgd2Ugc2VlIHBsb3RzIHNpbWlsYXIgdG8gdGhlIGFib3ZlLCBidXQgdGhpcyB0aW1lIHdlIHN1YnN0aXR1dGUgaW4gdGhlIHJlc3VsdHMgZm9yIGFubnVhbGx5IHZhcnlpbmcsIDMgYW5kIDUgeWVhciBzbGlkaW5nIHdpbmRvdyBtZWFucy4NCg0KYGBge3IgZmlnLmNhcD0gcGFzdGUwKCJNYXR1cml0eSBvZ2l2ZXMgZm9yIHRocmVlIHllYXIgc2xpZGluZyB3aW5kb3cgbWVhbnMgYXBwbGllZCBhcyBhbm51YWxseSB2YXJ5aW5nIG1hdHVyaXR5IHZhbHVlcy4gVGhlIHJ1bm5pbmcgbWVhbiB1dGlsaXNlZCBpbiB0aGUgUGxlLjI3LjIxLTIzIGFubmV4IGlzIG92ZXJsYWluIGZvciBjb21wYXJpc29uIChibGFjayBkb3R0ZWQgKy8tIDk1JSBDSSkuIil9DQojPT09DQojIEZpZ3VyZSBzaG93aW5nIDMgeWVhciBzbGlkaW5nIHdpbmRvdyBNTyB2cyBvdGhlcnMNCiM9PT09DQojIyBNYWtlIG9yZGVyZWQgbW8zc3dMLCB3aXRoIHltYXggbWF4IDENCm1vM3N3TE8gPC0gbW8zc3dMW29yZGVyKG1vM3N3TCR5ZWFyLCBtbzNzd0wkQWdlTiksIGMoInllYXIiLCAiQWdlTiIsICJQcm9wTWF0IiwgInltYXgiLCAieW1pbiIpXQ0KbW8zc3dMTyR5bWF4IDwtIGlmZWxzZShtbzNzd0xPJHltYXggPiAxLCAxLCBtbzNzd0xPJHltYXgpDQptbzNzd0xPJHltaW4gPC0gaWZlbHNlKG1vM3N3TE8keW1pbiA8IDAsIDAsIG1vM3N3TE8keW1pbikNCm1vM3N3TE8keWVhckYgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihtbzNzd0xPJHllYXIpKQ0KDQpwbHRfbW8zc3dMIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtbzNzd0xPLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHllYXJGKSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gbW8zc3dMTywNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSB5bWF4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0geW1pbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHllYXJGKSwNCiAgICAgICAgICAgIGFscGhhID0gMC4wNSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IG1vW21vJHllYXJGID09ICJSdW5uaW5nIE1lYW4iLF0sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gUHJvcE1hdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiksDQogICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgbGluZXR5cGUgPSAzLA0KICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKw0KICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBybXN0ZHIsDQogICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSB5bWF4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IHltaW4pLA0KICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgbGluZXR5cGUgPSAzLA0KICAgICAgICAgICAgICAgIHNpemUgPSAxKSArDQogIHRoZW1lX2NsZWFuKCkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSANCiAgDQpnZ3Bsb3RseShwbHRfbW8zc3dMKQ0KIz09PT09DQpgYGANCg0KYGBge3IgZmlnLmNhcD0gcGFzdGUwKCJNYXR1cml0eSBvZ2l2ZXMgZm9yIGZpdmUgeWVhciBzbGlkaW5nIHdpbmRvdyBtZWFucyBhcHBsaWVkIGFzIGFubnVhbGx5IHZhcnlpbmcgbWF0dXJpdHkgdmFsdWVzLiBUaGUgcnVubmluZyBtZWFuIHV0aWxpc2VkIGluIHRoZSBQbGUuMjcuMjEtMjMgYW5uZXggaXMgb3ZlcmxhaW4gZm9yIGNvbXBhcmlzb24gIChibGFjayBkb3R0ZWQgKy8tIDk1JSBDSSkuIil9DQojPT09DQojIEZpZ3VyZSBzaG93aW5nIDUgeWVhciBzbGlkaW5nIHdpbmRvdyBNTyB2cyBvdGhlcnMNCiM9PT09DQojIyBNYWtlIG9yZGVyZWQgbW81c3dMLCB3aXRoIHltYXggbWF4IDENCm1vNXN3TE8gPC0gbW81c3dMW29yZGVyKG1vNXN3TCR5ZWFyLCBtbzVzd0wkQWdlTiksIGMoInllYXIiLCAiQWdlTiIsICJQcm9wTWF0IiwgInltYXgiLCAieW1pbiIpXQ0KbW81c3dMTyR5bWF4IDwtIGlmZWxzZShtbzVzd0xPJHltYXggPiAxLCAxLCBtbzVzd0xPJHltYXgpDQptbzVzd0xPJHltaW4gPC0gaWZlbHNlKG1vNXN3TE8keW1pbiA8IDAsIDAsIG1vNXN3TE8keW1pbikNCm1vNXN3TE8keWVhckYgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihtbzVzd0xPJHllYXIpKQ0KDQpwbHRfbW81c3dMIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtbzVzd0xPLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHllYXJGKSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gbW81c3dMTywNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSB5bWF4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0geW1pbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHllYXJGKSwNCiAgICAgICAgICAgIGFscGhhID0gMC4wNSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IG1vW21vJHllYXJGID09ICJSdW5uaW5nIE1lYW4iLF0sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gUHJvcE1hdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiksDQogICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgbGluZXR5cGUgPSAzLA0KICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKw0KICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBybXN0ZHIsDQogICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSB5bWF4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IHltaW4pLA0KICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgbGluZXR5cGUgPSAzLA0KICAgICAgICAgICAgICAgIHNpemUgPSAxKSArDQogIHRoZW1lX2NsZWFuKCkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSANCiAgDQpnZ3Bsb3RseShwbHRfbW81c3dMKQ0KIz09PT09DQpgYGANCg0KYGBge3IgTU9UYWJsZV9Bbm51YWxTbW9vdGhlZEVzdGltYXRlc30NCm1vMncgPC0gcmVzaGFwZShtbzJbLCBjKCJ5ZWFyIiwgIkFnZSIsICJzbW9vdGhQcm9wTWF0IildLA0KICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gInNtb290aFByb3BNYXQiLA0KICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpDQoNCiMgZm9yKGkgaW4gMjpuY29sKG1vMncpKXsNCiMgICBmb3IoaiBpbiAyOm5yb3cobW8ydykpew0KIyAgICAgbW8yd1tqLCBpXSA8LSBpZmVsc2UoaXMubmEobW8yd1tqLCBpXSksIC05LCBtbzJ3W2osIGldKQ0KIyAgICAgbW8yd1tqLCBpXSA8LSBpZmVsc2UoKG1vMndbaiwgaV0+MSksIDEsIG1vMndbaiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyBNYWtlIGVhcmx5IHRpbWVzZXJpZXMgIk5BInMgaW50byBwbGF1c2libGUgdmFsdWUNCm1vMndTQU0gPC0gbW8yd1ttbzJ3JHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSwgXQ0KZm9yKGkgaW4gMTpuY29sKG1vMndTQU0pKXsNCiAgZm9yKGogaW4gMTpucm93KG1vMndTQU0pKXsNCiAgICBtbzJ3U0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShtbzJ3U0FNW2osIGldKSwgbWVkaWFuKGMobW8yd1NBTVssaV0pLCBuYS5ybSA9IFQpLCBtbzJ3U0FNW2osIGldKQ0KICAgIG1vMndbaiwgaV0gPC0gaWZlbHNlKChtbzJ3W2osIGldPjEpLCAxLCBtbzJ3W2osIGldKQ0KICB9DQp9DQoNCnJvd25hbWVzKG1vMncpIDwtIE5VTEwNCg0Kc2F2ZV9hc19sb3dlc3RvZnQoZGYgPSBtbzJ3W21vMnckeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdLA0KICAgICAgICAgICAgICAgICAgZmlsZV9wYXRoID0gIkFzc2Vzc21lbnQgSW5wdXQvQWx0ZXJuYXRlTW9kZWxfU1NiaW8vbW8uZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIk1hdHVyaXR5IE9naXZlIGZvciBQbGUuMjcuMjEtMzIuIFNtb290aCBTcGxpbmUgZm9yIGNvbWJpbmVkIHNleGVzLCBmcm9tIHN1cnZleSBkYXRhIiwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKDEsIDQpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpKQ0KDQprYWJsZShtbzJ3W21vMnckeWVhciA+PSAyMDAyLCBdLCANCiAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIk1hdHVyaXR5IE9naXZlcyBvZiBQbGUuMjcuMjEtMzIsIHVzaW5nIHNwbGluZSBzbW9vdGhlZCBlc3RpbWF0ZXMgZnJvbSBzdXJ2ZXkgb2JzZXJ2YXRpb25zIGZvciB0aGUgd2hvbGUgdGltZXNlcmllcywgMjAwMjoiLCBEYXRhWWVhcisxKSwNCiAgICAgIGRpZ2l0cyA9IDIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0gcGFzdGUwKCJNYXR1cml0eSBPZ2l2ZXMsIGFjdHVhbCB2YWx1ZXMgKGJsYWNrKSBhbmQgcHJlZGljdGVkIGZyb20gc21vb3RoZXIgKGNvbG91cnMpOyByaWJib25zID0gOTUlIENJLiIpLCBmaWcuaGVpZ2h0PTEwfQ0KIyBzd2FsYmEgPC0gbWVsdChzZXREVChXQUFfY29tYnNleCksIGlkLnZhcnMgPSAieWVhciIsIHZhcmlhYmxlLm5hbWUgPSAiQWdlIiwgdmFsdWUubmFtZSA9ICJNZWFuV2VpZ2h0IikNCg0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbW8yLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQpKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbW8yLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNtb290aFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IG1vMiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0gc21vb3RoUHJvcE1hdC0oMS45NipzZVNtb290aFByb3BNYXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSBzbW9vdGhQcm9wTWF0KygxLjk2KnNlU21vb3RoUHJvcE1hdCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjb2xvdXIgPSBBZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEFnZSksDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSkgKyANCiAgICAgICAgICAgZmFjZXRfd3JhcCgufkFnZSkrDQogICAgICAgICAgIHRoZW1lX2ZldygpKw0KICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpICsNCiAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGZ1bmN0aW9uKHgpIHByZXR0eSh4LCBuID0gNSkpICsNCiAgICAgICAgICAgIyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLCAwLjIsIDAuNCwgMC42KSkgKw0KICAgICAgICAgICAjIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDAuOTUpKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpDQopDQpgYGANCg0KSW4gcGxlbmFyeSBhdCB0aGUgQmVuY2htYXJrIFdvcmtzaG9wLCBpdCB3YXMgZGVjaWRlZCB0aGF0IHRoZSBsZXZlbHMgb2YgbWF0dXJpdHkgaW4gdGhlIGVhcmx5IGFnZXMgb2YgdGhlIGRhdGEgZG8gbm90IGxvb2sgYXBwcm9wcmlhdGUuIFRoaXMgY291bGQgYmUgZHVlIHRvIGJpYXMgaW4gdGVoIHNhbXBsaW5nIG9mIHRoZSBzdXJ2ZXlzLCB3aGVyZSBsYXJnZXIgZmlzaCBmcm9tIGEgZ2l2ZW4gYWdlIGdyb3VwIGFyZSBtb3JlIGxpa2VseSB0byBiZSBzYW1wbGVkIGluIHRoZSBkZWVwZXIgb3BlcmF0aW5nIGFyZWFzIG9mIHRoZSBzdXJ2ZXkgdmVzc2Vscy4gIFRoaXMgbWF5IGFsc28gYmUgZHVlIHRvIHRoZSBkaWZmaWN1bHR5IGluIGVzdGFibGlzaGluZyB0aGUgZmlyc3Qgd2ludGVyIHJpbmcgd2hlbiBhZ2luZywgbGVhZGluZyB0byBzb21lIGxhcmdlciB0d28gdG8gdGhyZWUgeWVhciBvbGRzIGJlaW5nIHJlYWQgYXMgYSB5ZWFyIHlvdW5nZXIgdGhhbiB0aGV5IGFyZS4NCg0KQmVjYXVzZSBvZiB0aGlzIHdlIGNhbiBwcm9kdWNlIHNvbWUgb2dpdmVzIHdpdGggYWdlcyAxLCBvciAxICYgMiBzZXQgdG8gemVybywgYmFzZWQgb24gZXhwZXJ0IG9waW5pb24uDQoNCmBgYHtyIGZpZy5jYXA9IkZpdmUteWVhciBzbGlkaW5nIHdpbmRvdyBtZWFuIG9mIG1hdHVyaXR5IGF0IGFnZSwgd2l0aCBhZ2UgMSBzZXQgdG8gMCwgcG9zdC1ob2MuIn0NCm1vNXN3TF8xemVybyA8LSBtbzVzd0wNCm1vNXN3TF8xemVyb1ttbzVzd0xfMXplcm8kQWdlTiAlaW4lIGMoMSksIGMoIlByb3BNYXQiLCAiU3RkRXJyUHJvcE1hdCIsInltYXgiLCAieW1pbiIpXSA8LSAwDQptbzVzd0xfMXplcm8keWVhckYgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihtbzVzd0xfMXplcm8keWVhcikpDQojIG1vNXN3TF8xemVybyRBZ2UgPC0gZmFjdG9yKGFzLmNoYXJhY3RlcihtbzVzd0xfMXplcm8kQWdlTiksIGxldmVscyA9IGFzLmNoYXJhY3Rlcihzb3J0KHVuaXF1ZShtbzVzd0xfMXplcm8kQWdlTikpKSkNCg0KbW81c3dXXzF6ZXJvIDwtIHJlc2hhcGUobW81c3dMXzF6ZXJvWywgYygieWVhciIsICJBZ2UiLCAiUHJvcE1hdCIpXSwNCiAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIndpZGUiKQ0KY29sbmFtZXMobW81c3dXXzF6ZXJvKSA8LSBnc3ViKHBhdHRlcm4gPSAiUHJvcE1hdC4iLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gY29sbmFtZXMobW81c3dXXzF6ZXJvKSkNCg0KDQojIyMgTWFrZSBlYXJseSB0aW1lc2VyaWVzICJOQSJzIGludG8gcGxhdXNpYmxlIHZhbHVlDQptbzVzd1dfMXplcm9TQU0gPC0gbW81c3dXXzF6ZXJvW21vNXN3V18xemVybyR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksIGMoLTEpXQ0KbW81c3dXXzF6ZXJvU0FNIDwtIG1vNXN3V18xemVyb1NBTVssIGFzLmNoYXJhY3Rlcihzb3J0KGFzLm51bWVyaWMobmFtZXMobW81c3dXXzF6ZXJvU0FNKSkpKV0NCmZvcihpIGluIDE6bmNvbChtbzVzd1dfMXplcm9TQU0pKXsNCiAgZm9yKGogaW4gMTpucm93KG1vNXN3V18xemVyb1NBTSkpew0KICAgIG1vNXN3V18xemVyb1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobW81c3dXXzF6ZXJvU0FNW2osIGldKSwgbWVkaWFuKGMobW81c3dXXzF6ZXJvU0FNWyxpXSksIG5hLnJtID0gVCksIG1vNXN3V18xemVyb1NBTVtqLCBpXSkNCiAgfQ0KfQ0KDQpzYXZlX2FzX2xvd2VzdG9mdChkZiA9IG1vNXN3V18xemVyb1NBTSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L01hdHVyaXR5VmFyaWFudHMvNXlzd18xemVyb21vLmRhdCIsDQogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJNYXR1cml0eSBPZ2l2ZSBmb3IgUGxlLjI3LjIxLTMyLiBGaXZlIHllYXIgc2xpZGluZyB3aW5kb3cgd2l0aCBhZ2UgMSBzZXQgdG8gMCwgY29tYmluZWQgc2V4ZXMsIGZyb20gc3VydmV5IGRhdGEiLA0KICAgICAgICAgICAgICAgICAgcmFuZG9fbnVtYmVycyA9IHBhc3RlKGMoMSwgNCksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgYWdlX3JhbmdlID0gcGFzdGUoYygxLCAxMCksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB0aW1lc2VyaWVzX3R5cGUgPSAxKQ0KDQpwbHRfbW81c3dMXzF6ZXJvIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtbzVzd0xfMXplcm8sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gUHJvcE1hdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0geWVhckYpKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBtbzVzd0xfMXplcm8sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IHltaW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSB5ZWFyRiksDQogICAgICAgICAgICBhbHBoYSA9IDAuMDUpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtb1ttbyR5ZWFyRiA9PSAiUnVubmluZyBNZWFuIixdLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYpLA0KICAgICAgICAgICAgY29sb3VyID0gIkJsYWNrIiwNCiAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gcm1zdGRyLA0KICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSB5bWluKSwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgICAgICBzaXplID0gMSkgKw0KICB0aGVtZV9jbGVhbigpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gZnVuY3Rpb24oeCkgcHJldHR5KHgsIG4gPSA1KSkgDQogIA0KZ2dwbG90bHkocGx0X21vNXN3TF8xemVybykNCmBgYA0KDQoNCmBgYHtyIGZpZy5jYXA9IkZpdmUteWVhciBzbGlkaW5nIHdpbmRvdyBtZWFuIG9mIG1hdHVyaXR5IGF0IGFnZSwgd2l0aCBhZ2VzIDEgJiAyIHNldCB0byAwLCBwb3N0LWhvYy4ifQ0KbW81c3dMXzJ6ZXJvIDwtIG1vNXN3TA0KbW81c3dMXzJ6ZXJvW21vNXN3TF8yemVybyRBZ2VOICVpbiUgYygxLDIpLCBjKCJQcm9wTWF0IiwgIlN0ZEVyclByb3BNYXQiLCJ5bWF4IiwgInltaW4iKV0gPC0gMA0KbW81c3dMXzJ6ZXJvJHllYXJGIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobW81c3dMXzJ6ZXJvJHllYXIpKQ0KDQpwbHRfbW81c3dMXzJ6ZXJvIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtbzVzd0xfMnplcm8sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gUHJvcE1hdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB5ZWFyRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0geWVhckYpKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBtbzVzd0xfMnplcm8sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IHltaW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSB5ZWFyRiksDQogICAgICAgICAgICBhbHBoYSA9IDAuMDUpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtb1ttbyR5ZWFyRiA9PSAiUnVubmluZyBNZWFuIixdLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BNYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0geWVhckYpLA0KICAgICAgICAgICAgY29sb3VyID0gIkJsYWNrIiwNCiAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gcm1zdGRyLA0KICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSB5bWluKSwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMywNCiAgICAgICAgICAgICAgICBzaXplID0gMSkgKw0KICB0aGVtZV9jbGVhbigpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gZnVuY3Rpb24oeCkgcHJldHR5KHgsIG4gPSA1KSkgDQogIA0KZ2dwbG90bHkocGx0X21vNXN3TF8yemVybykNCmBgYA0KDQoNCg0KIyMjIFNleCBSYXRpbw0KVGhlIHNleCByYXRpbyBpbiB0aGUgc3RvY2sgaGFzDQoNCmBgYHtyIGZpZy5jYXA9IlNleCByYXRpbyBvdmVyIHRpbWUsIGZhY2V0ZWQgYnkgYWdlLiJ9DQpzcl9sbmcgPC0gcmVzaGFwZShzZXhfcmF0aW9fZmVtYWxlLA0KICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGNvbG5hbWVzKHNleF9yYXRpb19mZW1hbGUpWy0xXSwNCiAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiUHJvcEZlbWFsZSIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKHNleF9yYXRpb19mZW1hbGUpWy0xXSwNCiAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0Kc3JfbG5nJEFnZU4gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZ3N1YihwYXR0ZXJuID0gImEiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gc3JfbG5nJEFnZSkpKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gc3JfbG5nLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFByb3BGZW1hbGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcCgufkFnZU4pKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSsNCiAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKSArDQogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgICAgIGd1aWRlcyhjb2xvdXIgPSAibm9uZSIsIGZpbGwgPSAibm9uZSIpDQopDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU2V4IHJhdGlvcy4gQWdlcyBmYWNldGVkIGJ5IHRpbWUuIn0NCmdncGxvdGx5KGdncGxvdChzcl9sbmcpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBQcm9wRmVtYWxlKSkgKw0KICAgICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAyKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gInllYXIiKSArDQogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KYGBgDQoNCiMjIyBTdG9jayBXZWlnaHQgQXQgQWdlIChTV0FBKQ0KVGhlIHN0b2NrIG1lYW4gd2VpZ2h0cyBieSBhZ2Ugd2VyZSBjYWxjdWxhdGVkIGZyb20gdGhlIHR3byBmaXJzdCBxdWFydGVyIHN1cnZleXMgZm9yIGVhY2ggaW5kaXZpZHVhbCB5ZWFyLiAgQklUUyBkYXRhIG9ubHkgZXhpc3QgZm9yIHRoZSBwZXJpb2Qgc2luY2UgMjAwOCBhbmQgTlMtSUJUUyBvbmx5IGZvciB0aGUgcGVyaW9kIHNpbmNlIDIwMDMuIFRoZXJlZm9yZSwgcHJpb3IgdG8gMjAxOSB0aGUgQklUUyBzZXJpZXMgd2FzIGV4dGVuZGVkIGJhY2t3YXJkcyB0byAyMDAzIGJhc2VkIG9uIHRoZSBhdmVyYWdlIG9mIDIwMDggdG8gMjAxMi4gSG93ZXZlciwgaW4gMjAxOSBpdCB3YXMgZm91bmQgb3V0IHRoYXQgdGhlIHByb2NlZHVyZSB1c2VkIGZvciBjb21wdXRpbmcgdGhpcyBhdmVyYWdlIHdhcyBlcnJvbmVvdXMsIGNvbXB1dGluZyBvbmx5IGEgc2ltcGxlIGF2ZXJhZ2UgYWNyb3NzIGFsbCBsZW5ndGggY2xhc3NlcyB3aXRob3V0IHdlaWdodGluZyBieSB0aGUgbnVtYmVyIG9mIGluZGl2aWR1YWxzIHdpdGhpbiBlYWNoIGxlbmd0aCBjbGFzcy4gVGhpcyBsZWFkIHRvIGEgdmVyeSBoaWdoIGVzdGltYXRlIG9mIHRoZSBtZWFuIHdlaWdodCBvZiB0aGUgb2xkZXIgZmlzaCwgYmVpbmcgZHJpdmVuIHVwIGJ5IHZlcnkgZmV3IG9ic2VydmF0aW9ucy4gQSBtb3JlIHN0YW5kYXJkIHByb2NlZHVyZSB3aXRoIHdlaWdodGVkIGF2ZXJhZ2Ugd2FzIGltcGxlbWVudGVkIGluIDIwMTkgKHRoZSBzYW1lIHByb2NlZHVyZSBhcyB1c2VkIGZvciBXZXN0ZXJuIEJhbHRpYyBjb2QpLiBUaGUgY29tbW9uIHNlcmllcyBpcyBmaW5hbGx5IGV4dGVuZGVkIGJhY2t3YXJkcyB0byAxOTk5IGJhc2VkIG9uIHRoZSBhdmVyYWdlIG9mIDIwMDMgdG8gMjAwNy4NCg0KQXMgZm9yIHRoZSBtYXR1cml0eSBvZ2l2ZXMsIHRoZSBTV0FBIG11c3QgYmUgY2FsY3VsYXRlZCBmcm9tIHRoZSByYXcgREFUUkFTIEV4Y2hhbmdlIHByb2R1Y3RzLiBUaGVzZSB3ZXJlIHJlYWQtaW4gYW5kIGNsZWFuZWQgaW4gYSBwcmV2aW91cyBzZWN0aW9uLiANCg0KVGhlIGJlbG93IGNodW5rcyAoaGlkZGVuKSBwcmVwYXJlIHRoZSBkYXRhLCBnZW5lcmF0ZSB1cC10by1kYXRlIFNXQUEgZm9yIHRoZSBhc3Nlc3NtZW50IGFuZCBwbG90cyBhIHRoZXNlIG91dCBpbiBmaWd1cmVzIGZvciBwcmVzZW50YXRpb25zL3JlcG9ydGluZy4gVGhlIGZsdWN0dWF0aW5nIHN0b2NrIG1lYW4gd2VpZ2h0cyBvZiB0aGUgb2xkZXIgYWdlIGNsYXNzZXMgaXMgY2F1c2VkIGJ5IHRoZSBzbWFsbCBudW1iZXIgb2YgaW5kaXZpZHVhbHMgY2F1Z2h0IGF0IHRoZSBzdXJ2ZXlzIGFuZCB0aGUgZXh0cmVtZWx5IGhpZ2ggdmFyaWFiaWxpdHkgb2Ygd2VpZ2h0IGZvciB0aGVzZSBhZ2UgY2xhc3Nlcy4NCg0KYGBge3IgU1dBQUNhbGNzfQ0KIz09PQ0KIyBTdWJzZXQgcHJvY2Vzc2VkIGV4Y2hhbmdlIGRhdGEgLS0tLQ0KIz09PQ0KIyBTZWxlY3QgdGhlIFNEIGFuZCBxdWFydGVyDQpjYV9xMTwtc3Vic2V0KGNhX2hoX2Zpbl9iaXRzX2lidHMsUXVhcnRlcj09MSZBZ2UhPS05JkFnZSE9MCZBZ2U8MTUpDQpobF9xMTwtc3Vic2V0KGhsX2hoX2Zpbl9iaXRzX2lidHMsUXVhcnRlcj09MSkNCiM9PT09PQ0KDQojPT09DQojIFN1bW1hcmlzZSBhbmQgYWdncmVnYXRlIGRhdGEgLS0tLQ0KIz09PQ0KIyBBZGQgMSB0byBhbGwgcm93cyBqdXN0IHRvIGJlIGFibGUgdG8gY291bnQgdGhlIGZpc2gNCmNhX3ExJE5yX2Zpc2g8LTENCg0KIyBSb3VuZCB0aGUgbGVuZ3RoIGNsYXNzDQpjYV9xMSRSTG5ndENsYXNzPC1yb3VuZChjYV9xMSRMbmd0Q2xhc3MpDQoNCiMgSG93IG1hbnkgZmlzaCB3ZSBoYXZlDQpucl9maXNoPC1hZ2dyZWdhdGUoY2FfcTEkQ0FOb0F0TG5ndCwNCiAgICAgICAgICAgICAgICAgICBieT1saXN0KGNhX3ExJENvdW50cnksY2FfcTEkUXVhcnRlcixjYV9xMSRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICBGVU49Imxlbmd0aCIpDQoNCm5yX2Zpc2g8LSBhZ2dyZWdhdGUoY2FfcTEkTnJfZmlzaCwNCiAgICAgICAgICAgICAgICAgICAgYnk9bGlzdChjYV9xMSRZZWFyLGNhX3ExJFNleCxjYV9xMSRSTG5ndENsYXNzLGNhX3ExJEFnZSksDQogICAgICAgICAgICAgICAgICAgIEZVTj0ic3VtIiwNCiAgICAgICAgICAgICAgICAgICAgbmEucm09VCkNCm5hbWVzKG5yX2Zpc2gpPC1jKCJ5ZWFyIiwic2V4IiwiTG5ndENsYXNzIiwiYWdlIiwibnJfZmlzaCIpDQoNCiMgQWdncmVnYXRlIG51bWJlciBvZiBmaXNoIGFuZCBhdmVyYWdlIHdlaWdodCBpbiBzYW1wbGVzDQp3ZWlnaHQ8LWFnZ3JlZ2F0ZShjYV9xMSRJbmRXZ3QsDQogICAgICAgICAgICAgICAgICBieT1saXN0KGNhX3ExJFllYXIsY2FfcTEkU2V4LHJvdW5kKGNhX3ExJFJMbmd0Q2xhc3MpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjYV9xMSRBZ2UpLA0KICAgICAgICAgICAgICAgICAgRlVOPSJtZWFuIixuYS5ybT1UKQ0KbmFtZXMod2VpZ2h0KTwtYygieWVhciIsInNleCIsIkxuZ3RDbGFzcyIsImFnZSIsIndlaWdodCIpDQojPT09PT0NCg0KIz09PQ0KIyBMZW5ndGggRnJlcXVlbmNpZXMgImF0IHNlYSIgLS0tLQ0KIz09PQ0KIyBTZXQgcGFyYW1ldGVycyBmb3IgZGF0YQ0KbGVuY2w8LWMoNDo2MCkNCmFnZTwtYygxOjEwKQ0KeWVhcjwtYygxOTk5OihEYXRhWWVhcisxKSkNCg0KIyBNYWtlIHRhYmxlcyBmb3IgbGVuZ3RoIGZyZXEgZGF0YQ0KbGVuZ3RoX2ZyZXFfdG1wPC1ieShobF9xMSxsaXN0KGhsX3ExJFllYXIscm91bmQoaGxfcTEkTG5ndENsYXNzKSksZnVuY3Rpb24gKHgpew0KICBzdW0oeCRITE5vQXRMbmd0XzEpDQp9KQ0KbGVuZ3RoX2ZyZXFfdGFiPC10KGFzLnRhYmxlKGxlbmd0aF9mcmVxX3RtcCkpDQpMZnJlcV9zZWE8LWRhdGEuZnJhbWUoeWVhcj1yZXAoeWVhciwgZWFjaD1sZW5ndGgobGVuY2wpKSxMbmd0Q2xhc3M9cmVwKGxlbmNsLGxlbmd0aCh5ZWFyKSksSExOb0xuZ3Q9TkEpDQoNCiMgRmlsbCB0aGUgdGFibGUNCmZvciAoaSBpbiBjKDE6bnJvdyhMZnJlcV9zZWEpKSl7DQogIHllYXJfaTwtTGZyZXFfc2VhW2ksbmFtZXMoTGZyZXFfc2VhKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogIGxlbmNsX2k8LUxmcmVxX3NlYVtpLG5hbWVzKExmcmVxX3NlYSk9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogIA0KICBpZihsZW5jbF9pJWluJWMoYXMubnVtZXJpYyhkaW1uYW1lcyhsZW5ndGhfZnJlcV90YWIpW1sxXV0pKSl7DQogICAgDQogICAgZGF0YV9pPC1sZW5ndGhfZnJlcV90YWJbYXMubnVtZXJpYyhkaW1uYW1lcyhsZW5ndGhfZnJlcV90YWIpW1sxXV0pPT1sZW5jbF9pLGRpbW5hbWVzKGxlbmd0aF9mcmVxX3RhYilbWzJdXT09eWVhcl9pXQ0KICAgIExmcmVxX3NlYVtpLG5hbWVzKExmcmVxX3NlYSk9PWFzLmNoYXJhY3RlcigiSExOb0xuZ3QiKV08LWRhdGFfaQ0KICAgIA0KICB9ZWxzZXsNCiAgICBMZnJlcV9zZWFbaSxuYW1lcyhMZnJlcV9zZWEpPT1hcy5jaGFyYWN0ZXIoIkhMTm9Mbmd0IildPC0wICAgICAgIA0KICB9DQp9DQoNCiMgcmVwbGFjZSBOQSB3aXRoIDANCkxmcmVxX3NlYVt3aGljaChpcy5uYShMZnJlcV9zZWEkSExOb0xuZ3QpKSxuYW1lcyhMZnJlcV9zZWEpPT1hcy5jaGFyYWN0ZXIoIkhMTm9Mbmd0IildPC0wDQoNCiM9PT09PQ0KDQojPT09DQojIFN1bW1hcnkgb2Ygc2FtcGxlZCBmaXNoOiB3ZWlnaHQgYnkgbGVuZ3RoIGFuZCBieSBhZ2UgLS0tLQ0KIz09PQ0KIyBOdW1iZXIgb2Ygc2FtcGxlcw0KIyMgTWFrZSB0YWJsZXMgIA0KbnJfZmlzaF9zYW1wX0Y8LWRhdGEuZnJhbWUoeWVhcj1yZXAoeWVhciwgZWFjaD1sZW5ndGgobGVuY2wpKSxMbmd0Q2xhc3M9cmVwKGxlbmNsLGxlbmd0aCh5ZWFyKSksIGExPU5BLGEyPU5BLGEzPU5BLGE0PU5BLGE1PU5BLGE2PU5BLGE3PU5BLGE4PU5BLGE5PU5BLGExMD1OQSkNCm5yX2Zpc2hfc2FtcF9NPC1ucl9maXNoX3NhbXBfRg0KDQp3Z3Rfc2FtcF9GPC1ucl9maXNoX3NhbXBfRg0Kd2d0X3NhbXBfTTwtbnJfZmlzaF9zYW1wX00NCg0KIyMgRmlsbGluZyB0aGUgdGFibGVzOiANCiMjIyBGZW1hbGUgIA0KZm9yIChpIGluIDE6bnJvdyggbnJfZmlzaF9zYW1wX0YpKXsNCiAgZm9yIChqIGluIDM6bmNvbCggbnJfZmlzaF9zYW1wX0YpKXsNCiAgICB5ZWFyX2k8LW5yX2Zpc2hfc2FtcF9GW2ksbmFtZXMobnJfZmlzaF9zYW1wX0YpPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBsZW5jbF9pPC1ucl9maXNoX3NhbXBfRltpLG5hbWVzKG5yX2Zpc2hfc2FtcF9GKT09YXMuY2hhcmFjdGVyKCJMbmd0Q2xhc3MiKV0NCiAgICBhZ2VfaTwtai0yDQogICAgDQogICAgaWYobGVuY2xfaSVpbiUgd2VpZ2h0W3doaWNoKHdlaWdodCR5ZWFyPT15ZWFyX2kmd2VpZ2h0JHNleD09YXMuY2hhcmFjdGVyKCJGIikmIHdlaWdodCRhZ2U9PWFnZV9pKSxuYW1lcyh3ZWlnaHQpPT1hcy5jaGFyYWN0ZXIoIkxuZ3RDbGFzcyIpXSl7DQogICAgICANCiAgICAgIHNob3dfd2d0PC13ZWlnaHRbd2hpY2god2VpZ2h0JHllYXI9PXllYXJfaSZ3ZWlnaHQkTG5ndENsYXNzPT1sZW5jbF9pJndlaWdodCRzZXg9PWFzLmNoYXJhY3RlcigiRiIpJndlaWdodCRhZ2U9PWFnZV9pKSxdDQogICAgICBzaG93X25yPC1ucl9maXNoW3doaWNoKG5yX2Zpc2gkeWVhcj09eWVhcl9pJm5yX2Zpc2gkTG5ndENsYXNzPT1sZW5jbF9pJm5yX2Zpc2gkc2V4PT1hcy5jaGFyYWN0ZXIoIkYiKSZucl9maXNoJGFnZT09YWdlX2kpLF0NCiAgICAgIA0KICAgICAgbnJfZmlzaF9zYW1wX0ZbaSxqXTwtc3VtKHNob3dfbnIkbnJfZmlzaCkNCiAgICAgIHdndF9zYW1wX0ZbaSxqXTwtbWVhbihzaG93X3dndCR3ZWlnaHQsIG5hLnJtPVQpDQogICAgICANCiAgICB9IGVsc2V7ICAgICAgICAgICAgICANCiAgICAgIG5yX2Zpc2hfc2FtcF9GW2ksal08LTANCiAgICAgIHdndF9zYW1wX0ZbaSxqXTwtTkENCiAgICB9DQogIH0NCn0NCg0KIyMjIE1hbGUNCmZvciAoaSBpbiAxOm5yb3coIG5yX2Zpc2hfc2FtcF9NKSl7DQogIGZvciAoaiBpbiAzOm5jb2woIG5yX2Zpc2hfc2FtcF9NKSl7DQogICAgeWVhcl9pPC1ucl9maXNoX3NhbXBfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9NKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgbGVuY2xfaTwtbnJfZmlzaF9zYW1wX01baSxuYW1lcyhucl9maXNoX3NhbXBfTSk9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogICAgYWdlX2k8LWotMg0KICAgIA0KICAgIGlmKGxlbmNsX2klaW4lIHdlaWdodFt3aGljaCh3ZWlnaHQkeWVhcj09eWVhcl9pJndlaWdodCRzZXg9PWFzLmNoYXJhY3RlcigiTSIpJiB3ZWlnaHQkYWdlPT1hZ2VfaSksbmFtZXMod2VpZ2h0KT09YXMuY2hhcmFjdGVyKCJMbmd0Q2xhc3MiKV0pew0KICAgICAgDQogICAgICBzaG93X3dndDwtd2VpZ2h0W3doaWNoKHdlaWdodCR5ZWFyPT15ZWFyX2kmd2VpZ2h0JExuZ3RDbGFzcz09bGVuY2xfaSZ3ZWlnaHQkc2V4PT1hcy5jaGFyYWN0ZXIoIk0iKSZ3ZWlnaHQkYWdlPT1hZ2VfaSksXQ0KICAgICAgc2hvd19ucjwtbnJfZmlzaFt3aGljaChucl9maXNoJHllYXI9PXllYXJfaSZucl9maXNoJExuZ3RDbGFzcz09bGVuY2xfaSZucl9maXNoJHNleD09YXMuY2hhcmFjdGVyKCJNIikmbnJfZmlzaCRhZ2U9PWFnZV9pKSxdDQogICAgICANCiAgICAgIG5yX2Zpc2hfc2FtcF9NW2ksal08LXN1bShzaG93X25yJG5yX2Zpc2gpDQogICAgICB3Z3Rfc2FtcF9NW2ksal08LW1lYW4oc2hvd193Z3Qkd2VpZ2h0LCBuYS5ybT1UKQ0KICAgICAgDQogICAgfSBlbHNleyAgICAgICAgICAgICAgDQogICAgICBucl9maXNoX3NhbXBfTVtpLGpdPC0wDQogICAgICB3Z3Rfc2FtcF9NW2ksal08LU5BDQogICAgfQ0KICB9DQp9DQoNCiMgTnVtYmVyIG9mIGZpc2ggc2FtcGxlZCBieSBsZW5ndGggY2xhc3M6DQojIyBGZW1hbGUNCm5yX2Zpc2hfc2FtcF9GJHRvdDwtTkENCg0KZm9yIChpIGluIDE6bnJvdyhucl9maXNoX3NhbXBfRikpew0KICBucl9maXNoX3NhbXBfRltpLG5hbWVzKG5yX2Zpc2hfc2FtcF9GKT09YXMuY2hhcmFjdGVyKCJ0b3QiKV08LXN1bShucl9maXNoX3NhbXBfRltpLG5hbWVzKG5yX2Zpc2hfc2FtcF9GKSVpbiVjKCJhMSIsImEyIiwiYTMiLCJhNCIsImE1IiwiYTYiLCJhNyIsImE4IiwiYTkiLCJhMTAiKV0pDQp9DQoNCiMjICBNYWxlICAgICAgICANCm5yX2Zpc2hfc2FtcF9NJHRvdDwtTkENCg0KZm9yIChpIGluIDE6bnJvdyhucl9maXNoX3NhbXBfTSkpew0KICBucl9maXNoX3NhbXBfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9NKT09YXMuY2hhcmFjdGVyKCJ0b3QiKV08LXN1bShucl9maXNoX3NhbXBfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9NKSVpbiVjKCJhMSIsImEyIiwiYTMiLCJhNCIsImE1IiwiYTYiLCJhNyIsImE4IiwiYTkiLCJhMTAiKV0pDQp9DQoNCiMjIEYgYW5kIE0gY29tYmluZWQNCkxmcmVxX3NhbXA8LWRhdGEuZnJhbWUoeWVhcj1yZXAoeWVhciwgZWFjaD1sZW5ndGgobGVuY2wpKSxMbmd0Q2xhc3M9cmVwKGxlbmNsLGxlbmd0aCh5ZWFyKSksIHRvdF9zYW1wPU5BKQ0KDQpmb3IgKGkgaW4gMTpucm93KExmcmVxX3NhbXApKXsNCiAgeWVhcl9pPC1MZnJlcV9zYW1wW2ksbmFtZXMoTGZyZXFfc2FtcCk9PWFzLmNoYXJhY3RlcigieWVhciIpXQ0KICBsZW5jbF9pPC1MZnJlcV9zYW1wW2ksbmFtZXMoTGZyZXFfc2FtcCk9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogIA0KICBGX3N1bTwtbnJfZmlzaF9zYW1wX0Zbd2hpY2gobnJfZmlzaF9zYW1wX0YkeWVhcj09eWVhcl9pJm5yX2Zpc2hfc2FtcF9GJExuZ3RDbGFzcz09bGVuY2xfaSksbmFtZXMobnJfZmlzaF9zYW1wX0YpPT1hcy5jaGFyYWN0ZXIoInRvdCIpXQ0KICBNX3N1bTwtbnJfZmlzaF9zYW1wX01bd2hpY2gobnJfZmlzaF9zYW1wX00keWVhcj09eWVhcl9pJm5yX2Zpc2hfc2FtcF9NJExuZ3RDbGFzcz09bGVuY2xfaSksbmFtZXMobnJfZmlzaF9zYW1wX00pPT1hcy5jaGFyYWN0ZXIoInRvdCIpXQ0KICANCiAgTGZyZXFfc2FtcFtpLG5hbWVzKExmcmVxX3NhbXApPT1hcy5jaGFyYWN0ZXIoInRvdF9zYW1wIildIDwtRl9zdW0rIE1fc3VtIA0KfSAgDQoNCiMgTnVtYmVyIG9mIGZpc2ggc2FtcGxlZCBieSBhZ2U6DQojIyBNYWtlIHRhYmxlcw0KdG90X3NhbXBfYWdlX0Y8LWRhdGEuZnJhbWUoeWVhcj15ZWFyLGExPU5BLGEyPU5BLGEzPU5BLGE0PU5BLGE1PU5BLGE2PU5BLGE3PU5BLGE4PU5BLGE5PU5BLGExMD1OQSkNCnRvdF9zYW1wX2FnZV9NPC1kYXRhLmZyYW1lKHllYXI9eWVhcixhMT1OQSxhMj1OQSxhMz1OQSxhND1OQSxhNT1OQSxhNj1OQSxhNz1OQSxhOD1OQSxhOT1OQSxhMTA9TkEpICANCg0KIyMgRmVtYWxlDQpmb3IgKGkgaW4gMTpucm93KHRvdF9zYW1wX2FnZV9GKSl7DQogIGZvciAoaiBpbiAyOm5jb2wodG90X3NhbXBfYWdlX0YpKXsgDQogICAgDQogICAgeWVhcl9pPC10b3Rfc2FtcF9hZ2VfRltpLG5hbWVzKHRvdF9zYW1wX2FnZV9GKT09YXMuY2hhcmFjdGVyKCJ5ZWFyIildDQogICAgc2hvd19kYXRhPC0gbnJfZmlzaF9zYW1wX0Zbd2hpY2gobnJfZmlzaF9zYW1wX0YkeWVhcj09eWVhcl9pKSxdDQogICAgDQogICAgdG90X3NhbXBfYWdlX0ZbaSxqXTwtc3VtKHNob3dfZGF0YVssbmFtZXMoc2hvd19kYXRhKT09bmFtZXModG90X3NhbXBfYWdlX0YpW2pdXSkNCiAgfSANCn0NCg0KIyMgTWFsZQ0KZm9yIChpIGluIDE6bnJvdyh0b3Rfc2FtcF9hZ2VfTSkpew0KICBmb3IgKGogaW4gMjpuY29sKHRvdF9zYW1wX2FnZV9NKSl7IA0KICAgIA0KICAgIHllYXJfaTwtdG90X3NhbXBfYWdlX01baSxuYW1lcyh0b3Rfc2FtcF9hZ2VfTSk9PWFzLmNoYXJhY3RlcigieWVhciIpXQ0KICAgIHNob3dfZGF0YTwtIG5yX2Zpc2hfc2FtcF9NW3doaWNoKG5yX2Zpc2hfc2FtcF9NJHllYXI9PXllYXJfaSksXQ0KICAgIA0KICAgIHRvdF9zYW1wX2FnZV9NW2ksal08LXN1bShzaG93X2RhdGFbLG5hbWVzKHNob3dfZGF0YSk9PW5hbWVzKHRvdF9zYW1wX2FnZV9NKVtqXV0pDQogIH0gDQp9DQojPT09PT0NCg0KIz09PQ0KIyBTZXggUmF0aW9zIC0tLS0NCiM9PT0NCiMgTWFrZSB0YWJsZXMNCnNleF9yYXRpb19GPC0gdG90X3NhbXBfYWdlX0YNCnNleF9yYXRpb19GWywtMV08LU5BDQoNCiMgRmlsbCB0YWJsZXMNCmZvciAoaSBpbiAxOm5yb3coc2V4X3JhdGlvX0YpKXsNCiAgZm9yIChqIGluIDI6bmNvbChzZXhfcmF0aW9fRikpew0KICAgIHNleF9yYXRpb19GW2ksal08LXRvdF9zYW1wX2FnZV9GW2ksal0vKHRvdF9zYW1wX2FnZV9GW2ksal0rdG90X3NhbXBfYWdlX01baSxqXSkNCiAgfQ0KfQ0KIz09PT09DQoNCiM9PT0NCiMgRnVsbCBzdXJ2ZXkgbnVtYmVycyBmb3IgcmFpc2luZyAtLS0tDQojPT09DQojIE1ha2UgVGFibGVzDQpucl9maXNoX3NlYV9NPC1ucl9maXNoX3NhbXBfTQ0KbnJfZmlzaF9zZWFfTVssLSgxOjIpXTwtTkENCm5yX2Zpc2hfc2VhX0Y8LW5yX2Zpc2hfc2VhX00NCg0KIyMgRmVtYWxlDQpmb3IgKGkgaW4gMTpucm93KG5yX2Zpc2hfc2VhX0YpKXsNCiAgZm9yIChqIGluIDM6KG5jb2wobnJfZmlzaF9zZWFfRiktMSkpew0KICAgIGlmKG5yX2Zpc2hfc2FtcF9GJHRvdFtpXT4wJiFpcy5uYShMZnJlcV9zZWEkSExOb0xuZ3RbaV0pKXsNCiAgICAgIA0KICAgICAgcGN0X2FnZV90b3Q8LW5yX2Zpc2hfc2FtcF9GW2ksal0vbnJfZmlzaF9zYW1wX0ZbaSxuYW1lcyhucl9maXNoX3NhbXBfRik9PWFzLmNoYXJhY3RlcigidG90IildICAgDQogICAgICBGX01fcmF0aW88LW5yX2Zpc2hfc2FtcF9GW2ksbmFtZXMobnJfZmlzaF9zYW1wX0YpPT1hcy5jaGFyYWN0ZXIoInRvdCIpXS9MZnJlcV9zYW1wJHRvdF9zYW1wW2ldDQogICAgICBMZnJlcTwtTGZyZXFfc2VhJEhMTm9Mbmd0W2ldDQogICAgICANCiAgICAgIG5yX2Zpc2hfc2VhX0ZbaSxqXTwtcGN0X2FnZV90b3QqTGZyZXEqIEZfTV9yYXRpbw0KICAgIH1lbHNlew0KICAgICAgbnJfZmlzaF9zZWFfRltpLGpdPC0wIA0KICAgIH0NCiAgfQ0KfSAgICAgICAgICAgDQoNCiMjIE1hbGUNCmZvciAoaSBpbiAxOm5yb3cobnJfZmlzaF9zZWFfTSkpew0KICBmb3IgKGogaW4gMzoobmNvbChucl9maXNoX3NlYV9NKS0xKSl7DQogICAgaWYobnJfZmlzaF9zYW1wX00kdG90W2ldPjAmIWlzLm5hKExmcmVxX3NlYSRITE5vTG5ndFtpXSkpew0KICAgICAgDQogICAgICBwY3RfYWdlX3RvdDwtbnJfZmlzaF9zYW1wX01baSxqXS9ucl9maXNoX3NhbXBfTVtpLG5hbWVzKG5yX2Zpc2hfc2FtcF9NKT09YXMuY2hhcmFjdGVyKCJ0b3QiKV0gICANCiAgICAgIE1fRl9yYXRpbzwtbnJfZmlzaF9zYW1wX01baSxuYW1lcyhucl9maXNoX3NhbXBfTSk9PWFzLmNoYXJhY3RlcigidG90IildL0xmcmVxX3NhbXAkdG90X3NhbXBbaV0NCiAgICAgIExmcmVxPC1MZnJlcV9zZWEkSExOb0xuZ3RbaV0NCiAgICAgIA0KICAgICAgbnJfZmlzaF9zZWFfTVtpLGpdPC1wY3RfYWdlX3RvdCpMZnJlcSogTV9GX3JhdGlvDQogICAgfWVsc2V7DQogICAgICBucl9maXNoX3NlYV9NW2ksal08LTAgDQogICAgfQ0KICB9DQp9ICAgICAgICAgICANCg0KIyBTdW0gb2YgbnVtYmVycyBvdmVyIGFnZS1ncm91cHMsIGJ5IGxlbmd0aA0KIyMgRmVtYWxlcw0KZm9yIChpIGluIDE6bnJvdyhucl9maXNoX3NlYV9GKSl7DQogIG5yX2Zpc2hfc2VhX0ZbaSxuYW1lcyhucl9maXNoX3NlYV9GKT09YXMuY2hhcmFjdGVyKCJ0b3QiKV08LXN1bShucl9maXNoX3NlYV9GW2ksbmFtZXMobnJfZmlzaF9zZWFfRiklaW4lYygiYTEiLCJhMiIsImEzIiwiYTQiLCJhNSIsImE2IiwiYTciLCJhOCIsImE5IiwiYTEwIildKSAgIA0KfSAgICANCiMjIE1hbGVzDQpmb3IgKGkgaW4gMTpucm93KG5yX2Zpc2hfc2VhX00pKXsNCiAgbnJfZmlzaF9zZWFfTVtpLG5hbWVzKCBucl9maXNoX3NlYV9NKT09YXMuY2hhcmFjdGVyKCJ0b3QiKV08LXN1bShucl9maXNoX3NlYV9NW2ksbmFtZXMobnJfZmlzaF9zZWFfTSklaW4lYygiYTEiLCJhMiIsImEzIiwiYTQiLCJhNSIsImE2IiwiYTciLCJhOCIsImE5IiwiYTEwIildKSAgIA0KfSAgDQoNCiMgU3VtIG9mIG51bWJlcnMgb3ZlciBsZW5ndGgtZ3JvdXBzLCBieSBhZ2UNCiMjIE1ha2UgdGFibGVzDQpzdW1fbnJfZmlzaF9zZWFfRjwtdG90X3NhbXBfYWdlX0YNCnN1bV9ucl9maXNoX3NlYV9GWywtMV08LU5BDQpzdW1fbnJfZmlzaF9zZWFfTTwtc3VtX25yX2Zpc2hfc2VhX0YNCg0KIyMgRmVtYWxlcw0KZm9yIChpIGluIDE6bnJvdyhzdW1fbnJfZmlzaF9zZWFfRikpeyANCiAgZm9yIChqIGluIDI6bmNvbChzdW1fbnJfZmlzaF9zZWFfRikpeyANCiAgICB5ZWFyX2k8LXN1bV9ucl9maXNoX3NlYV9GW2ksbmFtZXMoc3VtX25yX2Zpc2hfc2VhX0YpPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fbnJfZmlzaF9zZWFfRltpLGpdPC1zdW0obnJfZmlzaF9zZWFfRlt3aGljaChucl9maXNoX3NlYV9GJHllYXI9PXllYXJfaSksbmFtZXMobnJfZmlzaF9zZWFfRik9PW5hbWVzKHN1bV9ucl9maXNoX3NlYV9GKVtqXV0pIA0KICB9IA0KfQ0KDQojIyBNYWxlcw0KZm9yIChpIGluIDE6bnJvdyhzdW1fbnJfZmlzaF9zZWFfTSkpeyANCiAgZm9yIChqIGluIDI6bmNvbChzdW1fbnJfZmlzaF9zZWFfTSkpeyANCiAgICB5ZWFyX2k8LXN1bV9ucl9maXNoX3NlYV9NW2ksbmFtZXMoc3VtX25yX2Zpc2hfc2VhX00pPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fbnJfZmlzaF9zZWFfTVtpLGpdPC1zdW0obnJfZmlzaF9zZWFfTVt3aGljaChucl9maXNoX3NlYV9NJHllYXI9PXllYXJfaSksbmFtZXMobnJfZmlzaF9zZWFfTSk9PW5hbWVzKHN1bV9ucl9maXNoX3NlYV9NKVtqXV0pIA0KICB9IA0KfQ0KDQojPT09PT0NCg0KIz09PQ0KIyBSYWlzZSBwcm9wb3J0aW9ucyB0byBmdWxsIHN1cnZleSBudW1iZXJzIC0tLS0NCiM9PT0NCiMgTWFrZSB0YWJsZXMNCndndF9ucl9GPC1ucl9maXNoX3NlYV9GDQp3Z3RfbnJfRlssMzpuY29sKHdndF9ucl9GKV08LU5BDQp3Z3RfbnJfTTwtd2d0X25yX0YNCg0KIyMgRmVtYWxlDQpmb3IgKGkgaW4gMTpucm93KHdndF9ucl9GKSl7DQogIGZvciAoaiBpbiAzOihuY29sKHdndF9ucl9GKS0xKSkgew0KICAgIGlmKG5yX2Zpc2hfc2VhX0ZbaSxqXT4wJiFpcy5uYSh3Z3Rfc2FtcF9GW2ksal0pKXsNCiAgICAgIHdndDwtd2d0X3NhbXBfRltpLGpdDQogICAgICBucjwtbnJfZmlzaF9zZWFfRltpLGpdDQogICAgICB3Z3RfbnJfRltpLGpdPC13Z3QqbnINCiAgICB9ZWxzZXsNCiAgICAgIHdndF9ucl9GW2ksal08LTANCiAgICB9DQogIH0NCn0gICANCg0KIyMgTWFsZQ0KZm9yIChpIGluIDE6bnJvdyh3Z3RfbnJfTSkpew0KICBmb3IgKGogaW4gMzoobmNvbCh3Z3RfbnJfTSktMSkpIHsNCiAgICBpZihucl9maXNoX3NlYV9NW2ksal0+MCYhaXMubmEod2d0X3NhbXBfTVtpLGpdKSl7DQogICAgICB3Z3Q8LXdndF9zYW1wX01baSxqXQ0KICAgICAgbnI8LW5yX2Zpc2hfc2VhX01baSxqXQ0KICAgICAgd2d0X25yX01baSxqXTwtd2d0Km5yDQogICAgfWVsc2V7DQogICAgICB3Z3RfbnJfTVtpLGpdPC0wDQogICAgfQ0KICB9DQp9IA0KDQojIFN1bSB3ZWlnaHRzIGJ5IGFnZSBvdmVyIGxlbmd0aCBjbGFzc2VzDQojIyBNYWtlIFRhYmxlcw0Kc3VtX3dndF9ucl9GPC10b3Rfc2FtcF9hZ2VfRg0Kc3VtX3dndF9ucl9GWywtMV08LU5BDQpzdW1fd2d0X25yX008LXN1bV93Z3RfbnJfRg0KDQojIyBGZW1hbGVzDQpmb3IgKGkgaW4gMTpucm93KHN1bV93Z3RfbnJfRikpeyANCiAgZm9yIChqIGluIDI6bmNvbChzdW1fd2d0X25yX0YpKXsgDQogICAgeWVhcl9pPC1zdW1fd2d0X25yX0ZbaSxuYW1lcyhzdW1fd2d0X25yX0YpPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fd2d0X25yX0ZbaSxqXTwtc3VtKHdndF9ucl9GW3doaWNoKHdndF9ucl9GJHllYXI9PXllYXJfaSksbmFtZXMod2d0X25yX0YpPT1uYW1lcyhzdW1fd2d0X25yX0YpW2pdXSkgDQogIH0gDQp9DQoNCiMjIE1hbGVzDQpmb3IgKGkgaW4gMTpucm93KHN1bV93Z3RfbnJfTSkpeyANCiAgZm9yIChqIGluIDI6bmNvbChzdW1fd2d0X25yX00pKXsgDQogICAgeWVhcl9pPC1zdW1fd2d0X25yX01baSxuYW1lcyhzdW1fd2d0X25yX00pPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fd2d0X25yX01baSxqXTwtc3VtKHdndF9ucl9NW3doaWNoKHdndF9ucl9NJHllYXI9PXllYXJfaSksbmFtZXMod2d0X25yX00pPT1uYW1lcyhzdW1fd2d0X25yX00pW2pdXSkgDQogIH0gDQp9DQojPT09PT0NCg0KIz09PSANCiMgU3RvY2sgbWVhbiB3ZWlnaHQgYXQgYWdlIC0tLS0NCiM9PT0NCiMgTWFrZSBUYWJsZXMNCldBQV9GPC1zdW1fd2d0X25yX0YNCldBQV9GWywtMV08LU5BDQpXQUFfTTwtV0FBX0YNCldBQV9jb21ic2V4PC1XQUFfTQ0KDQojIyBGZW1hbGVzDQpmb3IgKGkgaW4gMTpucm93KFdBQV9GKSl7DQogIGZvciAoaiBpbiAyOm5jb2woV0FBX0YpKXsNCiAgICBXQUFfRltpLGpdPC1zdW1fd2d0X25yX0ZbaSxqXS9zdW1fbnJfZmlzaF9zZWFfRltpLGpdDQogIH0NCn0NCg0KIyMgTWFsZXMNCmZvciAoaSBpbiAxOm5yb3coV0FBX00pKXsNCiAgZm9yIChqIGluIDI6bmNvbChXQUFfTSkpew0KICAgIFdBQV9NW2ksal08LXN1bV93Z3RfbnJfTVtpLGpdL3N1bV9ucl9maXNoX3NlYV9NW2ksal0NCiAgfQ0KfQ0KDQojIyBjb21iIG9mIEYgYW5kIE0NCmZvciAoaSBpbiAxOm5yb3coV0FBX2NvbWJzZXgpKXsgDQogIGZvciAoaiBpbiAyOm5jb2woV0FBX2NvbWJzZXgpKXsgDQogICAgaWYoICFpcy5uYShXQUFfRltpLGpdKSYhaXMubmEoV0FBX01baSxqXSkpew0KICAgICAgV0FBX2NvbWJzZXhbaSxqXTwtKFdBQV9GW2ksal0qc2V4X3JhdGlvX0ZbaSxqXSkrKFdBQV9NW2ksal0qKDEtc2V4X3JhdGlvX0ZbaSxqXSkpDQogICAgfQ0KICAgIGlmKGlzLm5hKFdBQV9GW2ksal0pJiFpcy5uYShXQUFfTVtpLGpdKSl7DQogICAgICBXQUFfY29tYnNleFtpLGpdPC1XQUFfTVtpLGpdDQogICAgfQ0KICAgIGlmKGlzLm5hKFdBQV9NW2ksal0pJiFpcy5uYShXQUFfRltpLGpdKSl7DQogICAgICBXQUFfY29tYnNleFtpLGpdPC1XQUFfRltpLGpdICAgIA0KICAgIH0NCiAgfQ0KfQ0KDQojIyBDb252ZXJ0IHdlaWdodHMgdG8ga2csIG5vdCBncmFtcw0KV0FBX2NvbWJzZXggPC0gV0FBX2NvbWJzZXgvMTAwMA0KV0FBX2NvbWJzZXgkeWVhciA8LSBXQUFfY29tYnNleCR5ZWFyKjEwMDANCldBQV9jb21ic2V4JHllYXIgPC0gYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoV0FBX2NvbWJzZXgkeWVhcikpDQoNCiM9PT09PQ0KDQojPT09DQojIFJlc2hhcGUgV0FBIGRhdGEgYW5kIGNhbGN1bGF0ZSBtZWFucyArLy0gOTUlQ0kgIGZvciBwbG90dGluZyAgLS0tLQ0KIz09PQ0KIyBXaWRlIHRvIGxvbmcgZm9ybWF0DQpzd2FhbCA8LSByZXNoYXBlKFdBQV9jb21ic2V4LA0KICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMoV0FBX2NvbWJzZXgpWy0xXSwNCiAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJNZWFuV2VpZ2h0IiwNCiAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKFdBQV9jb21ic2V4KVstMV0sDQogICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQoNCg0KDQojIyBDYWxjdWxhdGUgbWVhbiBzd2FhIGZvciAxOTk5OjIwMTkgLS0tLQ0KbTE5V0FBIDwtIGFnZ3JlZ2F0ZShNZWFuV2VpZ2h0IH4gQWdlLA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gc3dhYWxbc3dhYWwkeWVhciAlaW4lIGMoMTk5OToyMDE5KSxdLA0KICAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQ0KDQojIENhbGN1bGF0ZSBzdGQgZXJyIGFyb3VuZCB0aGUgYWJvdmUgbWVhbiAxOTk5OjIwMTkNCm13MTlzdGRyIDwtIGFnZ3JlZ2F0ZShNZWFuV2VpZ2h0IH4gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygxOTk5OjIwMTkpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpe3NkKHgsIG5hLnJtID0gVFJVRSkvc3FydChsZW5ndGgobmEub21pdCh4KSkpfSkNCm13MTlzdGRyJEFnZU4gPC0gYXMubnVtZXJpYyhzdWIocGF0dGVybiA9ICJhIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IG13MTlzdGRyJEFnZSkpDQpjb2xuYW1lcyhtdzE5c3RkcilbY29sbmFtZXMobXcxOXN0ZHIpICVpbiUgYygiTWVhbldlaWdodCIpXSA8LSAiU3RkRXJyIg0KbXcxOXN0ZHIkTWVhbldlaWdodCA8LSBtMTlXQUEkTWVhbldlaWdodA0KbXcxOXN0ZHIkeW1heCA8LSBtdzE5c3RkciRNZWFuV2VpZ2h0ICsgMS45NiptdzE5c3RkciRTdGRFcnINCm13MTlzdGRyJHltaW4gPC0gbXcxOXN0ZHIkTWVhbldlaWdodCAtIDEuOTYqbXcxOXN0ZHIkU3RkRXJyDQptMTlXQUEkeWVhciA8LSBhcy5mYWN0b3IocmVwKCJNZWFuIDE5OTktMjAxOSIsIG4gPSBucm93KG0xOVdBQSkpKQ0KbXcxOXN0ZHIgPC0gbXcxOXN0ZHJbb3JkZXIobXcxOXN0ZHIkQWdlTiksIF0NCg0KIyMgQ2FsY3VsYXRlIHByZXZpb3VzIDMgeWVhciBtZWFuIC0tLS0NCm0zV0FBIDwtIGFnZ3JlZ2F0ZShNZWFuV2VpZ2h0IH4gQWdlLA0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygoKERhdGFZZWFyKzEpLTIpOihEYXRhWWVhcisxKSksXSwNCiAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQ0KDQojIENhbGN1bGF0ZSBzdGQgZXJyIGFyb3VuZCB0aGUgYWJvdmUgMyB5ZWFyIG1lYW4NCm0zd3N0ZHIgPC0gYWdncmVnYXRlKE1lYW5XZWlnaHQgfiBBZ2UsDQogICAgICAgICAgICAgICAgICAgICBkYXRhID0gc3dhYWxbc3dhYWwkeWVhciAlaW4lIGMoKChEYXRhWWVhcisxKS0yKTooRGF0YVllYXIrMSkpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0KbTN3c3RkciRBZ2VOIDwtIGFzLm51bWVyaWMoc3ViKHBhdHRlcm4gPSAiYSIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBtM3dzdGRyJEFnZSkpDQpjb2xuYW1lcyhtM3dzdGRyKVtjb2xuYW1lcyhtM3dzdGRyKSAlaW4lIGMoIk1lYW5XZWlnaHQiKV0gPC0gIlN0ZEVyciINCm0zd3N0ZHIkTWVhbldlaWdodCA8LSBtM1dBQSRNZWFuV2VpZ2h0DQptM3dzdGRyJHltYXggPC0gbTN3c3RkciRNZWFuV2VpZ2h0ICsgMS45NiptM3dzdGRyJFN0ZEVycg0KbTN3c3RkciR5bWluIDwtIG0zd3N0ZHIkTWVhbldlaWdodCAtIDEuOTYqbTN3c3RkciRTdGRFcnINCm0zV0FBJHllYXIgPC0gYXMuZmFjdG9yKHJlcCgiM3kgTWVhbiIsIG4gPSBucm93KG0zV0FBKSkpDQptM3dzdGRyIDwtIG0zd3N0ZHJbb3JkZXIobTN3c3RkciRBZ2VOKSwgXQ0KDQoNCiMjIENhbGN1bGF0ZSBtZWFuIG9mIDE5OTkgdG8gY3VycmVudCB5ZWFyIC0tLS0NCnJtV0FBIDwtIGFnZ3JlZ2F0ZShNZWFuV2VpZ2h0IH4gQWdlLA0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygxOTk5OihEYXRhWWVhcisxKSksXSwNCiAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQ0KDQojIFN0YW5kYXJkIGVycm9yIG9mIDE5OTkgLT4gbWVhbg0Kcm13c3RkciA8LSBhZ2dyZWdhdGUoTWVhbldlaWdodCB+IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygxOTk5OihEYXRhWWVhcisxKSksIF0sDQogICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KXtzZCh4LCBuYS5ybSA9IFRSVUUpL3NxcnQobGVuZ3RoKG5hLm9taXQoeCkpKX0pDQpybXdzdGRyJEFnZU4gPC0gYXMubnVtZXJpYyhzdWIocGF0dGVybiA9ICJhIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJtd3N0ZHIkQWdlKSkNCmNvbG5hbWVzKHJtd3N0ZHIpW2NvbG5hbWVzKHJtd3N0ZHIpICVpbiUgYygiTWVhbldlaWdodCIpXSA8LSAiU3RkRXJyIg0Kcm13c3RkciRNZWFuV2VpZ2h0IDwtIHJtV0FBJE1lYW5XZWlnaHQNCnJtd3N0ZHIkeW1heCA8LSBybXdzdGRyJE1lYW5XZWlnaHQgKyAxLjk2KnJtd3N0ZHIkU3RkRXJyDQpybXdzdGRyJHltaW4gPC0gcm13c3RkciRNZWFuV2VpZ2h0IC0gMS45NipybXdzdGRyJFN0ZEVycg0Kcm1XQUEkeWVhciA8LSBhcy5mYWN0b3IocmVwKCJSdW5uaW5nIE1lYW4iLCBuID0gbnJvdyhybVdBQSkpKQ0Kcm13c3RkciA8LSBybXdzdGRyW29yZGVyKHJtd3N0ZHIkQWdlTiksIF0NCg0KIyBDb21iaW5lIGFsbCB5ZWFycywgMjAwMiAtPiBtZWFuIGFuZCAxNSB5ZWFyIG1lYW4gaW50byBvbmUgb2JqZWN0DQpzd2FhbCA8LSByYmluZChzd2FhbCwgbTE5V0FBLCBybVdBQSwgbTNXQUEpDQpzd2FhbCRBZ2VOIDwtIGFzLm51bWVyaWMoc3ViKHBhdHRlcm4gPSAiYSIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBzd2FhbCRBZ2UpKQ0Kc3dhYWwgPC0gc3dhYWxbb3JkZXIoc3dhYWwkQWdlTiksIF0NCnN3YWFsJHllYXJGIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoc3dhYWwkeWVhcikpDQoNCiMjIENhbGN1bGF0ZSAzeSBzbGlkaW5nIHdpbmRvdyBhdmVyYWdlIGZvciB3aG9sZSB0aW1lc2VyaWVzIC0tLS0NCiMjIyBDYWxjdWxhdGUgdGhlIG1lYW4gLS0tLQ0KYWRhIDwtIGFuKDMsIG5yb3coV0FBX2NvbWJzZXgpKQ0Kc3czc3cgPC0gZnJvbGxtZWFuKFdBQV9jb21ic2V4WywgLTFdLCBuPWFkYSwgbmEucm0gPSBULCBhbGlnbiA9ICJyaWdodCIsIGFkYXB0aXZlID0gVFJVRSkNCnN3M3N3IDwtIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChjYmluZCwgc3czc3cpKQ0Kc3czc3ckeWVhciA8LSBXQUFfY29tYnNleCR5ZWFyDQoNCiMjIyMgV2lkZSB0byBsb25nIGZvcm1hdA0Kc3czc3dMIDwtIHJlc2hhcGUoc3czc3csDQogICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhzdzNzdylbLTExXSwNCiAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJNZWFuV2VpZ2h0IiwNCiAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKHN3M3N3KVstMTFdLA0KICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0Kc3czc3dMJEFnZSA8LSBhcy5udW1lcmljKGdzdWIocGF0dGVybiA9ICJWIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHN3M3N3TCRBZ2UpKQ0KDQojIyMgQ2FsY3VhbHRlIHRoZSBzdGFuZGFyZCBlcnJvciAtLS0tDQpzdzNzdGRyIDwtIGZyb2xsYXBwbHkoV0FBX2NvbWJzZXhbLCAtMV0sDQogICAgICAgICAgICAgICAgICAgICAgMywNCiAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KXtzZCh4LCBuYS5ybSA9IFRSVUUpL3NxcnQobGVuZ3RoKG5hLm9taXQoeCkpKX0pDQpzdzNzdGRyIDwtIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChjYmluZCwgc3czc3RkcikpDQpzdzNzdGRyJHllYXIgPC0gV0FBX2NvbWJzZXgkeWVhcg0KDQojIyMjIFdpZGUgdG8gbG9uZyBmb3JtYXQNCnN3M3N0ZHJMIDwtIHJlc2hhcGUoc3czc3RkciwNCiAgICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGNvbG5hbWVzKHN3M3N0ZHIpWy0xMV0sDQogICAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiU3RkRXJyV2VpZ2h0IiwNCiAgICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKHN3M3N0ZHIpWy0xMV0sDQogICAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQpzdzNzdGRyTCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBzdzNzdGRyTCRBZ2UpKQ0KDQojIyMgQ2FsY3VsYXRlIDk1JSBjb25maWRlbmNlIGludGVydmFscyAtLS0tDQpzdzNzd0wgPC0gbWVyZ2UoeCA9IHN3M3N3TCwgeSA9IHN3M3N0ZHJMLCBieSA9IGMoInllYXIiLCAiQWdlIiksIGFsbC54ID0gVFJVRSkNCnN3M3N3TCR5bWF4IDwtIHN3M3N3TCRNZWFuV2VpZ2h0ICsgKDEuOTYqc3czc3dMJFN0ZEVycldlaWdodCkNCnN3M3N3TCR5bWluIDwtIHN3M3N3TCRNZWFuV2VpZ2h0IC0gKDEuOTYqc3czc3dMJFN0ZEVycldlaWdodCkNCnN3M3N3TCRBZ2VOIDwtIHN3M3N3TCRBZ2UNCnN3M3N3TCRBZ2UgPC0gYXMuY2hhcmFjdGVyKHN3M3N3TCRBZ2UpDQpzdzNzd0wkeWVhciA8LSBhcy5udW1lcmljKHN3M3N3TCR5ZWFyKQ0Kc3czc3dMJHllYXJGIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoc3czc3dMJHllYXIpKQ0KDQoNCiMjIENhbGN1bGF0ZSA1eSBzbGlkaW5nIHdpbmRvdyBhdmVyYWdlIGZvciB3aG9sZSB0aW1lc2VyaWVzIC0tLS0NCiMjIyBDYWxjdWxhdGUgdGhlIG1lYW4gLS0tLQ0KYWRhIDwtIGFuKDUsIG5yb3coV0FBX2NvbWJzZXgpKQ0Kc3c1c3cgPC0gZnJvbGxtZWFuKFdBQV9jb21ic2V4WywgLTFdLCBuID0gYWRhLCBuYS5ybSA9IFQsIGFsaWduID0gInJpZ2h0IiwgYWRhcHRpdmUgPSBUUlVFKQ0Kc3c1c3cgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBzdzVzdykpDQpzdzVzdyR5ZWFyIDwtIFdBQV9jb21ic2V4JHllYXINCg0KIyMjIyBXaWRlIHRvIGxvbmcgZm9ybWF0DQpzdzVzd0wgPC0gcmVzaGFwZShzdzVzdywNCiAgICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhzdzVzdylbLTExXSwNCiAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiTWVhbldlaWdodCIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKHN3NXN3KVstMTFdLA0KICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQpzdzVzd0wkQWdlIDwtIGFzLm51bWVyaWMoZ3N1YihwYXR0ZXJuID0gIlYiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gc3c1c3dMJEFnZSkpDQoNCiMjIyBDYWxjdWFsdGUgdGhlIHN0YW5kYXJkIGVycm9yIC0tLS0NCnN3NXN0ZHIgPC0gZnJvbGxhcHBseShXQUFfY29tYnNleFssIC0xXSwNCiAgICAgICAgICAgICAgICAgICAgICA1LA0KICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpe3NkKHgsIG5hLnJtID0gVFJVRSkvc3FydChsZW5ndGgobmEub21pdCh4KSkpfSkNCnN3NXN0ZHIgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBzdzVzdGRyKSkNCnN3NXN0ZHIkeWVhciA8LSBXQUFfY29tYnNleCR5ZWFyDQpzdzVzdGRyW3N3NXN0ZHIkeWVhciA9PSAyMDAyLCAtbmNvbChzdzVzdGRyKV0gPC0gc3c1c3RkcltzdzVzdGRyJHllYXIgPT0gMjAwMywgLW5jb2woc3c1c3RkcildDQoNCiMjIyMgV2lkZSB0byBsb25nIGZvcm1hdA0Kc3c1c3RkckwgPC0gcmVzaGFwZShzdzVzdGRyLA0KICAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMoc3c1c3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJTdGRFcnJXZWlnaHQiLA0KICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMoc3c1c3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCnN3NXN0ZHJMJEFnZSA8LSBhcy5udW1lcmljKGdzdWIocGF0dGVybiA9ICJWIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHN3NXN0ZHJMJEFnZSkpDQoNCiMjIyBDYWxjdWxhdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIC0tLS0NCnN3NXN3TCA8LSBtZXJnZSh4ID0gc3c1c3dMLCB5ID0gc3c1c3RkckwsIGJ5ID0gYygieWVhciIsICJBZ2UiKSwgYWxsLnggPSBUUlVFKQ0Kc3c1c3dMJHltYXggPC0gc3c1c3dMJE1lYW5XZWlnaHQgKyAoMS45NipzdzVzd0wkU3RkRXJyV2VpZ2h0KQ0Kc3c1c3dMJHltaW4gPC0gc3c1c3dMJE1lYW5XZWlnaHQgLSAoMS45NipzdzVzd0wkU3RkRXJyV2VpZ2h0KQ0Kc3c1c3dMJEFnZU4gPC0gc3c1c3dMJEFnZQ0Kc3c1c3dMJEFnZSA8LSBhcy5jaGFyYWN0ZXIoc3c1c3dMJEFnZSkNCnN3NXN3TCR5ZWFyIDwtIGFzLm51bWVyaWMoc3c1c3dMJHllYXIpDQpzdzVzd0wkeWVhckYgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihzdzVzd0wkeWVhcikpDQoNCiMjIENhbGN1bGF0ZSBhbm51YWwgdmFsdWVzIGZyb20gYSBzbW9vdGhpbmcgc3BsaW5lIC0tLS0NCiMjIyBCdWlsZCB0aGUgc3BsaW5lDQpzd2FhbDIgPC0gc3dhYWxbIXN3YWFsJHllYXIgJWluJSBjKCJNZWFuIDE5OTktMjAxOSIsICJSdW5uaW5nIE1lYW4iLCAiM3kgTWVhbiIpLF0NCnN3YWFsMiRBZ2UgPC0gYXMuZmFjdG9yKHN3YWFsMiRBZ2UpDQpzd2FhbDIkeWVhciA8LSBhcy5udW1lcmljKHN3YWFsMiR5ZWFyKQ0KbXN3IDwtIGdhbShmb3JtdWxhID0gTWVhbldlaWdodCB+IHMoeWVhciwgYnMgPSAiY3IiLCBieSA9IEFnZSksIGRhdGEgPSBzd2FhbDIsIGZhbWlseSA9IGdhdXNzaWFuKGxpbmsgPSAiaWRlbnRpdHkiKSkNCg0KIyMjIFByZWRpY3Qgd2l0aCB0aGUgc21vb3RoZWQgc3BsaW5lDQpwcmVkd2VpZ2h0cyA8LSBwcmVkaWN0LmdhbShtc3csIG5ld2RhdGEgPSBzd2FhbDIsdHlwZSA9ICJyZXNwb25zZSIsIHNlLmZpdCA9IFRSVUUpDQpzd2FhbDIkc21vb3RoTWVhbldlaWdodHMgPC0gdW5uYW1lKHByZWR3ZWlnaHRzJGZpdCkNCnN3YWFsMiRzZVNtb290aE1lYW5XZWlnaHRzIDwtIHVubmFtZShwcmVkd2VpZ2h0cyRzZS5maXQpDQojPT09PT0NCg0KIz09PQ0KIyBzYXZlIHJlc3VsdHMNCiM9PT09DQp3cml0ZS5jc3YoV0FBX2NvbWJzZXgsZmlsZT0iRGF0YS9CaW9sb2dpY2FsRGF0YS9wbGUuMjcuMjEtMzJfU3RvY2tXZWlnaHRBdEFnZV8xOTk5LURhdGFZZWFyLmNzdiIpDQojIHNhdmVfYXNfbG93ZXN0b2Z0IEFubmF1bCBFc3RpbWF0ZXMNCldBQV9jb21ic2V4U0FNIDwtIGFzLmRhdGEuZnJhbWUoV0FBX2NvbWJzZXgpDQoNCiMjIyBzYXZlX2FzX2xvd2VzdG9mdCBNZWFuIDIwMDItRGF0YVllYXINCm1XQUEgPC0gZGF0YS5mcmFtZShsYXBwbHkoY29sTWVhbnMoV0FBX2NvbWJzZXhbV0FBX2NvbWJzZXgkeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCAhY29sbmFtZXMoV0FBX2NvbWJzZXgpICVpbiUgKCJ5ZWFyIildLCBuYS5ybSA9IFRSVUUpLCB0eXBlLmNvbnZlcnQpLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQ0KDQpzYXZlX2FzX2xvd2VzdG9mdChkZiA9IG1XQUEsICNbLCAhY29sbmFtZXMobVdBQSkgJWluJSAiQWdlIl0sDQogICAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSAiQXNzZXNzbWVudCBJbnB1dC9zdy5kYXQiLA0KICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiU3RvY2sgd2VpZ2h0cyBhdCBhZ2UgZm9yIFBsZS4yNy4yMS0zMi4gTWVhbiB2YWx1ZXMgZm9yIGNvbWJpbmVkIHNleGVzIDIwMDIgdG8gZGF0YSB5ZWFyLCBmcm9tIHN1cnZleSBkYXRhIiwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKDEsIDQpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gMikNCg0KIyMjIHNhdmVfYXNfbG93ZXN0b2Z0IFJhdyBBbm51YWwgRXN0aW1hdGVzDQoNCiMjIyMgb2xkIHJlbW92YWwgb2YgTkFzDQojIGZvcihpIGluIDE6bmNvbChXQUFfY29tYnNleFNBTSkpew0KIyAgIGZvcihqIGluIDE6bnJvdyhXQUFfY29tYnNleFNBTSkpew0KIyAgICAgV0FBX2NvbWJzZXhTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKFdBQV9jb21ic2V4U0FNW2osIGldKSwgLTksIFdBQV9jb21ic2V4U0FNW2osIGldKQ0KIyAgIH0NCiMgfQ0KDQojIyMjIE1ha2UgZWFybHkgdGltZXNlcmllcyAiTkEicyBpbnRvIHBsYXVzaWJsZSB2YWx1ZQ0KZm9yKGkgaW4gMTpuY29sKFdBQV9jb21ic2V4U0FNKSl7DQogIGZvcihqIGluIDE6bnJvdyhXQUFfY29tYnNleFNBTSkpew0KICAgIFdBQV9jb21ic2V4U0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShXQUFfY29tYnNleFNBTVtqLCBpXSksIG1lZGlhbihjKFdBQV9jb21ic2V4U0FNWyxpXSksIG5hLnJtID0gVCksIFdBQV9jb21ic2V4U0FNW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gV0FBX2NvbWJzZXhTQU1bV0FBX2NvbWJzZXhTQU0keWVhciAlaW4lIDIwMDI6KERhdGFZZWFyKzEpLCAhY29sbmFtZXMoV0FBX2NvbWJzZXhTQU0pICVpbiUgInllYXIiXSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L0FsdGVybmF0ZU1vZGVsX0FubnVhbFJhd0Jpby9zdy5kYXQiLA0KICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiU3RvY2sgd2VpZ2h0cyBhdCBhZ2UgZm9yIFBsZS4yNy4yMS0zMi4gQW5udWFsIHZhbHVlcyBmb3IgY29tYmluZWQgc2V4ZXMsIGZyb20gc3VydmV5IGRhdGEiLA0KICAgICAgICAgICAgICAgICAgcmFuZG9fbnVtYmVycyA9IHBhc3RlKGMoMSwgNCksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgYWdlX3JhbmdlID0gcGFzdGUoYygxLCAxMCksIGNvbGxhcHNlID0gIlx0IikpDQoNCiMjIyBzYXZlX2FzX2xvd2VzdG9mdCBUaHJlZSBZZWFyIFNsaWRpbmcgV2luZG93DQpzdzNzd1NBTSA8LSBhcy5kYXRhLmZyYW1lKHN3M3N3KQ0KDQojIGZvcihpIGluIDE6bmNvbChzdzNzd1NBTSkpew0KIyAgIGZvcihqIGluIDE6bnJvdyhzdzNzd1NBTSkpew0KIyAgICAgc3czc3dTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKHN3M3N3U0FNW2osIGldKSwgLTksIHN3M3N3U0FNW2osIGldKQ0KIyAgIH0NCiMgfQ0KDQojIyMjIE1ha2UgZWFybHkgdGltZXNlcmllcyAiTkEicyBpbnRvIHBsYXVzaWJsZSB2YWx1ZQ0KZm9yKGkgaW4gMTpuY29sKHN3M3N3U0FNKSl7DQogIGZvcihqIGluIDE6bnJvdyhzdzNzd1NBTSkpew0KICAgIHN3M3N3U0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShzdzNzd1NBTVtqLCBpXSksIG1lZGlhbihjKHN3M3N3U0FNWyxpXSksIG5hLnJtID0gVCksIHN3M3N3U0FNW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gc3czc3dTQU1bc3czc3dTQU0keWVhciAlaW4lIDIwMDI6KERhdGFZZWFyKzEpLCAhY29sbmFtZXMoc3czc3dTQU0pICVpbiUgInllYXIiXSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L0FsdGVybmF0ZU1vZGVsXzN5c3cvc3cuZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlN0b2NrIHdlaWdodHMgYXQgYWdlIGZvciBQbGUuMjcuMjEtMzIuIFRocmVlIHllYXIgc2xpZGluZyB3aW5kb3cgbWVhbnMgZm9yIGNvbWJpbmVkIHNleGVzLCBmcm9tIHN1cnZleSBkYXRhIiwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKDEsIDQpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpKQ0KDQojIyMgc2F2ZV9hc19sb3dlc3RvZnQgRml2ZSBZZWFyIFNsaWRpbmcgV2luZG93DQpzdzVzd1NBTSA8LSBhcy5kYXRhLmZyYW1lKHN3NXN3KQ0KDQojIGZvcihpIGluIDE6bmNvbChzdzVzd1NBTSkpew0KIyAgIGZvcihqIGluIDE6bnJvdyhzdzVzd1NBTSkpew0KIyAgICAgc3c1c3dTQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKHN3NXN3U0FNW2osIGldKSwgLTksIHN3NXN3U0FNW2osIGldKQ0KIyAgIH0NCiMgfQ0KDQojIyMjIE1ha2UgZWFybHkgdGltZXNlcmllcyAiTkEicyBpbnRvIHBsYXVzaWJsZSB2YWx1ZQ0KZm9yKGkgaW4gMTpuY29sKHN3NXN3U0FNKSl7DQogIGZvcihqIGluIDE6bnJvdyhzdzVzd1NBTSkpew0KICAgIHN3NXN3U0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShzdzVzd1NBTVtqLCBpXSksIG1lZGlhbihjKHN3NXN3U0FNWyxpXSksIG5hLnJtID0gVCksIHN3NXN3U0FNW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gc3c1c3dTQU1bc3c1c3dTQU0keWVhciAlaW4lIDIwMDI6KERhdGFZZWFyKzEpLCAhY29sbmFtZXMoc3c1c3dTQU0pICVpbiUgInllYXIiXSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L0FsdGVybmF0ZU1vZGVsXzV5c3cvc3cuZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlN0b2NrIHdlaWdodHMgYXQgYWdlIGZvciBQbGUuMjcuMjEtMzIuIEZpdmUgeWVhciBzbGlkaW5nIHdpbmRvdyBtZWFucyBmb3IgY29tYmluZWQgc2V4ZXMsIGZyb20gc3VydmV5IGRhdGEiLA0KICAgICAgICAgICAgICAgICAgcmFuZG9fbnVtYmVycyA9IHBhc3RlKGMoMSwgNCksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgYWdlX3JhbmdlID0gcGFzdGUoYygxLCAxMCksIGNvbGxhcHNlID0gIlx0IikpDQoNCiMjIyBzYXZlX2FzX2xvd2VzdG9mdCBzcGxpbmUtc21vb3RoZWQNCnN3YWEyIDwtIHJlc2hhcGUoc3dhYWwyWywgYygieWVhciIsICJBZ2UiLCAic21vb3RoTWVhbldlaWdodHMiKV0sDQogICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhXQUFfY29tYnNleClbLTFdLA0KICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gInNtb290aE1lYW5XZWlnaHRzIiwNCiAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIndpZGUiKQ0KDQojIGZvcihpIGluIDI6bmNvbChzd2FhMikpew0KIyAgIGZvcihqIGluIDI6bnJvdyhzd2FhMikpew0KIyAgICAgc3dhYTJbaiwgaV0gPC0gaWZlbHNlKGlzLm5hKHN3YWEyW2osIGldKSwgLTksIHN3YWEyW2osIGldKQ0KIyAgICAgc3dhYTJbaiwgaV0gPC0gaWZlbHNlKChzd2FhMltqLCBpXT49IDApLCAtOSwgc3dhYTJbaiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyMgTWFrZSBlYXJseSB0aW1lc2VyaWVzICJOQSJzIGludG8gcGxhdXNpYmxlIHZhbHVlDQpmb3IoaSBpbiAxOm5jb2woc3dhYTIpKXsNCiAgZm9yKGogaW4gMTpucm93KHN3YWEyKSl7DQogICAgc3dhYTJbaiwgaV0gPC0gaWZlbHNlKGlzLm5hKHN3YWEyW2osIGldKSwgbWVkaWFuKGMoc3dhYTJbLGldKSwgbmEucm0gPSBUKSwgc3dhYTJbaiwgaV0pDQogICAgc3dhYTJbaiwgaV0gPC0gaWZlbHNlKChzd2FhMltqLCBpXT4xKSwgMSwgc3dhYTJbaiwgaV0pDQogIH0NCn0NCg0Kc2F2ZV9hc19sb3dlc3RvZnQoZGYgPSBzd2FhMltzd2FhMiR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksIF0sDQogICAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSAiQXNzZXNzbWVudCBJbnB1dC9BbHRlcm5hdGVNb2RlbF9TU2Jpby9zdy5kYXQiLA0KICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiU3RvY2sgd2VpZ2h0cyBhdCBhZ2UgZm9yIFBsZS4yNy4yMS0zMi4gU21vb3RoIFNwbGluZSBmb3IgY29tYmluZWQgc2V4ZXMsIGZyb20gc3VydmV5IGRhdGEiLA0KICAgICAgICAgICAgICAgICAgcmFuZG9fbnVtYmVycyA9IHBhc3RlKGMoMSwgNCksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICB5ZWFyX3JhbmdlID0gcGFzdGUoYygyMDAyLCAoRGF0YVllYXIrMSkpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgYWdlX3JhbmdlID0gcGFzdGUoYygxLCAxMCksIGNvbGxhcHNlID0gIlx0IikpDQoNCg0KIyBzYXZlUkRTKHN3YWFsLCBmaWxlID0gIkJpb2xvZ2ljYWwgRGF0YS9QbGUuMjcuMjEtMjNfc3dhYWwuUkRTIikNCiMgc2F2ZVJEUyhtdzE5c3RkciwgZmlsZSgiQmlvbG9naWNhbCBEYXRhL1BsZS4yNy4yMS0yM19TV0FBX0F2ZVN0ZEVycl8xOTk5LTIwMTkuUkRTIikpDQojIHNhdmVSRFMocm13c3RkciwgZmlsZSgiQmlvbG9naWNhbCBEYXRhL1BsZS4yNy4yMS0yM19TV0FBX0F2ZVN0ZEVycl8xOTk5LURhdGFZZWFyLlJEUyIpKQ0KIyBzYXZlUkRTKG0zd3N0ZHIsIGZpbGUoIkJpb2xvZ2ljYWwgRGF0YS9QbGUuMjcuMjEtMjNfU1dBQV9BdmVTdGRFcnJfM3lyLlJEUyIpKQ0KIz09PT09DQoNCmsgPC0gYXBwZW5kKGssIGMoIldBQV9jb21ic2V4IiwgInN3YWFsIiwgInN3YWFsMiIsICJtdzE5c3RkciIsICJybXdzdGRyIiwgIm0zd3N0ZHIiLCAic3czc3dMIiwgInN3NXN3TCIsICJzd19hbm51YWxfcmF3IiwgInNleF9yYXRpb19GIikpDQojIHJtKGxpc3QgPSBscygpWyFscygpICVpbiUga10pDQpgYGANCg0KU2ltaWxhciB0byB0aGUgbWF0dXJpdHkgb2dpdmVzLCB0aGUgc3RvY2sgbWVhbiB3ZWlnaHQgYXQgYWdlIChTV0FBKSBpbiB0aGUgYXNzZXNzbWVudCBoYXMgaGlzdG9yaWNhbGx5LCBpbiB0aGUgcGxlLjI3LjIxLTIzIHN0b2NrLCBiZWVuIGFuIGF2ZXJhZ2Ugb2YgdGhlIHdob2xlIHRpbWUtc2VyaWVzLCBuYW1lbHkgZnJvbSAxOTk5IC0gYHIgRGF0YVllYXJgLiAgSG93ZXZlciwgYmVjYXVzZSB0aGUgd2VpZ2h0IGF0IGFnZSBoYXMgc2hpZnRlZCBmcm9tIGJlaW5nIHJlbGF0aXZlbHkgc3RhYmxlIHRvIGJlaW5nIHByb2dyZXNzaXZlbHkgbG93ZXIgc2luY2UgMjAyMCAocHJvYmFibHkgZHVlIHRvIGRlbnNpdHkgZGVwZW5kZW50IGNvbXBldGl0aW9uKSB3ZSBjYW4gbm8gbG9uZ2VyIHVzZSB0aGUgbWVhbiBvZiB0aGUgdGltZSBzZXJpZXMuICBPdmVyIHRoZSBsYXN0IHllYXJzIG9mIHRoZSBwbGUuMjcuMjEtMjMgc3RvY2ssIFdHQkZBUyBhZ3JlZWQgdG8sIGluc3RlYWQsIHVzZSB0aGUgbWVhbiBmb3IgdGhlIHBlcmlvZCB3aGVyZSBpdCB3YXMgc3RhYmxlLCBhbmQgc2FtcGxpbmcgd2FzIGxvdywgYW5kIHNoaWZ0IHRvIHRoZSBhbm51YWwgdmFsdWVzIGZvciBsYXRlciB5ZWFycy4gIFRoaXMgbWVhbnMgdGhlIG1lYW5zIGZvciB5ZWFycyAxOTk5OjIwMTkgYXJlIGFwcGxpZWQgdG8gdGhlIHllYXJzIDE5OTk6MjAxOSwgd2hpbGUgYWxsIHllYXJzIGZyb20gMjAyMDpgciBEYXRhWWVhcmAgdXRpbGlzZSB0aGUgYWN0dWFsIHllYXIncyBlc3RpbWF0ZWQgdmFsdWVzIGZyb20gc3VydmV5IHNhbXBsZXMuICBCZWxvdyB3ZSBpbnZlc3RpZ2F0ZSB3aGF0IHRoZSBTV0FBIHZhbHVlcyB3b3VsZCBiZSBhY2NvcmRpbmcgdG8gdGhlIHN0b2NrIGFubmV4IGNvbXBhcmVkIHRvIG91ciBuZXcgYXBwcm9hY2ggYnkgZmlyc3QgbG9va2luZyBhdCB0aGUgdmFsdWVzIGluIHRhYmxlcyBhbmQgdGhlbiBjb21wYXJpbmcgdGhlbSBncmFwaGljYWxseS4gDQoNCmBgYHtyIFNXQUFUYWJsZVNBfQ0KIz09PQ0KIyBUYWJsZSBvZiBTV0FBIGZyb20gc3RvY2sgYW5uZXgNCiM9PT09DQprYWJsZShzd2FhbFtzd2FhbCR5ZWFyID09ICJSdW5uaW5nIE1lYW4iLCBjKCJBZ2VOIiwgIk1lYW5XZWlnaHQiKV0sDQogICAgICBjYXB0aW9uID0gIlN0YXRpYyBTdG9jayBXZWlnaHQtYXQtYWdlIGZyb20gbWVhbiBvZiB0aW1lc2VyaWVzLCBhY2NvcmRpbmcgdG8gcGxlLjI3LjIxLTIzIHN0b2NrIGFubmV4LiIpDQojPT09PT0NCmBgYA0KDQpgYGB7ciBTV0FBVGFibGVTcGxpdH0NCiM9PT0NCiMgRGF0YSBQcmVwDQojPT09PQ0KbXcxOXN0ZHIkY2F0IDwtICJtdzE5OTlfMjAxOSINCmF3Q3VycmVudCA8LSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygyMDIwOkRhdGFZZWFyKzEpLCBdDQphd0N1cnJlbnQkY2F0IDwtIGFzLmNoYXJhY3Rlcihhd0N1cnJlbnQkeWVhcikNCmF3Q3VycmVudCRTdGRFcnIgPC0gTkENCmF3Q3VycmVudCR5bWF4IDwtIE5BDQphd0N1cnJlbnQkeW1pbiA8LSBOQQ0KeWVhcnMgPC0gcmVwKDE5OTk6MjAxOSwgMTApW29yZGVyKHJlcCgxOTk5OjIwMTksIDEwKSldDQptdzE5XzE5IDwtIGRhdGEuZnJhbWUoeWVhciA9IHllYXJzLA0KICAgICAgICAgICAgICAgICAgICAgIEFnZU4gPSByZXAoMToxMCwgbGVuZ3RoKDE5OTk6MjAxOSkpLA0KICAgICAgICAgICAgICAgICAgICAgIE1lYW5XZWlnaHQgPSByZXAobXcxOXN0ZHIkTWVhbldlaWdodCwgbGVuZ3RoKDE5OTk6MjAxOSkpLA0KICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSByZXAobXcxOXN0ZHIkeW1pbiwgbGVuZ3RoKDE5OTk6MjAxOSkpLA0KICAgICAgICAgICAgICAgICAgICAgIHltYXggPSByZXAobXcxOXN0ZHIkeW1heCwgbGVuZ3RoKDE5OTk6MjAxOSkpLA0KICAgICAgICAgICAgICAgICAgICAgIFN0ZEVyciA9IHJlcChtdzE5c3RkciRTdGRFcnIsIGxlbmd0aCgxOTk5OjIwMTkpKSkNCnN3YWFzZXBMb25nIDwtIHJiaW5kKG13MTlfMTksIGF3Q3VycmVudFssIGNvbG5hbWVzKGF3Q3VycmVudClbY29sbmFtZXMoYXdDdXJyZW50KSAlaW4lIGNvbG5hbWVzKG13MTlfMTkpXV0pDQoNCnN3YWFzZXBTQU0gPC0gZGNhc3QoZGF0YSA9IHN3YWFzZXBMb25nWywgYygieWVhciIsICJBZ2VOIiwgIk1lYW5XZWlnaHQiKV0sDQogICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSB5ZWFyIH4gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgdmFsdWUudmFyID0gIk1lYW5XZWlnaHQiKQ0KIyB3cml0ZS5jc3Yoc3dhYXNlcFNBTSwgZmlsZSA9ICJCaW9sb2dpY2FsIERhdGEvUGxlLjI3LjIxLTMyX1NXQUFfQXZlMTk5OS0yMDE5X1ZhbHVlMjAyMC1DdXJyZW50LmNzdiIpDQojPT09PQ0KIz09PQ0KIyBUYWJsZSBvZiBTV0FBIGZvciBBc3Nlc3NtZW50DQojPT09PQ0Ka2FibGUoc3dhYXNlcFNBTSwNCiAgICAgIGNhcHRpb24gPSAiU3RvY2sgd2VpZ2h0LWF0LWFnZSB3aXRoIG1lYW4gdmFsdWVzIGFwcGxpZWQgZm9yIDE5OTk6MjAxOSBhbmQgb2JzZXJ2ZWQgdmFsdWVzIGZvciAyMDIwIG9ud2FyZHMuIikNCiM9PT09PQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IHBhc3RlMCgiU3RvY2sgd2VpZ2h0IGF0IGFnZS4gVGhlIGxpZ2h0IGdyZWVuIGxpbmUgYW5kIHJpYmJvbiBhcmUgdGhlIGZ1bGwgdGltZS1zZXJpZXMgbWVhbiArLy0gOTUlQ0ksIHRvIGJlIHVzZWQgYXMgZml4ZWQgZm9yIGFsbCB5ZWFycyBhY2NvcmRpbmcgdG8gdGhlIHN0b2NrIGFubmV4LiAgVGhlIGxpZ2h0IGJsdWUgbGluZSBhbmQgcmliYm9uIGlzIHRoZSAxOTk5OjIwMTkgYXZlcmFnZSAoKy8tIDk1JUNJKSwgd2hpY2ggaXMgYXBwbGllZCB0byB0aG9zZSB5ZWFycy4gIFN1YnNlcXVlbnQgeWVhcnMsIDIwMjAgdG8gIiwgRGF0YVllYXIrMSwgIiwgYXJlIGluY2x1ZGVkIGluZGVwZW5kZW50bHkgaW4gdGhlIGFzc2Vzc21lbnQgcnVuIGFuZCBhcmUgc2hvd24gaW4gdGhlIHJlbWFpbmluZyBjb2xvdXJzLiIpfQ0KIz09PQ0KIyBGaWd1cmUgIHN0b2NrIHdlaWdodCBhdCBhZ2UgKENhbGN1bGF0ZWQgZnJvbSBEQVRSQVMgRXhjaGFuZ2UgRGF0YSkNCiM9PT09DQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gcm13c3RkciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBNZWFuV2VpZ2h0KSwNCiAgICAgICAgICAgIHNpemUgPSAxLjI1LA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pKw0KICAgIGdlb21fcmliYm9uKGRhdGEgPSBybXdzdGRyLA0KICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1BZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IHltaW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0geW1heCksDQogICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzJdLA0KICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSsNCiAgZ2VvbV9saW5lKGRhdGEgPSBtdzE5c3RkciwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBNZWFuV2VpZ2h0KSwNCiAgICAgICAgICAgIHNpemUgPSAxLjI1LA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0pKw0KICAgIGdlb21fcmliYm9uKGRhdGEgPSBtdzE5c3RkciwNCiAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9QWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSB5bWluLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IHltYXgpLA0KICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikrDQogICAgZ2VvbV9saW5lKGRhdGEgPSBzd2FhbFtzd2FhbCR5ZWFyICVpbiUgYygyMDIwOihEYXRhWWVhcisxKSksIF0sDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IE1lYW5XZWlnaHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0geWVhcikpKw0KICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBlYnBhbFszOmxlbmd0aChlYnBhbCldKSsNCiAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDEwKSkNCiAgKQ0KIz09PT09DQpgYGANCg0KYGBge3IgZmlnLmNhcD0gcGFzdGUwKCJTdG9jayB3ZWlnaHQgYXQgYWdlIGJ5IHllYXIsIG92ZXIgdGltZS4iKSwgZmlnLmhlaWdodD0xMH0NCnN3YWxiYSA8LSBtZWx0KHNldERUKFdBQV9jb21ic2V4KSwgaWQudmFycyA9ICJ5ZWFyIiwgdmFyaWFibGUubmFtZSA9ICJBZ2UiLCB2YWx1ZS5uYW1lID0gIk1lYW5XZWlnaHQiKQ0KDQoNCmdncGxvdGx5KGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBzd2FsYmEsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTWVhbldlaWdodCkpICsNCiAgZmFjZXRfd3JhcCgufkFnZSkrDQogIHRoZW1lX2ZldygpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGZ1bmN0aW9uKHgpIHByZXR0eSh4LCBuID0gNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwgMC4yLCAwLjQsIDAuNikpICsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMC42KSkNCikNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIlN0b2NrIHdlaWdodCBhdCBhZ2UgYnkgeWVhciwgb3ZlciB0aW1lLCBhbGwgaW4gb25lIHBhbmVsIChGT1IgSkVTUEVSKS4iKX0NCmdncGxvdGx5KGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBzd2FsYmEsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTWVhbldlaWdodCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQWdlKSkgKw0KICB0aGVtZV9mZXcoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDAuMiwgMC40LCAwLjYsIDAuOCkpICsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMC44KSkrDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDAwMDAiLCBlYnBhbCkpDQopDQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIlN0b2NrIHdlaWdodCBhdCBhZ2UgYnkgeWVhciwgb3ZlciB0aW1lLCBlc3RpbWF0ZWQgZnJvbSBzbW9vdGhlZCBzcGxpbmVzIGJ5IGFnZS4iKX0NCmdncGxvdGx5KGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBzd2FhbDIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gc21vb3RoTWVhbldlaWdodHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgZ2VvbV9yaWJib24oZGF0YSA9IHN3YWFsMiwNCiAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0gc21vb3RoTWVhbldlaWdodHMtKDEuOTYqc2VTbW9vdGhNZWFuV2VpZ2h0cyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IHNtb290aE1lYW5XZWlnaHRzKygxLjk2KnNlU21vb3RoTWVhbldlaWdodHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY29sb3VyID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBBZ2UpLA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuMTUpICsgDQogIHRoZW1lX2ZldygpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGZ1bmN0aW9uKHgpIHByZXR0eSh4LCBuID0gNSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwgMC4yLCAwLjQsIDAuNiwgMC44KSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwwLjk1KSkrDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpDQopDQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIlN0b2NrIHdlaWdodCBhdCBhZ2UgYnkgeWVhciwgb3ZlciB0aW1lLCBhY3R1YWwgdmFsdWVzIChibGFjaykgYW5kIHByZWRpY3RlZCBmcm9tIHNtb290aGVyIChjb2xvdXJzKTsgcmliYm9ucyA9IDk1JSBDSS4iKSwgZmlnLmhlaWdodD0xMH0NCnN3YWxiYSA8LSBtZWx0KHNldERUKFdBQV9jb21ic2V4KSwgaWQudmFycyA9ICJ5ZWFyIiwgdmFyaWFibGUubmFtZSA9ICJBZ2UiLCB2YWx1ZS5uYW1lID0gIk1lYW5XZWlnaHQiKQ0KDQoNCmdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBzd2FsYmEsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTWVhbldlaWdodCkpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBzd2FhbDIsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gc21vb3RoTWVhbldlaWdodHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IHN3YWFsMiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0gc21vb3RoTWVhbldlaWdodHMtKDEuOTYqc2VTbW9vdGhNZWFuV2VpZ2h0cyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IHNtb290aE1lYW5XZWlnaHRzKygxLjk2KnNlU21vb3RoTWVhbldlaWdodHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY29sb3VyID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBBZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMTUpICsgDQogICAgICAgICAgIGZhY2V0X3dyYXAoLn5BZ2UpKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSsNCiAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKSArDQogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSArDQogICAgICAgICAgICMgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwgMC4yLCAwLjQsIDAuNikpICsNCiAgICAgICAgICAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMC45NSkpICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKGVicGFsKSkNCikNCmBgYA0KDQojIyMgU3RvY2sgTGVuZ3RoIGF0IEFnZQ0KV2hpbGUgbm90IG5lY2Vzc2FyeSBmb3IgdGhlIGFzc2Vzc21lbnQsIHdlIGNhbiB1c2UgdGhlIGFib3ZlIGFnZ3JlZ2F0aW9ucyB0byBhbHNvIGdldCB0aGUgc3RvY2sgbWVhbiBsZW5ndGggYXQgYWdlLiANCg0KYGBge3IgbGVuZ3Roc0F0QWdlfQ0KIz09PQ0KIyBHZXQgbnVtYmVycyBvZiBsZW5ndGggc2FtcGxlcw0KIz09PT0NCiMgTWFrZSB0YWJsZXMNCmxlbl9ucl9GPC13Z3RfbnJfRg0KbGVuX25yX0ZbLDM6bmNvbChsZW5fbnJfRildPC1OQQ0KbGVuX25yX008LWxlbl9ucl9GDQoNCiMgRmVtYWxlcw0KZm9yIChpIGluIDE6bnJvdyhsZW5fbnJfRikpew0KICBmb3IgKGogaW4gMzoobmNvbChsZW5fbnJfRiktMSkpew0KICAgIA0KICAgIGlmKG5yX2Zpc2hfc2VhX0ZbaSxqXT4wKXsNCiAgICAgIGxlbl9ucl9GW2ksal08LW5yX2Zpc2hfc2VhX0ZbaSxqXSpucl9maXNoX3NlYV9GW2ksbmFtZXMobnJfZmlzaF9zZWFfRik9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogICAgfWVsc2V7DQogICAgICBsZW5fbnJfRltpLGpdPC0wDQogICAgfQ0KICB9DQp9ICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KIyBNYWxlcw0KZm9yIChpIGluIDE6bnJvdyhsZW5fbnJfTSkpew0KICBmb3IgKGogaW4gMzoobmNvbChsZW5fbnJfTSktMSkpew0KICAgIA0KICAgIGlmKG5yX2Zpc2hfc2VhX01baSxqXT4wKXsNCiAgICAgIGxlbl9ucl9NW2ksal08LW5yX2Zpc2hfc2VhX01baSxqXSpucl9maXNoX3NlYV9NW2ksbmFtZXMobnJfZmlzaF9zZWFfTSk9PWFzLmNoYXJhY3RlcigiTG5ndENsYXNzIildDQogICAgfWVsc2V7DQogICAgICBsZW5fbnJfTVtpLGpdPC0wDQogICAgfQ0KICB9DQp9ICAgICAgICAgIA0KDQojPT09DQojIFN1bSBvZiB0aGVzZSB2YWx1ZXMgb3ZlciBsZW5naHRjbGFzc2VzLCBieSBhZ2UNCiM9PT09DQojIE1ha2UgVGFibGVzDQpzdW1fbGVuX25yX0Y8LXN1bV93Z3RfbnJfRg0Kc3VtX2xlbl9ucl9GWywtMV08LU5BDQpzdW1fbGVuX25yX008LXN1bV9sZW5fbnJfRg0KDQojIEZlbWFsZXMNCmZvciAoaSBpbiAxOm5yb3coc3VtX2xlbl9ucl9GKSl7IA0KICBmb3IgKGogaW4gMjpuY29sKHN1bV9sZW5fbnJfRikpeyANCiAgICB5ZWFyX2k8LXN1bV9sZW5fbnJfRltpLG5hbWVzKHN1bV9sZW5fbnJfRik9PWFzLmNoYXJhY3RlcigieWVhciIpXQ0KICAgIHN1bV9sZW5fbnJfRltpLGpdPC1zdW0obGVuX25yX0Zbd2hpY2gobGVuX25yX0YkeWVhcj09eWVhcl9pKSxuYW1lcyhsZW5fbnJfRik9PW5hbWVzKHN1bV9sZW5fbnJfRilbal1dKSANCiAgfQ0KfQ0KDQojIE1hbGVzDQpmb3IgKGkgaW4gMTpucm93KHN1bV9sZW5fbnJfTSkpeyANCiAgZm9yIChqIGluIDI6bmNvbChzdW1fbGVuX25yX00pKXsgDQogICAgeWVhcl9pPC1zdW1fbGVuX25yX01baSxuYW1lcyhzdW1fbGVuX25yX00pPT1hcy5jaGFyYWN0ZXIoInllYXIiKV0NCiAgICBzdW1fbGVuX25yX01baSxqXTwtc3VtKGxlbl9ucl9NW3doaWNoKGxlbl9ucl9NJHllYXI9PXllYXJfaSksbmFtZXMobGVuX25yX00pPT1uYW1lcyhzdW1fbGVuX25yX00pW2pdXSkgDQogIH0NCn0NCiM9PT09PQ0KDQojPT09DQojIENhbGN1bGF0ZSBtZWFuIGxlbmd0aCBhdCBhZ2UgIA0KIz09PT0NCiMgTWFrZSB0YWJsZXMNCkxBQV9GPC1XQUFfRg0KTEFBX0ZbLC0xXTwtTkENCkxBQV9NPC1MQUFfRg0KTEFBX2NvbWJzZXg8LUxBQV9NDQoNCiMgRmVtYWxlcw0KZm9yIChpIGluIDE6bnJvdyhMQUFfRikpew0KICBmb3IgKGogaW4gMjpuY29sKExBQV9GKSl7DQogICAgTEFBX0ZbaSxqXTwtc3VtX2xlbl9ucl9GW2ksal0vc3VtX25yX2Zpc2hfc2VhX0ZbaSxqXQ0KICB9DQp9DQoNCiMgTWFsZXMNCmZvciAoaSBpbiAxOm5yb3coTEFBX00pKXsNCiAgZm9yIChqIGluIDI6bmNvbChMQUFfTSkpew0KICAgIExBQV9NW2ksal08LXN1bV9sZW5fbnJfTVtpLGpdL3N1bV9ucl9maXNoX3NlYV9NW2ksal0NCiAgfQ0KfQ0KDQojIGNvbWIgb2YgRiBhbmQgTQ0KZm9yIChpIGluIDE6bnJvdyhMQUFfY29tYnNleCkpeyANCiAgZm9yIChqIGluIDI6bmNvbChMQUFfY29tYnNleCkpeyANCiAgICBpZighaXMubmEoTEFBX0ZbaSxqXSkmIWlzLm5hKExBQV9NW2ksal0pKXsNCiAgICAgIExBQV9jb21ic2V4W2ksal08LShMQUFfRltpLGpdKnNleF9yYXRpb19GW2ksal0pKyhMQUFfTVtpLGpdKigxLXNleF9yYXRpb19GW2ksal0pKQ0KICAgIH0NCiAgICBpZihpcy5uYShMQUFfRltpLGpdKSYhaXMubmEoTEFBX01baSxqXSkpew0KICAgICAgTEFBX2NvbWJzZXhbaSxqXTwtTEFBX01baSxqXQ0KICAgIH0NCiAgICBpZihpcy5uYShMQUFfTVtpLGpdKSYhaXMubmEoTEFBX0ZbaSxqXSkpew0KICAgICAgTEFBX2NvbWJzZXhbaSxqXTwtTEFBX0ZbaSxqXSAgICANCiAgICB9DQogIH0NCn0NCg0KIz09PQ0KIyBDbGVhbiBEYXRhIEVudmlyb25tZW50DQojPT09PQ0KayA8LSBhcHBlbmQoaywgYygiTEFBX2NvbWJzZXgiLCAiTEFBX0YiLCAiTEFBX00iLCAiV0FBX2NvbWJzZXgiLCAiV0FBX0YiLCAiV0FBX00iLCAic3dhYWwiLCAibTE5V0FBIiwgInJtMTlXQUEiKSkNCnJtKGxpc3QgPSBscygpWyFscygpICVpbiUga10pDQojPT09PT0NCg0KYGBgDQojIyMjIFN0b2NrIExlbmd0aHMgYXQgYWdlDQpgYGB7ciBmaWcuY2FwPSBwYXN0ZTAoIlN0b2NrIGxlbmd0aHMgYXQgYWdlIGJ5IHllYXIsIG92ZXIgdGltZS4iKSwgZmlnLmhlaWdodD0xMH0NCnNsYWxiYSA8LSBtZWx0KHNldERUKExBQV9jb21ic2V4KSwgaWQudmFycyA9ICJ5ZWFyIiwgdmFyaWFibGUubmFtZSA9ICJBZ2UiLCB2YWx1ZS5uYW1lID0gIk1lYW5MZW5ndGgiKQ0KDQoNCmdncGxvdGx5KGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBzbGFsYmEsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTWVhbkxlbmd0aCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQWdlKSkgKw0KICBmYWNldF93cmFwKC5+QWdlKSsNCiAgdGhlbWVfZmV3KCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gZnVuY3Rpb24oeCkgcHJldHR5KHgsIG4gPSA1KSkgKw0KICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkNCikNCmBgYA0KDQojIyMjIFJhdyBsZW5ndGhzIGF0IGFnZSBvYnNlcnZhdGlvbnMNCmBgYHtyIGZpZy5jYXA9IlJhdyBsZW5ndGhzIGF0IGFnZSBmcm9tIHN1cnZleSJ9DQpjYV9oaF9maW5fYml0c19pYnRzJEFnZU4gPC0gY2FfaGhfZmluX2JpdHNfaWJ0cyRBZ2UNCmNhX2hoX2Zpbl9iaXRzX2lidHMkQWdlRiA8LSBmYWN0b3IoYXMuY2hhcmFjdGVyKGNhX2hoX2Zpbl9iaXRzX2lidHMkQWdlTiksIGxldmVscyA9IGFzLmNoYXJhY3RlcihjKDE6bWF4KGNhX2hoX2Zpbl9iaXRzX2lidHMkQWdlTiwgbmEucm0gPSBUKSkpKQ0KDQpnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGNhX2hoX2Zpbl9iaXRzX2lidHNbIWlzLm5hKGNhX2hoX2Zpbl9iaXRzX2lidHMkQWdlRikgJiBjYV9oaF9maW5fYml0c19pYnRzJExuZ3RDbGFzcyA8IDExMCAmIGNhX2hoX2Zpbl9iaXRzX2lidHMkUXVhcnRlciA9PSAxICYgY2FfaGhfZmluX2JpdHNfaWJ0cyRBZ2VOIDwgMjYsIF0sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTG5ndENsYXNzKSkgKw0KICB0aGVtZV9mZXcoKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogIGd1aWRlcyhjb2xvdXIgPSAibm9uZSIsIGZpbGwgPSAibm9uZSIpDQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJMZW5ndGhzIGF0IGFnZSwgb3ZlciB0aW1lLiJ9DQpnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGNhX2hoX2Zpbl9iaXRzX2lidHNbIWlzLm5hKGNhX2hoX2Zpbl9iaXRzX2lidHMkQWdlKSAmIGNhX2hoX2Zpbl9iaXRzX2lidHMkTG5ndENsYXNzIDwgMTEwICYgY2FfaGhfZmluX2JpdHNfaWJ0cyRRdWFydGVyID09IDEsIF0sDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTG5ndENsYXNzKSkgKw0KICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gIkFnZUYiKSArDQogIHRoZW1lX2ZldygpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gZnVuY3Rpb24oeCkgcHJldHR5KHgsIG4gPSA1KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgZ3VpZGVzKGNvbG91ciA9ICJub25lIiwgZmlsbCA9ICJub25lIikNCmBgYCANCg0KIyMjIE5hdHVyYWwgTW9ydGFsaXR5IEVzdGltYXRlcw0KVG8gdHJ5IGFuZCBpbXByb3ZlIHVwb24gdGhlIF9tYWdpYyBudW1iZXJzXyB0aGF0IGFyZSBjdXJyZW50bHkgdGhlIGJhc2lzIG9mIHRoZSBhc3N1bWVkIG5hdHVyYWwgbW9ydGFsaXR5IGFjcm9zcyBhZ2VzLCB3ZSBjYW4gdXNlIHRoZSBHaXNsYXNvbiAoZXQgYWwuIDIwMTApIG1ldGhvZCBmb3IgZXN0aW1hdGluZyBuYXR1cmFsIG1vcnRhbGl0eSBiYXNlZCBvbiBsZW5ndGgsICRMX3tcaW5mdHl9JCwgYW5kICRLJC4NCiQkDQpsbihNKSA9IDAuNTUgLSAxLjYxbG4oTCkgKyAxLjQ0bG4oTF97XGluZnR5fSkgKyBsbihLKQ0KJCQNCldoZXJlIE0gaXMgbmF0dXJhbCBtb3J0YWxpdHksICRMJCBpcyBsZW5ndGggYXQgYSBnaXZlbiBhZ2UgKGFuZC9vciBhZ2UqeWVhciksICRMX3tcaW5mdHl9JCBpcyB0aGUgYXN5bXB0b3RhbCBsZW5ndGggb2YgdGhlIHN0b2NrLCBhbmQgJEskIGlzIHRoZSBzaGFwZSBwYXJhbWV0ZXIgb2YgdGhlIFZvbiBCZXJ0YWxhbmZmeSBncm93dGggY3VydmUuIA0KDQpUbyBlc3RpbWF0ZSAkTF97XGluZnR5fSQgYW5kICRLJCwgd2UgY2FuIGZpdCBhIGxpbmVhciBtb2RlbCB0byB0aGUgMS15ZWFyIHN0YWdnZXJlZCBsZW5ndGhzIChGb3JkLVdhbGZvcmQgbWV0aG9kKSBhbmQgZGVyaXZlIHRoZXNlIHZhbHVlcyBmcm9tIHRoZSBzbG9wZSBhbmQgaW50ZXJjZXB0IHBhcmFtZXRlcnMuDQoNCmBgYHtyIFZCR0Z9DQojIyBDcmVhdGUgc3RhZ2dlcmVkIGxlbmd0aCBhdCBhZ2UgZGF0YQ0KTEFBX2xvbmcgPC0gcmVzaGFwZShkYXRhID0gTEFBX2NvbWJzZXgsDQogICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMoTEFBX2NvbWJzZXgpWy0xXSwNCiAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiTWVhbkxlbmd0aCIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKExBQV9jb21ic2V4KVstMV0sDQogICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikgDQpMQUFfbG9uZyRBZ2VOIDwtIGFzLm51bWVyaWMoZ3N1YihwYXR0ZXJuID0gImEiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gTEFBX2xvbmckQWdlKSkNCg0KdGVtcHNoaWZ0IDwtIExBQV9sb25nDQp0ZW1wc2hpZnQkQWdlTiA8LSB0ZW1wc2hpZnQkQWdlTiArMQ0KdGVtcHNoaWZ0JHllYXIgPC0gdGVtcHNoaWZ0JHllYXIgKzENCm5hbWVzKHRlbXBzaGlmdClbM10gPC0gIkZpcnN0TWVhbkxlbmd0aCINCg0KdGVtcF9kZiA8LSBtZXJnZShMQUFfbG9uZywgdGVtcHNoaWZ0LCBieSA9IGMoIkFnZU4iLCAieWVhciIpLCBhbGwueCA9IFRSVUUpDQoNCm0xIDwtIGxtKE1lYW5MZW5ndGggfiBGaXJzdE1lYW5MZW5ndGgsIGRhdGEgPSB0ZW1wX2RmWyFpcy5uYSh0ZW1wX2RmJE1lYW5MZW5ndGgpICYgIWlzLm5hKHRlbXBfZGYkRmlyc3RNZWFuTGVuZ3RoKSwgXSkNCg0KcGx0X2Z3IDwtIGdncGxvdCh0ZW1wX2RmWyFpcy5uYSh0ZW1wX2RmJE1lYW5MZW5ndGgpICYgIWlzLm5hKHRlbXBfZGYkRmlyc3RNZWFuTGVuZ3RoKSwgXSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IEZpcnN0TWVhbkxlbmd0aCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBNZWFuTGVuZ3RoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQWdlLngpKSArDQogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IEZpcnN0TWVhbkxlbmd0aCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBNZWFuTGVuZ3RoKSwNCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIikgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGVicGFsKSArDQogIHRoZW1lX2ZldygpDQoNCmdncGxvdGx5KHBsdF9mdykNCmBgYA0KDQpGcm9tIHRoaXMgbGluZWFyIG1vZGVsIHdlIGNhbiBjYWxjdWxhdGUgdGhhdCAkTF97XGluZnR5fSA9JCBgciB1bm5hbWUobTEkY29lZmZpY2llbnRzWzFdLygxLW0xJGNvZWZmaWNpZW50c1syXSkpYCwgYW5kICRLID0kIGByIHVubmFtZSgtbG9nKG0xJGNvZWZmaWNpZW50c1syXSkpYC4gTm93IHdlIGNhbiBjYWxjdWxhdGUgdGhlIG5hdHVyYWwgbW9ydGFsaXR5IGVzdGltYXRlcyBmb3IgZWFjaCBhZ2UgYWNyb3NzIHRpbWUuDQoNCkFsdGVybmF0ZWx5LCB3ZSBjYW4gZXN0aW1hdGUgIGFuZCAgZnJvbSByYXcgc3VydmV5IGRhdGEgdXNpbmcgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRpb24uIHdlIGNhbiBsb29rIGF0IHRoZSBsZW5ndGggYXQgYWdlIHBsb3RzIHRvIHByb3Bvc2Ugc29tZSBnb29kIHN0YXJ0aW5nIHBvaW50cyBmb3IgdGhpcyBlc3RpbWF0aW9uLg0KDQpgYGB7ciBlc3RMaW5mYW5kS2Zyb21SYXdEYXRhX1N2ZW59DQojIyBJbml0aWFsaXNpbmcgdmFsdWVzIGZvciBsaW5mLCBrIGFuZCB0MA0KdGhldGEgPC0gYyh1bm5hbWUobTEkY29lZmZpY2llbnRzWzFdLygxLW0xJGNvZWZmaWNpZW50c1syXSkpLA0KICAgICAgICAgICB1bm5hbWUoLWxvZyhtMSRjb2VmZmljaWVudHNbMl0pKSwgDQogICAgICAgICAgIDApDQoNCiMjIEV4cGxpY2l0IGFnZXMgYW5kIGxlbmd0aHMgdG8gYmUgdXNlZCBpbiBvcHRpbWlzYXRpb24NCnRlbXBkZiA8LSBjYV9oaF9maW5fYml0c19pYnRzWyFpcy5uYShjYV9oaF9maW5fYml0c19pYnRzJEFnZSkgJiBjYV9oaF9maW5fYml0c19pYnRzJExuZ3RDbGFzcyA8IDExMCAmIGNhX2hoX2Zpbl9iaXRzX2lidHMkUXVhcnRlciA9PSAxICYgY2FfaGhfZmluX2JpdHNfaWJ0cyRBZ2VOIDwgMjYsIF0NCg0KYWdlIDwtIHRlbXBkZlssICJBZ2VOIl0NCmx0IDwtIHRlbXBkZlssICJMbmd0Q2xhc3MiXQ0KDQojIyBPcHRpbWlzYXRpb24gZnVuY3Rpb24NClNTUSA8LSBmdW5jdGlvbih0aGV0YSwgeCkgew0KICBMaW5mIDwtIHRoZXRhWzFdDQogIEsgPC0gdGhldGFbMl0NCiAgdDAgPC0gdGhldGFbM10NCiAgZXBzaWxvbiA8LSByZXAoMCwgbGVuZ3RoKGFnZSkpDQogIGxwcmVkIDwtIHJlcCgwLCBsZW5ndGgoYWdlKSkNCiAgZm9yIChpIGluIDE6bGVuZ3RoKGFnZSkpIHsNCiAgICBscHJlZFtpXSA8LSBMaW5mICogKDEgLSBleHAoLUsgKiAoYWdlW2ldIC0gdDApKSkNCiAgICBlcHNpbG9uW2ldIDwtIChsdFtpXSAtIGxwcmVkW2ldKV4yDQogIH0NCiAgc3NxIDwtIHN1bShlcHNpbG9uKQ0KICByZXR1cm4oc3NxKQ0KfQ0Kb3V0IDwtIG9wdGltKHRoZXRhLCBmbiA9IFNTUSwgbWV0aG9kID0gIkJGR1MiLCB4ID0gYWdlLCBoZXNzaWFuID0gVFJVRSkNCm91dCRWIDwtIHNvbHZlKG91dCRoZXNzaWFuKSAgI3NvbHZlIHRoZSBoZXNzaWFuDQpvdXQkUyA8LSBzcXJ0KGRpYWcob3V0JFYpKSAgI1N0YW5kYXJkIEVycm9yDQpvdXQkUiA8LSBvdXQkVi8ob3V0JFMgJW8lIG91dCRTKSAgI0NvcnJlbGF0aW9uDQpgYGANCg0KYGBge3IgZXN0aW1hdGVMaW5mYW5kS19sb2dOb3JtRXJyLCBldmFsPUZBTFNFfQ0KTF9pbmYgPC0gdW5uYW1lKG0xJGNvZWZmaWNpZW50c1sxXS8oMS1tMSRjb2VmZmljaWVudHNbMl0pKQ0KSyA8LSB1bm5hbWUoLWxvZyhtMSRjb2VmZmljaWVudHNbMl0pKQ0KdDAgPC0gMA0Kc2QgPC0gMQ0KDQp2YmcgPC0gYmJtbGU6Om1sZTIobG9nKExuZ3RDbGFzcykgfiAjcmVzcG9uc2UgdmFyaWFibGUNCgkJZG5vcm0obWVhbiA9IGxvZyhMX2luZikrbG9nKDEtZXhwKC1LKihBZ2VOLXQwKSkpLCBzZD1zZCksIA0KCQlkYXRhPXRlbXBkZiwgI2RhdGEgZnJhbWUNCgkJc3RhcnQ9bGlzdChMX2luZj1MX2luZiAsIEs9SywgdDA9dDAsIHNkPXNkKSkNCg0KY29lZiA8LSBkYXRhLmZyYW1lKGNvZWZmID0gbmFtZXModmJnQGZ1bGxjb2VmKSwNCiAgICAgICAgICAgICAgICAgICBtZWNoID0gYyhMX2luZiwgSywgdDAsIHNkKSwNCiAgICAgICAgICAgICAgICAgICBlc3QgPSBhcy5udW1lcmljKHZiZ0BmdWxsY29lZikpDQoNCg0KYGBgDQoNCk5vdyBieSB1dGlsaXNpbmcgdGhlIHJhdyBpbnB1dCBkYXRhIHdlIGFycml2ZSBhdCBzaW1pbGFyIHZhbHVlcyBmb3IgTCBhbmQgayBhcyB3ZSBhY2hlaXZlZCB3aXRoIHRoZSBGb3JkLVdhbGZvcmQgbWV0aG9kLg0KDQpgYGB7ciBmaWcuY2FwPSJQbG90IGVzdGltYXRlZCBncm93dGggcGFyYW1ldGVycyBvdmVyIGxlbmd0aHMgYXQgYWdlLiJ9DQp0ZW1wZGYkZXN0X3N2IDwtIG91dCRwYXJbMV0qKDEgLSBleHAoLW91dCRwYXJbMl0gKiAodGVtcGRmJEFnZU4gLSBvdXQkcGFyWzNdKSkpDQp0ZGYgPC0gZGF0YS5mcmFtZShBZ2VOPXNlcShmcm9tID0gMCwgdG89bWF4KHRlbXBkZiRBZ2VOKSwgYnkgPSAwLjEpKQ0KdGRmJGVzdF9zdiA8LSBvdXQkcGFyWzFdKigxIC0gZXhwKC1vdXQkcGFyWzJdICogKHRkZiRBZ2VOIC0gb3V0JHBhclszXSkpKQ0KDQpnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IHRlbXBkZiwNCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBBZ2VGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IExuZ3RDbGFzcykpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSB0ZGYsIG1hcHBpbmcgPSBhZXMoeCA9IEFnZU4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBlc3Rfc3YpLA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0sDQogICAgICAgICAgICBzaXplID0gMikgKw0KICB0aGVtZV9mZXcoKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoZWJwYWwpKSArDQogIGd1aWRlcyhjb2xvdXIgPSAibm9uZSIsIGZpbGwgPSAibm9uZSIpDQpgYGANCg0KQWZ0ZXIgYWxsIG9mIHRoaXMsIHRoZXNlIGxpZmUgaGlzdG9yeSBwYXJhbWV0ZXJzIGRvIG5vdCBsb29rIGFjY2VwdGFibGUgZm9yIHRoaXMgc3BlY2llcy4gIFRoZXJlZm9yZSB3ZSB0YWtlIHZhbHVlcyBmcm9tIFtmaXNoYmFzZS5zZV0oaHR0cHM6Ly9maXNoYmFzZS5zZS9wb3BkeW4vUG9wR3Jvd3RoTGlzdC5waHA/SUQ9MTM0MiZHZW51c05hbWU9UGxldXJvbmVjdGVzJlNwZWNpZXNOYW1lPXBsYXRlc3NhJmZjPTQ0MCksIHN1Y2ggdGhhdDogJExfe1xpbmZ0eX0gPSQgNTJjbSBhbmQgJEsgPSQgMC4xNjggKCR0MCA9JCAtMC43MiwgaW4gdGhpcyBjYXNlKS4NCmBgYHtyIGFzZWxlY3RQYXJhbXN9DQojIyBTZWxlY3QgbGlmZSBoaXN0b3J5IHBhcmFtZXRlcnMNCkxpbmYgPC0gNTIgI0Zpc2hiYXNlIGZvciBCYWx0aWMNCksgPC0gMC4xNjggI0Zpc2hiYXNlIGZvciBCYWx0aWMNCnQwIDwtIC0wLjcyICNGaXNoYmFzZSBmb3IgQmFsdGljDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iUGxvdCBvZiBTZWxlY3RlZCBWQkdGLiJ9DQp0ZGYgPC0gZGF0YS5mcmFtZShBZ2VOPXNlcShmcm9tID0gMCwgdG89bWF4KHRlbXBkZiRBZ2VOKSwgYnkgPSAwLjEpKQ0KdGRmJHZiZ2YgPC0gTGluZiooMSAtIGV4cCgtSyAqICh0ZGYkQWdlTiAtIHQwKSkpDQpnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gdGRmLCBtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmJnZiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHRoZW1lX2ZldygpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYnBhbCkpICsNCiAgZ3VpZGVzKGNvbG91ciA9ICJub25lIiwgZmlsbCA9ICJub25lIikNCmBgYA0KDQpgYGB7ciBubUNhbGNzfQ0KIyMgQ2FsY3VsYXRlIGFubnVhbGx5IHZhcnlpbmcgbmF0dXJhbCBtb3J0YWxpdHkNCkxBQV9sb25nJG5tIDwtIGV4cCgwLjU1IC0gMS42MSpsb2coTEFBX2xvbmckTWVhbkxlbmd0aCkgKyAxLjQ0KmxvZyhMaW5mKSArIGxvZyhLKSkNCm5tX3ZhciA8LSBMQUFfbG9uZ1shaXMubmEoTEFBX2xvbmckbm0pLCBdDQoNCiMjIEFnZ3JlZ2F0ZSB0byB0aW1lIGludmFyaWFudCBuYXR1cmFsIG1vcnRhbGl0eSANCm5tX2ZpeCA8LSBhZ2dyZWdhdGUobm0gfiBBZ2VOLCBkYXRhID0gbm1fdmFyLCBGVU4gPSAibWVhbiIpDQoNCm5tX3N0ZHIgPC0gYWdncmVnYXRlKG5tIH4gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBubV92YXIsDQogICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KXtzZCh4LCBuYS5ybSA9IFRSVUUpL3NxcnQobGVuZ3RoKG5hLm9taXQoeCkpKX0pDQoNCm5hbWVzKG5tX3N0ZHIpWzJdIDwtICJTdGRFcnIiDQpubV9zdGRyIDwtIG1lcmdlKG5tX3N0ZHIsIG5tX2ZpeCwgYnk9IkFnZU4iLCBhbGwueSA9IFQpDQpubV9zdGRyJHltYXggPC0gbm1fc3RkciRubSArIDEuOTYqbm1fc3RkciRTdGRFcnINCm5tX3N0ZHIkeW1pbiA8LSBubV9zdGRyJG5tIC0gMS45NipubV9zdGRyJFN0ZEVycg0KDQpubV92YXIkWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKG5tX3ZhciR5ZWFyKSkNCm5tX3ZhciRBZ2UgPC0gZmFjdG9yKGFzLmNoYXJhY3RlcihubV92YXIkQWdlTiksIGxldmVscyA9IHVuaXF1ZShhcy5jaGFyYWN0ZXIobm1fdmFyJEFnZU4pKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJUaW1lIGFuZCBhZ2UgdmFyeWluZyBuYXR1cmFsIG1vcnRhbGl0eSBiYXNlZCBvbiBHaXNsYXNvbi4gVGltZSBmYWNldGVkIGJ5IGFnZS4ifQ0KcGx0X25tdmFyX2FnZSA8LSBnZ3Bsb3Qobm1fdmFyKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbm0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBBZ2UpKSArDQogIGZhY2V0X3dyYXAoZmFjZXRzID0gIkFnZSIsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCkgKw0KICB0aGVtZV9mZXcoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQ0KDQpnZ3Bsb3RseShwbHRfbm12YXJfYWdlKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlRpbWUgYW5kIGFnZSB2YXJ5aW5nIG5hdHVyYWwgbW9ydGFsaXR5IGJhc2VkIG9uIEdpc2xhc29uLiBBZ2VzIGZhY2V0ZWQgYnkgdGltZS4ifQ0KcGx0X25tdmFyX3llYXIgPC0gZ2dwbG90KG5tX3ZhcikgKw0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG5tKSkgKw0KICBmYWNldF93cmFwKGZhY2V0cyA9ICJZZWFyIikgKw0KICB0aGVtZV9mZXcoKQ0KDQpnZ3Bsb3RseShwbHRfbm12YXJfeWVhcikNCmBgYA0KDQpgYGB7ciBubXRpbWV2YXJHaXNsYXNvbn0NCm5tX3NhbSA8LSBhcy5kYXRhLmZyYW1lKG5tX3ZhclssIGMoIkFnZU4iLCAieWVhciIsICJubSIpXSkNCm5tX3NhbSA8LSByZXNoYXBlKG5tX3NhbSwNCiAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJubSIsDQogICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlTiIsDQogICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAid2lkZSIpDQoNCg0KI1JhdyBhbm51YWwgZXN0aW1hdGVzDQpubV9TQU0gPC0gbm1fc2FtDQojIGZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiMgICBmb3IoaiBpbiAxOm5yb3cobm1fU0FNKSl7DQojICAgICBubV9TQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG5tX1NBTVtqLCBpXSksIC05LCBubV9TQU1baiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyMgTWFrZSBlYXJseSAiTkEiIFZhbHVlcyBwbGF1c2libGUNCmZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiAgZm9yKGogaW4gMTpucm93KG5tX1NBTSkpew0KICAgIG5tX1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobm1fU0FNW2osIGldKSwgbWVkaWFuKGMobm1fU0FNWyxpXSksIG5hLnJtID0gVCksIG5tX1NBTVtqLCBpXSkNCiAgfQ0KfQ0KDQpzYXZlX2FzX2xvd2VzdG9mdChkZiA9IG5tX1NBTVtubV9TQU0keWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBjb2xuYW1lcyhubV9TQU0pWy0xXV0sDQogICAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSAiQXNzZXNzbWVudCBJbnB1dC9OYXR1cmFsTW9ydGFsaXR5VmFyaWFudHMvdGltZVZhcmlhbnRHaXNsYXNvblJhd19ubS5kYXQiLA0KICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiTmF0dXJhbCBtb3J0YWxpdHkgZXN0aW1hdGVzIGZyb20gR2lzbGFzb24gbWV0aG9kLCBhbm51YWwgZXN0aW1hdGlvbnMgYnkgYWdlIGFuZCB5ZWFyLiIsDQogICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygxLCA0KSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHllYXJfcmFuZ2UgPSBwYXN0ZShjKDIwMDIsIChEYXRhWWVhcisxKSksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICBhZ2VfcmFuZ2UgPSBwYXN0ZShjKDEsIDEwKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHRpbWVzZXJpZXNfdHlwZSA9IDEpDQoNCiMjIENhbGN1bGF0ZSAzeSBzbGlkaW5nIHdpbmRvdyBhdmVyYWdlIGZvciB3aG9sZSB0aW1lc2VyaWVzIC0tLS0NCiMjIyBDYWxjdWxhdGUgdGhlIG1lYW4gLS0tLQ0KYWRhIDwtIGFuKDMsIG5yb3cobm1fc2FtKSkNCm5tRzNzdyA8LSBmcm9sbG1lYW4oeCA9IG5tX3NhbVssIC0xXSwgbiA9IGFkYSwgbmEucm0gPSBULCBhbGlnbiA9ICJyaWdodCIsIGFkYXB0aXZlID0gVFJVRSkNCm5tRzNzdyA8LSBhcy5kYXRhLmZyYW1lKGRvLmNhbGwoY2JpbmQsIG5tRzNzdykpDQojIyMjIFJldGFpbiBvbmx5IHRoZSBjb3JyZWN0IHllYXJzDQpubUczc3ckeWVhciA8LSBubV9zYW0keWVhcg0Kbm1HM3N3IDwtIG5tRzNzd1tubUczc3ckeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBdDQoNCg0KDQojIyMjIFdpZGUgdG8gbG9uZyBmb3JtYXQNCm5tRzNzd0wgPC0gcmVzaGFwZShubUczc3csDQogICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMobm1HM3N3KVstMTFdLA0KICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJubSIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKG5tRzNzdylbLTExXSwNCiAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0Kbm1HM3N3TCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBubUczc3dMJEFnZSkpDQoNCiMjIyBDYWxjdWFsdGUgdGhlIHN0YW5kYXJkIGVycm9yIC0tLS0NCm5tRzNzdGRyIDwtIGZyb2xsYXBwbHkobm1fc2FtWywgLTFdLA0KICAgICAgICAgICAgICAgICAgICAgIDMsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0Kbm1HM3N0ZHIgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBubUczc3RkcikpDQpubUczc3RkciR5ZWFyIDwtIG5tX3NhbSR5ZWFyDQoNCiMjIyMgUmV0YWluIG9ubHkgdGhlIGNvcnJlY3QgeWVhcnMNCm5tRzNzdGRyIDwtIG5tRzNzdGRyW25tRzNzdGRyJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSxdDQoNCiMjIyMgV2lkZSB0byBsb25nIGZvcm1hdA0Kbm1HM3N0ZHJMIDwtIHJlc2hhcGUobm1HM3N0ZHIsDQogICAgICAgICAgICAgICAgICAgIHZhcnlpbmcgPSBjb2xuYW1lcyhubUczc3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJTdGRFcnJubSIsDQogICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgICAgICAgdGltZXMgPSBjb2xuYW1lcyhubUczc3RkcilbLTExXSwNCiAgICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCm5tRzNzdGRyTCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBubUczc3RkckwkQWdlKSkNCg0KIyMjIENhbGN1bGF0ZSA5MyUgY29uZmlkZW5jZSBpbnRlcnZhbHMgLS0tLQ0Kbm1HM3N3TCA8LSBtZXJnZSh4ID0gbm1HM3N3TCwgeSA9IG5tRzNzdGRyTCwgYnkgPSBjKCJ5ZWFyIiwgIkFnZSIpLCBhbGwueCA9IFRSVUUpDQpubUczc3dMJHltYXggPC0gbm1HM3N3TCRubSArICgxLjk2Km5tRzNzd0wkU3RkRXJybm0pDQpubUczc3dMJHltaW4gPC0gbm1HM3N3TCRubSAtICgxLjk2Km5tRzNzd0wkU3RkRXJybm0pDQpubUczc3dMJEFnZU4gPC0gbm1HM3N3TCRBZ2UNCm5tRzNzd0wkQWdlIDwtIGFzLmNoYXJhY3RlcihubUczc3dMJEFnZSkNCm5tRzNzd0wgPC0gbm1HM3N3TFtubUczc3dMJHllYXIgJWluJSBjKDIwMDI6KERhdGFZZWFyKzEpKSxdDQoNCm5tX1NBTSA8LSBubUczc3cNCiMgZm9yKGkgaW4gMTpuY29sKG5tX1NBTSkpew0KIyAgIGZvcihqIGluIDE6bnJvdyhubV9TQU0pKXsNCiMgICAgIG5tX1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobm1fU0FNW2osIGldKSwgLTksIG5tX1NBTVtqLCBpXSkNCiMgICB9DQojIH0NCg0KIyMjIyBNYWtlIGVhcmx5ICJOQSIgVmFsdWVzIHBsYXVzaWJsZQ0KZm9yKGkgaW4gMTpuY29sKG5tX1NBTSkpew0KICBmb3IoaiBpbiAxOm5yb3cobm1fU0FNKSl7DQogICAgbm1fU0FNW2osIGldIDwtIGlmZWxzZShpcy5uYShubV9TQU1baiwgaV0pLCBtZWRpYW4oYyhubV9TQU1bLGldKSwgbmEucm0gPSBUKSwgbm1fU0FNW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gbm1fU0FNW25tX1NBTSR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksIGNvbG5hbWVzKG5tX1NBTSlbLTExXV0sDQogICAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSAiQXNzZXNzbWVudCBJbnB1dC9OYXR1cmFsTW9ydGFsaXR5VmFyaWFudHMvdGltZVZhcmlhbnRHaXNsYXNvbjN5c3dfbm0uZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIk5hdHVyYWwgbW9ydGFsaXR5IGVzdGltYXRlcyBmcm9tIEdpc2xhc29uIG1ldGhvZCwgZml2ZSB5ZWFyIHNsaWRpbmcgd2luZG93IG1lYW5zLCBieSBhZ2UgYW5kIHllYXIuIiwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKDEsIDQpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gMSkNCg0KDQoNCiMjIENhbGN1bGF0ZSA1eSBzbGlkaW5nIHdpbmRvdyBhdmVyYWdlIGZvciB3aG9sZSB0aW1lc2VyaWVzIC0tLS0NCiMjIyBDYWxjdWxhdGUgdGhlIG1lYW4gLS0tLQ0KYWRhIDwtIGFuKDUsIG5yb3cobm1fc2FtKSkNCm5tRzVzdyA8LSBmcm9sbG1lYW4oeCA9IG5tX3NhbVssIC0xXSwgbiA9IGFkYSwgbmEucm0gPSBULCBhbGlnbiA9ICJyaWdodCIsIGFkYXB0aXZlID0gVFJVRSkNCm5tRzVzdyA8LSBhcy5kYXRhLmZyYW1lKGRvLmNhbGwoY2JpbmQsIG5tRzVzdykpDQojIyMjIE1ha2UgdGhlIGZpcnN0IHllYXIgZXF1YWwgdG8gdGhlIGZpcnN0IGNhbGN1bGFibGUgNXkgYXZlcmFnZQ0Kbm1HNXN3JHllYXIgPC0gbm1fc2FtJHllYXINCiMgbW81c3dbbW81c3ckeWVhciA9PSAyMDAyLCAtbmNvbChtbzVzdyldIDwtIG1vNXN3W21vNXN3JHllYXIgPT0gMjAwMywgLW5jb2wobW81c3cpXQ0Kbm1HNXN3IDwtIG5tRzVzd1tubUc1c3ckeWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLF0NCg0KDQojIyMjIFdpZGUgdG8gbG9uZyBmb3JtYXQNCm5tRzVzd0wgPC0gcmVzaGFwZShubUc1c3csDQogICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMobm1HNXN3KVstMTFdLA0KICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJubSIsDQogICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICB0aW1lcyA9IGNvbG5hbWVzKG5tRzVzdylbLTExXSwNCiAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0Kbm1HNXN3TCRBZ2UgPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSAiViIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSBubUc1c3dMJEFnZSkpDQoNCiMjIyBDYWxjdWFsdGUgdGhlIHN0YW5kYXJkIGVycm9yIC0tLS0NCm5tRzVzdGRyIDwtIGZyb2xsYXBwbHkobm1fc2FtWywgLTFdLA0KICAgICAgICAgICAgICAgICAgICAgIDUsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCl7c2QoeCwgbmEucm0gPSBUUlVFKS9zcXJ0KGxlbmd0aChuYS5vbWl0KHgpKSl9KQ0Kbm1HNXN0ZHIgPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBubUc1c3RkcikpDQpubUc1c3RkciR5ZWFyIDwtIG5tX3NhbSR5ZWFyDQoNCiMjIyMgTWFrZSB0aGUgZmlyc3QgeWVhciBlcXVhbCB0byB0aGUgZmlyc3QgY2FsY3VsYWJsZSA1eSBhdmVyYWdlDQpubUc1c3RkcltubUc1c3RkciR5ZWFyID09IDIwMDIsIC1uY29sKG5tRzVzdGRyKV0gPC0gbm1HNXN0ZHJbbm1HNXN0ZHIkeWVhciA9PSAyMDAzLCAtbmNvbChubUc1c3RkcildDQpubUc1c3RkciA8LSBubUc1c3RkcltubUc1c3RkciR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksXQ0KDQojIyMjIFdpZGUgdG8gbG9uZyBmb3JtYXQNCm5tRzVzdGRyTCA8LSByZXNoYXBlKG5tRzVzdGRyLA0KICAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gY29sbmFtZXMobm1HNXN0ZHIpWy0xMV0sDQogICAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAiU3RkRXJybm0iLA0KICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZSIsDQogICAgICAgICAgICAgICAgICAgIHRpbWVzID0gY29sbmFtZXMobm1HNXN0ZHIpWy0xMV0sDQogICAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQpubUc1c3RkckwkQWdlIDwtIGFzLm51bWVyaWMoZ3N1YihwYXR0ZXJuID0gIlYiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gbm1HNXN0ZHJMJEFnZSkpDQoNCiMjIyBDYWxjdWxhdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIC0tLS0NCm5tRzVzd0wgPC0gbWVyZ2UoeCA9IG5tRzVzd0wsIHkgPSBubUc1c3RkckwsIGJ5ID0gYygieWVhciIsICJBZ2UiKSwgYWxsLnggPSBUUlVFKQ0Kbm1HNXN3TCR5bWF4IDwtIG5tRzVzd0wkbm0gKyAoMS45NipubUc1c3dMJFN0ZEVycm5tKQ0Kbm1HNXN3TCR5bWluIDwtIG5tRzVzd0wkbm0gLSAoMS45NipubUc1c3dMJFN0ZEVycm5tKQ0Kbm1HNXN3TCRBZ2VOIDwtIG5tRzVzd0wkQWdlDQpubUc1c3dMJEFnZSA8LSBhcy5jaGFyYWN0ZXIobm1HNXN3TCRBZ2UpDQpubUc1c3dMIDwtIG5tRzVzd0xbbm1HNXN3TCR5ZWFyICVpbiUgYygyMDAyOihEYXRhWWVhcisxKSksXQ0KDQpubV9TQU0gPC0gbm1HNXN3DQojIGZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiMgICBmb3IoaiBpbiAxOm5yb3cobm1fU0FNKSl7DQojICAgICBubV9TQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG5tX1NBTVtqLCBpXSksIC05LCBubV9TQU1baiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyMgTWFrZSBlYXJseSAiTkEiIFZhbHVlcyBwbGF1c2libGUNCmZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiAgZm9yKGogaW4gMTpucm93KG5tX1NBTSkpew0KICAgIG5tX1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobm1fU0FNW2osIGldKSwgbWVkaWFuKGMobm1fU0FNWyxpXSksIG5hLnJtID0gVCksIG5tX1NBTVtqLCBpXSkNCiAgfQ0KfQ0KDQpzYXZlX2FzX2xvd2VzdG9mdChkZiA9IG5tX1NBTVtubV9TQU0keWVhciAlaW4lIGMoMjAwMjooRGF0YVllYXIrMSkpLCBjb2xuYW1lcyhubV9TQU0pWy0xMV1dLA0KICAgICAgICAgICAgICAgICAgZmlsZV9wYXRoID0gIkFzc2Vzc21lbnQgSW5wdXQvTmF0dXJhbE1vcnRhbGl0eVZhcmlhbnRzL3RpbWVWYXJpYW50R2lzbGFzb241eXN3X25tLmRhdCIsDQogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJOYXR1cmFsIG1vcnRhbGl0eSBlc3RpbWF0ZXMgZnJvbSBHaXNsYXNvbiBtZXRob2QsIGZpdmUgeWVhciBzbGlkaW5nIHdpbmRvdyBtZWFucywgYnkgYWdlIGFuZCB5ZWFyLiIsDQogICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygxLCA0KSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHllYXJfcmFuZ2UgPSBwYXN0ZShjKDIwMDIsIChEYXRhWWVhcisxKSksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICBhZ2VfcmFuZ2UgPSBwYXN0ZShjKDEsIDEwKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHRpbWVzZXJpZXNfdHlwZSA9IDEpDQoNCmBgYA0KDQoNCmBgYHtyIGZpZy5jYXA9IkFnZSB2YXJ5aW5nIG5hdHVyYWwgbW9ydGFsaXR5IGJhc2VkIG9uIEdpc2xhc29uIChtZWFuIHZhbHVlcyBmcm9tIGFib3ZlIHRpbWUgc2VyaWVzICsvLSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIn0NCnBsdF9ubWZpeCA8LSBnZ3Bsb3Qobm1fc3RkcikgKw0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gQWdlTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG5tKSkgKw0KICBnZW9tX3JpYmJvbihtYXBwaW5nID0gYWVzKHggPSBBZ2VOLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSB5bWF4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSB5bWluKSwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgdGhlbWVfZmV3KCkNCg0KZ2dwbG90bHkocGx0X25tZml4KQ0KYGBgDQpgYGB7ciB0YWJsZVRpbWVJbnZhcmlhbnRNb3J0YWxpdHl9DQojIyMgc2F2ZV9hc19sb3dlc3RvZnQgRml2ZSBZZWFyIFNsaWRpbmcgV2luZG93DQpubV9TQU0gPC0gbm1fc3Rkcg0Kbm1fU0FNJHllYXIgPC0gcmVwKCJhbGwiLCBucm93KG5tX1NBTSkpDQpubV9TQU0gPC0gcmVzaGFwZShubV9TQU1bLCBjKCJBZ2VOIiwgIm5tIiwgInllYXIiKV0sDQogICAgICAgICAgICAgICAgICMgdmFyeWluZyA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIobm1fc3RkciRBZ2VOKSksDQogICAgICAgICAgICAgICAgIHYubmFtZXMgPSAibm0iLA0KICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkFnZU4iLA0KICAgICAgICAgICAgICAgICBpZHZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIndpZGUiKQ0KDQojIGZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiMgICBmb3IoaiBpbiAxOm5yb3cobm1fU0FNKSl7DQojICAgICBubV9TQU1baiwgaV0gPC0gaWZlbHNlKGlzLm5hKG5tX1NBTVtqLCBpXSksIC05LCBubV9TQU1baiwgaV0pDQojICAgfQ0KIyB9DQoNCiMjIyMgTWFrZSBlYXJseSAiTkEiIFZhbHVlcyBwbGF1c2libGUNCmZvcihpIGluIDE6bmNvbChubV9TQU0pKXsNCiAgZm9yKGogaW4gMTpucm93KG5tX1NBTSkpew0KICAgIG5tX1NBTVtqLCBpXSA8LSBpZmVsc2UoaXMubmEobm1fU0FNW2osIGldKSwgbWVkaWFuKGMobm1fU0FNWyxpXSksIG5hLnJtID0gVCksIG5tX1NBTVtqLCBpXSkNCiAgfQ0KfQ0KDQpzYXZlX2FzX2xvd2VzdG9mdChkZiA9IG5tX1NBTVssIGNvbG5hbWVzKG5tX1NBTSlbLTFdXSwNCiAgICAgICAgICAgICAgICAgIGZpbGVfcGF0aCA9ICJBc3Nlc3NtZW50IElucHV0L05hdHVyYWxNb3J0YWxpdHlWYXJpYW50cy90aW1lSW52YXJpYW50R2lzbGFzb25fbm0uZGF0IiwNCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gIk5hdHVyYWwgbW9ydGFsaXR5IGVzdGltYXRlcyBmcm9tIEdpc2xhc29uIG1ldGhvZCwgdGltZXNlcmllcyBtZWFucyBieSBhZ2UgZm9yIHRpbWUtaW52YXJpYW50IHByb2ZpbGUuIiwNCiAgICAgICAgICAgICAgICAgIHJhbmRvX251bWJlcnMgPSBwYXN0ZShjKDEsIDQpLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgeWVhcl9yYW5nZSA9IHBhc3RlKGMoMjAwMiwgKERhdGFZZWFyKzEpKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIGFnZV9yYW5nZSA9IHBhc3RlKGMoMSwgMTApLCBjb2xsYXBzZSA9ICJcdCIpLA0KICAgICAgICAgICAgICAgICAgdGltZXNlcmllc190eXBlID0gMikNCg0KI1RhYmxlIGZvciBIVE1MDQprYWJsZShubV9zdGRyLA0KICAgICAgY2FwdGlvbiA9ICJNZWFuIG1vcnRhbGl0aWVzIGJ5IGFnZSBmb3IgdGltZSBpbnZhcmlhbnQgbmF0dXJhbCBtb3J0YWxpdHkgaW4gU0FNLiIpDQpgYGANCg0KQmFzZWQgb24gc2NhbGluZyB0aGVzZSB0aW1lLWludmFyaWFudCBuYXR1cmFsIG1vcnRhbGl0aWVzIHVwIGFuIGRvd24sIGFuIG9wdGltaXNlZCBsaWtlbGlob29kIHByb2ZpbGUgZm91bmQgdGhhdCBzY2FsaW5nIGFsbCBhZ2VzIGJ5IGEgZmFjdG9yIG9mIDEuMiBwcm9kdWNlZCB0aGUgYmVzdCBtb2RlbCBmaXQuIFRvIHNlZSB0aGUgZGV0YWlscyBvZiB0aGlzIHBsZWFzZSBzZWUgdGhlIHdvcmtpbmcgcmVwb3J0LCBvciBzY3JpcHQgaW4gdGhlIGFwcGVuZGl4Lg0KDQpgYGB7ciB0YWJsZVNjYWxlZFRpbWVJbnZhcmlhbnRNb3J0YWxpdHl9DQojIyMgc2F2ZV9hc19sb3dlc3RvZnQgRml2ZSBZZWFyIFNsaWRpbmcgV2luZG93DQpubV9zY2FsZWQgPC0gbm1fc3Rkcg0Kbm1fc2NhbGVkJHllYXIgPC0gcmVwKCJhbGwiLCBucm93KG5tX3NjYWxlZCkpDQpubV9zY2FsZWQkbm0gPC0gbm1fc2NhbGVkJG5tKjEuMg0Kbm1fc2NhbGVkIDwtIHJlc2hhcGUobm1fc2NhbGVkWywgYygiQWdlTiIsICJubSIsICJ5ZWFyIildLA0KICAgICAgICAgICAgICAgICAjIHZhcnlpbmcgPSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKG5tX3N0ZHIkQWdlTikpLA0KICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gIm5tIiwNCiAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2VOIiwNCiAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ3aWRlIikNCg0KIyBmb3IoaSBpbiAxOm5jb2wobm1fc2NhbGVkKSl7DQojICAgZm9yKGogaW4gMTpucm93KG5tX3NjYWxlZCkpew0KIyAgICAgbm1fc2NhbGVkW2osIGldIDwtIGlmZWxzZShpcy5uYShubV9zY2FsZWRbaiwgaV0pLCAtOSwgbm1fc2NhbGVkW2osIGldKQ0KIyAgIH0NCiMgfQ0KDQojIyMjIE1ha2UgZWFybHkgIk5BIiBWYWx1ZXMgcGxhdXNpYmxlDQpmb3IoaSBpbiAxOm5jb2wobm1fc2NhbGVkKSl7DQogIGZvcihqIGluIDE6bnJvdyhubV9zY2FsZWQpKXsNCiAgICBubV9zY2FsZWRbaiwgaV0gPC0gaWZlbHNlKGlzLm5hKG5tX3NjYWxlZFtqLCBpXSksIG1lZGlhbihjKG5tX3NjYWxlZFssaV0pLCBubV9zY2FsZWQgPSBUKSwgbm1fc2NhbGVkW2osIGldKQ0KICB9DQp9DQoNCnNhdmVfYXNfbG93ZXN0b2Z0KGRmID0gbm1fc2NhbGVkWywgY29sbmFtZXMobm1fc2NhbGVkKVstMV1dLA0KICAgICAgICAgICAgICAgICAgZmlsZV9wYXRoID0gIkFzc2Vzc21lbnQgSW5wdXQvTmF0dXJhbE1vcnRhbGl0eVZhcmlhbnRzL3NjYWxlZFRpbWVJbnZhcmlhbnRHaXNsYXNvbl9ubS5kYXQiLA0KICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiVGltZSBpbnZhcmlhbnQgbmF0dXJhbCBtb3J0YWxpdHkgZXN0aW1hdGVzIGZyb20gR2lzbGFzb24gbWV0aG9kIHNjYWxlZCBhY2NvcmRpbmcgdG8gb3B0aW1pc2VkIGxpa2VsaWhvb2QgcHJvZmlsZSBydW5zLiIsDQogICAgICAgICAgICAgICAgICByYW5kb19udW1iZXJzID0gcGFzdGUoYygxLCA0KSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHllYXJfcmFuZ2UgPSBwYXN0ZShjKDIwMDIsIChEYXRhWWVhcisxKSksIGNvbGxhcHNlID0gIlx0IiksDQogICAgICAgICAgICAgICAgICBhZ2VfcmFuZ2UgPSBwYXN0ZShjKDEsIDEwKSwgY29sbGFwc2UgPSAiXHQiKSwNCiAgICAgICAgICAgICAgICAgIHRpbWVzZXJpZXNfdHlwZSA9IDIpDQoNCiNUYWJsZSBmb3IgSFRNTA0Ka2FibGUobm1fc3RkciwNCiAgICAgIGNhcHRpb24gPSAiVGltZSBpbnZhcmlhbnQgbmF0dXJhbCBtb3J0YWxpdHkgZXN0aW1hdGVzIGZyb20gR2lzbGFzb24gbWV0aG9kIHNjYWxlZCBhY2NvcmRpbmcgdG8gb3B0aW1pc2VkIGxpa2VsaWhvb2QgcHJvZmlsZSBydW5zLiIpDQpgYGANCg0KDQojIyMgQ2F0Y2ggd2VpZ2h0IGF0IGFnZSAoQ1dBQSkNClRoaXMgc2VjdGlvbiBpcyBjdXJyZW50bHkgYSB3b3JrIGluIHByb2dyZXNzIC0gbmVlZCB0byBmaWd1cmUgb3V0IHRoZSBhcHByb3ByaWF0ZSBtZXRob2QgdG8gcmFpc2UgaW50ZXJjYXRjaCBkYXRhIGFjY29yZGluZyB0byB0aGUgYWxsb2NhdGlvbnMsIG1hbnVhbGx5LCB0byBiZSBhYmxlIHRvIGF1dG9tYXRpY2FsbHkgdXBkYXRlIHRoZSBzZWN0aW9uIGVhY2ggeWVhciAoaW5zdGVhZCBvZiBjb3B5LXBhc3RpbmcgaW50ZXJjYXRjaCBvdXB1dCBmb3IgbXVsdGlwbGUgdGFibGVzIGV2ZXJ5IHllYXIpLg0KYGBge3IgQ1dBQSB0YWJsZSwgZXZhbD1GQUxTRX0NCmN3X2RmIDwtIGN3DQoNCmBgYA0KIyMgQ29ob3J0IFRyYWNraW5nDQpXZSBjYW4gdHJhY2sgdGhlIHByb2dyZXNzaW9uIG9mIGRpZmZlcmVudCBjb2hvcnRzIHRocm91Z2ggdGltZSBmcm9tIGJvdGggY29tbWVyY2lhbCBhbmQgc3VydmV5IGRhdGEuDQoNCkxldCdzIHN0YXJ0IHdpdGggY2F0Y2hlcy4NCmBgYHtyIGZpZy5jYXA9ICJCdWJibGUgcGxvdCBzaG93aW5nIG51bWJlcnMgKHNpemUgb2YgYnViYmxlKSBhdCBhZ2UgKHktYXhpcyksIG92ZXIgdGltZSAoeC1heGlzKSBpbiBjYXRjaGVzLiAgVGhlIGRvdHRlZCBsaW5lcyBzaG93IHRoZSBwcm9ncmVzc2lvbiBvZiBjby1ob3J0cyB3aGVyZSBsYXJnZSBhbmQgc21hbGwgbnVtYmVycyBhdCBhZ2UgY2FuIGJlIHRyYWNrZWQgeWVhciB0byB5ZWFyLiJ9DQojPT09DQojIERhdGEgUHJlcA0KIz09PT0NCmNhdGNoTnVtTG5nIDwtIHJlc2hhcGUoZGF0YSA9IGNhdGNoTnVtLA0KICAgICAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gbGlzdChjb2xuYW1lcyhjYXRjaE51bSlbMjpsZW5ndGgoKGNvbG5hbWVzKGNhdGNoTnVtKSkpXSksDQogICAgICAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSBjKCJOdW1iZXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQojIGNhdGNoTnVtTG5nJEFnZSA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGNhdGNoTnVtTG5nJEFnZSkpDQojIGNhdGNoTnVtTG5nJEFnZSA8LSBmYWN0b3IoY2F0Y2hOdW1MbmckQWdlLCBsZXZlbHMgPSBjKCIxIiwgIjIiLCAiMyIsICI0IiwgIjUiLCAiNiIsICI3IiwgIjgiLCAiOSIsICIxMCIpKQ0KIyBjYXRjaE51bUxuZyRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoY2F0Y2hOdW1MbmckWWVhcikpDQpjYXRjaE51bUxuZyRZZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNhdGNoTnVtTG5nJFllYXIpKQ0KDQpjYXRjaGNvaG9ydHNMbmcgPC0gcmVzaGFwZShkYXRhID0gY2F0Y2hjb2hvcnRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGxpc3QoY29sbmFtZXMoY2F0Y2hjb2hvcnRzKVsyOmxlbmd0aCgoY29sbmFtZXMoY2F0Y2hjb2hvcnRzKSkpXSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gYygiQWdlIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1ldmFyID0gIkNvaG9ydCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQojIGNhdGNoY29ob3J0c0xuZyRBZ2UgPC0gZmFjdG9yKGNhdGNoY29ob3J0c0xuZyRBZ2UsIGxldmVscyA9IGMoIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIsICI2IiwgIjciLCAiOCIsICI5IiwgIjEwIikpDQojIGNhdGNoY29ob3J0c0xuZyRBZ2UgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihjYXRjaGNvaG9ydHNMbmckQWdlKSwgbGV2ZWxzID0gYygiMSIsICIyIiwgIjMiLCAiNCIsICI1IiwgIjYiLCAiNyIsICI4IiwgIjkiLCAiMTAiKSkNCiMgY2F0Y2hjb2hvcnRzTG5nJFllYXIgPC0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihjYXRjaGNvaG9ydHNMbmckWWVhcikpDQpjYXRjaGNvaG9ydHNMbmckWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihjYXRjaGNvaG9ydHNMbmckWWVhcikpDQojPT09PT0NCg0KIz09PQ0KIyBGaWd1cmUgQ29ob3J0cyBvdmVyIHRpbWUgZnJvbSBjYXRjaGVzDQojPT09PQ0KcGx0X2NhdGNoQ29ob3J0cyA8LSBnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gY2F0Y2hjb2hvcnRzTG5nLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb2hvcnQpLA0KICAgICAgICAgICAgbGluZXR5cGUgPSAiZG90dGVkIikgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBjYXRjaE51bUxuZywNCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBOdW1iZXIpKSArDQogIHRoZW1lX2NsZWFuKCkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMTk5OSxEYXRhWWVhcikpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpDQoNCmdncGxvdGx5KHBsdF9jYXRjaENvaG9ydHMpDQojPT09PQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9ICJOdW1iZXJzIHBlciBhZ2Ugb3ZlciB0aW1lLiIsIGZpZy5oZWlnaHQ9N30NCiM9PT0NCiMgRmlndXJlIE51bWJlcnMgcGVyIGFnZSBncm91cCBvdmVyIHRpbWUgKGxlc3MgaW50dWl0aXZlIHRoYW4gYWJvdmUgY29ob3J0IHBsb3QpDQojPT09PQ0KcGx0X2NhdGNoVGltZSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gY2F0Y2hOdW1MbmcsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gTnVtYmVyLzEwMDAwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQWdlKSkgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKEFnZSksIHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgeWxhYigiTnVtYmVyIChtaWxsaW9ucykiKSArDQogIHRoZW1lX2ZldygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSkpDQoNCmdncGxvdGx5KHBsdF9jYXRjaFRpbWUpDQojPT09PT0NCmBgYA0KDQpOb3csIGxldCdzIGRvIHRoZSBzYW1lIHdpdGggc3VydmV5IGVzdGltYXRpb25zIG9mIG51bWJlcnMgYXQgYWdlLg0KYGBge3IgZmlnLmNhcD0gIkJ1YmJsZSBwbG90IHNob3dpbmcgbnVtYmVycyAoc2l6ZSBvZiBidWJibGUpIGF0IGFnZSAoeS1heGlzKSwgb3ZlciB0aW1lICh4LWF4aXMpIGVzdGltYXRlZCBmcm9tIHN1cnZleXMuICBUaGUgZG90dGVkIGxpbmVzIHNob3cgdGhlIHByb2dyZXNzaW9uIG9mIGNvLWhvcnRzIHdoZXJlIGxhcmdlIGFuZCBzbWFsbCBudW1iZXJzIGF0IGFnZSBjYW4gYmUgdHJhY2tlZCB5ZWFyIHRvIHllYXIuIn0NCiM9PT0NCiMgRGF0YSBQcmVwDQojPT09PQ0Kc3VydmNvaG9ydHMgPC0gcmVhZC5jc3YoZmlsZSA9ICJEYXRhL3BsZS4yNy4yMS0zMl9Db2hvcnRNYXRyaXhfMTk5OC1Xb3JraW5nWWVhci5jc3YiLCBoZWFkZXIgPSBUKQ0Kc3VydmNvaG9ydHMkWWVhciA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHN1cnZjb2hvcnRzJFllYXIpKQ0KDQpzdXJ2Y29ob3J0c0xuZyA8LSByZXNoYXBlKGRhdGEgPSBzdXJ2Y29ob3J0cywNCiAgICAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gbGlzdChjb2xuYW1lcyhzdXJ2Y29ob3J0cylbMjpsZW5ndGgoKGNvbG5hbWVzKHN1cnZjb2hvcnRzKSkpXSksDQogICAgICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9IGMoIkFnZSIpLA0KICAgICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQ29ob3J0IiwNCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpDQojIHN1cnZjb2hvcnRzTG5nJEFnZSA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHN1cnZjb2hvcnRzTG5nJEFnZSkpDQpzdXJ2Y29ob3J0c0xuZyRZZWFyIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoc3VydmNvaG9ydHNMbmckWWVhcikpDQpzdXJ2Y29ob3J0c0xuZyA8LSBzdXJ2Y29ob3J0c0xuZ1tzdXJ2Y29ob3J0c0xuZyRBZ2UgPD0gNiwgXQ0KIz09PT09DQoNCiM9PT0NCiMgUGxvdA0KIz09PT09DQpwbHRfc3VydkNvaG9ydHMgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzdXJ2VHVuTG5nLA0KICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IEluZGV4KSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHN1cnZjb2hvcnRzTG5nLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb2hvcnQpLA0KICAgICAgICAgICAgbGluZXR5cGUgPSAiZG90dGVkIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKFN1cnZleSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpDQoNCmdncGxvdGx5KHBsdF9zdXJ2Q29ob3J0cykNCmsgPC0gYXBwZW5kKGssICJzdXJ2Y29ob3J0c0xuZyIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGtdKQ0KIz09PT09PQ0KYGBgDQo=