Chill Portions: Background
‘Chill hours’ and ‘Chill portions’ are commonly used to estimate when tree crops will “wake up” from their winter slumber and start to grow their fruit / nuts. The timing and rate of chill also affects fruit productivity and scheduling of management actions (including harvest). Many tree crops (e.g., nuts) require a certain number of hours at chilly temperatures in order for the tree to blossom and the fruit to ripen. This presents a concern for climate change, because if the winters aren’t cold enough the operation may no longer be economically viable.
Computing ‘chill hours’ essentially involves adding up the total amount of time during the cold season within a temperature range (e.g., 32 - 45 °F). ‘Chill portions’ is a similar calculation, however instead of simply adding up the number of hours within a certain temperature range, additional weights are assigned based on bands of temperature and/or warming periods periods between cold spells (this mimics tree physiology thus producing better predictions).
Computing chill hours and chill portions requires hourly temperature data. You may be lucky enough to have hourly temperature recordings from weather stations for historic and real-time analyses. However for projected climate scenarios, the smallest unit of time for the CMIP5 family of climate models is daily min and max. This creates a conundrum if you want to explore how cumulative chill hours may change due to climate change.
To deal with this, we can estimate hourly temperatures based on the daily minimum and maximum temperature. The model that does this uses the time of sunrise and sunset to model temperature variation over the day. The chillR package, developed by Dr. Eike Luedeling, has functions for modeling hourly temperatures and computing chill portions (see the chillR Vignette for details).
See also:
Luedeling, E., M. Zhang and E. H. Girvetz (2009). Climatic Changes Lead to Declining Winter Chill for Fruit and Nut Trees in California during 1950–2099. PLOS ONE 4(7): e6166.
Exercise Summary
In this example, we:
Download from Cal-Adapt downscaled daily projected minimum and maximum temperatures for a single point on the west side of the San Joaquin Valley from September 2080 thru June 2090 (10 growing seasons), for two emissions scenarios and 10 GCMs (global climate modesl).
Use chillR to compute a) modeled hourly temperatures, and b) accumulated chill portions.
Plot the results
Note: This notebook is primarily intended to demonstrate how to write code to compute chill portions using projected climate data. It is not presented as best practice for assessing the viability of tree crops under climate change!
Want to skip the details? You can ⇊ cut to the chase ⇊.
Setup
The following chunk will install any packages you don’t already have that will be needed below:
pkgs_req <- c("remotes", "ggplot2", "dplyr", "tmap", "conflicted", "tidyr", "lubridate", "tibble", "chillR", "stringr", "magrittr")
The working directory was changed to d:/github/cal-adapt/caladaptr inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
pkgs_missing <- pkgs_req[!(pkgs_req %in% installed.packages()[,"Package"])]
if (length(pkgs_missing)) install.packages(pkgs_missing, dependencies=TRUE)
Install caladaptr
from GitHub (if needed):
## Uncomment and run the following line if you don't have the latest version of caladaptr
## devtools::install_github("ucanr-igis/caladaptr")
Load all the libraries we’ll be using below:
library(caladaptr)
library(units)
library(ggplot2)
library(dplyr)
library(conflicted)
library(tidyr)
library(lubridate)
library(tibble)
library(chillR)
library(magrittr)
library(stringr)
library(sf)
The last setup task is to define your preferences when you’re forced to use an ambiguous function name (i.e., a function that exists in more than one package). This is particularly needed with a few common generic functions from dplyr
:
conflict_prefer("filter", "dplyr", quiet = TRUE)
conflict_prefer("count", "dplyr", quiet = TRUE)
conflict_prefer("select", "dplyr", quiet = TRUE)
Getting Started: Chill Portions for a Single Season
1) Create a Cal-Adapt API Request
The first step in getting climate data with caladaptR is to create an API request object. This involves stringing together a series of functions together that specify the pieces of the request.
To illustrate how to write code for this analysis, we’ll create an API request to query a single point, single GCM, and a single scenario for a single season. This of course is not the recommended practice, and you should always look at a minimum 10-20 year time spans and take averages.
## Pick a location
pt1_xy <- c(-119.964, 36.019)
## Create the API Request object
pt1_cap <- ca_loc_pt(coords = pt1_xy) %>%
ca_gcm(gcms[1]) %>%
ca_scenario("rcp45") %>%
ca_period("day") %>%
ca_dates(start = "2080-09-01", end = "2081-06-30") %>%
ca_cvar(c("tasmax", "tasmin"))
pt1_cap
Cal-Adapt API Request
Location(s):
x: -119.964
y: 36.019
Variable(s): tasmax, tasmin
Temporal aggregration period(s): day
GCM(s): HadGEM2-ES
Scenario(s): rcp45
Dates: 2080-09-01 to 2081-06-30
To verify the location saved in an API request, you can plot it. (Note we still haven’t fetched any data yet, this just shows you the location the request will ask for.)
plot(pt1_cap)
2) Fetch Data from Cal-Adapt
Next we fetch the temperature data with ca_getvals_tbl()
, which returns a tibble. We then use mutate()
to create a new column with the temperature values in Celsius.
pt1_tbl <- pt1_cap %>%
ca_getvals_tbl(quiet = TRUE) %>%
mutate(temp_c = set_units(val, degC)) %>%
select(id, cvar, period, gcm, scenario, dt, temp_c)
head(pt1_tbl)
4) Model Hourly Temperature
Now we’re ready to compute the hourly temps. In addition to the daily min/max values, we need to pass the latitude of our site (which is used to determine sunrise and sunset time):
library(chillR)
pt1_hrtmp_wide <- make_hourly_temps(latitude = pt1_xy[2],
year_file = pt1_dyr_tbl,
keep_sunrise_sunset = FALSE)
head(pt1_hrtmp_wide)
5) Plot Modelled Hourly Temps
To plot the hourly temperatures, we need to convert the ‘wide’ format of the table to a ‘long’ format. Fortunately tidyr
has everything we need to pivot between long and wide formats:
pt1_hrtmp_long <- pt1_hrtmp_wide %>%
pivot_longer(cols = starts_with("Hour_"),
names_to = "Hour",
names_prefix = "Hour_",
names_transform = list(hour = as.integer),
values_to = "temp_c") %>%
mutate(date_hour = ISOdatetime(Year, Month, Day, Hour, 0, 0, tz = "America/Los_Angeles")) %>%
select(date_hour, temp_c) %>%
arrange(date_hour)
head(pt1_hrtmp_long)
Now we can plot the hourly temperatures. To illustrate we’ll plot just the month of December, 2079:
ts_start <- as.Date("2080-12-01")
ts_end <- as.Date("2080-12-31")
pt1_hrtmp_onewk <- pt1_hrtmp_long %>%
filter(date_hour >= ts_start, date_hour <= ts_end)
ggplot(data = pt1_hrtmp_onewk,
aes(x = date_hour, y = temp_c)) +
geom_line(aes(color="red"), show.legend = FALSE) +
labs(title = "Modelled Hourly Temperature for Pt 1: RCP 4.5",
subtitle = "December 1-31, 2080",
caption = "GCM: HadGEM2-ES",
x = "date", y = "Chill Portion") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
6) Compute Chill Portions
The Dynamic_Model()
function from chillR
computes cumulative chill portions. We can add these values to the table as a new column with mutate()
:
pt1_hrtmpchill_long <- pt1_hrtmp_long %>%
mutate(accum_chill_prtn = Dynamic_Model(pt1_hrtmp_long$temp_c))
head(pt1_hrtmpchill_long)
Lastly, we plot the accumulated chill portions with ggplot()
:
ggplot(data = pt1_hrtmpchill_long,
aes(x = date_hour, y = accum_chill_prtn)) +
geom_line(aes(color="red"), show.legend = FALSE) +
labs(title = "Projected Chill Portion Accumulation for Pt 1: RCP 4.5",
subtitle = "Sept 2080 - June 2081",
caption = "GCM: HadGEM2-ES",
x = "date", y = "Chill Portion") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
7) Identify when Accumulated Chill Reaches a Threshhold
Suppose you’re hoping to grow the Kerman variety of Pistachios in 2080, which require [54 accumulated chill hours] (http://fruitsandnuts.ucdavis.edu/Weather_Services/chilling_accumulation_models/CropChillReq/) to ripen. We can easily find the date when the required accumulated chill is predicted to be reached:
chill_min <- 54
chill_date <- pt1_hrtmpchill_long %>%
filter(accum_chill_prtn > chill_min) %>%
slice(1) %>%
pull(date_hour) %>%
as.Date()
chill_date
[1] "2081-02-08"
Compare Chill Accumulation for Multiple Growing Seasons, Climate Models, and Emissions Scenarios
Climate models are not crystal balls, so thinking about the consequences of climate change generally involves looking at the predictions from a) a number of climate models (GCMs), 2) multiple emissions scenarios, and 3) multiple years.
Here we’ll compute the date when the chill portion reaches 36 for the 10 GCMs recommended for California, and 10 growing seasons. That should give us 100 maturation dates, which will plot using a box plot. We’ll do this twice, once with RCP 4.5 (low emissions scenario) and RCP 8.5 (higher emission scenario).
1) Create the API Request
## Pick a location
pt1_xy <- c(-119.964, 36.019)
pt1_10yrs_cap <- ca_loc_pt(coords = pt1_xy) %>%
ca_gcm(gcms[1:10]) %>%
ca_scenario(c("rcp45", "rcp85")) %>%
ca_period("day") %>%
ca_dates(start = "2080-09-01", end = "2090-06-30") %>%
ca_cvar(c("tasmax", "tasmin"))
pt1_10yrs_cap
Cal-Adapt API Request
Location(s):
x: -119.964
y: 36.019
Variable(s): tasmax, tasmin
Temporal aggregration period(s): day
GCM(s): HadGEM2-ES, CNRM-CM5, CanESM2, MIROC5, ACCESS1-0, CCSM4, CESM1-BGC, CMCC-CMS, GFDL-CM3, HadGEM2-CC
Scenario(s): rcp45, rcp85
Dates: 2080-09-01 to 2090-06-30
2) Fetch Data
Our API request asks for >140,000 temperature values, so fetching the data could take a minute or two.
pt1_10yrs_tbl <- pt1_10yrs_cap %>% ca_getvals_tbl(quiet = TRUE)
dim(pt1_10yrs_tbl)
[1] 143600 8
head(pt1_10yrs_tbl)
3) Munge the Results
This tibble has daily min/max values from September 1 2079 thru June 30, 2090. We need to break it up into groups by 1) growing season, 2) GCM, and 3) RCP. Grouping it up by GCM and RCP will be easy - there are already columns for those. We need to add a column for growing season however, which (for the purposes of this example) we define as September thru June. In other words, every day from Nov 1 2079 thru June 30 2080 should be part of growing season 2080, Nov 2080 thru June 2081 should be part of growing season 2081, and so on.
To construct the growing season column, we’ll first create columns for Year, Month, and Day. Later on, we’ll use these columns in a formula to compute the growing season year.
pt1_10yrs_ymd_tbl <- pt1_10yrs_tbl %>%
mutate(Year = as.integer(substr(dt, 1, 4)),
Month = as.integer(substr(dt, 6, 7)),
Day = as.integer(substr(dt, 9, 10))) %>%
select(cvar, gcm, scenario, Year, Month, Day, val)
head(pt1_10yrs_ymd_tbl)
We can now add a column for growing season using a case_when statement. While we’re at it, we’ll remove rows that don’t belong to any growing season, and convert the temperature from Kelvin to Celcius.
pt1_10yrs_ymd_gs_tbl <- pt1_10yrs_ymd_tbl %>%
mutate(gs = case_when(Month <= 6 ~ Year,
Month >= 9 ~ as.integer(Year + 1))) %>%
filter(!is.na(gs)) %>%
mutate(temp_c = set_units(val, degC))
head(pt1_10yrs_ymd_gs_tbl)
Next, we convert this ‘long’ format into a ‘wide’ format which chillR::make_hourly_temps()
requires:
library(tidyr); library(lubridate)
pt1_10yrs_ymd_gcmrcp_gs_tbl <- pt1_10yrs_ymd_gs_tbl %>%
select(cvar, temp_c, Year, Month, Day, gcm, scenario, gs) %>%
pivot_wider(names_from = cvar, values_from = temp_c) %>%
rename(Tmax = tasmax, Tmin = tasmin)
dim(pt1_10yrs_ymd_gcmrcp_gs_tbl)
[1] 60640 8
head(pt1_10yrs_ymd_gcmrcp_gs_tbl)
4) Model Hourly Temperature
Now we’re ready to compute the hourly temps. In addition to the daily min/max values, we need to pass the latitude of our site (which is used to determine sunrise and sunset time):
pt1_10yrs_hrtmp_wide <- make_hourly_temps(latitude = pt1_xy[2],
year_file = pt1_10yrs_ymd_gcmrcp_gs_tbl,
keep_sunrise_sunset = FALSE)
dim(pt1_10yrs_hrtmp_wide)
[1] 60640 33
head(pt1_10yrs_hrtmp_wide)
Now we go from wide back to long, and recreate the date-time column. This generates over a million rows so it can take several seconds.
pt1_10yrs_hrtmp_long <- pt1_10yrs_hrtmp_wide %>%
pivot_longer(cols = starts_with("Hour_"),
names_to = "Hour",
names_prefix = "Hour_",
names_transform = list(Hour = as.integer),
values_to = "temp_c") %>%
mutate(date_hour = ISOdatetime(Year, Month, Day, Hour, 0, 0, tz = "America/Los_Angeles")) %>%
arrange(date_hour)
dim(pt1_10yrs_hrtmp_long)
[1] 1455360 12
head(pt1_10yrs_hrtmp_long)
To reality-check, we can plot a portion of the hourly temperature:
ts_start <- as.Date("2081-01-01")
ts_end <- as.Date("2081-03-01")
sample_time_series <- pt1_10yrs_hrtmp_long %>%
filter(date_hour >= ts_start, date_hour <= ts_end,
gcm == "CanESM2", scenario == "rcp45") %>%
arrange(date_hour)
dim(sample_time_series)
[1] 1417 12
ggplot(data = sample_time_series,
aes(x = date_hour, y = as.numeric(temp_c))) +
geom_line(aes(color="red"), show.legend = FALSE) +
labs(title = "Modelled Hourly Temperature", x = "date", y = "temp (C)") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
5) Compute Chill Portions
Now we’re ready to compute cumulative chill portions. We need to break this up by growing season, gcm and rcp.
pt1_10yrs_hrtmpcp <- pt1_10yrs_hrtmp_long %>%
mutate(temp_c = as.numeric(temp_c)) %>%
group_by(gs, gcm, scenario) %>%
mutate(accum_chill_prtn = Dynamic_Model(temp_c))
head(pt1_10yrs_hrtmpcp)
View the maximum accumulated chill portion per RCP:
pt1_10yrs_maxchill <- pt1_10yrs_hrtmpcp %>%
group_by(scenario, gs, gcm) %>%
summarise(max_chill = max(accum_chill_prtn), .groups = 'drop')
pt1_10yrs_maxchill %>% head()
6) Compute Safe Chill
For each RCP, we compute the ‘safe winter chill’ value. ‘Safe winter chill’ is the minimum chill portion one can expect 90% of the time (Luedeling et al, 2009). For growers, safe winter chill reflects the economic need for an orchard operation to produce good yields in most years, rather than an average year. Here it is computed as the 10% quantile of all end-of-season chill portions in the analysis (ie., all GCMs and all growing seasons 2080-2090), with the assumption that all of these outcomes are equally likely.
## Compute safe winter chill for each RCP
safe_chill_tbl <- pt1_10yrs_maxchill %>%
group_by(scenario) %>%
summarize(safe_chill = quantile(max_chill, probs = 0.1), .groups = "drop")
safe_chill_tbl
Plot distribution of chill portion:
## Plot the histogram and overlay the safe chill value
projected_histo <- ggplot(pt1_10yrs_maxchill, aes(x=max_chill)) +
geom_histogram() +
geom_vline(data = safe_chill_tbl, color = "red", aes(xintercept = safe_chill), size = 1) +
facet_wrap("scenario", nrow = 1) +
labs(title = "Maximum Projected Chill Portion",
subtitle = "2080 - 2090",
caption = paste0(
str_wrap(paste0("GCMs: ", paste(unique(pt1_10yrs_maxchill$gcm), collapse = ", "), width = 105)),
"\n",
str_wrap("The red line is the 10% quantile and represents the safe winter chill (the mimimum chill portion one may expect 90% of the time assumming all projections are equally likely).", width = 105)),
x = "end-of-season chill portion", y = "count") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
projected_histo
7) How Many Growing Seasons Reach the Minimum Chill Requirement?
Next, for each RCP we compute how many projected temperature series resulted in at least 54 accumulated chill portions needed for a viable crop of the Kerman cultivar of Pistachios:
chill_min <- 54
pt1_10yrs_prct_reached_min <- pt1_10yrs_hrtmpcp %>%
group_by(gs, gcm, scenario) %>%
summarise(reached_thresh = max(accum_chill_prtn) >= chill_min) %>%
ungroup() %>%
group_by(scenario) %>%
summarise(percent_reached_thresh = sum(reached_thresh) / n()) %>%
mutate(time_period = "2081 - 2090", percent_reached_thresh = scales::percent(percent_reached_thresh)) %>%
relocate(time_period, scenario, percent_reached_thresh)
pt1_10yrs_prct_reached_min
8) Accumulated Chill Curves
Next, we plot the curves for accumulated chill for RCP 4.5 and 8.5. We have 10 growing seasons and 10 GCMs, for a total of 100 curves. The lines that end above the minimum chill requirement represent simulations where the minimum chill for a viable crop was reached.
## First make a copy of data, manually set the year to the same value (so the dates are in the same range), and keep
## only midnight values
pt1_10yrs_hrtmpcp_4plot <- pt1_10yrs_hrtmpcp %>%
filter(Hour == 0) %>%
mutate(YearPlot = if_else(Month >= 9, 1970, 1971)) %>%
mutate(date_hour = ISOdatetime(YearPlot, Month, Day, Hour, 0, 0, tz = "America/Los_Angeles"),
gs_gcm = paste(gs, gcm, sep = "_")) %>%
select(scenario, gs, gcm, gs_gcm, date_hour, accum_chill_prtn)
## Create plot
ggplot(data = pt1_10yrs_hrtmpcp_4plot %>% filter(scenario == "rcp45"),
aes(x = date_hour, y = accum_chill_prtn)) +
geom_line(aes(color=gs_gcm), show.legend = FALSE) +
geom_hline(yintercept = chill_min, size = 1) +
labs(title = "Projected Chill Portion Accumulation for Pt 1: RCP 4.5",
subtitle = "2080 - 2090",
caption = str_wrap(paste0("GCMs: ", paste(unique(pt1_10yrs_hrtmpcp_4plot$gcm), collapse = ", "), width = 60)),
x = "date", y = "Chill Portion") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
## RCP 85
ggplot(data = pt1_10yrs_hrtmpcp_4plot %>% filter(scenario == "rcp85"),
aes(x = date_hour, y = accum_chill_prtn)) +
geom_line(aes(color=gs_gcm), show.legend = FALSE) +
geom_hline(yintercept = chill_min, size = 1) +
labs(title = "Projected Chill Portion Accumulation for Pt 1: RCP 8.5",
subtitle = "2080 - 2090",
caption = stringr::str_wrap(paste0("GCMs: ", paste(unique(pt1_10yrs_hrtmpcp_4plot$gcm), collapse = ", "), width = 60)),
x = "date", y = "Chill Portion") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
9) Distribution of Required Accumulation Date
Here we plot the distribution of projected dates when the accumulated chill reaches the minimum requirement.
## Number of runs for each emissions scenario = number of growing seasons * number of gcms
num_runs <- length(unique(pt1_10yrs_hrtmpcp$gs)) * length(unique(pt1_10yrs_hrtmpcp$gcm))
## For each run, find the first date when the minimum chill portion was reached.
pt1_10yrs_scen_chilldt <- pt1_10yrs_hrtmpcp %>%
filter(Hour == 0) %>%
filter(accum_chill_prtn >= chill_min) %>%
group_by(gs, gcm) %>%
slice_min(order_by = date_hour, n = 1) %>%
ungroup() %>%
mutate(date_1970 = ISOdate(year = 1970, month = Month, day = Day)) %>%
select(scenario, date_1970)
## we're getting one NA - investigate
## pt1_10yrs_scen_chilldt %>% filter(is.na(date_1970))
## Make a data frame for the total number of dates and middle date per scenario
## (This is for the labels on the box plot)
scen_stats_tbl <- pt1_10yrs_scen_chilldt %>%
group_by(scenario) %>%
summarize(num_dates = n(), mid_dt = median(date_1970, na.rm = TRUE))
`summarise()` ungrouping output (override with `.groups` argument)
## Make a list object for easy reference. NOT NEEDED ANYMORE
## num_runs_lst <- scen_stats_tbl %$% split(num_dates, scenario)
## Plot the results
ggplot(pt1_10yrs_scen_chilldt, aes(date_1970 , scenario)) +
geom_boxplot() +
geom_label(data = scen_stats_tbl,
aes(label=paste0("n=", num_dates), x = mid_dt + (3.5 * 24 * 3600)),
size = 3.5, fill = "white", label.size = 0) +
labs(title = paste0("Date Accumlated Chill Portion Reaches ", chill_min ),
subtitle = "2080 - 2090",
caption = str_wrap(paste("GCMs: ", paste(unique(pt1_10yrs_hrtmpcp_4plot$gcm), collapse = ", ")), width = 80),
x = "date", y = "Emissions Scenario") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
Historical Baseline
When looking at historical data, we can either use modeled or observed. Here we use modeled because 1) modeled data has been shown to matches observed patterns very well, and 2) it facilitates comparisons with modeled predictions.
## Pick a location
pt1_xy <- c(-119.964, 36.019)
pt1_baseline_cap <- ca_loc_pt(coords = pt1_xy) %>%
ca_gcm(gcms[1:10]) %>%
ca_scenario(c("historical")) %>%
ca_period("day") %>%
ca_dates(start = "1995-01-01", end = "2005-12-31") %>%
ca_cvar(c("tasmax", "tasmin"))
pt1_baseline_cap
Cal-Adapt API Request
Location(s):
x: -119.964
y: 36.019
Variable(s): tasmax, tasmin
Temporal aggregration period(s): day
GCM(s): HadGEM2-ES, CNRM-CM5, CanESM2, MIROC5, ACCESS1-0, CCSM4, CESM1-BGC, CMCC-CMS, GFDL-CM3, HadGEM2-CC
Scenario(s): historical
Dates: 1995-01-01 to 2005-12-31
pt1_baseline_tbl <- pt1_baseline_cap %>% ca_getvals_tbl(quiet = TRUE)
dim(pt1_baseline_tbl)
[1] 80360 8
head(pt1_baseline_tbl)
Add columns:
pt1_baseline_ymd_tbl <- pt1_baseline_tbl %>%
mutate(Year = as.integer(substr(dt, 1, 4)),
Month = as.integer(substr(dt, 6, 7)),
Day = as.integer(substr(dt, 9, 10))) %>%
select(cvar, gcm, scenario, Year, Month, Day, val)
pt1_baseline_ymd_tbl
Add growing season column:
pt1_baseline_ymd_gs_tbl <- pt1_baseline_ymd_tbl %>%
mutate(gs = case_when(Month <= 6 ~ Year,
Month >= 9 ~ as.integer(Year + 1))) %>%
filter(!is.na(gs)) %>%
mutate(temp_c = set_units(val, degC))
head(pt1_baseline_ymd_gs_tbl)
Pivot wider (make tasmax and tasmin separate columns):
pt1_baseline_ymd_gcmrcp_gs_tbl <- pt1_baseline_ymd_gs_tbl %>%
select(cvar, temp_c, Year, Month, Day, gcm, scenario, gs) %>%
pivot_wider(names_from = cvar, values_from = temp_c) %>%
rename(Tmax = tasmax, Tmin = tasmin)
dim(pt1_baseline_ymd_gcmrcp_gs_tbl)
[1] 33360 8
head(pt1_baseline_ymd_gcmrcp_gs_tbl)
NA
Compute hourly temps (in wide format):
pt1_baseline_hrtmp_wide <- make_hourly_temps(latitude = pt1_xy[2],
year_file = pt1_baseline_ymd_gcmrcp_gs_tbl,
keep_sunrise_sunset = FALSE)
dim(pt1_baseline_hrtmp_wide)
[1] 33360 33
head(pt1_baseline_hrtmp_wide)
Convert wide to long:
pt1_baseline_hrtmp_long <- pt1_baseline_hrtmp_wide %>%
pivot_longer(cols = starts_with("Hour_"),
names_to = "Hour",
names_prefix = "Hour_",
names_transform = list(Hour = as.integer),
values_to = "temp_c") %>%
mutate(date_hour = ISOdatetime(Year, Month, Day, Hour, 0, 0, tz = "America/Los_Angeles")) %>%
arrange(date_hour)
dim(pt1_baseline_hrtmp_long)
[1] 800640 12
head(pt1_baseline_hrtmp_long)
Compute baseline chill portions:
pt1_baseline_hrtmpcp <- pt1_baseline_hrtmp_long %>%
mutate(temp_c = as.numeric(temp_c)) %>%
group_by(gs, gcm, scenario) %>%
mutate(accum_chill_prtn = Dynamic_Model(temp_c))
head(pt1_baseline_hrtmpcp)
NA
Compute the max-chill reached each growing season / GCM during the baseline period. Next we compute the ‘safe chill’ (10% quantile):
pt1_baseline_maxchill <- pt1_baseline_hrtmpcp %>%
group_by(scenario, gs, gcm) %>%
summarise(max_chill = max(accum_chill_prtn), .groups = 'drop')
dim(pt1_baseline_maxchill)
[1] 120 4
pt1_baseline_maxchill %>% head()
safe_chill_baseline_tbl <- pt1_baseline_maxchill %>%
group_by(scenario) %>%
summarize(safe_chill = quantile(max_chill, probs = 0.1), .groups = "drop")
safe_chill_baseline_tbl
Plot distribution of the baseline maximum chill portion:
## Plot the histogram and overlay the safe chill value
baseline_histo <- ggplot(pt1_baseline_maxchill, aes(x=max_chill)) +
geom_histogram() +
geom_vline(data = safe_chill_baseline_tbl, color = "red", aes(xintercept = safe_chill), size = 1) +
facet_wrap("scenario", nrow = 1) +
labs(title = "Maximum Projected Chill Portion",
subtitle = "1995 - 2005",
caption = paste0(
str_wrap(paste0("GCMs: ", paste(unique(pt1_baseline_maxchill$gcm), collapse = ", "), width = 105)),
"\n",
str_wrap("The red line is the 10% quantile and represents the safe winter chill (the mimimum chill portion one may expect 90% of the time assumming all projections are equally likely).", width = 105)),
x = "end-of-season chill portion", y = "count") +
theme(plot.caption = element_text(hjust = 0),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_rect(colour = "gray50", size = 3))
baseline_histo
How Many Growing Seasons and Simulated (Backcast) Climate Conditions During the Baseline Seasons Reached Our Minimum Chill Requirement?
chill_min <- 54
pt1_baseline_prct_reached_min <- pt1_baseline_hrtmpcp %>%
group_by(gs, gcm, scenario) %>%
summarise(reached_thresh = max(accum_chill_prtn) >= chill_min) %>%
ungroup() %>%
group_by(scenario) %>%
summarise(percent_reached_thresh = sum(reached_thresh) / n()) %>%
mutate(time_period = "1995-2005", percent_reached_thresh = scales::percent(percent_reached_thresh)) %>%
relocate(time_period, scenario, percent_reached_thresh)
pt1_baseline_prct_reached_min
NA
LS0tDQp0aXRsZTogIk1vZGVsaW5nIENoaWxsIEFjY3VtdWxhdGlvbiBVbmRlciBDbGltYXRlIENoYW5nZSB3aXRoIENhbC1BZGFwdCBEYXRhIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCi0tLQ0KDQpgYGB7Y3NzIGVjaG8gPSBGQUxTRX0NCmgxIHsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IGRhcmtvbGl2ZWdyZWVuOw0KICBib3JkZXItdG9wOiAzcHggc29saWQgZGltZ3JleTsNCiAgbWFyZ2luLXRvcDogMWVtOw0KICBwYWRkaW5nLXRvcDogMC41ZW07DQp9DQpoMS50aXRsZSB7DQogIGNvbG9yOiBibGFjazsNCiAgYm9yZGVyOiBub25lOw0KfQ0KaDIgew0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAyMnB4Ow0KICBjb2xvcjogZGltZ3JheTsNCn0NCg0KaDMgew0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxOHB4Ow0KICBjb2xvcjogYmxhY2s7DQp9DQoNCmBgYA0KDQo8cD48aW1nIHNyYz0iaHR0cHM6Ly91Y2Fuci1pZ2lzLmdpdGh1Yi5pby9jYWxhZGFwdHIvcmVmZXJlbmNlL2ZpZ3VyZXMvY2FsYWRhcHRyLWJldGFfbG9nby5zdmciIHdpZHRoPSIyNDAiIC8+PC9wPg0KDQojIEFib3V0IHRoaXMgUiBOb3RlYm9vaw0KDQpSIE5vdGVib29rcyBhcmUgYSAnZmxhdm9yJyBvZiBSIG1hcmtkb3duIHRoYXQgY29tYmluZSBwbGFpbiB0ZXh0IGFuZCBSIGNvbW1hbmRzIGluIGNvZGUgY2h1bmtzLiAoWW91IGNhbiBkb3dubG9hZCB0aGUgUm1kIGZpbGUgZnJvbSB0aGUgJ2NvZGUnIGJ1dHRvbiBhdCB0aGUgdG9wIG9mIHRoZSBwYWdlLikgWW91IHJ1biBjb2RlIGNodW5rcyBpbiB0aGUgZG9jdW1lbnQgbGluZS1ieS1saW5lLCBhbmQgdGhlIG91dHB1dCBhcHBlYXJzIGltbWVkaWF0ZWx5IGJlbG93IHRoZSBjb2RlIGNodW5rLg0KDQpJZiB5b3UncmUgaW4gUlN0dWRpbywgeW91IGNhbiAqbWluaW1pemUgdGhlIGNvbnNvbGUgd2luZG93KiAoYW5kIHByb2JhYmx5IGNsb3NlIHRoZSByaWdodC1oYW5kIHBhbmVzIGFzIHdlbGwpLiBZb3Ugd29uJ3QgbmVlZCBpdCwgIGJlY2F1c2Ugd2hlbiB5b3UgcnVuIFIgY29tbWFuZHMgaW4gYSBSIE5vdGVib29rIHRoZSAqb3V0cHV0IGFwcGVhcnMgYmVsb3cgdGhlIGNvZGUgY2h1bmsqIChub3QgdGhlIGNvbnNvbGUpLiBUaGlzIHRha2VzIHNvbWUgZ2V0dGluZyB1c2VkIHRvIGlmIHlvdSdyZSB1c2VkIHRvIHdvcmtpbmcgYXQgdGhlIGNvbnNvbGUuIA0KDQpLZXlib2FyZCBzaG9ydGN1dHMgeW91IGNhbiB1c2Ugd2l0aGluIGEgUiBOb3RlYm9vazogIA0KDQotIHJ1biB0aGUgY3VycmVudCBsaW5lIG9mIFI6ICpjdHJsICsgZW50ZXIqICANCi0gcnVuIGV2ZXJ5dGhpbmcgaW4gdGhlIGN1cnJlbnQgY29kZSBjaHVuazogKmN0cmwgKyBzaGlmdCArIGVudGVyKiAgDQotIGluc2VydCBhIG5ldyBjb2RlIGNodW5rOiAqY3RybCArIGFsdCArIGkqICANCg0KIyBDaGlsbCBQb3J0aW9uczogQmFja2dyb3VuZA0KDQpbJ0NoaWxsIGhvdXJzJ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ2hpbGxpbmdfcmVxdWlyZW1lbnQpIGFuZCAnQ2hpbGwgcG9ydGlvbnMnIGFyZSBjb21tb25seSB1c2VkIHRvIGVzdGltYXRlIHdoZW4gdHJlZSBjcm9wcyB3aWxsICJ3YWtlIHVwIiBmcm9tIHRoZWlyIHdpbnRlciBzbHVtYmVyIGFuZCBzdGFydCB0byBncm93IHRoZWlyIGZydWl0IC8gbnV0cy4gVGhlIHRpbWluZyBhbmQgcmF0ZSBvZiBjaGlsbCBhbHNvIGFmZmVjdHMgZnJ1aXQgcHJvZHVjdGl2aXR5IGFuZCBzY2hlZHVsaW5nIG9mIG1hbmFnZW1lbnQgYWN0aW9ucyAoaW5jbHVkaW5nIGhhcnZlc3QpLiBNYW55IHRyZWUgY3JvcHMgKGUuZy4sIG51dHMpIHJlcXVpcmUgYSBjZXJ0YWluIG51bWJlciBvZiBob3VycyBhdCBjaGlsbHkgdGVtcGVyYXR1cmVzIGluIG9yZGVyIGZvciB0aGUgdHJlZSB0byBibG9zc29tIGFuZCB0aGUgZnJ1aXQgdG8gcmlwZW4uIFRoaXMgcHJlc2VudHMgYSBjb25jZXJuIGZvciBjbGltYXRlIGNoYW5nZSwgYmVjYXVzZSBpZiB0aGUgd2ludGVycyBhcmVuJ3QgY29sZCBlbm91Z2ggdGhlIG9wZXJhdGlvbiBtYXkgbm8gbG9uZ2VyIGJlIGVjb25vbWljYWxseSB2aWFibGUuIA0KDQpDb21wdXRpbmcgJ2NoaWxsIGhvdXJzJyBlc3NlbnRpYWxseSBpbnZvbHZlcyBhZGRpbmcgdXAgdGhlIHRvdGFsIGFtb3VudCBvZiB0aW1lIGR1cmluZyB0aGUgY29sZCBzZWFzb24gd2l0aGluIGEgIHRlbXBlcmF0dXJlIHJhbmdlIChlLmcuLCAzMiAtIDQ1ICYjMTc2O0YpLiAnQ2hpbGwgcG9ydGlvbnMnIGlzIGEgc2ltaWxhciBjYWxjdWxhdGlvbiwgaG93ZXZlciBpbnN0ZWFkIG9mIHNpbXBseSBhZGRpbmcgdXAgdGhlIG51bWJlciBvZiBob3VycyB3aXRoaW4gYSBjZXJ0YWluIHRlbXBlcmF0dXJlIHJhbmdlLCBhZGRpdGlvbmFsIHdlaWdodHMgYXJlIGFzc2lnbmVkIGJhc2VkIG9uIGJhbmRzIG9mIHRlbXBlcmF0dXJlIGFuZC9vciB3YXJtaW5nIHBlcmlvZHMgcGVyaW9kcyBiZXR3ZWVuIGNvbGQgc3BlbGxzICh0aGlzIG1pbWljcyB0cmVlIHBoeXNpb2xvZ3kgdGh1cyBwcm9kdWNpbmcgYmV0dGVyIHByZWRpY3Rpb25zKS4NCg0KQ29tcHV0aW5nIGNoaWxsIGhvdXJzIGFuZCBjaGlsbCBwb3J0aW9ucyByZXF1aXJlcyBob3VybHkgdGVtcGVyYXR1cmUgZGF0YS4gWW91IG1heSBiZSBsdWNreSBlbm91Z2ggdG8gaGF2ZSBob3VybHkgdGVtcGVyYXR1cmUgcmVjb3JkaW5ncyBmcm9tIHdlYXRoZXIgc3RhdGlvbnMgZm9yIGhpc3RvcmljIGFuZCByZWFsLXRpbWUgYW5hbHlzZXMuIEhvd2V2ZXIgZm9yIHByb2plY3RlZCBjbGltYXRlIHNjZW5hcmlvcywgdGhlIHNtYWxsZXN0IHVuaXQgb2YgdGltZSBmb3IgdGhlIENNSVA1IGZhbWlseSBvZiBjbGltYXRlIG1vZGVscyBpcyBkYWlseSBtaW4gYW5kIG1heC4gVGhpcyBjcmVhdGVzIGEgY29udW5kcnVtIGlmIHlvdSB3YW50IHRvIGV4cGxvcmUgaG93IGN1bXVsYXRpdmUgY2hpbGwgaG91cnMgbWF5IGNoYW5nZSBkdWUgdG8gY2xpbWF0ZSBjaGFuZ2UuDQoNClRvIGRlYWwgd2l0aCB0aGlzLCB3ZSBjYW4gZXN0aW1hdGUgaG91cmx5IHRlbXBlcmF0dXJlcyBiYXNlZCBvbiB0aGUgZGFpbHkgbWluaW11bSBhbmQgbWF4aW11bSB0ZW1wZXJhdHVyZS4gVGhlIG1vZGVsIHRoYXQgZG9lcyB0aGlzIHVzZXMgdGhlIHRpbWUgb2Ygc3VucmlzZSBhbmQgc3Vuc2V0IHRvIG1vZGVsIHRlbXBlcmF0dXJlIHZhcmlhdGlvbiBvdmVyIHRoZSBkYXkuIFRoZSBbKipjaGlsbFIqKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvcGFja2FnZT1jaGlsbFIpIHBhY2thZ2UsIGRldmVsb3BlZCBieSBbRHIuIEVpa2UgTHVlZGVsaW5nXShodHRwOi8vZWlrZWx1ZWRlbGluZy5jb20vKSwgaGFzIGZ1bmN0aW9ucyBmb3IgbW9kZWxpbmcgaG91cmx5IHRlbXBlcmF0dXJlcyBhbmQgY29tcHV0aW5nIGNoaWxsIHBvcnRpb25zIChzZWUgdGhlIGNoaWxsUiBbVmlnbmV0dGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jaGlsbFIvdmlnbmV0dGVzL2hvdXJseV90ZW1wZXJhdHVyZXMuaHRtbCkgZm9yIGRldGFpbHMpLg0KDQpTZWUgYWxzbzoNCg0KTHVlZGVsaW5nLCBFLiwgTS4gWmhhbmcgYW5kIEUuIEguIEdpcnZldHogKDIwMDkpLiAqQ2xpbWF0aWMgQ2hhbmdlcyBMZWFkIHRvIERlY2xpbmluZyBXaW50ZXIgQ2hpbGwgZm9yIEZydWl0IGFuZCBOdXQgVHJlZXMgaW4gQ2FsaWZvcm5pYSBkdXJpbmcgMTk1MOKAkzIwOTkqLiBbUExPUyBPTkUgNCg3KTogZTYxNjZdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMzcxL2pvdXJuYWwucG9uZS4wMDA2MTY2KS4NCg0KIyMgRXhlcmNpc2UgU3VtbWFyeQ0KDQpJbiB0aGlzIGV4YW1wbGUsIHdlOg0KDQoxKSBEb3dubG9hZCBmcm9tIENhbC1BZGFwdCBkb3duc2NhbGVkICoqZGFpbHkgcHJvamVjdGVkIG1pbmltdW0gYW5kIG1heGltdW0gdGVtcGVyYXR1cmVzKiogZm9yIGEgKipzaW5nbGUgcG9pbnQqKiBvbiB0aGUgd2VzdCBzaWRlIG9mIHRoZSBTYW4gSm9hcXVpbiBWYWxsZXkgZnJvbSBTZXB0ZW1iZXIgMjA4MCB0aHJ1IEp1bmUgMjA5MCAoKioxMCBncm93aW5nIHNlYXNvbnMqKiksIGZvciAqKnR3byBlbWlzc2lvbnMgc2NlbmFyaW9zKiogYW5kICoqMTAgR0NNcyoqIChnbG9iYWwgY2xpbWF0ZSBtb2Rlc2wpLg0KDQoyKSBVc2UgY2hpbGxSIHRvIGNvbXB1dGUgYSkgbW9kZWxlZCBob3VybHkgdGVtcGVyYXR1cmVzLCBhbmQgYikgYWNjdW11bGF0ZWQgY2hpbGwgcG9ydGlvbnMuDQoNCjMpIFBsb3QgdGhlIHJlc3VsdHMNCg0KKipOb3RlOioqIFRoaXMgbm90ZWJvb2sgaXMgcHJpbWFyaWx5IGludGVuZGVkIHRvIGRlbW9uc3RyYXRlICpob3cgdG8gd3JpdGUgY29kZSogdG8gY29tcHV0ZSBjaGlsbCBwb3J0aW9ucyB1c2luZyBwcm9qZWN0ZWQgY2xpbWF0ZSBkYXRhLiBJdCBpcyAqbm90KiBwcmVzZW50ZWQgYXMgKmJlc3QgcHJhY3RpY2UqIGZvciBhc3Nlc3NpbmcgdGhlIHZpYWJpbGl0eSBvZiB0cmVlIGNyb3BzIHVuZGVyIGNsaW1hdGUgY2hhbmdlIQ0KDQpXYW50IHRvIHNraXAgdGhlIGRldGFpbHM/IFlvdSBjYW4gWyoqJmRkYXJyOyBjdXQgdG8gdGhlIGNoYXNlICZkZGFycjsqKl0oI2NvbmNsdXNpb25zKS4NCg0KIyBTZXR1cA0KDQpUaGUgZm9sbG93aW5nIGNodW5rIHdpbGwgaW5zdGFsbCBhbnkgcGFja2FnZXMgeW91IGRvbid0IGFscmVhZHkgaGF2ZSB0aGF0IHdpbGwgYmUgbmVlZGVkIGJlbG93Og0KDQpgYGB7ciBsb2FkX3BrZ3MsIGNhY2hlID0gVFJVRX0NCnBrZ3NfcmVxIDwtIGMoInJlbW90ZXMiLCAiZ2dwbG90MiIsICJkcGx5ciIsICJ0bWFwIiwgImNvbmZsaWN0ZWQiLCAidGlkeXIiLCAibHVicmlkYXRlIiwgInRpYmJsZSIsICJjaGlsbFIiLCAic3RyaW5nciIsICJtYWdyaXR0ciIpDQpwa2dzX21pc3NpbmcgPC0gcGtnc19yZXFbIShwa2dzX3JlcSAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywiUGFja2FnZSJdKV0NCmlmIChsZW5ndGgocGtnc19taXNzaW5nKSkgaW5zdGFsbC5wYWNrYWdlcyhwa2dzX21pc3NpbmcsIGRlcGVuZGVuY2llcz1UUlVFKQ0KYGBgDQoNCkluc3RhbGwgYGNhbGFkYXB0cmAgZnJvbSBHaXRIdWIgKGlmIG5lZWRlZCk6DQoNCmBgYHtyfQ0KIyMgVW5jb21tZW50IGFuZCBydW4gdGhlIGZvbGxvd2luZyBsaW5lIGlmIHlvdSBkb24ndCBoYXZlIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBjYWxhZGFwdHINCiMjIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigidWNhbnItaWdpcy9jYWxhZGFwdHIiKQ0KYGBgDQoNCkxvYWQgYWxsIHRoZSBsaWJyYXJpZXMgd2UnbGwgYmUgdXNpbmcgYmVsb3c6DQoNCmBgYHtyIGxpYnJhcnlfYWxsLCBtZXNzYWdlID0gRkFMU0V9DQpsaWJyYXJ5KGNhbGFkYXB0cikNCmxpYnJhcnkodW5pdHMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShjb25mbGljdGVkKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KGNoaWxsUikNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHNmKQ0KYGBgDQoNClRoZSBsYXN0IHNldHVwIHRhc2sgaXMgdG8gZGVmaW5lIHlvdXIgcHJlZmVyZW5jZXMgd2hlbiB5b3UncmUgZm9yY2VkIHRvIHVzZSBhbiBhbWJpZ3VvdXMgZnVuY3Rpb24gbmFtZSAoaS5lLiwgYSBmdW5jdGlvbiB0aGF0IGV4aXN0cyBpbiBtb3JlIHRoYW4gb25lIHBhY2thZ2UpLiBUaGlzIGlzIHBhcnRpY3VsYXJseSBuZWVkZWQgd2l0aCBhIGZldyBjb21tb24gZ2VuZXJpYyBmdW5jdGlvbnMgZnJvbSBgZHBseXJgOg0KDQpgYGB7ciBzZXRfY29uZmxpY3RzfQ0KY29uZmxpY3RfcHJlZmVyKCJmaWx0ZXIiLCAiZHBseXIiLCBxdWlldCA9IFRSVUUpDQpjb25mbGljdF9wcmVmZXIoImNvdW50IiwgImRwbHlyIiwgcXVpZXQgPSBUUlVFKQ0KY29uZmxpY3RfcHJlZmVyKCJzZWxlY3QiLCAiZHBseXIiLCBxdWlldCA9IFRSVUUpDQpgYGANCg0KDQojIEdldHRpbmcgU3RhcnRlZDogQ2hpbGwgUG9ydGlvbnMgZm9yIGEgU2luZ2xlIFNlYXNvbg0KDQojIyAxKSBDcmVhdGUgYSBDYWwtQWRhcHQgQVBJIFJlcXVlc3QNCg0KVGhlIGZpcnN0IHN0ZXAgaW4gZ2V0dGluZyBjbGltYXRlIGRhdGEgd2l0aCBjYWxhZGFwdFIgaXMgdG8gY3JlYXRlIGFuIEFQSSByZXF1ZXN0IG9iamVjdC4gVGhpcyBpbnZvbHZlcyBzdHJpbmdpbmcgdG9nZXRoZXIgYSBzZXJpZXMgb2YgZnVuY3Rpb25zIHRvZ2V0aGVyIHRoYXQgc3BlY2lmeSB0aGUgcGllY2VzIG9mIHRoZSByZXF1ZXN0LiANCg0KVG8gaWxsdXN0cmF0ZSBob3cgdG8gd3JpdGUgY29kZSBmb3IgdGhpcyBhbmFseXNpcywgd2UnbGwgY3JlYXRlIGFuIEFQSSByZXF1ZXN0IHRvIHF1ZXJ5IGEgc2luZ2xlIHBvaW50LCBzaW5nbGUgR0NNLCBhbmQgYSBzaW5nbGUgc2NlbmFyaW8gZm9yIGEgc2luZ2xlIHNlYXNvbi4gVGhpcyBvZiBjb3Vyc2UgaXMgbm90IHRoZSByZWNvbW1lbmRlZCBwcmFjdGljZSwgYW5kIHlvdSBzaG91bGQgYWx3YXlzIGxvb2sgYXQgYSBtaW5pbXVtIDEwLTIwIHllYXIgdGltZSBzcGFucyBhbmQgdGFrZSBhdmVyYWdlcy4gDQoNCmBgYHtyfQ0KIyMgUGljayBhIGxvY2F0aW9uDQpwdDFfeHkgPC0gYygtMTE5Ljk2NCwgMzYuMDE5KQ0KDQojIyBDcmVhdGUgdGhlIEFQSSBSZXF1ZXN0IG9iamVjdA0KcHQxX2NhcCA8LSBjYV9sb2NfcHQoY29vcmRzID0gcHQxX3h5KSAlPiUNCiAgY2FfZ2NtKGdjbXNbMV0pICU+JQ0KICBjYV9zY2VuYXJpbygicmNwNDUiKSAlPiUNCiAgY2FfcGVyaW9kKCJkYXkiKSAlPiUNCiAgY2FfZGF0ZXMoc3RhcnQgPSAiMjA4MC0wOS0wMSIsIGVuZCA9ICIyMDgxLTA2LTMwIikgJT4lDQogIGNhX2N2YXIoYygidGFzbWF4IiwgInRhc21pbiIpKQ0KDQpwdDFfY2FwDQpgYGANClRvIHZlcmlmeSB0aGUgbG9jYXRpb24gc2F2ZWQgaW4gYW4gQVBJIHJlcXVlc3QsIHlvdSBjYW4gcGxvdCBpdC4gKE5vdGUgd2Ugc3RpbGwgaGF2ZW4ndCBmZXRjaGVkIGFueSBkYXRhIHlldCwgdGhpcyBqdXN0IHNob3dzIHlvdSB0aGUgbG9jYXRpb24gdGhlIHJlcXVlc3Qgd2lsbCBhc2sgZm9yLikNCg0KYGBge3IgcGxvdF9jYXAxfQ0KcGxvdChwdDFfY2FwKQ0KYGBgDQoNCiMjIDIpIEZldGNoIERhdGEgZnJvbSBDYWwtQWRhcHQNCg0KTmV4dCB3ZSBmZXRjaCB0aGUgdGVtcGVyYXR1cmUgZGF0YSB3aXRoIGBjYV9nZXR2YWxzX3RibCgpYCwgd2hpY2ggcmV0dXJucyBhIHRpYmJsZS4gV2UgdGhlbiB1c2UgYG11dGF0ZSgpYCB0byBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggdGhlIHRlbXBlcmF0dXJlIHZhbHVlcyBpbiBDZWxzaXVzLg0KDQpgYGB7ciBjYXAxX2xzdCwgY2FjaGUgPSBUUlVFfQ0KcHQxX3RibCA8LSBwdDFfY2FwICU+JSANCiAgY2FfZ2V0dmFsc190YmwocXVpZXQgPSBUUlVFKSAlPiUgDQogIG11dGF0ZSh0ZW1wX2MgPSBzZXRfdW5pdHModmFsLCBkZWdDKSkgJT4lIA0KICBzZWxlY3QoaWQsIGN2YXIsIHBlcmlvZCwgZ2NtLCBzY2VuYXJpbywgZHQsIHRlbXBfYykNCg0KaGVhZChwdDFfdGJsKQ0KYGBgDQoNCiMjIDMpIFdyYW5nbGUgUmVzdWx0cyBpbnRvIHRoZSBGb3JtYXQgUmVxdWlyZWQgYnkgYGNoaWxsUmANCg0KR3VpZGVkIGJ5IGNoaWxsUidzIGRvY3VtZW50YXRpb24gYW5kIFZpZ25ldHRlIG9uIFtob3VybHkgdGVtcGVyYXR1cmUgcmVjb3Jkc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2NoaWxsUi92aWduZXR0ZXMvaG91cmx5X3RlbXBlcmF0dXJlcy5odG1sKSwgd2UgcHJlcGFyZSBhIGZpdmUtY29sdW1uIHRpYmJsZSB3aXRoIHRoZSBwcm9qZWN0ZWQgdGVtcGVyYXR1cmUgdmFsdWVzOg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXIpOyBsaWJyYXJ5KGx1YnJpZGF0ZSkNCg0KcHQxX2R5cl90YmwgPC0gcHQxX3RibCAlPiUNCiAgbXV0YXRlKERBVEUgPSBhcy5QT1NJWGN0KGZvcm1hdChkdCksIHR6PSJBbWVyaWNhL0xvc19BbmdlbGVzIikpICU+JQ0KICBtdXRhdGUoWWVhciA9IGFzLmludGVnZXIoeWVhcihEQVRFKSksIA0KICAgICAgICAgTW9udGggPSBhcy5pbnRlZ2VyKG1vbnRoKERBVEUpKSwgDQogICAgICAgICBEYXkgPSBkYXkoREFURSksDQogICAgICAgICB0ZW1wX2MgPSBhcy5udW1lcmljKHRlbXBfYykpICU+JQ0KICBzZWxlY3QoY3ZhciwgdGVtcF9jLCBZZWFyLCBNb250aCwgRGF5KSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGN2YXIsIHZhbHVlc19mcm9tID0gdGVtcF9jKSAlPiUNCiAgcmVuYW1lKFRtYXggPSB0YXNtYXgsIFRtaW4gPSB0YXNtaW4pDQoNCmhlYWQocHQxX2R5cl90YmwpDQpgYGANCg0KIyMgNCkgTW9kZWwgSG91cmx5IFRlbXBlcmF0dXJlDQoNCk5vdyB3ZSdyZSByZWFkeSB0byBjb21wdXRlIHRoZSBob3VybHkgdGVtcHMuIEluIGFkZGl0aW9uIHRvIHRoZSBkYWlseSBtaW4vbWF4IHZhbHVlcywgd2UgbmVlZCB0byBwYXNzIHRoZSBsYXRpdHVkZSBvZiBvdXIgc2l0ZSAod2hpY2ggaXMgdXNlZCB0byBkZXRlcm1pbmUgc3VucmlzZSBhbmQgc3Vuc2V0IHRpbWUpOg0KDQpgYGB7ciBjb21wdXRlX2hvdXJseSwgY2FjaGUgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0V9DQpsaWJyYXJ5KGNoaWxsUikNCg0KcHQxX2hydG1wX3dpZGUgPC0gbWFrZV9ob3VybHlfdGVtcHMobGF0aXR1ZGUgPSBwdDFfeHlbMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJfZmlsZSA9IHB0MV9keXJfdGJsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwX3N1bnJpc2Vfc3Vuc2V0ID0gRkFMU0UpDQpoZWFkKHB0MV9ocnRtcF93aWRlKQ0KYGBgDQoNCiMjIDUpIFBsb3QgTW9kZWxsZWQgSG91cmx5IFRlbXBzDQoNClRvIHBsb3QgdGhlIGhvdXJseSB0ZW1wZXJhdHVyZXMsIHdlIG5lZWQgdG8gY29udmVydCB0aGUgJ3dpZGUnIGZvcm1hdCBvZiB0aGUgdGFibGUgdG8gYSAnbG9uZycgZm9ybWF0LiBGb3J0dW5hdGVseSBgdGlkeXJgIGhhcyBldmVyeXRoaW5nIHdlIG5lZWQgdG8gW3Bpdm90IGJldHdlZW4gbG9uZyBhbmQgd2lkZSBmb3JtYXRzXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvcGl2b3QuaHRtbCl7dGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIifTogDQoNCmBgYHtyfQ0KcHQxX2hydG1wX2xvbmcgPC0gcHQxX2hydG1wX3dpZGUgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoIkhvdXJfIiksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJIb3VyIiwNCiAgICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJIb3VyXyIsDQogICAgICAgICAgICAgICBuYW1lc190cmFuc2Zvcm0gPSBsaXN0KGhvdXIgPSBhcy5pbnRlZ2VyKSwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ0ZW1wX2MiKSAlPiUNCiAgbXV0YXRlKGRhdGVfaG91ciA9IElTT2RhdGV0aW1lKFllYXIsIE1vbnRoLCBEYXksIEhvdXIsIDAsIDAsIHR6ID0gIkFtZXJpY2EvTG9zX0FuZ2VsZXMiKSkgJT4lDQogIHNlbGVjdChkYXRlX2hvdXIsIHRlbXBfYykgJT4lDQogIGFycmFuZ2UoZGF0ZV9ob3VyKQ0KDQpoZWFkKHB0MV9ocnRtcF9sb25nKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gcGxvdCB0aGUgaG91cmx5IHRlbXBlcmF0dXJlcy4gVG8gaWxsdXN0cmF0ZSB3ZSdsbCBwbG90IGp1c3QgdGhlIG1vbnRoIG9mIERlY2VtYmVyLCAyMDc5Og0KDQpgYGB7ciBwbG90X2hvdXJseV90ZW1wLCBjYWNoZSA9IFRSVUV9DQp0c19zdGFydCA8LSBhcy5EYXRlKCIyMDgwLTEyLTAxIikNCnRzX2VuZCA8LSBhcy5EYXRlKCIyMDgwLTEyLTMxIikNCg0KcHQxX2hydG1wX29uZXdrIDwtIHB0MV9ocnRtcF9sb25nICU+JSANCiAgZmlsdGVyKGRhdGVfaG91ciA+PSB0c19zdGFydCwgZGF0ZV9ob3VyIDw9IHRzX2VuZCkNCg0KZ2dwbG90KGRhdGEgPSBwdDFfaHJ0bXBfb25ld2ssDQogICAgICAgYWVzKHggPSBkYXRlX2hvdXIsIHkgPSB0ZW1wX2MpKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9InJlZCIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGxhYnModGl0bGUgPSAiTW9kZWxsZWQgSG91cmx5IFRlbXBlcmF0dXJlIGZvciBQdCAxOiBSQ1AgNC41IiwgDQogICAgIHN1YnRpdGxlID0gIkRlY2VtYmVyIDEtMzEsIDIwODAiLA0KICAgICBjYXB0aW9uID0gIkdDTTogSGFkR0VNMi1FUyIsDQogICAgIHggPSAiZGF0ZSIsIHkgPSAiQ2hpbGwgUG9ydGlvbiIpICsNCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksDQogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDIwLCAyMCwgMjAsIDIwKSwNCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmF5NTAiLCBzaXplID0gMykpDQoNCmBgYA0KDQojIyA2KSBDb21wdXRlIENoaWxsIFBvcnRpb25zDQoNClRoZSBgRHluYW1pY19Nb2RlbCgpYCBmdW5jdGlvbiBmcm9tIGBjaGlsbFJgIGNvbXB1dGVzIGN1bXVsYXRpdmUgY2hpbGwgcG9ydGlvbnMuIFdlIGNhbiBhZGQgdGhlc2UgdmFsdWVzIHRvIHRoZSB0YWJsZSBhcyBhIG5ldyBjb2x1bW4gd2l0aCBgbXV0YXRlKClgOiAgDQoNCmBgYHtyfQ0KcHQxX2hydG1wY2hpbGxfbG9uZyA8LSBwdDFfaHJ0bXBfbG9uZyAlPiUgDQogIG11dGF0ZShhY2N1bV9jaGlsbF9wcnRuID0gRHluYW1pY19Nb2RlbChwdDFfaHJ0bXBfbG9uZyR0ZW1wX2MpKQ0KDQpoZWFkKHB0MV9ocnRtcGNoaWxsX2xvbmcpDQpgYGANCg0KTGFzdGx5LCB3ZSBwbG90IHRoZSBhY2N1bXVsYXRlZCBjaGlsbCBwb3J0aW9ucyB3aXRoIGBnZ3Bsb3QoKWA6DQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwdDFfaHJ0bXBjaGlsbF9sb25nLA0KICAgICAgIGFlcyh4ID0gZGF0ZV9ob3VyLCB5ID0gYWNjdW1fY2hpbGxfcHJ0bikpICsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj0icmVkIiksIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICJQcm9qZWN0ZWQgQ2hpbGwgUG9ydGlvbiBBY2N1bXVsYXRpb24gZm9yIFB0IDE6IFJDUCA0LjUiLCANCiAgICAgICBzdWJ0aXRsZSA9ICJTZXB0IDIwODAgLSBKdW5lIDIwODEiLA0KICAgICAgIGNhcHRpb24gPSAiR0NNOiBIYWRHRU0yLUVTIiwNCiAgICAgICB4ID0gImRhdGUiLCB5ID0gIkNoaWxsIFBvcnRpb24iKSArDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigyMCwgMjAsIDIwLCAyMCksDQogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JheTUwIiwgc2l6ZSA9IDMpKQ0KDQpgYGANCg0KIyMgNykgSWRlbnRpZnkgd2hlbiBBY2N1bXVsYXRlZCBDaGlsbCBSZWFjaGVzIGEgVGhyZXNoaG9sZA0KDQpTdXBwb3NlIHlvdSdyZSBob3BpbmcgdG8gZ3JvdyB0aGUgS2VybWFuIHZhcmlldHkgb2YgUGlzdGFjaGlvcyBpbiAyMDgwLCB3aGljaCByZXF1aXJlIFsqKjU0IGFjY3VtdWxhdGVkIGNoaWxsIGhvdXJzKipdDQooaHR0cDovL2ZydWl0c2FuZG51dHMudWNkYXZpcy5lZHUvV2VhdGhlcl9TZXJ2aWNlcy9jaGlsbGluZ19hY2N1bXVsYXRpb25fbW9kZWxzL0Nyb3BDaGlsbFJlcS8pIHRvIHJpcGVuLiBXZSBjYW4gZWFzaWx5IGZpbmQgdGhlIGRhdGUgd2hlbiB0aGUgcmVxdWlyZWQgYWNjdW11bGF0ZWQgY2hpbGwgaXMgcHJlZGljdGVkIHRvIGJlIHJlYWNoZWQ6DQoNCg0KYGBge3J9DQpjaGlsbF9taW4gPC0gNTQNCg0KY2hpbGxfZGF0ZSA8LSBwdDFfaHJ0bXBjaGlsbF9sb25nICU+JSANCiAgZmlsdGVyKGFjY3VtX2NoaWxsX3BydG4gPiBjaGlsbF9taW4pICU+JSANCiAgc2xpY2UoMSkgJT4lIA0KICBwdWxsKGRhdGVfaG91cikgJT4lIA0KICBhcy5EYXRlKCkNCg0KY2hpbGxfZGF0ZQ0KYGBgDQoNCiMgQ29tcGFyZSBDaGlsbCBBY2N1bXVsYXRpb24gZm9yIE11bHRpcGxlIEdyb3dpbmcgU2Vhc29ucywgQ2xpbWF0ZSBNb2RlbHMsIGFuZCBFbWlzc2lvbnMgU2NlbmFyaW9zDQoNCkNsaW1hdGUgbW9kZWxzIGFyZSBub3QgY3J5c3RhbCBiYWxscywgc28gdGhpbmtpbmcgYWJvdXQgdGhlIGNvbnNlcXVlbmNlcyBvZiBjbGltYXRlIGNoYW5nZSBnZW5lcmFsbHkgaW52b2x2ZXMgbG9va2luZyBhdCB0aGUgcHJlZGljdGlvbnMgZnJvbSBhKSBhIG51bWJlciBvZiBjbGltYXRlIG1vZGVscyAoR0NNcyksIDIpIG11bHRpcGxlIGVtaXNzaW9ucyBzY2VuYXJpb3MsIGFuZCAzKSBtdWx0aXBsZSB5ZWFycy4NCg0KSGVyZSB3ZSdsbCBjb21wdXRlIHRoZSBkYXRlIHdoZW4gdGhlIGNoaWxsIHBvcnRpb24gcmVhY2hlcyAzNiBmb3IgdGhlICoqMTAgR0NNcyoqIHJlY29tbWVuZGVkIGZvciBDYWxpZm9ybmlhLCBhbmQgKioxMCBncm93aW5nIHNlYXNvbnMqKi4gVGhhdCBzaG91bGQgZ2l2ZSB1cyAxMDAgbWF0dXJhdGlvbiBkYXRlcywgd2hpY2ggd2lsbCBwbG90IHVzaW5nIGEgYm94IHBsb3QuIFdlJ2xsIGRvIHRoaXMgdHdpY2UsIG9uY2Ugd2l0aCBSQ1AgNC41IChsb3cgZW1pc3Npb25zIHNjZW5hcmlvKSBhbmQgUkNQIDguNSAoaGlnaGVyIGVtaXNzaW9uIHNjZW5hcmlvKS4NCg0KIyMgMSkgQ3JlYXRlIHRoZSBBUEkgUmVxdWVzdA0KDQpgYGB7ciBjYXAyX21ha2UsIGNhY2hlPVRSVUV9DQojIyBQaWNrIGEgbG9jYXRpb24NCnB0MV94eSA8LSBjKC0xMTkuOTY0LCAzNi4wMTkpDQoNCnB0MV8xMHlyc19jYXAgPC0gY2FfbG9jX3B0KGNvb3JkcyA9IHB0MV94eSkgJT4lDQogIGNhX2djbShnY21zWzE6MTBdKSAlPiUNCiAgY2Ffc2NlbmFyaW8oYygicmNwNDUiLCAicmNwODUiKSkgJT4lDQogIGNhX3BlcmlvZCgiZGF5IikgJT4lDQogIGNhX2RhdGVzKHN0YXJ0ID0gIjIwODAtMDktMDEiLCBlbmQgPSAiMjA5MC0wNi0zMCIpICU+JQ0KICBjYV9jdmFyKGMoInRhc21heCIsICJ0YXNtaW4iKSkNCg0KcHQxXzEweXJzX2NhcA0KYGBgDQoNCiMjIDIpIEZldGNoIERhdGENCg0KT3VyIEFQSSByZXF1ZXN0IGFza3MgZm9yID4xNDAsMDAwIHRlbXBlcmF0dXJlIHZhbHVlcywgc28gZmV0Y2hpbmcgdGhlIGRhdGEgY291bGQgdGFrZSBhIG1pbnV0ZSBvciB0d28uDQoNCmBgYHtyIHB0MV8xMHlyc190YmxfZmV0Y2gsIGNhY2hlID0gVFJVRX0NCnB0MV8xMHlyc190YmwgPC0gcHQxXzEweXJzX2NhcCAlPiUgY2FfZ2V0dmFsc190YmwocXVpZXQgPSBUUlVFKSANCg0KZGltKHB0MV8xMHlyc190YmwpDQpoZWFkKHB0MV8xMHlyc190YmwpDQpgYGANCg0KIyMgMykgTXVuZ2UgdGhlIFJlc3VsdHMNCg0KVGhpcyB0aWJibGUgaGFzIGRhaWx5IG1pbi9tYXggdmFsdWVzIGZyb20gU2VwdGVtYmVyIDEgMjA3OSB0aHJ1IEp1bmUgMzAsIDIwOTAuIFdlIG5lZWQgdG8gYnJlYWsgaXQgdXAgaW50byBncm91cHMgYnkgMSkgZ3Jvd2luZyBzZWFzb24sIDIpIEdDTSwgYW5kIDMpIFJDUC4gR3JvdXBpbmcgaXQgdXAgYnkgR0NNIGFuZCBSQ1Agd2lsbCBiZSBlYXN5IC0gdGhlcmUgYXJlIGFscmVhZHkgY29sdW1ucyBmb3IgdGhvc2UuIFdlIG5lZWQgdG8gYWRkIGEgY29sdW1uIGZvciBncm93aW5nIHNlYXNvbiBob3dldmVyLCB3aGljaCAoZm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGV4YW1wbGUpIHdlIGRlZmluZSBhcyBTZXB0ZW1iZXIgdGhydSBKdW5lLiBJbiBvdGhlciB3b3JkcywgZXZlcnkgZGF5IGZyb20gTm92IDEgMjA3OSB0aHJ1IEp1bmUgMzAgMjA4MCBzaG91bGQgYmUgcGFydCBvZiBncm93aW5nIHNlYXNvbiAyMDgwLCBOb3YgMjA4MCB0aHJ1IEp1bmUgMjA4MSBzaG91bGQgYmUgcGFydCBvZiBncm93aW5nIHNlYXNvbiAyMDgxLCBhbmQgc28gb24uIA0KDQpUbyBjb25zdHJ1Y3QgdGhlIGdyb3dpbmcgc2Vhc29uIGNvbHVtbiwgd2UnbGwgZmlyc3QgY3JlYXRlIGNvbHVtbnMgZm9yIFllYXIsIE1vbnRoLCBhbmQgRGF5LiBMYXRlciBvbiwgd2UnbGwgdXNlIHRoZXNlIGNvbHVtbnMgaW4gYSBmb3JtdWxhIHRvIGNvbXB1dGUgdGhlIGdyb3dpbmcgc2Vhc29uIHllYXIuDQoNCmBgYHtyfQ0KcHQxXzEweXJzX3ltZF90YmwgPC0gcHQxXzEweXJzX3RibCAlPiUgDQogIG11dGF0ZShZZWFyID0gYXMuaW50ZWdlcihzdWJzdHIoZHQsIDEsIDQpKSwgDQogICAgICAgICBNb250aCA9IGFzLmludGVnZXIoc3Vic3RyKGR0LCA2LCA3KSksDQogICAgICAgICBEYXkgPSBhcy5pbnRlZ2VyKHN1YnN0cihkdCwgOSwgMTApKSkgJT4lIA0KICBzZWxlY3QoY3ZhciwgZ2NtLCBzY2VuYXJpbywgWWVhciwgTW9udGgsIERheSwgdmFsKQ0KDQpoZWFkKHB0MV8xMHlyc195bWRfdGJsKQ0KYGBgDQoNCldlIGNhbiBub3cgYWRkIGEgY29sdW1uIGZvciBncm93aW5nIHNlYXNvbiB1c2luZyBhIGNhc2Vfd2hlbiBzdGF0ZW1lbnQuIFdoaWxlIHdlJ3JlIGF0IGl0LCB3ZSdsbCByZW1vdmUgcm93cyB0aGF0IGRvbid0IGJlbG9uZyB0byBhbnkgZ3Jvd2luZyBzZWFzb24sIGFuZCBjb252ZXJ0IHRoZSB0ZW1wZXJhdHVyZSBmcm9tIEtlbHZpbiB0byBDZWxjaXVzLg0KDQpgYGB7ciBwdDFfMTB5cnNfZ3J3c25fdGJsX21ha2UsIGNhY2hlID0gVFJVRX0NCnB0MV8xMHlyc195bWRfZ3NfdGJsIDwtIHB0MV8xMHlyc195bWRfdGJsICU+JSANCiAgbXV0YXRlKGdzID0gY2FzZV93aGVuKE1vbnRoIDw9IDYgfiBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgTW9udGggPj0gOSB+IGFzLmludGVnZXIoWWVhciArIDEpKSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGdzKSkgJT4lIA0KICBtdXRhdGUodGVtcF9jID0gc2V0X3VuaXRzKHZhbCwgZGVnQykpDQoNCmhlYWQocHQxXzEweXJzX3ltZF9nc190YmwpDQpgYGANCg0KTmV4dCwgd2UgY29udmVydCB0aGlzICdsb25nJyBmb3JtYXQgaW50byBhICd3aWRlJyBmb3JtYXQgd2hpY2ggYGNoaWxsUjo6bWFrZV9ob3VybHlfdGVtcHMoKWAgcmVxdWlyZXM6DQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5cik7IGxpYnJhcnkobHVicmlkYXRlKQ0KDQpwdDFfMTB5cnNfeW1kX2djbXJjcF9nc190YmwgPC0gcHQxXzEweXJzX3ltZF9nc190YmwgJT4lDQogIHNlbGVjdChjdmFyLCB0ZW1wX2MsIFllYXIsIE1vbnRoLCBEYXksIGdjbSwgc2NlbmFyaW8sIGdzKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGN2YXIsIHZhbHVlc19mcm9tID0gdGVtcF9jKSAlPiUNCiAgcmVuYW1lKFRtYXggPSB0YXNtYXgsIFRtaW4gPSB0YXNtaW4pDQoNCmRpbShwdDFfMTB5cnNfeW1kX2djbXJjcF9nc190YmwpDQpoZWFkKHB0MV8xMHlyc195bWRfZ2NtcmNwX2dzX3RibCkNCmBgYA0KDQojIyA0KSBNb2RlbCBIb3VybHkgVGVtcGVyYXR1cmUNCg0KTm93IHdlJ3JlIHJlYWR5IHRvIGNvbXB1dGUgdGhlIGhvdXJseSB0ZW1wcy4gSW4gYWRkaXRpb24gdG8gdGhlIGRhaWx5IG1pbi9tYXggdmFsdWVzLCB3ZSBuZWVkIHRvIHBhc3MgdGhlIGxhdGl0dWRlIG9mIG91ciBzaXRlICh3aGljaCBpcyB1c2VkIHRvIGRldGVybWluZSBzdW5yaXNlIGFuZCBzdW5zZXQgdGltZSk6DQoNCmBgYHtyIGNvbXB1dGVfMTB5cnNfaG91cmx5LCBjYWNoZSA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRX0NCnB0MV8xMHlyc19ocnRtcF93aWRlIDwtIG1ha2VfaG91cmx5X3RlbXBzKGxhdGl0dWRlID0gcHQxX3h5WzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyX2ZpbGUgPSBwdDFfMTB5cnNfeW1kX2djbXJjcF9nc190YmwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBfc3VucmlzZV9zdW5zZXQgPSBGQUxTRSkNCmRpbShwdDFfMTB5cnNfaHJ0bXBfd2lkZSkNCmhlYWQocHQxXzEweXJzX2hydG1wX3dpZGUpDQpgYGANCg0KTm93IHdlIGdvIGZyb20gd2lkZSBiYWNrIHRvIGxvbmcsIGFuZCByZWNyZWF0ZSB0aGUgZGF0ZS10aW1lIGNvbHVtbi4gVGhpcyBnZW5lcmF0ZXMgb3ZlciBhIG1pbGxpb24gcm93cyBzbyBpdCBjYW4gdGFrZSBzZXZlcmFsIHNlY29uZHMuDQoNCmBgYHtyIHB0MV8xMHlyc19ocnRtcF9sb25nLCBjYWNoZSA9IFRSVUV9DQpwdDFfMTB5cnNfaHJ0bXBfbG9uZyA8LSBwdDFfMTB5cnNfaHJ0bXBfd2lkZSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiSG91cl8iKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkhvdXIiLA0KICAgICAgICAgICAgICAgbmFtZXNfcHJlZml4ID0gIkhvdXJfIiwNCiAgICAgICAgICAgICAgIG5hbWVzX3RyYW5zZm9ybSA9IGxpc3QoSG91ciA9IGFzLmludGVnZXIpLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInRlbXBfYyIpICU+JQ0KICBtdXRhdGUoZGF0ZV9ob3VyID0gSVNPZGF0ZXRpbWUoWWVhciwgTW9udGgsIERheSwgSG91ciwgMCwgMCwgdHogPSAiQW1lcmljYS9Mb3NfQW5nZWxlcyIpKSAlPiUNCiAgYXJyYW5nZShkYXRlX2hvdXIpDQoNCmRpbShwdDFfMTB5cnNfaHJ0bXBfbG9uZykNCmhlYWQocHQxXzEweXJzX2hydG1wX2xvbmcpDQpgYGANCg0KVG8gcmVhbGl0eS1jaGVjaywgd2UgY2FuIHBsb3QgYSBwb3J0aW9uIG9mIHRoZSBob3VybHkgdGVtcGVyYXR1cmU6DQoNCmBgYHtyIHBsb3RfaG91cmx5X3RlbXAyLCBjYWNoZSA9IFRSVUV9DQp0c19zdGFydCA8LSBhcy5EYXRlKCIyMDgxLTAxLTAxIikNCnRzX2VuZCA8LSBhcy5EYXRlKCIyMDgxLTAzLTAxIikNCg0Kc2FtcGxlX3RpbWVfc2VyaWVzIDwtIHB0MV8xMHlyc19ocnRtcF9sb25nICU+JSANCiAgZmlsdGVyKGRhdGVfaG91ciA+PSB0c19zdGFydCwgZGF0ZV9ob3VyIDw9IHRzX2VuZCwgDQogICAgICAgICBnY20gPT0gIkNhbkVTTTIiLCBzY2VuYXJpbyA9PSAicmNwNDUiKSAlPiUgDQogIGFycmFuZ2UoZGF0ZV9ob3VyKQ0KDQpkaW0oc2FtcGxlX3RpbWVfc2VyaWVzKQ0KDQpnZ3Bsb3QoZGF0YSA9IHNhbXBsZV90aW1lX3NlcmllcywNCiAgICAgICBhZXMoeCA9IGRhdGVfaG91ciwgeSA9IGFzLm51bWVyaWModGVtcF9jKSkpICsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj0icmVkIiksIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICJNb2RlbGxlZCBIb3VybHkgVGVtcGVyYXR1cmUiLCB4ID0gImRhdGUiLCB5ID0gInRlbXAgKEMpIikgKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXk1MCIsIHNpemUgPSAzKSkNCg0KYGBgDQoNCg0KIyMgNSkgQ29tcHV0ZSBDaGlsbCBQb3J0aW9ucw0KDQpOb3cgd2UncmUgcmVhZHkgdG8gY29tcHV0ZSBjdW11bGF0aXZlIGNoaWxsIHBvcnRpb25zLiBXZSBuZWVkIHRvIGJyZWFrIHRoaXMgdXAgYnkgZ3Jvd2luZyBzZWFzb24sIGdjbSBhbmQgcmNwLg0KDQpgYGB7ciBhY2N1bV9jaGlsbF9wcnRuX2NvbXB1dGUsIGNhY2hlID0gVFJVRX0NCnB0MV8xMHlyc19ocnRtcGNwIDwtIHB0MV8xMHlyc19ocnRtcF9sb25nICU+JSANCiAgbXV0YXRlKHRlbXBfYyA9IGFzLm51bWVyaWModGVtcF9jKSkgJT4lIA0KICBncm91cF9ieShncywgZ2NtLCBzY2VuYXJpbykgJT4lIA0KICBtdXRhdGUoYWNjdW1fY2hpbGxfcHJ0biA9IER5bmFtaWNfTW9kZWwodGVtcF9jKSkNCg0KaGVhZChwdDFfMTB5cnNfaHJ0bXBjcCkNCmBgYA0KDQpWaWV3IHRoZSBtYXhpbXVtIGFjY3VtdWxhdGVkIGNoaWxsIHBvcnRpb24gcGVyIFJDUDoNCg0KYGBge3J9DQpwdDFfMTB5cnNfbWF4Y2hpbGwgPC0gcHQxXzEweXJzX2hydG1wY3AgJT4lIA0KICBncm91cF9ieShzY2VuYXJpbywgZ3MsIGdjbSkgJT4lIA0KICBzdW1tYXJpc2UobWF4X2NoaWxsID0gbWF4KGFjY3VtX2NoaWxsX3BydG4pLCAuZ3JvdXBzID0gJ2Ryb3AnKSANCg0KcHQxXzEweXJzX21heGNoaWxsICU+JSBoZWFkKCkNCmBgYA0KDQojIyA2KSBDb21wdXRlIFNhZmUgQ2hpbGwNCg0KRm9yIGVhY2ggUkNQLCB3ZSBjb21wdXRlIHRoZSAnc2FmZSB3aW50ZXIgY2hpbGwnIHZhbHVlLiAnU2FmZSB3aW50ZXIgY2hpbGwnIGlzIHRoZSBtaW5pbXVtIGNoaWxsIHBvcnRpb24gb25lIGNhbiBleHBlY3QgOTAlIG9mIHRoZSB0aW1lIChbTHVlZGVsaW5nIGV0IGFsLCAyMDA5XShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBvbmUuMDAwNjE2NikpLiBGb3IgZ3Jvd2Vycywgc2FmZSB3aW50ZXIgY2hpbGwgcmVmbGVjdHMgdGhlIGVjb25vbWljIG5lZWQgZm9yIGFuIG9yY2hhcmQgb3BlcmF0aW9uIHRvIHByb2R1Y2UgZ29vZCB5aWVsZHMgaW4gbW9zdCB5ZWFycywgcmF0aGVyIHRoYW4gYW4gYXZlcmFnZSB5ZWFyLiBIZXJlIGl0IGlzIGNvbXB1dGVkIGFzIHRoZSAxMCUgcXVhbnRpbGUgb2YgYWxsIGVuZC1vZi1zZWFzb24gY2hpbGwgcG9ydGlvbnMgaW4gdGhlIGFuYWx5c2lzIChpZS4sIGFsbCBHQ01zIGFuZCBhbGwgZ3Jvd2luZyBzZWFzb25zIDIwODAtMjA5MCksIHdpdGggdGhlIGFzc3VtcHRpb24gdGhhdCBhbGwgb2YgdGhlc2Ugb3V0Y29tZXMgYXJlIGVxdWFsbHkgbGlrZWx5Lg0KDQpgYGB7ciBmaW5kX3NhZmVfY2hpbGwsIGNhY2hlPVRSVUV9DQojIyBDb21wdXRlIHNhZmUgd2ludGVyIGNoaWxsIGZvciBlYWNoIFJDUA0Kc2FmZV9jaGlsbF90YmwgPC0gcHQxXzEweXJzX21heGNoaWxsICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8pICU+JSANCiAgc3VtbWFyaXplKHNhZmVfY2hpbGwgPSBxdWFudGlsZShtYXhfY2hpbGwsIHByb2JzID0gMC4xKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0Kc2FmZV9jaGlsbF90YmwNCmBgYA0KDQpQbG90IGRpc3RyaWJ1dGlvbiBvZiBjaGlsbCBwb3J0aW9uOg0KDQpgYGB7ciBjaGlsbF9oaXN0bywgY2FjaGUgPSBUUlVFfQ0KIyMgUGxvdCB0aGUgaGlzdG9ncmFtIGFuZCBvdmVybGF5IHRoZSBzYWZlIGNoaWxsIHZhbHVlDQpwcm9qZWN0ZWRfaGlzdG8gPC0gZ2dwbG90KHB0MV8xMHlyc19tYXhjaGlsbCwgYWVzKHg9bWF4X2NoaWxsKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArDQogIGdlb21fdmxpbmUoZGF0YSA9IHNhZmVfY2hpbGxfdGJsLCBjb2xvciA9ICJyZWQiLCBhZXMoeGludGVyY2VwdCA9IHNhZmVfY2hpbGwpLCBzaXplID0gMSkgKw0KICBmYWNldF93cmFwKCJzY2VuYXJpbyIsIG5yb3cgPSAxKSArDQogIGxhYnModGl0bGUgPSAiTWF4aW11bSBQcm9qZWN0ZWQgQ2hpbGwgUG9ydGlvbiIsIA0KICAgICBzdWJ0aXRsZSA9ICIyMDgwIC0gMjA5MCIsDQogICAgIGNhcHRpb24gPSBwYXN0ZTAoDQogICAgICAgc3RyX3dyYXAocGFzdGUwKCJHQ01zOiAiLCBwYXN0ZSh1bmlxdWUocHQxXzEweXJzX21heGNoaWxsJGdjbSksIGNvbGxhcHNlID0gIiwgIiksIHdpZHRoID0gMTA1KSksDQogICAgICAgIlxuIiwNCiAgICAgICBzdHJfd3JhcCgiVGhlIHJlZCBsaW5lIGlzIHRoZSAxMCUgcXVhbnRpbGUgYW5kIHJlcHJlc2VudHMgdGhlIHNhZmUgd2ludGVyIGNoaWxsICh0aGUgbWltaW11bSBjaGlsbCBwb3J0aW9uIG9uZSBtYXkgZXhwZWN0IDkwJSBvZiB0aGUgdGltZSBhc3N1bW1pbmcgYWxsIHByb2plY3Rpb25zIGFyZSBlcXVhbGx5IGxpa2VseSkuIiwgd2lkdGggPSAxMDUpKSwNCiAgICAgeCA9ICJlbmQtb2Ytc2Vhc29uIGNoaWxsIHBvcnRpb24iLCB5ID0gImNvdW50IikgKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXk1MCIsIHNpemUgPSAzKSkNCg0KcHJvamVjdGVkX2hpc3RvDQpgYGANCg0KIyMgNykgSG93IE1hbnkgR3Jvd2luZyBTZWFzb25zIFJlYWNoIHRoZSBNaW5pbXVtIENoaWxsIFJlcXVpcmVtZW50Pw0KDQpOZXh0LCBmb3IgZWFjaCBSQ1Agd2UgY29tcHV0ZSBob3cgbWFueSBwcm9qZWN0ZWQgdGVtcGVyYXR1cmUgc2VyaWVzIHJlc3VsdGVkIGluIGF0IGxlYXN0IGByIGNoaWxsX21pbmAgYWNjdW11bGF0ZWQgY2hpbGwgcG9ydGlvbnMgbmVlZGVkIGZvciBhIHZpYWJsZSBjcm9wIG9mIHRoZSBbS2VybWFuIGN1bHRpdmFyIG9mIFBpc3RhY2hpb3NdKGh0dHA6Ly9mcnVpdHNhbmRudXRzLnVjZGF2aXMuZWR1L1dlYXRoZXJfU2VydmljZXMvY2hpbGxpbmdfYWNjdW11bGF0aW9uX21vZGVscy9Dcm9wQ2hpbGxSZXEvKToNCg0KYGBge3IgcHJjdF9taW5fY2hpbGxfcmVhY2hlZCwgY2FjaGU9VFJVRSwgbWVzc2FnZT1GQUxTRX0NCmNoaWxsX21pbiA8LSA1NA0KDQpwdDFfMTB5cnNfcHJjdF9yZWFjaGVkX21pbiA8LSBwdDFfMTB5cnNfaHJ0bXBjcCAlPiUgDQogIGdyb3VwX2J5KGdzLCBnY20sIHNjZW5hcmlvKSAlPiUgDQogIHN1bW1hcmlzZShyZWFjaGVkX3RocmVzaCA9IG1heChhY2N1bV9jaGlsbF9wcnRuKSA+PSBjaGlsbF9taW4pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8pICU+JSANCiAgc3VtbWFyaXNlKHBlcmNlbnRfcmVhY2hlZF90aHJlc2ggPSBzdW0ocmVhY2hlZF90aHJlc2gpIC8gbigpKSAlPiUgDQogIG11dGF0ZSh0aW1lX3BlcmlvZCA9ICIyMDgxIC0gMjA5MCIsIHBlcmNlbnRfcmVhY2hlZF90aHJlc2ggPSBzY2FsZXM6OnBlcmNlbnQocGVyY2VudF9yZWFjaGVkX3RocmVzaCkpICU+JSANCiAgcmVsb2NhdGUodGltZV9wZXJpb2QsIHNjZW5hcmlvLCBwZXJjZW50X3JlYWNoZWRfdGhyZXNoKQ0KDQpwdDFfMTB5cnNfcHJjdF9yZWFjaGVkX21pbg0KYGBgDQoNCg0KIyMgOCkgQWNjdW11bGF0ZWQgQ2hpbGwgQ3VydmVzDQoNCk5leHQsIHdlIHBsb3QgdGhlIGN1cnZlcyBmb3IgYWNjdW11bGF0ZWQgY2hpbGwgZm9yIFJDUCA0LjUgYW5kIDguNS4gV2UgaGF2ZSAxMCBncm93aW5nIHNlYXNvbnMgYW5kIDEwIEdDTXMsIGZvciBhIHRvdGFsIG9mIDEwMCBjdXJ2ZXMuIFRoZSBsaW5lcyB0aGF0IGVuZCBhYm92ZSB0aGUgbWluaW11bSBjaGlsbCByZXF1aXJlbWVudCByZXByZXNlbnQgc2ltdWxhdGlvbnMgd2hlcmUgdGhlIG1pbmltdW0gY2hpbGwgZm9yIGEgdmlhYmxlIGNyb3Agd2FzIHJlYWNoZWQuIA0KDQpgYGB7ciBwbG90X2FjY19jdXJ2ZXNfcmNwNDUsIGNhY2hlID0gVFJVRX0NCiMjIEZpcnN0IG1ha2UgYSBjb3B5IG9mIGRhdGEsIG1hbnVhbGx5IHNldCB0aGUgeWVhciB0byB0aGUgc2FtZSB2YWx1ZSAoc28gdGhlIGRhdGVzIGFyZSBpbiB0aGUgc2FtZSByYW5nZSksIGFuZCBrZWVwDQojIyBvbmx5IG1pZG5pZ2h0IHZhbHVlcw0KDQpwdDFfMTB5cnNfaHJ0bXBjcF80cGxvdCA8LSBwdDFfMTB5cnNfaHJ0bXBjcCAlPiUgDQogIGZpbHRlcihIb3VyID09IDApICU+JSANCiAgbXV0YXRlKFllYXJQbG90ID0gaWZfZWxzZShNb250aCA+PSA5LCAxOTcwLCAxOTcxKSkgJT4lIA0KICBtdXRhdGUoZGF0ZV9ob3VyID0gSVNPZGF0ZXRpbWUoWWVhclBsb3QsIE1vbnRoLCBEYXksIEhvdXIsIDAsIDAsIHR6ID0gIkFtZXJpY2EvTG9zX0FuZ2VsZXMiKSwNCiAgICAgICAgIGdzX2djbSA9IHBhc3RlKGdzLCBnY20sIHNlcCA9ICJfIikpICU+JSANCiAgc2VsZWN0KHNjZW5hcmlvLCBncywgZ2NtLCBnc19nY20sIGRhdGVfaG91ciwgYWNjdW1fY2hpbGxfcHJ0bikNCg0KIyMgQ3JlYXRlIHBsb3QNCmdncGxvdChkYXRhID0gcHQxXzEweXJzX2hydG1wY3BfNHBsb3QgJT4lIGZpbHRlcihzY2VuYXJpbyA9PSAicmNwNDUiKSwNCiAgICAgICBhZXMoeCA9IGRhdGVfaG91ciwgeSA9IGFjY3VtX2NoaWxsX3BydG4pKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9Z3NfZ2NtKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjaGlsbF9taW4sIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiUHJvamVjdGVkIENoaWxsIFBvcnRpb24gQWNjdW11bGF0aW9uIGZvciBQdCAxOiBSQ1AgNC41IiwgDQogICAgICAgc3VidGl0bGUgPSAiMjA4MCAtIDIwOTAiLA0KICAgICAgIGNhcHRpb24gPSBzdHJfd3JhcChwYXN0ZTAoIkdDTXM6ICIsIHBhc3RlKHVuaXF1ZShwdDFfMTB5cnNfaHJ0bXBjcF80cGxvdCRnY20pLCBjb2xsYXBzZSA9ICIsICIpLCB3aWR0aCA9IDYwKSksDQogICAgICAgeCA9ICJkYXRlIiwgeSA9ICJDaGlsbCBQb3J0aW9uIikgKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXk1MCIsIHNpemUgPSAzKSkNCmBgYA0KDQoNCg0KYGBge3IgcGxvdF9hY2NfY3VydmVzX3JjcDg1LCBjYWNoZSA9IFRSVUV9DQojIyBSQ1AgODUNCmdncGxvdChkYXRhID0gcHQxXzEweXJzX2hydG1wY3BfNHBsb3QgJT4lIGZpbHRlcihzY2VuYXJpbyA9PSAicmNwODUiKSwNCiAgICAgICBhZXMoeCA9IGRhdGVfaG91ciwgeSA9IGFjY3VtX2NoaWxsX3BydG4pKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9Z3NfZ2NtKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjaGlsbF9taW4sIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiUHJvamVjdGVkIENoaWxsIFBvcnRpb24gQWNjdW11bGF0aW9uIGZvciBQdCAxOiBSQ1AgOC41IiwgDQogICAgICAgc3VidGl0bGUgPSAiMjA4MCAtIDIwOTAiLA0KICAgICAgIGNhcHRpb24gPSBzdHJpbmdyOjpzdHJfd3JhcChwYXN0ZTAoIkdDTXM6ICIsIHBhc3RlKHVuaXF1ZShwdDFfMTB5cnNfaHJ0bXBjcF80cGxvdCRnY20pLCBjb2xsYXBzZSA9ICIsICIpLCB3aWR0aCA9IDYwKSksDQogICAgICAgeCA9ICJkYXRlIiwgeSA9ICJDaGlsbCBQb3J0aW9uIikgKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXk1MCIsIHNpemUgPSAzKSkNCmBgYA0KDQojIyA5KSBEaXN0cmlidXRpb24gb2YgUmVxdWlyZWQgQWNjdW11bGF0aW9uIERhdGUNCg0KSGVyZSB3ZSBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgcHJvamVjdGVkIGRhdGVzIHdoZW4gdGhlIGFjY3VtdWxhdGVkIGNoaWxsIHJlYWNoZXMgdGhlIG1pbmltdW0gcmVxdWlyZW1lbnQuDQoNCmBgYHtyfQ0KIyMgTnVtYmVyIG9mIHJ1bnMgZm9yIGVhY2ggZW1pc3Npb25zIHNjZW5hcmlvID0gbnVtYmVyIG9mIGdyb3dpbmcgc2Vhc29ucyAqIG51bWJlciBvZiBnY21zDQpudW1fcnVucyA8LSBsZW5ndGgodW5pcXVlKHB0MV8xMHlyc19ocnRtcGNwJGdzKSkgKiBsZW5ndGgodW5pcXVlKHB0MV8xMHlyc19ocnRtcGNwJGdjbSkpIA0KDQojIyBGb3IgZWFjaCBydW4sIGZpbmQgdGhlIGZpcnN0IGRhdGUgd2hlbiB0aGUgbWluaW11bSBjaGlsbCBwb3J0aW9uIHdhcyByZWFjaGVkLiANCnB0MV8xMHlyc19zY2VuX2NoaWxsZHQgPC0gcHQxXzEweXJzX2hydG1wY3AgJT4lIA0KICBmaWx0ZXIoSG91ciA9PSAwKSAlPiUgDQogIGZpbHRlcihhY2N1bV9jaGlsbF9wcnRuID49IGNoaWxsX21pbikgJT4lIA0KICBncm91cF9ieShncywgZ2NtKSAlPiUgDQogIHNsaWNlX21pbihvcmRlcl9ieSA9IGRhdGVfaG91ciwgbiA9IDEpICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoZGF0ZV8xOTcwID0gSVNPZGF0ZSh5ZWFyID0gMTk3MCwgbW9udGggPSBNb250aCwgZGF5ID0gRGF5KSkgJT4lIA0KICBzZWxlY3Qoc2NlbmFyaW8sIGRhdGVfMTk3MCkNCg0KIyMgd2UncmUgZ2V0dGluZyBvbmUgTkEgLSBpbnZlc3RpZ2F0ZQ0KIyMgcHQxXzEweXJzX3NjZW5fY2hpbGxkdCAlPiUgZmlsdGVyKGlzLm5hKGRhdGVfMTk3MCkpICANCg0KIyMgTWFrZSBhIGRhdGEgZnJhbWUgZm9yIHRoZSB0b3RhbCBudW1iZXIgb2YgZGF0ZXMgYW5kIG1pZGRsZSBkYXRlIHBlciBzY2VuYXJpbyANCiMjIChUaGlzIGlzIGZvciB0aGUgbGFiZWxzIG9uIHRoZSBib3ggcGxvdCkNCnNjZW5fc3RhdHNfdGJsIDwtIHB0MV8xMHlyc19zY2VuX2NoaWxsZHQgJT4lIA0KICBncm91cF9ieShzY2VuYXJpbykgJT4lIA0KICBzdW1tYXJpemUobnVtX2RhdGVzID0gbigpLCBtaWRfZHQgPSBtZWRpYW4oZGF0ZV8xOTcwLCBuYS5ybSA9IFRSVUUpKQ0KDQojIyBNYWtlIGEgbGlzdCBvYmplY3QgZm9yIGVhc3kgcmVmZXJlbmNlLiBOT1QgTkVFREVEIEFOWU1PUkUNCiMjIG51bV9ydW5zX2xzdCA8LSBzY2VuX3N0YXRzX3RibCAlJCUgc3BsaXQobnVtX2RhdGVzLCBzY2VuYXJpbykgDQoNCiMjIFBsb3QgdGhlIHJlc3VsdHMNCmdncGxvdChwdDFfMTB5cnNfc2Nlbl9jaGlsbGR0LCBhZXMoZGF0ZV8xOTcwICwgc2NlbmFyaW8pKSArIA0KICBnZW9tX2JveHBsb3QoKSArDQogIGdlb21fbGFiZWwoZGF0YSA9IHNjZW5fc3RhdHNfdGJsLCANCiAgICAgICAgICAgIGFlcyhsYWJlbD1wYXN0ZTAoIm49IiwgbnVtX2RhdGVzKSwgeCA9IG1pZF9kdCArICgzLjUgKiAyNCAqIDM2MDApKSwgDQogICAgICAgICAgICBzaXplID0gMy41LCBmaWxsID0gIndoaXRlIiwgbGFiZWwuc2l6ZSA9IDApICsNCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiRGF0ZSBBY2N1bWxhdGVkIENoaWxsIFBvcnRpb24gUmVhY2hlcyAiLCBjaGlsbF9taW4gKSwgDQogICAgICAgc3VidGl0bGUgPSAiMjA4MCAtIDIwOTAiLA0KICAgICAgIGNhcHRpb24gPSBzdHJfd3JhcChwYXN0ZSgiR0NNczogIiwgcGFzdGUodW5pcXVlKHB0MV8xMHlyc19ocnRtcGNwXzRwbG90JGdjbSksIGNvbGxhcHNlID0gIiwgIikpLCB3aWR0aCA9IDgwKSwNCiAgICAgICB4ID0gImRhdGUiLCB5ID0gIkVtaXNzaW9ucyBTY2VuYXJpbyIpICsNCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksDQogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDIwLCAyMCwgMjAsIDIwKSwNCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmF5NTAiLCBzaXplID0gMykpDQpgYGANCg0KDQojIEhpc3RvcmljYWwgQmFzZWxpbmUNCg0KV2hlbiBsb29raW5nIGF0IGhpc3RvcmljYWwgZGF0YSwgd2UgY2FuIGVpdGhlciB1c2UgbW9kZWxlZCBvciBvYnNlcnZlZC4gSGVyZSB3ZSB1c2UgbW9kZWxlZCBiZWNhdXNlIDEpIG1vZGVsZWQgZGF0YSBoYXMgYmVlbiBzaG93biB0byBtYXRjaGVzIG9ic2VydmVkIHBhdHRlcm5zIHZlcnkgd2VsbCwgYW5kIDIpIGl0IGZhY2lsaXRhdGVzIGNvbXBhcmlzb25zIHdpdGggbW9kZWxlZCBwcmVkaWN0aW9ucy4NCg0KYGBge3IgY2FwMmJhc2VsaW5lX21ha2UsIGNhY2hlPVRSVUV9DQojIyBQaWNrIGEgbG9jYXRpb24NCnB0MV94eSA8LSBjKC0xMTkuOTY0LCAzNi4wMTkpDQoNCnB0MV9iYXNlbGluZV9jYXAgPC0gY2FfbG9jX3B0KGNvb3JkcyA9IHB0MV94eSkgJT4lDQogIGNhX2djbShnY21zWzE6MTBdKSAlPiUNCiAgY2Ffc2NlbmFyaW8oYygiaGlzdG9yaWNhbCIpKSAlPiUNCiAgY2FfcGVyaW9kKCJkYXkiKSAlPiUNCiAgY2FfZGF0ZXMoc3RhcnQgPSAiMTk5NS0wMS0wMSIsIGVuZCA9ICIyMDA1LTEyLTMxIikgJT4lDQogIGNhX2N2YXIoYygidGFzbWF4IiwgInRhc21pbiIpKQ0KDQpwdDFfYmFzZWxpbmVfY2FwDQpgYGANCg0KYGBge3IgcHQxX2Jhc2VsaW5lX3RibF9mZXRjaCwgY2FjaGUgPSBUUlVFfQ0KcHQxX2Jhc2VsaW5lX3RibCA8LSBwdDFfYmFzZWxpbmVfY2FwICU+JSBjYV9nZXR2YWxzX3RibChxdWlldCA9IFRSVUUpIA0KZGltKHB0MV9iYXNlbGluZV90YmwpDQpoZWFkKHB0MV9iYXNlbGluZV90YmwpDQpgYGANCg0KQWRkIGNvbHVtbnM6DQoNCmBgYHtyfQ0KcHQxX2Jhc2VsaW5lX3ltZF90YmwgPC0gcHQxX2Jhc2VsaW5lX3RibCAlPiUgDQogIG11dGF0ZShZZWFyID0gYXMuaW50ZWdlcihzdWJzdHIoZHQsIDEsIDQpKSwgDQogICAgICAgICBNb250aCA9IGFzLmludGVnZXIoc3Vic3RyKGR0LCA2LCA3KSksDQogICAgICAgICBEYXkgPSBhcy5pbnRlZ2VyKHN1YnN0cihkdCwgOSwgMTApKSkgJT4lIA0KICBzZWxlY3QoY3ZhciwgZ2NtLCBzY2VuYXJpbywgWWVhciwgTW9udGgsIERheSwgdmFsKQ0KcHQxX2Jhc2VsaW5lX3ltZF90YmwNCmBgYA0KDQpBZGQgZ3Jvd2luZyBzZWFzb24gY29sdW1uOg0KDQpgYGB7ciBiYXNlbGluZV9ncywgY2FjaGUgPSBUUlVFfQ0KcHQxX2Jhc2VsaW5lX3ltZF9nc190YmwgPC0gcHQxX2Jhc2VsaW5lX3ltZF90YmwgJT4lIA0KICBtdXRhdGUoZ3MgPSBjYXNlX3doZW4oTW9udGggPD0gNiB+IFllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICBNb250aCA+PSA5IH4gYXMuaW50ZWdlcihZZWFyICsgMSkpKSAlPiUgDQogIGZpbHRlcighaXMubmEoZ3MpKSAlPiUgDQogIG11dGF0ZSh0ZW1wX2MgPSBzZXRfdW5pdHModmFsLCBkZWdDKSkNCmhlYWQocHQxX2Jhc2VsaW5lX3ltZF9nc190YmwpDQpgYGANCg0KUGl2b3Qgd2lkZXIgKG1ha2UgdGFzbWF4IGFuZCB0YXNtaW4gc2VwYXJhdGUgY29sdW1ucyk6DQoNCmBgYHtyIHB0MV9iYXNlbGluZV95bWRfZ2NtcmNwX2dzX3RibCwgY2FjaGUgPSBUUlVFfQ0KcHQxX2Jhc2VsaW5lX3ltZF9nY21yY3BfZ3NfdGJsIDwtIHB0MV9iYXNlbGluZV95bWRfZ3NfdGJsICU+JQ0KICBzZWxlY3QoY3ZhciwgdGVtcF9jLCBZZWFyLCBNb250aCwgRGF5LCBnY20sIHNjZW5hcmlvLCBncykgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjdmFyLCB2YWx1ZXNfZnJvbSA9IHRlbXBfYykgJT4lDQogIHJlbmFtZShUbWF4ID0gdGFzbWF4LCBUbWluID0gdGFzbWluKQ0KDQpkaW0ocHQxX2Jhc2VsaW5lX3ltZF9nY21yY3BfZ3NfdGJsKQ0KaGVhZChwdDFfYmFzZWxpbmVfeW1kX2djbXJjcF9nc190YmwpDQoNCmBgYA0KQ29tcHV0ZSBob3VybHkgdGVtcHMgKGluIHdpZGUgZm9ybWF0KToNCg0KYGBge3IgcHQxX2Jhc2VsaW5lX2hydG1wX3dpZGUsIGNhY2hlID0gVFJVRX0NCnB0MV9iYXNlbGluZV9ocnRtcF93aWRlIDwtIG1ha2VfaG91cmx5X3RlbXBzKGxhdGl0dWRlID0gcHQxX3h5WzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyX2ZpbGUgPSBwdDFfYmFzZWxpbmVfeW1kX2djbXJjcF9nc190YmwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBfc3VucmlzZV9zdW5zZXQgPSBGQUxTRSkNCmRpbShwdDFfYmFzZWxpbmVfaHJ0bXBfd2lkZSkNCmhlYWQocHQxX2Jhc2VsaW5lX2hydG1wX3dpZGUpDQpgYGANCg0KQ29udmVydCB3aWRlIHRvIGxvbmc6DQoNCmBgYHtyIHB0MV9iYXNlbGluZV9ocnRtcF9sb25nLCBjYWNoZSA9IFRSVUV9DQpwdDFfYmFzZWxpbmVfaHJ0bXBfbG9uZyA8LSBwdDFfYmFzZWxpbmVfaHJ0bXBfd2lkZSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiSG91cl8iKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkhvdXIiLA0KICAgICAgICAgICAgICAgbmFtZXNfcHJlZml4ID0gIkhvdXJfIiwNCiAgICAgICAgICAgICAgIG5hbWVzX3RyYW5zZm9ybSA9IGxpc3QoSG91ciA9IGFzLmludGVnZXIpLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInRlbXBfYyIpICU+JQ0KICBtdXRhdGUoZGF0ZV9ob3VyID0gSVNPZGF0ZXRpbWUoWWVhciwgTW9udGgsIERheSwgSG91ciwgMCwgMCwgdHogPSAiQW1lcmljYS9Mb3NfQW5nZWxlcyIpKSAlPiUNCiAgYXJyYW5nZShkYXRlX2hvdXIpDQoNCmRpbShwdDFfYmFzZWxpbmVfaHJ0bXBfbG9uZykNCmhlYWQocHQxX2Jhc2VsaW5lX2hydG1wX2xvbmcpDQpgYGANCg0KQ29tcHV0ZSBiYXNlbGluZSBjaGlsbCBwb3J0aW9uczoNCg0KYGBge3IgcHQxX2Jhc2VsaW5lX2hydG1wY3AsIGNhY2hlID0gVFJVRX0NCnB0MV9iYXNlbGluZV9ocnRtcGNwIDwtIHB0MV9iYXNlbGluZV9ocnRtcF9sb25nICU+JSANCiAgbXV0YXRlKHRlbXBfYyA9IGFzLm51bWVyaWModGVtcF9jKSkgJT4lIA0KICBncm91cF9ieShncywgZ2NtLCBzY2VuYXJpbykgJT4lIA0KICBtdXRhdGUoYWNjdW1fY2hpbGxfcHJ0biA9IER5bmFtaWNfTW9kZWwodGVtcF9jKSkNCg0KaGVhZChwdDFfYmFzZWxpbmVfaHJ0bXBjcCkNCg0KYGBgDQoNCkNvbXB1dGUgdGhlIG1heC1jaGlsbCByZWFjaGVkIGVhY2ggZ3Jvd2luZyBzZWFzb24gLyBHQ00gZHVyaW5nIHRoZSBiYXNlbGluZSBwZXJpb2QuIE5leHQgd2UgY29tcHV0ZSB0aGUgJ3NhZmUgY2hpbGwnICgxMCUgcXVhbnRpbGUpOg0KDQpgYGB7ciBwdDFfYmFzZWxpbmVfbWF4Y2hpbGwsIGNhY2hlID0gVFJVRX0NCnB0MV9iYXNlbGluZV9tYXhjaGlsbCA8LSBwdDFfYmFzZWxpbmVfaHJ0bXBjcCAlPiUgDQogIGdyb3VwX2J5KHNjZW5hcmlvLCBncywgZ2NtKSAlPiUgDQogIHN1bW1hcmlzZShtYXhfY2hpbGwgPSBtYXgoYWNjdW1fY2hpbGxfcHJ0biksIC5ncm91cHMgPSAnZHJvcCcpIA0KDQpkaW0ocHQxX2Jhc2VsaW5lX21heGNoaWxsKQ0KcHQxX2Jhc2VsaW5lX21heGNoaWxsICU+JSBoZWFkKCkNCg0Kc2FmZV9jaGlsbF9iYXNlbGluZV90YmwgPC0gcHQxX2Jhc2VsaW5lX21heGNoaWxsICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8pICU+JSANCiAgc3VtbWFyaXplKHNhZmVfY2hpbGwgPSBxdWFudGlsZShtYXhfY2hpbGwsIHByb2JzID0gMC4xKSwgLmdyb3VwcyA9ICJkcm9wIikgDQoNCnNhZmVfY2hpbGxfYmFzZWxpbmVfdGJsDQpgYGANCg0KUGxvdCBkaXN0cmlidXRpb24gb2YgdGhlIGJhc2VsaW5lIG1heGltdW0gY2hpbGwgcG9ydGlvbjoNCg0KYGBge3IgY2hpbGxfYmFzZWxpbmVfaGlzdG8sIGNhY2hlID0gVFJVRX0NCiMjIFBsb3QgdGhlIGhpc3RvZ3JhbSBhbmQgb3ZlcmxheSB0aGUgc2FmZSBjaGlsbCB2YWx1ZQ0KYmFzZWxpbmVfaGlzdG8gPC0gZ2dwbG90KHB0MV9iYXNlbGluZV9tYXhjaGlsbCwgYWVzKHg9bWF4X2NoaWxsKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArDQogIGdlb21fdmxpbmUoZGF0YSA9IHNhZmVfY2hpbGxfYmFzZWxpbmVfdGJsLCBjb2xvciA9ICJyZWQiLCBhZXMoeGludGVyY2VwdCA9IHNhZmVfY2hpbGwpLCBzaXplID0gMSkgKw0KICBmYWNldF93cmFwKCJzY2VuYXJpbyIsIG5yb3cgPSAxKSArDQogIGxhYnModGl0bGUgPSAiTWF4aW11bSBQcm9qZWN0ZWQgQ2hpbGwgUG9ydGlvbiIsIA0KICAgICBzdWJ0aXRsZSA9ICIxOTk1IC0gMjAwNSIsDQogICAgIGNhcHRpb24gPSBwYXN0ZTAoDQogICAgICAgc3RyX3dyYXAocGFzdGUwKCJHQ01zOiAiLCBwYXN0ZSh1bmlxdWUocHQxX2Jhc2VsaW5lX21heGNoaWxsJGdjbSksIGNvbGxhcHNlID0gIiwgIiksIHdpZHRoID0gMTA1KSksDQogICAgICAgIlxuIiwNCiAgICAgICBzdHJfd3JhcCgiVGhlIHJlZCBsaW5lIGlzIHRoZSAxMCUgcXVhbnRpbGUgYW5kIHJlcHJlc2VudHMgdGhlIHNhZmUgd2ludGVyIGNoaWxsICh0aGUgbWltaW11bSBjaGlsbCBwb3J0aW9uIG9uZSBtYXkgZXhwZWN0IDkwJSBvZiB0aGUgdGltZSBhc3N1bW1pbmcgYWxsIHByb2plY3Rpb25zIGFyZSBlcXVhbGx5IGxpa2VseSkuIiwgd2lkdGggPSAxMDUpKSwNCiAgICAgeCA9ICJlbmQtb2Ytc2Vhc29uIGNoaWxsIHBvcnRpb24iLCB5ID0gImNvdW50IikgKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDIwLCAyMCwgMjApLA0KICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXk1MCIsIHNpemUgPSAzKSkNCg0KYmFzZWxpbmVfaGlzdG8NCmBgYA0KDQpIb3cgTWFueSBHcm93aW5nIFNlYXNvbnMgYW5kIFNpbXVsYXRlZCAoQmFja2Nhc3QpIENsaW1hdGUgQ29uZGl0aW9ucyBEdXJpbmcgdGhlIEJhc2VsaW5lIFNlYXNvbnMgUmVhY2hlZCBPdXIgTWluaW11bSBDaGlsbCBSZXF1aXJlbWVudD8NCg0KYGBge3IgYmFzZWxpbmVfcHJjdF9taW5fY2hpbGxfcmVhY2hlZCwgY2FjaGU9VFJVRSwgbWVzc2FnZT1GQUxTRX0NCmNoaWxsX21pbiA8LSA1NA0KDQpwdDFfYmFzZWxpbmVfcHJjdF9yZWFjaGVkX21pbiA8LSBwdDFfYmFzZWxpbmVfaHJ0bXBjcCAlPiUgDQogIGdyb3VwX2J5KGdzLCBnY20sIHNjZW5hcmlvKSAlPiUgDQogIHN1bW1hcmlzZShyZWFjaGVkX3RocmVzaCA9IG1heChhY2N1bV9jaGlsbF9wcnRuKSA+PSBjaGlsbF9taW4pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8pICU+JSANCiAgc3VtbWFyaXNlKHBlcmNlbnRfcmVhY2hlZF90aHJlc2ggPSBzdW0ocmVhY2hlZF90aHJlc2gpIC8gbigpKSAlPiUgDQogIG11dGF0ZSh0aW1lX3BlcmlvZCA9ICIxOTk1LTIwMDUiLCBwZXJjZW50X3JlYWNoZWRfdGhyZXNoID0gc2NhbGVzOjpwZXJjZW50KHBlcmNlbnRfcmVhY2hlZF90aHJlc2gpKSAlPiUgDQogIHJlbG9jYXRlKHRpbWVfcGVyaW9kLCBzY2VuYXJpbywgcGVyY2VudF9yZWFjaGVkX3RocmVzaCkNCg0KcHQxX2Jhc2VsaW5lX3ByY3RfcmVhY2hlZF9taW4NCg0KYGBgDQoNCiMgQ29uY2x1c2lvbnMNCg0KSW4gdGhpcyBhbmFseXNpcyB3ZSBleGFtaW5lZCBwcm9qZWN0ZWQgYW5kIGhpc3RvcmljIGFjY3VtdWxhdGVkIGNoaWxsIHBvcnRpb25zIGZvciB0aGlzIHBvaW50Og0KDQpgYGB7ciBwdDFfMTB5cnNfY2FwX3Bsb3QsIGNhY2hlID0gVFJVRX0NCnBsb3QocHQxXzEweXJzX2NhcCkNCmBgYA0KDQpXZSBsb29rZWQgYXQgdGhlIHByb2plY3RlZCB0ZW1wZXJhdHVyZXMgYXQgdGhpcyBsb2NhdGlvbiBhY2NvcmRpbmcgdG8gMTAgR0NNcyBpbiB0aGUgcmVjZW50IGhpc3RvcmljIHRpbWUgcGVyaW9kICgxOTk1LTIwMDUpLCBhcyB3ZWxsIGFzIHByb2plY3RlZCBmb3IgMjA4MC0yMDkwIHVuZGVyIHR3byBjYXJib24gZW1pc3Npb25zIHNjZW5hcmlvcyAoUkNQNC41ICYgOC41KS4gT3VyIGFuYWx5c2lzIHNob3dzIHRoYXQgdGhlIHBlcmNlbnQgb2Ygc2Vhc29ucyAmIG1vZGVscyB3aGVyZSB0aGUgbWF4aW11bSBjaGlsbCBwb3J0aW9uIGJ5IHRoZSBlbmQgb2Ygd2ludGVyIGlzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgYW1vdW50IG9mIGNoaWxsIG5lZWRlZCB0byBncm93IEtlcm1hbiB2YXJpZXR5IG9mIFBpc3RhY2hpb3MgKGByIGNoaWxsX21pbmApIHdhczoNCg0KYGBge3IgcGVyY250X3JlYWNoZWRfYWxsX3RibCwgY2FjaGUgPSBUUlVFfQ0KcHQxX2Jhc2VsaW5lX3ByY3RfcmVhY2hlZF9taW4gJT4lIA0KICBiaW5kX3Jvd3MocHQxXzEweXJzX3ByY3RfcmVhY2hlZF9taW4pDQpgYGANCg0KV2UgYWxzbyBjb21wdXRlZCB0aGUgJ3NhZmUtY2hpbGwnIHBvcnRpb24gZm9yIGVhY2ggb2YgdGhlIHRpbWUgcGVyaW9kcy4gVGhpcyBpcyB0aGUgYW1vdW50IG9mIGNoaWxsIG9uZSBjYW4gZXhwZWN0IHRvIHJlYWNoIDkwJSBvZiB0aGUgdGltZToNCg0KYGBge3IgaGlzdG9zX3JlcGVhdGVkLCBjYWNoZSA9IFRSVUV9DQpzYWZlX2NoaWxsX2Jhc2VsaW5lX3RibCAlPiUgYmluZF9yb3dzKHNhZmVfY2hpbGxfdGJsKQ0KDQpiYXNlbGluZV9oaXN0bw0KcHJvamVjdGVkX2hpc3RvDQpgYGANCg0KIyMgSW50ZXJwcmV0YXRpb24NCg0KVGhpcyBleGFtcGxlIHdhcyBwcmltYXJpbHkgYW4gZXhlcmNpc2Ugb24gaG93IHRvIHdyaXRlIGNvZGUsIGFuZCBzaG91bGQgYmUgdGFrZW4gd2l0aCBhIGdyYWluIG9mIHNhbHQuIEhvd2V2ZXIgdGhlIHJlc3VsdHMgd2UgY2FtZSB1cCB3aXRoIHN1Z2dlc3QgdGhhdCB0aGlzIGxvY2F0aW9uIG1heSBjb250aW51ZSB0byBiZSB2aWFibGUgZm9yIHRoZSBLZXJtYW4gdmFyaWV0eSBvZiBQaXN0YWNoaW9zIGluIDIwODAtMjA5MCB1bmRlciBlbWlzc2lvbiBzY2VuYXJpbyA0LjUsIGJ1dCBtYXkgbm90IHByb2R1Y2UgZW5vdWdoIHdpbnRlciBjaGlsbCBwb3J0aW9ucyBjb25zaXN0ZW50bHkgZW5vdWdoIHRvIGJlIGVjb25vbWljYWxseSB2aWFibGUgdW5kZXIgUkNQIDguNS4gDQoNClRoaXMgYW5hbHlzaXMgd2FzIGJhc2VkIG9uIHRoZSBhc3N1bXB0aW9uIHRoYXQgYWxsIDEwIEdDTXMgcmVjb21tZW5kZWQgZm9yIENhbGlmb3JuaWEgdW5kZXIgdGhlIDR0aCBDbGltYXRlIENoYW5nZSBBc3Nlc3NtZW50IGFyZSBlcXVhbGx5IGxpa2VseS4gV2UgYWxzbyBpbnRlcnBvbGF0ZWQgaG91cmx5IHRlbXBlcmF0dXJlcyBiYXNlZCBvbiBhIGdlbmVyaWMgc3RhdGlzdGljYWwgbW9kZWwgdGhhdCB3YXMgbm90IHNwZWNpZmljIHRvIHRoaXMgbG9jYXRpb24uIFdlIGNvdWxkIGltcHJvdmUgdGhpcyBhbmFseXNpcyBieToNCg0KMS4gU2VsZWN0aW5nIEdDTXMgdGhhdCBhcmUgYmVzdCBzdWl0ZWQgZm9yIENhbGlmb3JuaWEncyBTYW4gSm9hcXVpbiBWYWxsZXkgIA0KMS4gUmV2aWV3aW5nIHRoZSBsYXRlc3QgbGl0ZXJhdHVyZSB0byBhc3Nlc3Mgd2hldGhlciBlbWlzc2lvbiBzY2VuYXJpbyA0LjUgb3IgOC41IHNlZW1zIG1vcmUgbGlrZWx5DQoxLiBXYWl0aW5nIGZvciBDTUlQNiBwcm9qZWN0ZWQgY2xpbWF0ZSBkYXRhIHdoaWNoIHdpbGwgaW5jbHVkZSBzdWItZGFpbHkgdGVtcGVyYXR1cmUgdmFsdWVzIChlLmcuLCBldmVyeSAyIGhvdXJzKQ0KDQojIFF1ZXN0aW9ucyBhbmQgTmV4dCBTdGVwcw0KDQpJcyB0aGlzIGEgZ29vZCB3YXkgdG8gY29tYmluZSAvIGF2ZXJhZ2UgcmVzdWx0cyBmcm9tIG11bHRpcGxlIG1vZGVscywgbXVsdGlwbGUgeWVhcnM/DQoNClNob3VsZCB3ZSB1c2UgYWN0dWFsIG9yIG1vZGVsbGVkIGRhdGEgZm9yIHRoZSBoaXN0b3JpY2FsIGJhc2VsaW5lPw0KDQpXb3VsZCBpdCBiZSB1c2VmdWwgdG8gYWxzbyBjb21wdXRlICoqY2hpbGwgaG91cnMqKj8gT3RoZXIgYWdyb2NsaW1hdGljIG1ldHJpY3M/DQoNCkRvIHlvdSBhbHdheXMgc3RhcnQgY29tcHV0aW5nIGNoaWxsIHBvcnRpb25zIG9uIFNlcHQgMT8gU2hvdWxkIHRoaXMgYmUgYSB2YXJpYWJsZT8NCg0KQWRkIGNhdmVhdHMgYWJvdXQgbm90IGxvb2tpbmcgYXQgYSBzaW5nbGUgbW9kZWwsIHNpbmdsZS15ZWFyLg0KDQpUdXJuIHRoaXMgaW50byBhIFNoaW55IGFwcCB3aXRoIHNlbGVjdGFibGUgc3RhcnQgZGF0ZSBhbmQgcmVxdWlyZWQgbnVtYmVyIG9mIGNoaWxsIHBvcnRpb25zLiANCg0KDQo=