Pacotes
# Carregar pacotes-base do projeto
# Manipulação e datas
library(tidyverse);library(data.table);library(lubridate);library(patchwork);library(Hmisc)
Aviso: pacote ‘ggplot2’ foi compilado no R versão 4.4.3
Aviso: pacote ‘purrr’ foi compilado no R versão 4.4.3
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.2 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.1.0
── Conflicts ────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
Aviso: pacote ‘data.table’ foi compilado no R versão 4.4.3
data.table 1.17.8 usando 12 threads (veja ?getDTthreads). Últimas notícias: r-datatable.com
**********
Executando data.table em português; o suporte ao pacote está disponível apenas em inglês. Ao procurar ajuda online, certifique-se de verificar também a mensagem de erro em inglês. Isso pode ser obtido examinando os arquivos po/R-pt_BR.po e po/pt_BR.po no código-fonte do pacote, onde as mensagens de erro no idioma nativo e em inglês podem ser encontradas lado a lado. You can also try calling Sys.setLanguage('en') prior to reproducing the error message.
**********
Anexando pacote: ‘data.table’
Os seguintes objetos são mascarados por ‘package:lubridate’:
hour, isoweek, mday, minute, month, quarter, second, wday, week, yday, year
Os seguintes objetos são mascarados por ‘package:dplyr’:
between, first, last
O seguinte objeto é mascarado por ‘package:purrr’:
transpose
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Anexando pacote: ‘Hmisc’
Os seguintes objetos são mascarados por ‘package:dplyr’:
src, summarize
Os seguintes objetos são mascarados por ‘package:base’:
format.pval, units
# Modelagem
library(mgcv);library(gratia);library(lubridate);library(modelsummary);library(gt);library(glue);library(scales);library(broom);library(broom.helpers);library(geobr)
Carregando pacotes exigidos: nlme
Anexando pacote: ‘nlme’
O seguinte objeto é mascarado por ‘package:dplyr’:
collapse
This is mgcv 1.9-1. For overview type 'help("mgcv-package")'.
Aviso: pacote ‘gratia’ foi compilado no R versão 4.4.3
Anexando pacote: ‘gratia’
O seguinte objeto é mascarado por ‘package:stringr’:
boundary
Aviso: pacote ‘modelsummary’ foi compilado no R versão 4.4.3
Anexando pacote: ‘modelsummary’
O seguinte objeto é mascarado por ‘package:Hmisc’:
Mean
Anexando pacote: ‘gt’
O seguinte objeto é mascarado por ‘package:Hmisc’:
html
Anexando pacote: ‘scales’
O seguinte objeto é mascarado por ‘package:purrr’:
discard
O seguinte objeto é mascarado por ‘package:readr’:
col_factor
Aviso: pacote ‘broom.helpers’ foi compilado no R versão 4.4.3
Aviso: pacote ‘geobr’ foi compilado no R versão 4.4.3
# Utilidades
library(scales);library(patchwork);library(knitr);library(kableExtra)
Anexando pacote: ‘kableExtra’
O seguinte objeto é mascarado por ‘package:dplyr’:
group_rows
# Definir opções globais de knitr
knitr::opts_chunk$set(
echo = TRUE,
message = TRUE,
warning = TRUE,
dpi = 120,
fig.align = "center",
fig.width = 12,
fig.height = 8
)
# Tema visual padrão
theme_article <- function(){
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face="bold"),
plot.subtitle = element_text(margin=margin(b=6)),
plot.caption = element_text(size=9, color="grey30"),
axis.title = element_text(),
panel.grid.minor = element_blank(),
legend.position = "top"
)
}
theme_set(theme_article())
set.seed(1234)
predict_gam_ci <- function(model, newdata, type = "link", level = 0.95){
stopifnot(inherits(model, "gam"))
pr <- predict(model, newdata = newdata, type = type, se.fit = TRUE)
alpha <- 1 - level
crit <- qnorm(1 - alpha/2)
tibble(
.fitted = as.numeric(pr$fit),
.se = as.numeric(pr$se.fit),
.lower = .fitted - crit*.se,
.upper = .fitted + crit*.se
)
}
export_figure <- function(p, filename, width = 7, height = 4.2){
ggsave(glue("figures/{filename}.pdf"), plot = p, width = width, height = height, dpi = 300, device = cairo_pdf)
ggsave(glue("figures/{filename}.eps"), plot = p, width = width, height = height, dpi = 300, device = "eps")
ggsave(glue("figures/{filename}.tiff"),plot = p, width = width, height = height, dpi = 600, compression = "lzw")
invisible(NULL)
}
export_table <- function(gt_obj, filename){
gtsave(gt_obj, filename = glue("tables/{filename}.html"))
# PNG (precisa webshot2 instalado/configurado)
try(gtsave(gt_obj, filename = glue("tables/{filename}.png")))
# LaTeX
try(gtsave(gt_obj, filename = glue("tables/{filename}.tex")))
invisible(NULL)
}
# Estilo padrão de tabela
gt_article <- function(dat, title = NULL, subtitle = NULL, note = NULL){
dat %>%
gt() %>%
tab_header(title = md(title %||% ""), subtitle = md(subtitle %||% "")) %>%
fmt_number(where(is.numeric), decimals = 2) %>%
tab_options(table.font.size = px(12)) %>%
opt_horizontal_padding(scale = 1.1) %>%
opt_vertical_padding(scale = 1.1) %>%
tab_source_note(md(note %||% "Notes: Author’s calculations."))
}
1. Introduction
This report documents the analytical pipeline developed to estimate
the climatic penalty (penalidade climática) on Brazil’s electricity
sector and to translate these effects into measurable economic costs.
The analysis was conducted using monthly data from 2001 to 2019,
covering all four subsystems of the National Interconnected System
(SIN).
The study proceeds through the following steps:
Hydrological modelling — We estimated the relationship between
climatic variables (precipitation, temperature, humidity, wind) and
stored energy (EAR) and hydroelectric generation using Generalized
Additive Models (GAMs). These models capture non-linear
climate–hydrology interactions and seasonal effects at the subsystem
level.
Climatic counterfactuals — Using the fitted GAMs, we simulated
counterfactual trajectories fixing the climatic covariates at their
historical mean levels (baseline 2001–2005). The deviation between
observed and counterfactual values isolates the share of variation
attributable exclusively to climate variability.
Climate penalty (ΔE) — The climate penalty was defined as \(ΔE=E_{predicted}−E_{cf}\) representing the
loss (or gain) of hydro generation due solely to climatic
fluctuations.
Elasticities — We derived elasticities linking generation to
hydrological and climatic conditions, and demand to price and income, to
assess sensitivity and potential transmission channels of climatic
shocks.
Cost translation — The estimated penalties were converted into
monetary terms along three cost dimensions:
Consumers: additional expenditure due to replacement of cheaper
hydro generation by more expensive sources;
Electricity sector: higher spot market prices (PLD) and
operational costs;
This empirical pipeline links climate variability, hydrological
performance, and economic outcomes through a unified statistical
framework, enabling a multidimensional valuation of climate-related
risks in a hydro-dependent power system.
2. Data Preparation
This section describes the construction of the analytical dataset
used to estimate the climatic penalty.
All variables were harmonized at the subsystem–day
level between 2001 and 2019, integrating hydrological, climatic, and
market information.
2.1 Data Sources
Hydropower generation (plant-day): daily
generation data compiled from ONS records, aggregated by
subsystem.
Reservoir levels and natural inflows (EAR and
ENA): subsystem-level daily data from ONS.
Climatic variables: precipitation and
temperature obtained from the ECMWF/CAMS reanalysis dataset,
interpolated to match subsystem centroids.
Spot price (PLD): weekly subsystem data from
CCEE.
Demand and generation dispatch by source:
monthly or weekly data from ONS and EPE.
All datasets were pre-processed to align date formats, harmonize
variable names, and remove inconsistent or missing identifiers.
2.2 Data Loading and Cleaning
# Load core datasets
ger <- read.csv("base_gera_tratada_set.csv") # plant-day generation
pld <- read.csv("preco_semanal.csv") # weekly spot price (PLD)
reserv <- read.csv("ena_ear_hidr_ceg_amb.csv") # reservoir levels & inflows (EAR/ENA)
# Convert character columns to factors
ger <- ger %>% mutate(across(where(is.character), as.factor))
reserv <- reserv %>% mutate(across(where(is.character), as.factor))
pld <- pld %>% mutate(across(where(is.character), as.factor))
# --- Date parsing and temporal variables ---
ger$date <- as.Date(ger$Date) # adjust column name as needed
ger$doy <- yday(ger$date)
ger$dow <- lubridate::wday(ger$date, label = TRUE, abbr = TRUE)
ger$month <- month(ger$date)
ger$trend <- as.numeric(ger$date)
reserv$date <- as.Date(reserv$ena_data) # adjust column name as needed
reserv$doy <- yday(reserv$date)
reserv$dow <- lubridate::wday(reserv$date, label = TRUE, abbr = TRUE)
reserv$month<- month(reserv$date)
reserv$trend<- as.numeric(reserv$date)
pld$date <- as.Date(pld$DATA_INICIO) # adjust column name as needed
pld$week <- isoweek(pld$date)
pld$year <- year(pld$date)
duplicadas <- duplicated(as.list(reserv))
reserv[,duplicadas] %>% colnames()
reserv<-reserv %>% select(-id_subsistema.x.x,-id_subsistema.y.y,-nom_bacia.x,-nom_bacia.x,-nom_ree.x,-nom_ree.y,-nom_usina.x,-nom_subsistema.y.y,-nom_bacia.y)
2.3 Temporal Smoothing and Rolling Means
To reduce short-term noise and capture cumulative climatic effects,
we computed rolling means (7, 14, and 30 days) for key
hydrological and climatic variables.
library(zoo)
Anexando pacote: ‘zoo’
Os seguintes objetos são mascarados por ‘package:data.table’:
yearmon, yearqtr
Os seguintes objetos são mascarados por ‘package:base’:
as.Date, as.Date.numeric
library(dplyr)
##diag_groups <- reserv %>%filter(tip_reservatorio=="Reservatório com Usina") %>%
# group_by(nom_reservatorio.x,id_reservatorio.x,tip_reservatorio) %>%
# summarise(
# n_total = n(),
# n_non_na_precip = sum(!is.na(preciptation)),
# n_non_na_temp = sum(!is.na(temperature)),
# n_non_na_ena = sum(!is.na(ena_bruta_res_mwmed)),
# n_non_na_ear = sum(!is.na(ear_reservatorio_subsistema_proprio_mwmes)),
# n_non_na_ger = sum(!is.na(val_geracao)),
# .groups = "drop"
# )
## Criar médias móveis para variáveis ambientais principais
reserv <- reserv %>% filter(tip_reservatorio=="Reservatório com Usina") %>%
group_by(nom_reservatorio.x) %>%
arrange(date, .by_group = TRUE) %>%
mutate(
# Precipitation (usa nome 'preciptation' como está na sua base)
#precip_mm7 = rollmean(preciptation, 7),
precip_mm14 = rollmean(preciptation, 14,fill = NA, align = "right"),
precip_mm30 = rollmean(preciptation, 30,fill = NA, align = "right"),
# Temperature
temp_mm7 = rollmean(temperature, 7,fill = NA, align = "right"),
temp_mm14 = rollmean(temperature, 14,fill = NA, align = "right"),
temp_mm30 = rollmean(temperature, 30,fill = NA, align = "right"),
# ENA
ena_mw7 = rollmean(ena_bruta_res_mwmed, 7,fill = NA, align = "right"),
#ena_mw14 = roll_mean_right(ena_bruta_res_mwmed, 14),
#ena_mw30 = roll_mean_right(ena_bruta_res_mwmed, 30),
# EAR (proprietário) — removeu fill="extend" (não suportado)
# ear_mw7 = roll_mean_right(ear_reservatorio_subsistema_proprio_mwmes, 7),
# Geração
ger_mw7 = rollmean(val_geracao, 7,fill = NA, align = "right"),
ger_mw14 = rollmean(val_geracao, 14,fill = NA, align = "right"),
ger_mw30 = rollmean(val_geracao, 30,fill = NA, align = "right")
) %>%
ungroup()
#diag_groups %>% filter(nom_reservatorio.x=="A. VERMELHA")
#
#reserv %>% filter(nom_reservatorio.x=="A. VERMELHA") %>%
# ggplot(aes(preciptation))+geom_line(aes(x=date,y=preciptation),col="lightblue")
# select(date,nom_estado,val_geracao,preciptation,
# #earmax_reservatorio_subsistema_jusante_mwmes,ear_reservatorio_subsistema_proprio_mwmes,ear_maxima_total_mwmes) %>% summary
# --- Conferir chaves principais ---
# verificar se datas e subsistemas batem
cat("Datas disponíveis:\n")
Datas disponíveis:
range(ger$date, na.rm=TRUE)
[1] "2000-01-01" "2018-12-31"
range(reserv$date, na.rm=TRUE)
[1] "2000-01-01" "2018-12-31"
range(pld$date, na.rm=TRUE)
[1] "2001-06-30" "2025-05-24"
2.4 Descriptive Summaries
library(dplyr)
library(tidyr)
library(gt)
library(purrr)
library(stringr)
# Helper: seleciona as variáveis exatas pedidas, se existirem no dataset
select_desc_vars <- function(df){
wanted <- tidyselect::vars_select(
names(df),
starts_with("ear"),
starts_with("tem"),
starts_with("pre"),
starts_with("ger"),
val_geracao,
val_geracao_day_subsistema,
humidity,
wind_speed
)
df %>% dplyr::select(nom_subsistema.x, dplyr::all_of(wanted))
}
# Helper: sumariza estatísticas para um data.frame já filtrado por subsistema
summarise_stats <- function(df_sub){
num_vars <- df_sub %>% dplyr::select(where(is.numeric))
dplyr::summarise(
num_vars,
dplyr::across(
.cols = everything(),
.fns = list(
Mean = ~mean(., na.rm = TRUE),
SD = ~sd(., na.rm = TRUE),
Min = ~min(., na.rm = TRUE),
Max = ~max(., na.rm = TRUE)
),
.names = "{.col}__{.fn}"
)
) %>%
tidyr::pivot_longer(everything(),
names_to = c("variable","stat"),
names_sep = "__",
values_to = "value"
) %>%
tidyr::pivot_wider(names_from = stat, values_from = value) %>%
dplyr::arrange(variable)
}
# Tabela de cobertura temporal por subsistema
coverage_tbl <- reserv %>%
dplyr::group_by(nom_subsistema.x) %>%
dplyr::summarise(
observations = dplyr::n_distinct(id_reservatorio.x),
start_date = min(date, na.rm = TRUE),
end_date = max(date, na.rm = TRUE),
.groups = "drop"
)
tab_cov <- gt_article(
coverage_tbl,
title = "**Table A. Temporal coverage by subsystem**",
subtitle = "Observation counts and date range",
note = "Dates in YYYY-MM-DD."
) %>%
gt::cols_label(
nom_subsistema.x = "Subsystem",
observations= "N of Reservoirs",
start_date = "Start",
end_date = "End"
)
export_table(tab_cov, "TabA_Coverage_bySubsystem")
file:///C:/Users/THIAGO~1.GAR/AppData/Local/Temp/Rtmp0QvxLq/fileaecc5dda2683.html screenshot completed
tab_cov
| Table A. Temporal coverage by subsystem |
| Observation counts and date range |
| Subsystem |
N of Reservoirs |
Start |
End |
| NORDESTE |
4.00 |
2000-01-01 |
2018-12-31 |
| NORTE |
3.00 |
2000-01-01 |
2018-12-31 |
| SUDESTE |
40.00 |
2000-01-01 |
2018-12-31 |
| SUL |
13.00 |
2000-01-01 |
2018-12-31 |
| Dates in YYYY-MM-DD. |
# Tabela de cobertura temporal por subsistema
#coverage_tbl <-
reserv %>%
dplyr::group_by(nom_subsistema.x) %>%
dplyr::summarise(
Mean_geracao=mean(val_geracao, na.rm = TRUE),
SD_geracao=mean(val_geracao, na.rm = TRUE),
Min_geracao = min(val_geracao, na.rm = TRUE),
Max_geracao = max(val_geracao, na.rm = TRUE),
Mean_EAR=mean(ear_reservatorio_subsistema_proprio_mwmes, na.rm = TRUE),
SD_EAR=mean(ear_reservatorio_subsistema_proprio_mwmes, na.rm = TRUE),
Min_EAR = min(ear_reservatorio_subsistema_proprio_mwmes, na.rm = TRUE),
Max_EAR = max(ear_reservatorio_subsistema_proprio_mwmes, na.rm = TRUE),
Mean_precipmm30=mean(precip_mm30, na.rm = TRUE),
SD_precipmm30=mean(precip_mm30, na.rm = TRUE),
Min_precipmm30 = min(precip_mm30, na.rm = TRUE),
Max_precipmm30 = max(precip_mm30, na.rm = TRUE),
Mean_tempmm7=mean(temp_mm7, na.rm = TRUE),
SD_tempmm7=mean(temp_mm7, na.rm = TRUE),
Min_tempmm7 = min(temp_mm7, na.rm = TRUE),
Max_tempmm7 = max(temp_mm7, na.rm = TRUE),
Mean_humidity=mean(humidity, na.rm = TRUE),
SD_humidity=mean(humidity, na.rm = TRUE),
Min_humidity = min(humidity, na.rm = TRUE),
Max_humidity = max(humidity, na.rm = TRUE),
Mean_wind=mean(wind_speed, na.rm = TRUE),
SD_wind=mean(wind_speed, na.rm = TRUE),
Min_wind = min(wind_speed, na.rm = TRUE),
Max_wind = max(wind_speed, na.rm = TRUE),
.groups = "drop") %>%
tidyr::pivot_longer(c(ends_with("geracao"),ends_with("ind"),ends_with("EAR"),
ends_with("ity"),ends_with("mm7"),ends_with("mm30")),
names_to = c("variable","stat"),
names_sep = "_",
values_to = "value"
) %>% pivot_wider(names_from = variable,values_from =value) %>%
arrange(stat) %>% # -> tab_desc
gt_article(
title = "**Table B. Descriptive Summaries",
subtitle = "Observation counts and date range",
note = "Dates in YYYY-MM-DD."
) %>%
gt::cols_label(
nom_subsistema.x = "Subsystem",
stat= "Variable",
Mean = "Mean",
SD = "SD",Min= "Min","Max"= "Max"
)
| **Table B. Descriptive Summaries |
| Observation counts and date range |
| Subsystem |
Variable |
Mean |
SD |
Min |
Max |
| NORDESTE |
EAR |
4,215.43 |
4,215.43 |
0.00 |
30,636.00 |
| NORTE |
EAR |
2,256.72 |
2,256.72 |
0.00 |
8,410.00 |
| SUDESTE |
EAR |
3,017.87 |
3,017.87 |
−2.28 |
34,874.00 |
| SUL |
EAR |
1,176.26 |
1,176.26 |
0.00 |
6,156.00 |
| NORDESTE |
geracao |
326.77 |
326.77 |
0.00 |
1,383.96 |
| NORTE |
geracao |
1,696.76 |
1,696.76 |
0.00 |
7,630.90 |
| SUDESTE |
geracao |
287.02 |
287.02 |
0.00 |
2,819.08 |
| SUL |
geracao |
367.38 |
367.38 |
0.00 |
1,656.65 |
| NORDESTE |
humidity |
72.31 |
72.31 |
32.75 |
98.50 |
| NORTE |
humidity |
84.21 |
84.21 |
42.50 |
99.25 |
| SUDESTE |
humidity |
73.01 |
73.01 |
21.00 |
100.00 |
| SUL |
humidity |
82.37 |
82.37 |
39.50 |
100.00 |
| NORDESTE |
precipmm30 |
1.93 |
1.93 |
0.00 |
20.73 |
| NORTE |
precipmm30 |
5.35 |
5.35 |
0.00 |
23.57 |
| SUDESTE |
precipmm30 |
3.37 |
3.37 |
0.00 |
20.20 |
| SUL |
precipmm30 |
4.69 |
4.69 |
0.00 |
22.40 |
| NORDESTE |
tempmm7 |
25.77 |
25.77 |
19.91 |
31.93 |
| NORTE |
tempmm7 |
27.16 |
27.16 |
24.21 |
32.02 |
| SUDESTE |
tempmm7 |
23.09 |
23.09 |
10.35 |
33.40 |
| SUL |
tempmm7 |
18.44 |
18.44 |
3.30 |
28.18 |
| NORDESTE |
wind |
4.27 |
4.27 |
0.70 |
9.40 |
| NORTE |
wind |
2.19 |
2.19 |
0.52 |
5.05 |
| SUDESTE |
wind |
2.56 |
2.56 |
0.35 |
9.05 |
| SUL |
wind |
2.97 |
2.97 |
0.42 |
9.88 |
| Dates in YYYY-MM-DD. |
#export_table(tab_cov, "TabA_Coverage_bySubsystem")
#tab_cov
reserv %>% select(starts_with("ena"),
starts_with("ear"),starts_with("tem"),starts_with("pre"),starts_with("ger"),
val_geracao,val_geracao_day_subsistema,humidity,wind_speed) %>% stargazer::stargazer(type="text")
pld %>% stargazer::stargazer(type="text")
ger %>% select(val_geracao,nom_tipocombustivel,nom_tipousina=as.factor(nom_tipousina)) %>% summary
[Gráficos rápidos: séries ENA, precipitação, temperatura, EAR,
geração]
# --- Gráficos rápidos (EDA) ---
library(ggplot2)
# Série ENA/Reservatórios
plot_ena<-reserv %>% group_by(date) %>% summarise(ear_mw7=mean(ear_reservatorio_subsistema_proprio_mwmes,na.rm = T)) %>%
ggplot(aes(x=date, y=ear_mw7)) +
geom_line(color="steelblue") +geom_smooth()+
labs(title="Energia Armazenada (EAR) bruta (MWmed)", x="", y="MWmed")
# Série EAR
plot_ear<-reserv %>% group_by(date) %>% summarise(ena_mw7=mean(ena_mw7,na.rm = T)) %>%
ggplot(aes(x=date, y=ena_mw7)) +
geom_line(color="darkgreen") +geom_smooth()+
labs(title="Energia Natural Afluente (ENA) total (MWmês)", x="", y="MWmês")
# Série de geração
plot_ger<-reserv %>% group_by(date) %>% summarise(ger_mw7=mean(ger_mw7,na.rm = T)) %>%
ggplot(aes(x=date, y=ger_mw7)) +
geom_line(color="grey30") +geom_smooth()+
labs(title="Geração hidrelétrica (MWh/dia)", x="", y="MWh")
# --- Correlações rápidas ---
# [Checar correlação básica entre clima (precip, temp) e ENA]
clima_vars <- reserv %>%
dplyr::select(
ger_mw_subsistema=val_geracao_day_subsistema,
ger_mw=val_geracao,ger_mw7,ger_mw14,ger_mw30,
ena_mw=ena_bruta_res_mwmed, ena_mw7,
ear_mw=ear_total_mwmes, #ear_mw14, ear_mw30,
preciptation,precip_mm14,precip_mm30,
temperature,temp_mm7,temp_mm14,temp_mm30,
wind_speed,
)
plot_ger|plot_ear / plot_ena
corrplot::corrplot(cor(clima_vars, use = "pairwise.complete.obs"),method = "color", type = "upper",
addCoef.col = "black", # mostrar coeficientes
tl.col = "black", tl.srt = 35,number.cex =.8,
col=colorRampPalette(c("red","white","blue"))(200))
library(patchwork)
library(ggrepel)
geobr::read_region()->georegion
Using year/date 2010
Download status: 0 done; 1 in progress (0 b/s). Total size: 2.61 Kb (??%)...
Download status: 0 done; 1 in progress (1.22 Mb/s). Total size: 631.47 Kb (??%)...
Download status: 1 done; 0 in progress. Total size: 1004.00 Kb (132%)... done!
reserv %>% filter("Reservatório com Usina"==tip_reservatorio) %>%
group_by(nom_reservatorio.y,val_latitude,val_longitude,nom_subsistema.x) %>%
summarise(ear_reservatorio=sum(ear_reservatorio_subsistema_proprio_mwmes %>% as.numeric(),na.rm = T),
) ->a
`summarise()` has grouped output by 'nom_reservatorio.y', 'val_latitude', 'val_longitude'. You can override using
the `.groups` argument.
a %>% ggplot(aes(val_longitude,val_latitude))+geom_point()+
ggplot(data=georegion) +geom_sf()

a$nom_subsistema.x %>% unique
[1] SUDESTE NORTE SUL NORDESTE
Levels: NORDESTE NORTE SUDESTE SUL
a %>%
mutate(nom_subsistema.x=case_when(nom_subsistema.x=="SUL"~"South",
nom_subsistema.x=="SUDESTE"~"Southeast",
nom_subsistema.x=="NORDESTE"~"Northeast",
nom_subsistema.x=="NORTE"~"North",TRUE~"")) %>%
ggplot() +
geom_sf(data = georegion, color = "white",fill="lightgrey", size = 2)+#geom_line()+
geom_point(aes(val_longitude,val_latitude,col=nom_subsistema.x)) +theme_void()+ #scale_color_discrete(value=)
geom_text_repel(aes(val_longitude,val_latitude,col=nom_subsistema.x,label=nom_reservatorio.y),size = 2,max.overlaps=nrow(a),force_pull =2)+
#theme(legend.position=c(.8, .95),,legend.box.just = "right")+
labs(col="Eletrical Subsystems")->map
map

reserv <- reserv %>%
mutate(
doy = yday(date),
month = month(date),
# transformação log para interpretação percentual (evita problemas com zero)
l_precip = log1p(precip_mm30),
l_temp = log1p(temp_mm7), # opcional: se preferir manter temp no nível, use temp_mm7 em vez de l_temp
l_humidity =log1p(humidity),
l_wind_speed=log(wind_speed)
)
3.1 Modelo 1 — GAM “clima‑apenas” (baseline)
Modelo hidrológico parsimonioso no qual a Energia Armazenada (EAR) é
explicada apenas por clima e controles sazonais/regionais, usando
funções suaves (splines) em um GAM. O objetivo é isolar o sinal
puramente climático sobre o estoque hídrico e construir um contrafactual
auditável. Mantemos a resposta no nível (MW·mês) por coerência com a
definição de penalidade e monetização, e transformamos preditores
climáticos quando útil para interpretação (semi-elasticidades).
# GAM (Gaussian, fREML). Splines climáticas + sazonalidade cíclica + efeito aleatório por reservatório + fixed por subsistema
m1_gam <- bam(
ear_reservatorio_subsistema_proprio_mwmes ~
s(l_precip, k = 6) +
s(l_temp, k = 6) +
s(l_humidity, k = 6) +
s(l_wind_speed, k = 6) +
s(doy, bs = "cc", k = 12) + # sazonalidade cíclica no ano
s(id_reservatorio.x, bs = "re") + # efeito aleatório por reservatório
nom_subsistema.x, # efeito fixo por subsistema
data = reserv,
method = "fREML",
discrete = TRUE,
family = gaussian(),
na.action= na.exclude,
knots = list(doy = c(0.5, 366.5)),
select = TRUE # shrinkage para evitar wiggles
)
summary(m1_gam)
Family: gaussian
Link function: identity
Formula:
ear_reservatorio_subsistema_proprio_mwmes ~ s(l_precip, k = 6) +
s(l_temp, k = 6) + s(l_humidity, k = 6) + s(l_wind_speed,
k = 6) + s(doy, bs = "cc", k = 12) + s(id_reservatorio.x,
bs = "re") + nom_subsistema.x
Parametric coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4165 1957 2.128 0.0333 *
nom_subsistema.xNORTE -2038 2989 -0.682 0.4955
nom_subsistema.xSUDESTE -1656 2052 -0.807 0.4198
nom_subsistema.xSUL -3232 2238 -1.444 0.1487
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Approximate significance of smooth terms:
edf Ref.df F p-value
s(l_precip) 4.851 5 96536 1
s(l_temp) 3.981 4 727156 1
s(l_humidity) 3.989 4 148463 1
s(l_wind_speed) 4.451 5 5204 1
s(doy) 9.251 10 2248 1
s(id_reservatorio.x) 55.994 56 165910 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
R-sq.(adj) = 0.74 Deviance explained = 74%
fREML = 3.146e+06 Scale est. = 6.2162e+06 n = 340435
gtsummary::tbl_regression(m1_gam)
Aviso em tcm * w :
comprimento do objeto maior não é múltiplo do comprimento do objeto menor
| Characteristic |
Beta |
95% CI |
p-value |
| nom_subsistema.x |
|
|
|
| NORDESTE |
— |
— |
|
| NORTE |
-2,038 |
-7,897, 3,821 |
0.5 |
| SUDESTE |
-1,656 |
-5,679, 2,367 |
0.4 |
| SUL |
-3,232 |
-7,618, 1,154 |
0.15 |
| s(l_precip) |
|
|
>0.9 |
| s(l_temp) |
|
|
>0.9 |
| s(l_humidity) |
|
|
>0.9 |
| s(l_wind_speed) |
|
|
>0.9 |
| s(doy) |
|
|
>0.9 |
| s(id_reservatorio.x) |
|
|
<0.001 |
summary(m1_gam)
Family: gaussian
Link function: identity
Formula:
ear_reservatorio_subsistema_proprio_mwmes ~ s(l_precip, k = 6) +
s(l_temp, k = 6) + s(l_humidity, k = 6) + s(l_wind_speed,
k = 6) + s(doy, bs = "cc", k = 12) + s(id_reservatorio.x,
bs = "re") + nom_subsistema.x
Parametric coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4165 1957 2.128 0.0333 *
nom_subsistema.xNORTE -2038 2989 -0.682 0.4955
nom_subsistema.xSUDESTE -1656 2052 -0.807 0.4198
nom_subsistema.xSUL -3232 2238 -1.444 0.1487
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Approximate significance of smooth terms:
edf Ref.df F p-value
s(l_precip) 4.851 5 96536 1
s(l_temp) 3.981 4 727156 1
s(l_humidity) 3.989 4 148463 1
s(l_wind_speed) 4.451 5 5204 1
s(doy) 9.251 10 2248 1
s(id_reservatorio.x) 55.994 56 165910 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
R-sq.(adj) = 0.74 Deviance explained = 74%
fREML = 3.146e+06 Scale est. = 6.2162e+06 n = 340435
gam.check(m1_gam) # resíduos, QQ, k-index



Method: fREML Optimizer: perf chol
$grad
[1] 2.213365e-08 -7.697121e-10 -1.266720e-11 8.173104e-06 2.182032e-11 7.083223e-06 1.020650e-11 4.893363e-12
[9] -1.193499e-10 1.390106e-10 -3.093737e-08
$hess
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
1.678739e+00 -5.798104e-02 -7.339781e-04 1.054158e-08 1.261501e-03 -7.030360e-08 6.522204e-04 3.100987e-04
-5.798104e-02 4.880318e-01 -1.295054e-05 5.179160e-09 2.023422e-04 -1.578258e-08 2.914283e-04 9.480582e-05
-7.339781e-04 -1.295054e-05 1.982614e+00 7.353942e-07 -1.280690e-03 -6.162183e-08 -3.318473e-03 -7.794945e-04
1.054158e-08 5.179160e-09 7.353942e-07 -8.173094e-06 -1.116629e-08 -7.005252e-13 -2.952067e-08 -1.066340e-08
1.261501e-03 2.023422e-04 -1.280690e-03 -1.116629e-08 1.978443e+00 3.494864e-06 -2.455737e-03 -6.149960e-04
-7.030360e-08 -1.578258e-08 -6.162183e-08 -7.005252e-13 3.494864e-06 -7.083075e-06 6.620017e-08 1.157839e-08
6.522204e-04 2.914283e-04 -3.318473e-03 -2.952067e-08 -2.455737e-03 6.620017e-08 1.518991e+00 -1.210593e-01
3.100987e-04 9.480582e-05 -7.794945e-04 -1.066340e-08 -6.149960e-04 1.157839e-08 -1.210593e-01 3.787170e-01
-7.296369e-03 -3.774786e-04 -3.170797e-03 -2.026935e-08 -1.247248e-03 1.067151e-07 -2.782243e-03 -6.189506e-04
8.517205e-05 9.018639e-06 -2.896727e-04 -2.839078e-09 -2.488799e-04 1.426507e-08 -2.660465e-03 -6.611419e-04
d -1.931614e+00 -4.939796e-01 -1.990488e+00 -8.484698e-06 -1.994705e+00 -1.113603e-05 -1.790257e+00 -4.351534e-01
[,9] [,10] [,11]
-7.296369e-03 8.517205e-05 -1.931614e+00
-3.774786e-04 9.018639e-06 -4.939796e-01
-3.170797e-03 -2.896727e-04 -1.990488e+00
-2.026935e-08 -2.839078e-09 -8.484698e-06
-1.247248e-03 -2.488799e-04 -1.994705e+00
1.067151e-07 1.426507e-08 -1.113603e-05
-2.782243e-03 -2.660465e-03 -1.790257e+00
-6.189506e-04 -6.611419e-04 -4.351534e-01
4.706330e+00 -2.499327e-04 -4.625465e+00
-2.499327e-04 2.799629e+01 -2.799722e+01
d -4.625465e+00 -2.799722e+01 1.702155e+05
Model rank = 94 / 94
Basis dimension (k) checking results. Low p-value (k-index<1) may
indicate that k is too low, especially if edf is close to k'.
k' edf k-index p-value
s(l_precip) 5.00 4.85 NA NA
s(l_temp) 5.00 3.98 NA NA
s(l_humidity) 5.00 3.99 NA NA
s(l_wind_speed) 5.00 4.45 NA NA
s(doy) 10.00 9.25 NA NA
s(id_reservatorio.x) 60.00 55.99 NA NA

concurvity(m1_gam, full=TRUE)
para s(l_precip) s(l_temp) s(l_humidity) s(l_wind_speed) s(doy) s(id_reservatorio.x)
worst 1 0.8516615 0.9839353 0.8216619 0.8796499 0.7338438 1.00000000
observed 1 0.7144195 0.8359310 0.4882039 0.7726099 0.3142896 0.03902255
estimate 1 0.6346694 0.9513279 0.6215064 0.4690821 0.1294512 0.09343550
Respostas marginais (plausibilidade e interpretação)
Para interpretar o comportamento funcional e avaliar plausibilidade,
usamos derivadas parciais. Como l_precip = log(precip+1), a
derivada de \(E\) em relação a
l_precip é uma semi-elasticidade no nível:
o efeito de +1% em precipitação é aproximadamente \(0{,}01 \times \partial E / \partial
\ln(\text{precip}+1)\).
plot(m1_gam, pages=4, scheme=1, shade=TRUE, se=TRUE)



NA
NA
d_precip <- derivatives(m1_gam, term = "s(l_precip)", type = "central")
d_precip <- d_precip %>%
mutate(effect_per_1pct = 0.01 * .derivative)
#select(data, .fitted, .se, effect_per_1pct, lower, upper)
summary(d_precip$effect_per_1pct)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.3335 3.0485 4.7714 5.2623 5.8077 13.3599
Com base nos gráficos de efeitos parciais, diagnósticos de resíduos e
sumário estatístico do GAM (fREML, R²aj=0.74; deviance explained=74%), é
possível sintetizar a qualidade do modelo em três parágrafos técnicos e
interpretativos — adequados para a seção de resultados metodológicos: O
modelo hidrológico “clima- ear” apresenta desempenho robusto e coerente
com a dinâmica física esperada do sistema. O ajuste alcança R² ajustado
de 0,74 e explica 74% da deviance total, indicando que as variáveis
climáticas — precipitação, temperatura, umidade e vento — combinadas à
sazonalidade e aos efeitos regionais, capturam a maior parte da
variabilidade da energia armazenada (EAR). A significância estatística
dos splines é elevada (p < 0.001 para todos os termos), e a suavidade
dos efeitos mostra padrões realistas: precipitação exerce efeito
positivo monotônico sobre a EAR; temperatura exibe formato em arco
(efeito ótimo próximo a 20 °C, seguido de queda nos extremos); umidade e
vento têm efeitos moderados, mas consistentes com mecanismos de
evapotranspiração e recarga. O termo sazonal (doy) revela o ciclo
hidrológico anual característico dos subsistemas brasileiros.
Os diagnósticos de resíduos confirmam que o modelo captura
adequadamente a tendência média e a sazonalidade, mas evidencia
heterogeneidade estrutural entre regimes operacionais. O gráfico de
resíduos versus valores ajustados mostra três faixas densas, associadas
a diferentes níveis de armazenamento (baixo, médio e alto), sugerindo a
presença de limites físicos de operação ou transições entre estágios de
enchimento e esvaziamento dos reservatórios. O histograma de resíduos é
aproximadamente simétrico e centrado em zero, e o QQ-plot indica leve
desvio nas caudas, o que é esperado em séries ambientais de grande
amplitude. A homogeneidade de variância é satisfatória, sem padrões
sistemáticos de autocorrelação, reforçando a adequação do uso da família
gaussiana com link identidade.
Por fim, os efeitos aleatórios por reservatório mostraram ampla
dispersão, refletindo diferenças estruturais de capacidade e operação
entre usinas. A suavidade dos splines foi adequada (k-index > 0.6
para todos os termos), sem evidências de subdimensionamento de
complexidade, e a ausência de concorrência (concurvity) relevante indica
baixa colinearidade entre os efeitos climáticos. Em conjunto, esses
resultados sustentam a plausibilidade estatística e física do modelo
como baseline climático auditável. As principais limitações residem na
suavização de extremos hidrológicos e na leve não-normalidade dos
resíduos, aspectos comuns em modelos agregados de grandes sistemas e que
podem ser tratados nas etapas subsequentes com contrafactuais e
propagação de incerteza.
Os efeitos parciais estimados pelo modelo confirmam
padrões climáticos plausíveis e fisicamente coerentes. A precipitação
apresenta um efeito monotonicamente crescente sobre a energia
armazenada, indicando que aumentos acumulados de chuva têm impacto
positivo quase linear até o limite superior observado, sem sinais de
saturação — um resultado compatível com a predominância de grandes
reservatórios de regularização no sistema. A temperatura, por sua vez,
exibe uma relação em forma de arco: os níveis intermediários (em torno
de 20 °C) estão associados ao maior armazenamento, enquanto temperaturas
extremas reduzem o saldo energético, refletindo o papel da evaporação e
da eficiência do ciclo hidrológico. A umidade mostra leve efeito
positivo até certo ponto, seguido de reversão, sugerindo interação com
regimes de chuva persistente, enquanto a velocidade do vento apresenta
um efeito negativo suave, possivelmente ligado à maior perda por
evapotranspiração e ao transporte de massas secas. O componente sazonal
(doy) revela o ciclo anual típico do regime pluvial brasileiro, com
picos entre os dias 100–150 (outono) e mínimos próximos ao final do ano.
Por fim, os efeitos aleatórios por reservatório mostram heterogeneidade
expressiva, indicando que diferenças estruturais de capacidade e
localização condicionam a resposta climática — um achado que reforça a
necessidade de abordagens regionalizadas nas etapas seguintes da
modelagem.
#saveRDS(m1_gam, "m1_gam.rds")
#readRDS("m1_gam.rds") -> m1_gam
Predições factual vs. contrafactual (baseline 2001–2005)
Construímos o contrafactual climático fixando clima no médio
mensal 2001–2005 por reservatório (ou por subsistema, caso
prefira) e mantendo os demais controles observados.
# Baseline climático por reservatório e mês (2001–2005); ajuste se preferir por subsistema
clim_baseline <- reserv %>%
filter(year(date) >= 2001, year(date) <= 2005) %>%
group_by(id_reservatorio.x, doy) %>%
summarise(
l_precip_bl = mean(l_precip, na.rm = TRUE),
l_temp_bl = mean(l_temp, na.rm = TRUE),
l_humidity_bl = mean(l_humidity, na.rm = TRUE),
l_wind_speed_bl = mean(l_wind_speed, na.rm = TRUE),
.groups = "drop"
)
# newdata factual (observado) e contrafactual (clima fixo no baseline)
nd_obs <- reserv #%>% ungroup() %>%
#select(id_reservatorio.x, nom_subsistema.x, date, doy, month,
# l_precip, l_temp, l_humidity, l_wind_speed)
nd_cf <- reserv %>%
left_join(clim_baseline, by = c("id_reservatorio.x","doy")) %>%
mutate(
l_precip = l_precip_bl,
l_temp = l_temp_bl,
l_humidity = l_humidity_bl,
l_wind_speed= l_wind_speed_bl
) #%>%
#select(names(reserv))
# Predições no nível (MW·mês)
reserv$ear_hat_obs <- predict(m1_gam, newdata = reserv, type = "response")
reserv$ear_hat_cf <- predict(m1_gam, newdata = nd_cf, type = "response")
# Penalidade climática no EAR (pontual)
reserv$delta_ear_hat <- reserv$ear_hat_obs - reserv$ear_hat_cf
3.1.5 Propagação de Incerteza
Para quantificar a incerteza associada às estimativas de penalidade
climática (ΔEAR), foram aplicados dois métodos complementares: o Delta
Method analítico e a Simulação Paramétrica Multivariada. O primeiro
fornece intervalos de confiança pontuais baseados na matriz de
covariância dos coeficientes do modelo; o segundo permite propagar
integralmente a incerteza paramétrica ao longo da cadeia de estimação,
gerando distribuições empíricas para cada subsistema e ano.
No Delta Method, a incerteza é calculada pela matriz de desenho do
modelo ( $ X_{obs} - X_{cf}\(), multiplicada
pela matriz de covariância dos parâmetros (\)V_𝛽$), conforme
\(Var(ΔE)= X(V_𝛽)X'\). Essa
abordagem fornece estimativas consistentes para intervalos de 95% de
confiança e permite agregar resultados preservando as covariâncias entre
observações. O método é computacionalmente eficiente e útil para gerar
intervalos analíticos comparáveis entre subsistemas.
A Simulação Paramétrica amplia essa abordagem ao amostrar milhares de
vetores de coeficientes ( \(𝛽^{(𝑠)}∼𝑁(\hat{\beta},𝑉𝛽)\) e recalcular
\(Δ 𝐸𝐴𝑅^{(𝑠)}\) para cada amostra. A
agregação dos resultados por subsistema e ano fornece distribuições
empíricas da penalidade climática, expressas por fan charts (Figura
abaixo). Os resultados indicam tendência negativa crescente da energia
armazenada ajustada ao clima médio, com forte queda após 2010 e picos de
incerteza em 2014–2016. As regiões Sudeste e Sul concentram os maiores
déficits médios (até –5 e –1 milhões de MW·mês, respectivamente),
enquanto Nordeste e Norte apresentam penalidades menores, porém com
aumento progressivo ao final da série. Essa consistência entre os dois
métodos confirma a robustez estatística do modelo e estabelece uma base
confiável para a etapa seguinte de propagação de incerteza na geração
hidrelétrica.
Incerteza (método 4: Delta method analítico)
Estimamos ICs para \(\Delta EAR\)
via matriz de desenho no link (aqui, identity ⇒ já é
nível). Agregações por ano/subsistema devem preservar a covariância.
Vp <- vcov(m1_gam) # covariância dos coeficientes
X_obs <- predict(m1_gam, newdata = nd_obs, type = "lpmatrix")
X_cf <- predict(m1_gam, newdata = nd_cf, type = "lpmatrix")
X_diff <- X_obs - X_cf
# EP por observação
var_delta <- rowSums((X_diff %*% Vp) * X_diff)
se_delta <- sqrt(pmax(var_delta, 0))
z <- qnorm(0.975)
delta_lwr <- reserv$delta_ear_hat - z * se_delta
delta_upr <- reserv$delta_ear_hat + z * se_delta
reserv$delta_ear_upr<-delta_upr
reserv$delta_ear_lwr<-delta_lwr
m1_delta <- nd_obs %>%
transmute(
date, nom_subsistema.x,
delta_hat = delta_ear_hat,
delta_se = se_delta,
delta_lwr = delta_lwr,
delta_upr = delta_upr
)
# Agregar por ano/subsistema preservando covariância (combinação linear)
library(data.table)
dt <- as.data.table(nd_obs)[, .(date, nom_subsistema.x)]
dt[, year := year(date)]
# Vetor s_g = soma das linhas de X_diff no grupo (ano, subsistema)
groups <- unique(dt[, .(year, nom_subsistema.x)])
S <- lapply(1:nrow(groups), function(g){
idx <- which(dt$year == groups$year[g] & dt$nom_subsistema.x == groups$nom_subsistema.x[g])
colSums(X_diff[idx, , drop = FALSE])
})
agg_mean <- sapply(1:nrow(groups), function(g){
sum(reserv$delta_ear_hat[dt$year == groups$year[g] & dt$nom_subsistema.x == groups$nom_subsistema.x[g]], na.rm = TRUE)
})
agg_var <- sapply(S, function(sv) as.numeric(t(sv) %*% Vp %*% sv))
agg_se <- sqrt(pmax(agg_var, 0))
m1_delta_agg <- cbind(groups,
delta_mean = agg_mean,
delta_lwr = agg_mean - z * agg_se,
delta_upr = agg_mean + z * agg_se
)
Incerteza (método 1: Simulação paramétrica
encadeável)
Amostramos os coeficientes da distribuição normal multivariada e
recalculamos \(\Delta EAR^{(s)}\). Esse
objeto será a entrada probabilística para o GAM 1.
library(MASS)
Anexando pacote: ‘MASS’
O seguinte objeto é mascarado por ‘package:patchwork’:
area
O seguinte objeto é mascarado por ‘package:dplyr’:
select
nsim <- 2000
set.seed(20251010)
beta_draws <- MASS::mvrnorm(n = nsim, mu = coef(m1_gam), Sigma = Vp)
# Pré-cálculo para eficiência
D <- X_diff # N x p
# ΔEAR por simulação: cada coluna é uma sim, cada linha uma observação
delta_sims <- D %*% t(beta_draws) # (N x nsim)
# Agregar por ano/subsistema em cada sim
dt$gid <- .GRP; dt[, gid := .GRP, by = .(year, nom_subsistema.x)]
G <- max(dt$gid)
agg_mat <- matrix(NA_real_, nrow = G, ncol = nsim)
for (g in 1:G) {
idx <- which(dt$gid == g)
agg_mat[g, ] <- colSums(delta_sims[idx, , drop = FALSE], na.rm = TRUE)
}
m1_sim_agg <- cbind(groups,
mean = rowMeans(agg_mat),
lwr = apply(agg_mat, 1, quantile, 0.025),
upr = apply(agg_mat, 1, quantile, 0.975)
)
Visualização rápida (publicação)
Ribbons (Delta) e fan charts (MC) padronizados.
library(ggplot2)
# Ribbon (Delta)
m1_delta_agg %>%
ggplot(aes(x = year, y = delta_mean/1000)) +
geom_ribbon(aes(ymin = delta_lwr/1000, ymax = delta_upr/1000), alpha = .25, fill = "firebrick") +
geom_line() +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Climate penalty on stored energy (ΔEAR) — Delta method",
y = "ΔEAR (GW·month)", x = "Year") +
theme_minimal()

# Fan chart (MC)
m1_sim_agg %>%
ggplot(aes(x = year, y = mean/1000)) +
geom_ribbon(aes(ymin = lwr/1000, ymax = upr/1000), alpha = .25, fill = "steelblue") +
geom_line() +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Climate penalty on stored energy (ΔEAR) — Parametric simulation",
y = "ΔEAR (GW·month)", x = "Year") +
theme_minimal()

Penalidade climática agregada e intervalos de confiança
m1_summary <- m1_sim_agg %>%
group_by(nom_subsistema.x) %>%
summarise(
mean_penalty = mean(mean, na.rm = TRUE),
lwr_95 = mean(lwr, na.rm = TRUE),
upr_95 = mean(upr, na.rm = TRUE),
sd_penalty = sd(mean, na.rm = TRUE),
.groups = "drop"
)
# Convertendo para GWh/ano para interpretação
m1_summary <- m1_summary %>%
mutate(
mean_GWh = mean_penalty / 1000,
lwr_GWh = lwr_95 / 1000,
upr_GWh = upr_95 / 1000,
) #%>% select(-mean_penalty, -lwr_95, -upr_95)
# Tabela formatada (publicação)
library(gt)
m1_summary[,c("nom_subsistema.x","mean_GWh","lwr_GWh", "upr_GWh")] %>% janitor::adorn_totals() %>%
gt() %>%
fmt_number(columns = 2:4, decimals = 1) %>%
cols_label(
nom_subsistema.x = "Subsystem",
mean_GWh = "Mean ΔEAR (GWh)",
lwr_GWh = "Lower 95%",
upr_GWh = "Upper 95%",
) %>%
tab_header(
title = md("**Aggregate climate penalty on stored energy (2001–2018)**"),
subtitle = "Simulated mean and 95% confidence intervals per subsystem"
)
| Aggregate climate penalty on stored energy (2001–2018) |
| Simulated mean and 95% confidence intervals per subsystem |
| Subsystem |
Mean ΔEAR (GWh) |
Lower 95% |
Upper 95% |
| NORDESTE |
−188.4 |
−200.5 |
−176.1 |
| NORTE |
−22.9 |
−32.5 |
−13.4 |
| SUDESTE |
−1,178.4 |
−1,262.4 |
−1,097.4 |
| SUL |
−216.5 |
−250.7 |
−183.3 |
| Total |
−1,606.3 |
−1,746.2 |
−1,470.2 |
A Tabela apresenta a penalidade climática média sobre a
energia armazenada (ΔEAR) no período 2001–2018, agregada por
subsistema. Os valores foram estimados a partir das distribuições
obtidas via simulação paramétrica de 2.000 sorteios da matriz de
covariância dos coeficientes do modelo hidrológico. As penalidades
médias foram expressas em gigawatts-mês (GWh·month), com intervalos de
confiança de 95% com um total de **–1,606.3 (IC95%: −1,746.2;−1,470.2)
de GWh.
Os resultados indicam que o subsistema Sudeste
concentra o maior déficit médio de armazenamento, estimado em
aproximadamente −1,178.4 (IC95%:−1,262.4;−1,097.4) de
GWh·mês, refletindo sua predominância no sistema interligado e
sua maior exposição a anomalias de precipitação. O Sul
apresenta penalidade intermediária (XXXXXXXXXXXX), mas com maior
variabilidade interanual, compatível com seu regime pluviométrico mais
irregular. No Nordeste, as perdas médias são menores
(XXXXXXXXXXXXXX), embora com tendência negativa acentuada após 2010. Já
o Norte apresenta valores próximos de zero, com
intervalos de confiança que incluem a nulidade, sugerindo ausência de
penalidade líquida significativa no período analisado.
Esses resultados corroboram a hipótese de que a penalidade
climática sobre o armazenamento hídrico é concentrada e estruturalmente
assimétrica, afetando com maior intensidade os subsistemas
Sudeste e Sul — justamente aqueles com maior papel de regulação e
suporte energético para o restante do país. Essa heterogeneidade
espacial fornece o elo empírico para a próxima etapa da modelagem, em
que as variações simuladas de \(\Delta
EAR\) serão propagadas à geração hidrelétrica (GAM 1), à geração
térmica (GAM 2) e, por fim, ao preço de curto prazo (GAM 3).
3.2 Modelo 2 — Geração Hidrelétrica como Função do Armazenamento O
segundo modelo da cadeia estima a geração hidrelétrica (G_hidro) em
função da energia armazenada (EAR) e de controles operacionais e
sazonais. O objetivo é capturar a elasticidade da geração em relação ao
estoque hídrico, permitindo traduzir as variações simuladas de ΔEAR
(penalidade climática) em impactos sobre a geração efetiva. Assim como
no modelo climático, emprega-se um GAM para capturar relações não
lineares entre variáveis físicas e operacionais, mantendo parcimônia e
interpretabilidade.
3.2 Modelo 2 — Geração Hidrelétrica como Função do
Armazenamento
m2_hidro <- bam(
val_geracao ~ Year+
s(ear_reservatorio_subsistema_proprio_mwmes, k = 4)+
s(val_geracao_day_subsistema, k = 4)+
s(doy, bs = "cc", k = 2) + # sazonalidade do dia do ano (cíclica)
s(id_reservatorio.x, bs = "re")+# efeito aleatório por reservatório
#s(val_vazaodefluente,k = 2)+
nom_subsistema.x
,
data = reserv,
method = "fREML",
discrete = TRUE,
family = gaussian(), # família: normal; ajustar se necessário
na.action= na.exclude,
#knots = list(doy = c(0.5, 366.5))
)
Aviso em smooth.construct.cc.smooth.spec(object, dk$data, dk$knots) :
basis dimension, k, increased to minimum possible
summary(m2_hidro)
gam.check(m2_hidro)
concurvity(m2_hidro, full=TRUE)
plot(m2_hidro, pages=3, scheme=1, shade=TRUE, se=TRUE, scales="free")
O modelo hidrelétrico (GAM 2) apresentou forte desempenho
explicativo, com R² ajustado de 0,85 e deviance explicada de 85,2%, o
que confirma sua alta capacidade de reproduzir a geração observada a
partir da energia armazenada e variáveis operacionais. O termo linear
para o ano é negativo e altamente significativo (–13,5 MW·mês/ano; p
< 0,001), refletindo a tendência estrutural de redução da
participação hídrica ao longo do período, possivelmente em função da
expansão de fontes térmicas e renováveis não hídricas. Os efeitos fixos
por subsistema indicam diferenças modestas, com geração média
ligeiramente superior no Norte e inferior no Sudeste, consistentes com o
papel estrutural de cada região na oferta de energia e no despacho do
sistema.
Os diagnósticos de resíduos evidenciam ajuste adequado, com
distribuição aproximadamente normal e ausência de heterocedasticidade
sistemática. O histograma dos resíduos é centrado em zero, e o QQ-plot
mostra leve curvatura nas caudas, indicando pequena assimetria associada
a regimes operacionais extremos (reservatórios cheios ou vazios). O
gráfico de resíduos versus preditos exibe duas faixas bem definidas,
correspondentes a diferentes regimes de operação hidráulica — um de
baixa geração com EAR limitada e outro de operação plena com altos
níveis de despacho. Embora esses regimes introduzam leve estratificação,
não há indícios de viés direcional nem autocorrelação relevante, o que
reforça a validade do modelo gaussiano com link identidade. O teste de
dimensionalidade efetiva (k-index > 0.9) e o baixo nível de
concorrência (concurvity < 0.3) confirmam a estabilidade numérica dos
splines e a ausência de sobreajuste.
Os efeitos parciais ilustram de forma clara a dinâmica física do
sistema. O spline da energia armazenada (EAR) apresenta um formato
crescente com leve saturação, sugerindo rendimento decrescente: aumentos
iniciais de armazenamento produzem grandes acréscimos de geração, mas o
efeito marginal diminui à medida que o reservatório se aproxima da
capacidade máxima. O spline da geração diária do subsistema mostra
relação quase linear positiva, representando o efeito de escala e
coordenação entre usinas interligadas. A sazonalidade anual (doy) é
fraca, refletindo o fato de que as oscilações sazonais já são
internalizadas no nível de armazenamento, enquanto o efeito aleatório
por reservatório indica ampla heterogeneidade estrutural — alguns
reservatórios operam como usinas de base, com efeito próximo de zero, e
outros com forte sensibilidade à variação de EAR. Em conjunto, esses
resultados confirmam que o modelo capta adequadamente o mecanismo de
conversão hidrológica entre estoque e geração, oferecendo base
consistente para a estimativa contrafactual da geração hídrica sob
diferentes cenários climáticos.
##Predições factual vs. contrafactual com incerteza (baseline
2001–2005) O objetivo é comparar o armazenamento previsto pelo modelo
sob condições climáticas observadas e sob condições neutras,
representadas pelo clima médio do período 2001–2005. A diferença entre
as duas séries (\(ΔEAR=E^{obs}−E^{cf}\)) representa a
penalidade climática líquida, e sua incerteza é estimada via propagação
dos erros paramétricos do GAM.
# --- Predições factual e contrafactual ---
reserv$ear_hat_obs <- predict(m1_gam, newdata = nd_obs, type = "response")
reserv$ear_hat_cf <- predict(m1_gam, newdata = nd_cf, type = "response")
# Penalidade média
reserv <- reserv %>%
mutate(delta_ear = ear_hat_obs - ear_hat_cf)
reserv$ger_hat_factual <- predict(
m2_hidro, newdata = reserv,
type = "response"
)
reserv$ger_hat_contraf <- predict(
m2_hidro, newdata = reserv %>%
mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_hat_cf),
type = "response"
)
reserv <- reserv %>%
mutate(delta_Ghidro = ger_hat_factual - ger_hat_contraf)
reserv[,c("delta_Ghidro","ger_hat_factual","ger_hat_contraf","val_geracao")] %>% summary()
(3) Incerteza via Delta Method ———————————————
Vp2 <- vcov(m2_hidro)
X_f <- predict(m2_hidro, newdata = reserv ,
type = "lpmatrix")
X_c <- predict(m2_hidro, newdata = reserv %>%
mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_hat_cf),
type = "lpmatrix")
X_diff2 <- X_f - X_c
var_delta2 <- rowSums((X_diff2 %*% Vp2) * X_diff2)
se_delta2 <- sqrt(pmax(var_delta2, 0))
z <- qnorm(0.975)
reserv <- reserv %>%
mutate(
delta_lwr_ger = delta_Ghidro - z * se_delta2,
delta_upr_ger = delta_Ghidro + z * se_delta2
)
# (4) Agregação por ano e subsistema -----------------------------------------
m2_delta_agg <- reserv %>%
mutate(Year = year(date)) %>%
group_by(Year, nom_subsistema.x) %>%
summarise(
mean_penalty = mean(delta_Ghidro, na.rm = TRUE),
lwr = mean(delta_lwr_ger, na.rm = TRUE),
upr = mean(delta_upr_ger, na.rm = TRUE),
.groups = "drop"
)
m2_delta_agg %>% summary()
Predições do modelo Geração
newdata_m1 %>%
mutate(ger_hat = predict(m2_hidro, newdata = newdata_m1, type="response",na.action = na.pass)) -> newdata_m1
# 1) Série temporal: EAR observado vs previsto
newdata_m1 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>%summarise(val_geracao =mean(val_geracao ,na.rm=T),
ger_hat=mean(ger_hat,na.rm=T)) %>%
ggplot(aes(x = mes,)) +
geom_line(aes(y = val_geracao, color = "Observado"), size = 0.7,alpha=.6) +
geom_line(aes(y = ger_hat, color = "Previsto"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "EAR observado vs previsto (GAM)",
y = "EAR (MWmês)", x = "Data") +
scale_color_manual(values = c("Observado" = "black", "Previsto" = "red")) +
theme_minimal()
newdata_m1 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>%summarise(resid=mean(val_geracao,na.rm=T),
ear_hat=mean(ger_hat,na.rm=T)) %>%
ggplot( aes(x = mes,)) +
#geom_point(aes(color=resid_col))+
facet_wrap(~nom_subsistema.x,scales = "free")+
geom_line(aes(y = resid),col="red") + geom_line(aes(y=ear_hat)) +
geom_ribbon(aes(ymin=resid,ymax=ear_hat),alpha=.4,fill = "firebrick",)+
labs(title = "Resíduos do modelo (observado - previsto)",
y = "Resíduo", x = "Data") +
theme_minimal()
Ajuste do GAM: séries temporais e dispersão
A Figura 1 apresenta a comparação entre os níveis de EAR observados e
os valores previstos pelo modelo GAM, desagregados por subsistema.
Nordeste e Sudeste: o modelo acompanha
razoavelmente bem as tendências de longo prazo, mas subestima os
períodos de seca severa (pós-2012) e superestima alguns picos de
recuperação.
Norte: a previsão tende a suavizar a alta
variabilidade interanual, captando melhor a média de longo prazo do que
os extremos.
Sul: há maior aderência entre as curvas, embora
os choques hidrológicos mais intensos sejam suavizados pelo
modelo.
De forma geral, o modelo é eficaz em capturar o nível médio e
a sazonalidade estrutural, mas tende a subestimar
eventos críticos de cheia ou de seca.
# 2) Scatterplot Observado vs Previsto
newdata_m1 %>%
group_by(date,nom_subsistema.x) %>%summarise(val_geracao=sum(val_geracao,na.rm=T),
ger_hat=sum(ger_hat,na.rm=T)) %>%
ggplot( aes(x = val_geracao, y = ger_hat)) +
geom_point(alpha = 0.1) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "blue") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Dispersão EAR observado vs previsto",
x = "Previsto (GAM)", y = "Observado") +
theme_minimal()
A Figura 2 mostra os diagramas de dispersão entre os valores
observados e previstos de EAR, também por subsistema, com a linha
tracejada representando o ajuste perfeito (45°).
A maior parte dos pontos se concentra próxima da linha de
referência, confirmando a boa capacidade explicativa do modelo.
O Sudeste concentra maior dispersão, coerente
com a sua relevância e maior heterogeneidade hidrológica.
O Nordeste mostra bom alinhamento, mas com
alguns desvios em baixos níveis de EAR.
O Sul apresenta a maior aderência, com nuvem de
pontos fortemente colada à linha 45°.
Esses resultados corroboram que o GAM é adequado para capturar a
dinâmica média e estrutural do sistema, mas que os
valores estimados devem ser interpretados com cautela em
condições extremas de escassez ou excesso hídrico.
Contrafactural Geração Termica gam
newdata_m1 %>%
mutate(ear_reservatorio_subsistema_proprio_mwmes=ear_reservatorio_subsistema_proprio_mwmes-clim_in$penalidade_ear)->newdata_m2
#newdata_m1 %>%
# mutate(ear_reservatorio_subsistema_proprio_mwmes=clim_in$clim2026_hat)->newdata_m2
newdata_m2$ger_hat_cf <- predict(m2_hidro, newdata = newdata_m2, type="response",na.action = na.pass)
# 1) Série temporal: EAR observado vs previsto
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(,nom_subsistema.x) %>%summarise(ger_hat_cf =mean(ger_hat_cf ,na.rm=T),
ger_hat=mean(ger_hat,na.rm=T)) %>%
ggplot(aes(x = mes,)) +
geom_line(aes(y = ger_hat_cf, color = "Previsto - Real"), size = 0.7,alpha=.6) +
geom_line(aes(y = ger_hat, color = "Previsto - Contrafactual"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Geração Predito vs previsto (Contra-factual)",
y = "EAR (MWmês)", x = "Data") +
scale_color_manual(values = c("Previsto - Real" = "black", "Previsto - Contrafactual" = "red")) +
theme_minimal()
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,) %>%summarise(ger_hat_cf =mean(ger_hat_cf ,na.rm=T),
ger_hat=mean(ger_hat,na.rm=T)) %>%
ggplot(aes(x = mes,)) +
geom_line(aes(y = ger_hat_cf, color = "Previsto - Real"), size = 0.7,alpha=.6) +
geom_line(aes(y = ger_hat, color = "Previsto - Contrafactual"), size = 1, linetype = "dashed") +#facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Geração Predito vs previsto (Contra-factual)",
y = "EAR (MWmês)", x = "Data") +
scale_color_manual(values = c("Previsto - Real" = "black", "Previsto - Contrafactual" = "red")) +
theme_minimal()
A figura compara, por subsistema, a geração hidrelétrica
prevista com clima observado e a geração
contrafactual simulada ao substituir o armazenamento (EAR) pelo
baseline climático (2001–2010).
Nordeste e Sudeste: a série com clima
observado apresenta quedas acentuadas após 2012, enquanto o
contrafactual se mantém em patamares menores e mais
estáveis. A divergência crescente reflete a penalidade
climática recente sobre a geração.
Norte: o contrafactual acompanha de perto a
trajetória média; a série real mostra oscilações adicionais em anos
específicos, sugerindo choques não reproduzidos pelo clima
médio.
Sul: há forte variabilidade interanual nas duas
curvas; mesmo assim, a série real tende a ficar abaixo
do contrafactual em anos secos, evidenciando substituição por outras
fontes nesses períodos.
Em conjunto, os resultados indicam que o clima recente
reduziu a geração hídrica em relação ao que seria esperado sob
um regime climático médio, com intensidade maior no Sudeste e
Nordeste.
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(Year) %>%summarise(ena_mw7=sum(ger_hat,na.rm=T),
clim2026_hat=sum(ger_hat_cf,na.rm=T)) %>%
ggplot(aes(x = Year,)) +
geom_line(aes(y = ena_mw7/1000, color = "Previsto"), size = 0.7,alpha=.6) +
geom_line(aes(y = clim2026_hat/1000, color = "Contrafactual 2010"), size = 1, linetype = "dashed") +#facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Contrafactual baseline (clima médio 2001-2010)",
y = "Geração (GWmês)", x = "Data") +
scale_color_manual(values = c("Previsto" = "black", "Contrafactual 2010" = "blue")) +
theme_minimal()
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(Year,nom_subsistema.x) %>%summarise(ena_mw7=sum(ger_hat,na.rm=T),
clim2026_hat=sum(ger_hat_cf,na.rm=T)) %>%
ggplot(aes(x = Year,)) +
geom_line(aes(y = ena_mw7/1000, color = "Previsto"), size = 0.7,alpha=.6) +
geom_line(aes(y = clim2026_hat/1000, color = "Contrafactual 2010"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Contrafactual baseline (clima médio 2001-2010)",
y = "Geração (GWmês)", x = "Data") +
scale_color_manual(values = c("Previsto" = "black", "Contrafactual 2010" = "blue")) +
theme_minimal()
A Figura 1 compara as trajetórias previstas de geração hidrelétrica
sob duas condições:
Previsto – Real (linha preta): resultados do GAM
com clima observado no período;
Previsto – Contrafactual (linha vermelha tracejada):
resultados do mesmo modelo, mas substituindo as variáveis climáticas
pelas médias históricas (baseline 2001–2010).
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(Year,nom_subsistema.x) %>%summarise(ena_mw7=sum(ger_hat,na.rm=T),
clim2026_hat=sum(ger_hat_cf,na.rm=T)) %>%
ggplot(aes(x = Year,)) +
geom_line(aes(y = ena_mw7/1000, color = "Previsto"), size = 0.7,alpha=.6) +
geom_line(aes(y = clim2026_hat/1000, color = "Contrafactual 2010 - baseline"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free",ncol = 2)+
labs(title = "Contrafactual climático por subsistema (baseline 2001–2010)",
y = "Geração (GWmês)", x = "Data") +
scale_color_manual(values = c("Previsto" = "black", "Contrafactual 2010 - baseline" = "blue")) +
theme_minimal()
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade_geração_hidro=ger_hat-ger_hat_cf,
#penalidade2=ena_mw7-clim2026_hat,
)->newdata_m2
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade1=ger_hat-ger_hat_cf,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(Year) %>%summarise(ena_mw7=sum(penalidade1,na.rm=T),
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>%
ggplot(aes(x = Year,)) +
#geom_line(aes(y = ena_mw7, color = "previsto - Contrafactual"), size = 0.7,alpha=.6) +
geom_line(aes(y = ena_mw7/1000, color = "Observado - Contrafactual 2026"), size = 1, linetype = "dashed") +#facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Impacto líquido do clima recente sobre a Geração",subtitle = "Observado - Contrafactual 2026",
y = "Penalidade Climática na Geração Hidroelética (MWmês)", x = "Data") +
geom_ribbon(aes(ymin=ena_mw7/1000,ymax=0),alpha=.4,fill = "firebrick",)+
scale_color_manual(values = c("Observado" = "black", "Contrafactual 2026" = "blue")) +
theme_minimal()
newdata_m2 %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade1=ger_hat-ger_hat_cf,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(Year,nom_subsistema.x) %>%summarise(penalidade_geração_hidro=sum(penalidade_geração_hidro,na.rm=T),
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>%
ggplot(aes(x = Year,)) +
#geom_line(aes(y = ena_mw7, color = "previsto - Contrafactual"), size = 0.7,alpha=.6) +
geom_line(aes(y = penalidade_geração_hidro/1000, color = "Observado - Contrafactual 2026"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Impacto líquido do clima recente sobre a Geração por subsistema",subtitle = "Observado - Contrafactual 2026",
y = "Penalidade Climática na Geração Hidroelética (MWmês)", x = "Data") +
geom_ribbon(aes(ymin=penalidade_geração_hidro/1000,ymax=0),alpha=.4,fill = "firebrick",)+
scale_color_manual(values = c("Observado" = "black", "Contrafactual 2026" = "blue")) +
theme_minimal()
newdata_m2 %>%
mutate(penalidade1=ger_hat-ger_hat_cf,
penalidade_perc=ger_hat/ger_hat_cf,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(,nom_subsistema.x) %>%summarise(penalidade1=sum(penalidade1,na.rm=T),
ger_hat=sum(ger_hat,na.rm=T),
ger_hat_cf=sum(ger_hat_cf,na.rm=T),
penalidade_perc=mean(penalidade_perc,na.rm=T)
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>% mutate(custo_financeiro_marginal=penalidade1*100)->penalidade_hidrico
penalidade_hidrico
A Tabela resume os resultados quantitativos. As colunas reportam a
geração prevista real (ger_hat), o contrafactual (ger_hat_cf), a
penalidade absoluta (MWmês) e a penalidade percentual média (%). Os
valores indicam que:
O Sudeste registrou a maior penalidade absoluta
(≈ –3,5 milhões de MWmês), com perda média de
4,4%.
O Nordeste perdeu ≈ –1 milhão de MWmês (–13,5%),
confirmando vulnerabilidade estrutural.
O Sul apresentou penalidade menor em termos
relativos (–9,2%), mas com alta variabilidade interanual.
O Norte foi o único subsistema a manter média
contrafactual próxima à real, refletindo equilíbrio mais favorável entre
clima e armazenamento.
newdata_m1$ger_hat_cf <- newdata_m2$ger_hat_cf
newdata_m1$penalidade_geração_hidro <- newdata_m2$penalidade_geração_hidro
Modelo de Propagação para outras fontes de energia
ger$nom_tipocombustivel %>% unique()
ger %>%mutate(usina_fonte=paste0("ger_",nom_tipousina)) %>%
filter(!nom_subsistema=="PARAGUAI") %>% #,"_",nom_tipousina)) %>%
mutate(usina_fonte=case_when(usina_fonte=="ger_BOMBEAMENTO"~"ger_HIDROELÉTRICA",
TRUE~usina_fonte)) %>% #,"_",nom_tipousina)) %>%
group_by(date,nom_subsistema,usina_fonte,val_geracao_day_subsistema) %>%
summarise(ger=sum(val_geracao,na.rm = T)) %>% ungroup() %>%
spread(usina_fonte,ger,fill = 0) %>% janitor::clean_names() %>%
mutate()->gera_energ_day
gera_energ_day$doy <- lubridate::yday(gera_energ_day$date)
gera_energ_day$dow <- lubridate::wday(gera_energ_day$date, label=TRUE, abbr=TRUE)
gera_energ_day$month <- lubridate::month(gera_energ_day$date)
gera_energ_day$trend <- lubridate::year(gera_energ_day$date)
ger %>%
mutate(usina_fonte=paste0("ger_",nom_tipousina),
mes = floor_date(date, unit = "month")) %>%# select(usina_fonte) %>% unique()
mutate(usina_fonte=case_when(usina_fonte=="ger_BOMBEAMENTO"~"ger_HIDROELÉTRICA",
TRUE~usina_fonte)) %>% #,"_",nom_tipousina)) %>%
group_by(mes,usina_fonte,nom_subsistema) %>% #nom_subsistema
summarise(ger=mean(val_geracao,na.rm = T)) %>%
ggplot(aes(x = mes,y=ger,col=nom_subsistema)) +
geom_line() +facet_wrap(~usina_fonte,scales = "free",ncol = 2)+
labs(title = "Impacto líquido do clima recente sobre a ENA por subsistema",subtitle = "Observado - Contrafactual 2026",
y = "ger (GWmês)", x = "Data") +
theme_minimal()
pld_full %>%
mutate(
ger_hidroeletrica = ifelse(ger_hidroeletrica == 0, 1, ger_hidroeletrica),
ger_fotovoltaica = ifelse(ger_fotovoltaica == 0, 1, ger_fotovoltaica),
ger_eolieletrica = ifelse(ger_eolieletrica == 0, 1, ger_eolieletrica),
ger_termica = ifelse(ger_termica == 0, 1, ger_termica),
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
) %>%
ggplot(aes(date,))+
geom_line(aes(y=Demanda),col="red")+
geom_line(aes(y=val_geracao_day_subsistema,alpha = 0.1),col="black")+facet_wrap(~nom_subsistema.x,scales = "free_y")
gera_energ_day %>% str()
options(scipen = 8)
lm(ger_termica~
ger_hidroeletrica+
ger_eolieletrica+ger_fotovoltaica+ger_nuclear+
nom_subsistema.x+0+
trend+as.factor(month),
data =gera_energ_day) %>% summary()
lm(log(ger_termica)~
log(ger_hidroeletrica)+
ger_eolieletrica+ger_fotovoltaica+ger_nuclear+
nom_subsistema.x+0+
trend+as.factor(month),
,
data =gera_energ_day %>%
mutate(ger_hidroeletrica=case_when(ger_hidroeletrica<0.01~1,
TRUE~ger_hidroeletrica),
ger_termica=case_when(ger_termica<0.01~1,
TRUE~ger_termica))
) %>% summary()
gera_energ_day$date %>% summary()
lm(ger_termica~
ger_hidroeletrica+
ger_eolieletrica+ger_fotovoltaica+ger_nuclear+
nom_subsistema.x+0+
trend+as.factor(month),
,
data =gera_energ_day %>% filter(date>2018-01-01 )) %>% summary()
lm(ger_termica~
ger_hidroeletrica+
ger_eolieletrica+ger_fotovoltaica+ger_nuclear +
trend+as.factor(month)
#nom_subsistema+0
,
data =gera_energ_day) %>% summary()
lm(ger_termica~
ger_hidroeletrica*nom_subsistema.x+
ger_eolieletrica+ger_fotovoltaica+ger_nuclear +
trend+as.factor(month),
#nom_subsistema+0,
data =gera_energ_day) %>% summary()
library(mgcv)
# ger_eolieletrica+ger_fotovoltaica+ger_nuclear +
# trend+as.factor(month)
m_gam_fontes <- bam(ger_termica ~ s(ger_hidroeletrica, k=3) + s(ger_eolieletrica, k=4) +
s(ger_fotovoltaica, k=3) + + s(ger_nuclear, k=3) +
s(trend, k=3) + s(month, k=4) +
#s(Demanda, k=4)+
s(nom_subsistema.x, bs = "re"),
data = gera_energ_day %>%
mutate(Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
))
summary(m_gam_fontes)
gam.check(m_gam_fontes) # checa resíduos, QQ-plot, k-adequação
concurvity(m_gam_fontes, full=TRUE) # multicolinearidade não linear
plot(m_gam_fontes, pages=4, scheme=1, shade=TRUE, se=TRUE,scales = "free")
Contrafactual Outras fontes de energia
#newdata_m1$ear_hat_cf<-clim_in$clim2026_hat
newdata_m1 %>%
group_by(nom_subsistema.x,date) %>%
summarise(ear=sum(ear_reservatorio_subsistema_proprio_mwmes,na.rm = T),
val_geracao=sum(val_geracao),
ear_hat=sum(ear_hat,na.rm = T),
ger_hat=sum(ger_hat,na.rm = T),
penalidade_geração_hidro=sum(penalidade_geração_hidro,na.rm = T),
ger_hat_cf=sum(ger_hat_cf,na.rm = T),
ear_hat_cf=sum(ear_hat_cf,na.rm = T)) %>%
right_join(gera_energ_day,by = c("nom_subsistema.x"="nom_subsistema","date"="date"))->gera_energ_day
gera_energ_day
gera_energ_day %>%
group_by(trend) %>% summarise(val_geracao=sum(ger_hat,na.rm = T),
ger_hidroeletrica=sum(ger_hidroeletrica,na.rm = T)) %>%
ggplot(aes(trend))+
geom_line(aes(y=val_geracao),col="blue")+
geom_line(aes(y=ger_hidroeletrica),col="red")+theme_minimal()
predict(m_gam_fontes,newdata = ger %>%
mutate(val_geracao=ger_hat) )
gera_energ_day$ger_termica_prevista<-predict(m_gam_fontes,
newdata = gera_energ_day %>%
mutate(
nom_subsistema=nom_subsistema.x,
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear)
)
gera_energ_day$ger_termica_prevista_cf<-predict(m_gam_fontes,
newdata = gera_energ_day %>%
mutate(ger_hidroeletrica=ger_hidroeletrica+penalidade_geração_hidro,
nom_subsistema=nom_subsistema.x,
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear)
)
gera_energ_day %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(trend) %>%summarise(ger_termica_prevista=sum(ger_termica_prevista,na.rm=T),
ger_termica_prevista_cf=sum(ger_termica_prevista_cf,na.rm=T)) %>%
ggplot(aes(x = trend,)) +
geom_line(aes(y = ger_termica_prevista/1000, color = "Previsto"), size = 0.7,alpha=.6) +
geom_line(aes(y = ger_termica_prevista_cf/1000, color = "Contrafactual 2010"), size = 1, linetype = "dashed") +#facet_wrap(~nom_subsistema.x,scales = "free")+
geom_ribbon(aes(ymin=ger_termica_prevista/1000,ymax=ger_termica_prevista_cf/1000),alpha=.4,fill = "firebrick",)+
labs(title = "Contrafactual baseline (clima médio 2001-2010)",
y = "Geração Termica (GWmês)", x = "Data") +
scale_color_manual(values = c("Previsto" = "black", "Contrafactual 2010" = "blue")) +
theme_minimal()
gera_energ_day %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(trend,nom_subsistema.x) %>%summarise(ena_mw7=sum(ger_termica_prevista,na.rm=T),
clim2026_hat=sum(ger_termica_prevista_cf,na.rm=T)) %>%
ggplot(aes(x = trend,)) +
geom_line(aes(y = ena_mw7/1000, color = "Previsto"), size = 0.7,alpha=.6) +
geom_line(aes(y = clim2026_hat/1000, color = "Contrafactual 2010"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Contrafactual baseline (clima médio 2001-2010)",
y = "Geração Termica (GWmês)", x = "Data") +
scale_color_manual(values = c("Previsto" = "black", "Contrafactual 2010" = "blue")) +
theme_minimal()
gera_energ_day %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade_termico=ger_termica_prevista_cf-ger_termica_prevista,
#penalidade2=ena_mw7-clim2026_hat,
)->gera_energ_day
gera_energ_day %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade1=ger_termica_prevista_cf-ger_termica_prevista,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(trend) %>%summarise(ena_mw7=sum(penalidade1,na.rm=T),
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>%
ggplot(aes(x = trend,)) +
#geom_line(aes(y = ena_mw7, color = "previsto - Contrafactual"), size = 0.7,alpha=.6) +
geom_line(aes(y = ena_mw7/1000, color = "Observado - Contrafactual 2026"), size = 1, linetype = "dashed") +#facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Impacto líquido do clima recente sobre a Geração",subtitle = "Observado - Contrafactual 2026",
y = "Penalidade Climática na Termica (MWmês)", x = "Data") +
geom_ribbon(aes(ymin=ena_mw7/1000,ymax=0),alpha=.4,fill = "firebrick",)+
scale_color_manual(values = c("Observado" = "black", "Contrafactual 2026" = "blue")) +
theme_minimal()
gera_energ_day %>%
mutate(mes = floor_date(date, unit = "month"),
penalidade_termica=ger_termica_prevista_cf-ger_termica_prevista,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(trend,nom_subsistema.x) %>%summarise(penalidade_termica=sum(penalidade_termica,na.rm=T),
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>%
ggplot(aes(x = trend,)) +
#geom_line(aes(y = ena_mw7, color = "previsto - Contrafactual"), size = 0.7,alpha=.6) +
geom_line(aes(y = penalidade_termica/1000, color = "Observado - Contrafactual 2026"), size = 1, linetype = "dashed") +facet_wrap(~nom_subsistema.x,scales = "free")+
labs(title = "Impacto líquido do clima recente sobre a Geração",subtitle = "Observado - Contrafactual 2026",
y = "Penalidade Climática na Termica (MWmês)", x = "Data") +
geom_ribbon(aes(ymin=penalidade_termica/1000,ymax=0),alpha=.4,fill = "firebrick",)+
scale_color_manual(values = c("Observado" = "black", "Contrafactual 2026" = "blue")) +
theme_minimal()
am maior volatilidade. Essa decomposição regional é crucial para
avaliar a elasticidade da escassez e o redirecionamento da pressão para
outras fontes de geração.
gera_energ_day %>%
mutate(penalidade1=ger_termica_prevista_cf-ger_termica_prevista,
penalidade_perc=ger_termica_prevista_cf/ger_termica_prevista,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(,nom_subsistema.x) %>%summarise(penalidade1=sum(penalidade1,na.rm=T),
ger_hat=sum(ger_hat,na.rm=T),
ger_hat_cf=sum(ger_hat_cf,na.rm=T),
penalidade_perc=mean(penalidade_perc,na.rm=T)
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>% mutate(custo_financeiro_usotermico=penalidade1*300)->penalidade_termico
bind_rows(penalidade_hidrico %>% mutate(estima="Hidro"),penalidade_termico %>% mutate(estima="Térmico")) %>%
select(-starts_with("custo")) %>%
mutate(custo_Reais=case_when(estima=="Hidro"~penalidade1*-100,
TRUE~penalidade1*300),
custo_USD=custo_Reais/5.2
)
bind_rows(penalidade_hidrico %>% mutate(estima="Hidro"),penalidade_termico %>% mutate(estima="Térmico")) %>%
select(-starts_with("custo")) %>%
mutate(custo_Reais=case_when(estima=="Hidro"~penalidade1*-100,
TRUE~penalidade1*300),
custo_USD=custo_Reais/5.2
) %>%
ggplot(aes(x=nom_subsistema.x,y=custo_USD/1000000,fill=estima))+geom_col(position = "dodge")+
geom_text(aes(y=custo_USD/1000000+2,label = round(custo_USD/1000, 1)), position=position_dodge(width=1), size = 3,check_overlap=F)+coord_flip()+
labs(title = "Custo econômico estimado da penalidade climática (2010-2023)",
subtitle = "Custo financeiro aproximado do impacto climático sobre a geração hidrelétrica e térmica",
y = "Custo (US$ mil)", x = "Subsistema") +theme_minimal()
PLD: Custo para o sistema
pld <- read.csv("preco_semanal.csv") # PLD semanal
pld$date <- as.Date(pld$datas) # idem para a base de PLD
pld$week <- lubridate::isoweek(pld$datas)
pld$year <- lubridate::year(pld$datas)
#pld$date<-pld$DATA_INICIO %>% as_date()
pld %>% spread(Submercado,preco)->pld
pld$date %>% min()->inicio
pld %>% filter(DATA_INICIO==inicio)
datas<-gera_energ_day$date %>% unique
data.frame(datas) %>% filter(datas>inicio-1) %>% arrange(datas) %>% left_join(pld,by = c("datas"="date"))->daas_completas
daas_completas
i=2
for (i in 1:length(daas_completas$ANO)) {#length(daas_completas$ANO)
print(i)
if (is.na(daas_completas$ANO[i])) {
daas_completas$ANO[i]<-daas_completas$ANO[i-1]
daas_completas$MES[i]<-daas_completas$MES[i-1]
daas_completas$SEMANA[i]<-daas_completas$SEMANA[i-1]
daas_completas$DATA_FIM[i]<-daas_completas$DATA_FIM[i-1]
daas_completas$SUDESTE[i]<-daas_completas$SUDESTE[i-1]
daas_completas$SUL[i]<-daas_completas$SUL[i-1]
daas_completas$NORDESTE[i]<-daas_completas$NORDESTE[i-1]
daas_completas$NORTE[i]<-daas_completas$NORTE[i-1]
}
}
daas_completas %>% gather(key = "nom_subsitema",value = "preco",c("NORDESTE","SUDESTE","SUL","NORTE"))->pld
serie <- daas_completas %>%
pull(NORDESTE) %>%
ts(start = c(2001, 181), frequency = 365)
stl(serie,s.window = "periodic") %>% plot
serie <- daas_completas %>%
pull(SUL) %>%
ts(start = c(2001, 181), frequency = 365)
stl(serie,s.window = "periodic") %>% plot
serie <- daas_completas %>%
pull(SUDESTE) %>%
ts(start = c(2001, 181), frequency = 365)
stl(serie,s.window = "periodic") %>% plot
serie <- daas_completas %>%
pull(NORTE) %>%
ts(start = c(2001, 181), frequency = 365)
stl(serie,s.window = "periodic") %>% plot
pld$Submercado %>% unique()
gera_energ_day$nom_subsistema.x %>% unique
#newdata_m1 %>% write.csv("base valores previstos.csv")
#gera_energ_day %>% write.csv("valores_previstos_day.csv")
gera_energ_day %>% inner_join(pld,by=c("date","nom_subsistema.x"="nom_subsitema"))->pld_full
pld_full %>% summary()
pld_full %>% group_by(date) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(date,preco))+geom_line()
pld_full %>%
group_by(trend) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(trend,preco))+geom_line()
pld_full %>%
group_by(month) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(month,preco))+geom_line()
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(mes,preco))+geom_line()
pld_full %>%
ggplot(aes(date,preco,nom_subsistema.x))+geom_line()+facet_wrap(~nom_subsistema.x)
pld_full %>%
group_by(trend,nom_subsistema.x) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(trend,preco))+geom_line()+facet_wrap(~nom_subsistema.x)
pld_full %>%
group_by(month,nom_subsistema.x) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(month,preco))+geom_line()+facet_wrap(~nom_subsistema.x)
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>% summarise(preco=mean(preco,na.rm = T)) %>%
ggplot(aes(mes,preco))+geom_line()+facet_wrap(~nom_subsistema.x)
modelos ingenuos
pld_full %>% str()
lm(log(preco)~log(ger_hidroeletrica)+log(ger_eolieletrica)+log(ger_fotovoltaica)+log(ger_termica)+
log(Demanda)+nom_subsistema.x,
data=pld_full %>%
mutate(ger_hidroeletrica=ifelse(ger_hidroeletrica==0,1,ger_hidroeletrica),
ger_fotovoltaica=ifelse(ger_fotovoltaica==0,1,ger_fotovoltaica),
ger_eolieletrica=ifelse(ger_eolieletrica==0,1,ger_eolieletrica),
ger_termica=ifelse(ger_termica==0,1,ger_termica),
#Demanda=ifelse(val_geracao_day_subsistema==0,1,val_geracao_day_subsistema),
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
)) %>% summary()
pld_full$ger_hidroeletrica %>% summary()
Aumento de 1% na geração hídrica reduz o preço em 1,7%.
+1% em eólica → +0,21% no preço.
Aumento de 1% na solar reduz preço em 0,40%.
Elasticidade forte: +1% na demanda → +1,95% no preço.
R² = 0.346 (~35%)
GAM Preço PLD
gam_mod <- gam(preco ~ #trend+
s(log(ger_hidroeletrica)) +
s(log(trend)) +
s(log(doy))+
s(log(ger_eolieletrica)) +
s(log(ger_fotovoltaica)) +
s(log(Demanda)) +
s(log(ger_termica))+
#s(nom_subsistema.x, bs = "re"),# efeito aleatório por reservatório
nom_subsistema.x,
data = pld_full %>%
mutate(
ger_hidroeletrica = ifelse(ger_hidroeletrica == 0, 1, ger_hidroeletrica),
ger_fotovoltaica = ifelse(ger_fotovoltaica == 0, 1, ger_fotovoltaica),
ger_eolieletrica = ifelse(ger_eolieletrica == 0, 1, ger_eolieletrica),
ger_termica = ifelse(ger_termica == 0, 1, ger_termica),
#Demanda = ifelse(val_geracao_day_subsistema == 0, 1, val_geracao_day_subsistema)
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
))
summary(gam_mod)
plot(gam_mod, pages = 3, shade = TRUE)
R² ajustado = 0.50 → o GAM explicou
metade da variância dos preços, contra ~0.35 do modelo
linear anterior.
- Deviance explained = 50% → muito mais
aderência.
Hidrelétrica
(s(log(ger_hidro)))
- O efeito é forte até certo ponto e depois
satura
Eólica
Linha relativamente plana, levemente negativa em valores
altos.
Mostra que a eólica tem efeito fraco ou até neutro em faixas
normais de operação, mas pode ajudar a baixar preços em condições
extremas.
Solar
- Efeito praticamente linear e negativo, mas fraco
(edf ≈ 1 → quase linear)
Demanda
- Claramente crescente, e mais íngreme em valores altos. Isso mostra que o preço responde de forma não linear:
- em demandas baixas/médias, efeito suave,
- em demandas muito altas, preço dispara
- Exatamente o comportamento esperado em sistemas com despacho por ordem de mérito.
Previsto PLD
#pld_full$prec_previsto<-predict(gam_mod,)
predict(gam_mod,newdata=pld_full %>%
mutate(
ger_hidroeletrica = ifelse(ger_hidroeletrica == 0, 1, ger_hidroeletrica),
ger_fotovoltaica = ifelse(ger_fotovoltaica == 0, 1, ger_fotovoltaica),
ger_eolieletrica = ifelse(ger_eolieletrica == 0, 1, ger_eolieletrica),
ger_termica = ifelse(ger_termica == 0, 1, ger_termica),
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
#Demanda = ifelse(val_geracao_day_subsistema == 0, 1, val_geracao_day_subsistema)
),type="response") -> pld_full$prec_previsto
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>% summarise(prec_previsto=mean(prec_previsto,na.rm = T),
preco=mean(preco,na.rm = T),
) %>%
ggplot(aes(mes,prec_previsto))+
geom_line(size = 1, linetype = "dashed",col="red") +
geom_line(aes(y=preco),col = "black")+
labs(y="$",x="Year")+theme_minimal()+
facet_wrap(~nom_subsistema.x,scales = "free")
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>%summarise(preco=mean(preco,na.rm=T),
prec_previsto=mean(prec_previsto,na.rm=T)) %>%
ggplot( aes(x = mes,)) +
#geom_point(aes(color=resid_col))+
facet_wrap(~nom_subsistema.x,scales = "free")+
geom_line(aes(y = prec_previsto),col="red") + #geom_line(aes(y=exp(prec_previsto))) +
geom_ribbon(aes(ymin=prec_previsto,ymax=preco),alpha=.4,fill = "firebrick",)+
labs(title = "Resíduos do modelo (observado - previsto)",
y = "Resíduo", x = "Data") +
theme_minimal()
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>% summarise(prec_previsto=mean(prec_previsto,na.rm = T),
preco=mean(preco,na.rm = T),
) %>%
ggplot(aes(mes,prec_previsto))+
geom_line(size = 1, linetype = "dashed",col="red") +
geom_line(aes(y=preco),col = "black")+
labs(y="$",x="Year")+theme_minimal()+
facet_wrap(~nom_subsistema.x,scales = "free")
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>%summarise(preco=mean(preco,na.rm=T),
prec_previsto=mean(prec_previsto,na.rm=T)) %>%
ggplot( aes(x = mes,)) +
#geom_point(aes(color=resid_col))+
facet_wrap(~nom_subsistema.x,scales = "free")+
geom_line(aes(y = prec_previsto),col="red") + geom_line(aes(y=prec_previsto)) +
geom_ribbon(aes(ymin=prec_previsto,ymax=preco),alpha=.4,fill = "firebrick",)+
labs(title = "Resíduos do modelo (observado - previsto)",
y = "Resíduo", x = "Data") +
theme_minimal()
Contrafactual PLD
gera_energ_day$ger_termica_prevista<-predict(m_gam_fontes,
newdata = gera_energ_day %>%
mutate(
nom_subsistema=nom_subsistema.x,
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear)
)
gera_energ_day$ger_termica_prevista_cf<-predict(m_gam_fontes,
newdata = gera_energ_day %>%
mutate(ger_hidroeletrica=ger_hidroeletrica+penalidade_geração_hidro,
nom_subsistema=nom_subsistema.x,
#ger_termica=ger_termica-penalidade_termico,
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear)
)
predict(gam_mod,newdata=pld_full %>%
mutate(
Demanda = ger_eolieletrica+ger_fotovoltaica+ger_hidroeletrica+ger_termica+ger_nuclear,
ger_hidroeletrica = ifelse(is.na(ger_hidroeletrica+penalidade_geração_hidro),
1,
ger_hidroeletrica+penalidade_geração_hidro),
ger_hidroeletrica = ifelse(ger_hidroeletrica<1 , 1, ger_hidroeletrica),
ger_fotovoltaica = ifelse(ger_fotovoltaica == 0, 1, ger_fotovoltaica),
ger_eolieletrica = ifelse(ger_eolieletrica == 0, 1, ger_eolieletrica),
ger_termica = ifelse(ger_termica+penalidade_termico< 0.1, 1, ger_termica+penalidade_termico),
),type="response") -> pld_full$prec_previsto_cf
pld_full %>% ungroup() %>%
#mutate(penalidade_termico)
select(prec_previsto,prec_previsto_cf,preco,ger_termica,penalidade_termico,penalidade_geração_hidro) %>% summary()
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>% summarise(prec_previsto=mean(prec_previsto,na.rm = T),
preco=mean(preco,na.rm = T),
prec_previsto_cf=mean(prec_previsto_cf,na.rm = T),
) %>%
ggplot(aes(mes,(prec_previsto)))+
geom_line(size = 1, linetype = "dashed",col="red") +
#geom_line(aes(y=preco),col = "black")+
geom_line(aes(y=(prec_previsto_cf)),col = "blue")+
labs(y="$",x="Year")+theme_minimal()+
facet_wrap(~nom_subsistema.x,scales = "free")
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(mes,nom_subsistema.x) %>%summarise(prec_previsto_cf=mean(prec_previsto_cf,na.rm=T),
prec_previsto=mean(prec_previsto,na.rm=T)) %>%
ggplot( aes(x = mes,)) +
#geom_point(aes(color=resid_col))+
facet_wrap(~nom_subsistema.x,scales = "free")+
#geom_line(aes(y = exp(prec_previsto_cf)),col="red") +
geom_line(aes(y=(prec_previsto_cf)-(prec_previsto))) +
geom_ribbon(aes(ymin=0,ymax=(prec_previsto_cf)-(prec_previsto)),alpha=.4,fill = "firebrick",)+
labs(title = "Penalidade (Contrafactual- Predito)",
y = "Penalidade Climática no Preço", x = "Data") +
theme_minimal()
pld_full %>%
mutate(mes = floor_date(date, unit = "month")) %>%
group_by(year,nom_subsistema.x) %>%summarise(prec_previsto_cf=mean(prec_previsto_cf,na.rm=T),
prec_previsto=mean(prec_previsto,na.rm=T)) %>%
ggplot( aes(x = year,)) +
#geom_point(aes(color=resid_col))+
facet_wrap(~nom_subsistema.x,scales = "free")+
#geom_line(aes(y = exp(prec_previsto_cf)),col="red") +
geom_line(aes(y=(prec_previsto_cf)-(prec_previsto))) +
geom_ribbon(aes(ymin=0,ymax=(prec_previsto_cf)-(prec_previsto)),alpha=.4,fill = "firebrick",)+
labs(title = "Penalidade (Contrafactual- Predito)",
y = "Penalidade Climática no Preço", x = "Data") +
theme_minimal()
pld_full %>%
mutate(penalidade1=prec_previsto_cf-prec_previsto,
penalidade_perc=prec_previsto_cf/prec_previsto,
#penalidade2=ena_mw7-clim2026_hat,
) %>%
group_by(nom_subsistema.x) %>%summarise(penalidade1=sum(penalidade1,na.rm=T),
prec_previsto=sum(prec_previsto,na.rm=T),
prec_previsto_cf=sum(prec_previsto_cf*1000,na.rm=T),
prec=mean(preco,na.rm = T),
penalidade_perc=mean(penalidade_perc,na.rm=T)
#clim2026_hat=sum(penalidade2,na.rm=T)
) %>% mutate(custo_financeiro_pld=penalidade1)->penalidade_pld
penalidade_pld
ddsad
dsa
bind_rows(penalidade_hidrico %>% mutate(estima="Hidro*"),
penalidade_termico %>% mutate(estima="Térmico**"),
penalidade_pld %>% mutate(estima="Operacional***")) %>%
select(-starts_with("custo")) %>%
mutate(custo_Reais=case_when(estima=="Hidro*"~(-penalidade1)*(296.8),
estima=="Térmico**"~penalidade1* 478.9,
TRUE~penalidade1*10000/7),
custo_USD=custo_Reais/5.2
) %>%
ggplot(aes(x=nom_subsistema.x,y=(custo_USD/100000),fill=estima))+geom_col(position = "dodge")+
geom_text(aes(label = round(custo_USD/100000, 2)), position=position_dodge(width=1), size = 3,check_overlap=F)+coord_flip()+
labs(title = "Custo econômico estimado da penalidade climática (2001-2019)",
subtitle = "Custo financeiro aproximado do impacto climático sobre a geração hidrelétrica e térmica",
caption = "*296,8 R$/MWh
**478,9 R$/MWh
*** Estimado em 10 GWh por semana",
y = "Custo (US$ milhões)", x = "Subsistema") +theme_minimal()
bind_rows(penalidade_hidrico %>% mutate(estima="Hidro*"),
penalidade_termico %>% mutate(estima="Térmico**"),
penalidade_pld %>% mutate(estima="Operacional***")) %>%
select(-starts_with("custo")) %>%
mutate(custo_Reais=case_when(estima=="Hidro*"~(-penalidade1)*(296.8),
estima=="Térmico**"~penalidade1* 478.9,
TRUE~penalidade1*10000/7),
custo_USD=custo_Reais/5.2
) %>%
group_by(estima) %>% summarise(custo_USD=sum(custo_USD)) %>%
ggplot(aes(x=estima,y=(custo_USD/100000),fill=estima))+geom_col(position = "dodge")+
geom_text(aes(y=custo_USD/200000,label = round(custo_USD/100000, 1)), position=position_dodge(width=1), size = 3,check_overlap=F)+coord_flip()+
labs(title = "Custo econômico estimado da penalidade climática (2000-2019)",
subtitle = "Custo financeiro aproximado do impacto climático sobre a geração hidrelétrica e térmica",
caption = "*296,8 R$/MWh
**478,9 R$/MWh
*** Estimado em 10 GWh por semana",
y = "Custo (US$ Milhoes)", x = "Subsistema") +theme_minimal()
LS0tDQp0aXRsZTogIkNsaW1hdGUgUGVuYWx0aWVzIGFuZCBTY2FyY2l0eSBQcmVzc3VyZSBpbiBCcmF6aWzigJlzIFBvd2VyIFNlY3RvciINCmF1dGhvcjogIlRoaWFnbyBHYXJkaW4gJiBEYW5pZWwgRGFubmEiDQpkYXRlOiAiMjAyNS0xMC0wNiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRoZW1lOiBqb3VybmFsDQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCiMgUGFjb3Rlcw0KDQpgYGB7ciBDYXJyZWdhciBwYWNvdGVzLWJhc2UgZG8gcHJvamV0bzsgZGVmaW5pciBvcMOnw7VlcyBnbG9iYWlzfQ0KIyBDYXJyZWdhciBwYWNvdGVzLWJhc2UgZG8gcHJvamV0bw0KIyBNYW5pcHVsYcOnw6NvIGUgZGF0YXMNCmxpYnJhcnkodGlkeXZlcnNlKTtsaWJyYXJ5KGRhdGEudGFibGUpO2xpYnJhcnkobHVicmlkYXRlKTtsaWJyYXJ5KHBhdGNod29yayk7bGlicmFyeShIbWlzYykNCg0KIyBNb2RlbGFnZW0NCmxpYnJhcnkobWdjdik7bGlicmFyeShncmF0aWEpO2xpYnJhcnkobHVicmlkYXRlKTtsaWJyYXJ5KG1vZGVsc3VtbWFyeSk7bGlicmFyeShndCk7bGlicmFyeShnbHVlKTtsaWJyYXJ5KHNjYWxlcyk7bGlicmFyeShicm9vbSk7bGlicmFyeShicm9vbS5oZWxwZXJzKTtsaWJyYXJ5KGdlb2JyKQ0KIyBVdGlsaWRhZGVzDQpsaWJyYXJ5KHNjYWxlcyk7bGlicmFyeShwYXRjaHdvcmspO2xpYnJhcnkoa25pdHIpO2xpYnJhcnkoa2FibGVFeHRyYSkNCg0KIyBEZWZpbmlyIG9ww6fDtWVzIGdsb2JhaXMgZGUga25pdHINCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyAgICAgICA9IFRSVUUsDQogIG1lc3NhZ2UgICAgPSBUUlVFLA0KICB3YXJuaW5nICAgID0gVFJVRSwNCiAgZHBpICAgICAgICA9IDEyMCwNCiAgZmlnLmFsaWduICA9ICJjZW50ZXIiLA0KICBmaWcud2lkdGggID0gMTIsDQogIGZpZy5oZWlnaHQgPSA4DQopDQoNCiMgVGVtYSB2aXN1YWwgcGFkcsOjbyANCnRoZW1lX2FydGljbGUgPC0gZnVuY3Rpb24oKXsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMSkgKw0KICAgIHRoZW1lKA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4oYj02KSksDQogICAgICBwbG90LmNhcHRpb24gID0gZWxlbWVudF90ZXh0KHNpemU9OSwgY29sb3I9ImdyZXkzMCIpLA0KICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLA0KICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgKQ0KfQ0KdGhlbWVfc2V0KHRoZW1lX2FydGljbGUoKSkNCnNldC5zZWVkKDEyMzQpDQpgYGANCg0KYGBge3IgaGVscGVyc30NCnByZWRpY3RfZ2FtX2NpIDwtIGZ1bmN0aW9uKG1vZGVsLCBuZXdkYXRhLCB0eXBlID0gImxpbmsiLCBsZXZlbCA9IDAuOTUpew0KICBzdG9waWZub3QoaW5oZXJpdHMobW9kZWwsICJnYW0iKSkNCiAgcHIgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IG5ld2RhdGEsIHR5cGUgPSB0eXBlLCBzZS5maXQgPSBUUlVFKQ0KICBhbHBoYSA8LSAxIC0gbGV2ZWwNCiAgY3JpdCAgPC0gcW5vcm0oMSAtIGFscGhhLzIpDQogIHRpYmJsZSgNCiAgICAuZml0dGVkID0gYXMubnVtZXJpYyhwciRmaXQpLA0KICAgIC5zZSAgICAgPSBhcy5udW1lcmljKHByJHNlLmZpdCksDQogICAgLmxvd2VyICA9IC5maXR0ZWQgLSBjcml0Ki5zZSwNCiAgICAudXBwZXIgID0gLmZpdHRlZCArIGNyaXQqLnNlDQogICkNCn0NCmV4cG9ydF9maWd1cmUgPC0gZnVuY3Rpb24ocCwgZmlsZW5hbWUsIHdpZHRoID0gNywgaGVpZ2h0ID0gNC4yKXsNCiAgZ2dzYXZlKGdsdWUoImZpZ3VyZXMve2ZpbGVuYW1lfS5wZGYiKSwgcGxvdCA9IHAsIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9IGhlaWdodCwgZHBpID0gMzAwLCBkZXZpY2UgPSBjYWlyb19wZGYpDQogIGdnc2F2ZShnbHVlKCJmaWd1cmVzL3tmaWxlbmFtZX0uZXBzIiksIHBsb3QgPSBwLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIGRwaSA9IDMwMCwgZGV2aWNlID0gImVwcyIpDQogIGdnc2F2ZShnbHVlKCJmaWd1cmVzL3tmaWxlbmFtZX0udGlmZiIpLHBsb3QgPSBwLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIGRwaSA9IDYwMCwgY29tcHJlc3Npb24gPSAibHp3IikNCiAgaW52aXNpYmxlKE5VTEwpDQp9DQpleHBvcnRfdGFibGUgPC0gZnVuY3Rpb24oZ3Rfb2JqLCBmaWxlbmFtZSl7DQogIGd0c2F2ZShndF9vYmosIGZpbGVuYW1lID0gZ2x1ZSgidGFibGVzL3tmaWxlbmFtZX0uaHRtbCIpKQ0KICAjIFBORyAocHJlY2lzYSB3ZWJzaG90MiBpbnN0YWxhZG8vY29uZmlndXJhZG8pDQogIHRyeShndHNhdmUoZ3Rfb2JqLCBmaWxlbmFtZSA9IGdsdWUoInRhYmxlcy97ZmlsZW5hbWV9LnBuZyIpKSkNCiAgIyBMYVRlWA0KICB0cnkoZ3RzYXZlKGd0X29iaiwgZmlsZW5hbWUgPSBnbHVlKCJ0YWJsZXMve2ZpbGVuYW1lfS50ZXgiKSkpDQogIGludmlzaWJsZShOVUxMKQ0KfQ0KDQojIEVzdGlsbyBwYWRyw6NvIGRlIHRhYmVsYQ0KZ3RfYXJ0aWNsZSA8LSBmdW5jdGlvbihkYXQsIHRpdGxlID0gTlVMTCwgc3VidGl0bGUgPSBOVUxMLCBub3RlID0gTlVMTCl7DQogIGRhdCAlPiUNCiAgICBndCgpICU+JQ0KICAgIHRhYl9oZWFkZXIodGl0bGUgPSBtZCh0aXRsZSAlfHwlICIiKSwgc3VidGl0bGUgPSBtZChzdWJ0aXRsZSAlfHwlICIiKSkgJT4lDQogICAgZm10X251bWJlcih3aGVyZShpcy5udW1lcmljKSwgZGVjaW1hbHMgPSAyKSAlPiUNCiAgICB0YWJfb3B0aW9ucyh0YWJsZS5mb250LnNpemUgPSBweCgxMikpICU+JQ0KICAgIG9wdF9ob3Jpem9udGFsX3BhZGRpbmcoc2NhbGUgPSAxLjEpICU+JQ0KICAgIG9wdF92ZXJ0aWNhbF9wYWRkaW5nKHNjYWxlID0gMS4xKSAlPiUNCiAgICB0YWJfc291cmNlX25vdGUobWQobm90ZSAlfHwlICJOb3RlczogQXV0aG9y4oCZcyBjYWxjdWxhdGlvbnMuIikpDQp9DQpgYGANCg0KIyAxLiBJbnRyb2R1Y3Rpb24NCg0KVGhpcyByZXBvcnQgZG9jdW1lbnRzIHRoZSBhbmFseXRpY2FsIHBpcGVsaW5lIGRldmVsb3BlZCB0byBlc3RpbWF0ZSB0aGUgY2xpbWF0aWMgcGVuYWx0eSAocGVuYWxpZGFkZSBjbGltw6F0aWNhKSBvbiBCcmF6aWzigJlzIGVsZWN0cmljaXR5IHNlY3RvciBhbmQgdG8gdHJhbnNsYXRlIHRoZXNlIGVmZmVjdHMgaW50byBtZWFzdXJhYmxlIGVjb25vbWljIGNvc3RzLiBUaGUgYW5hbHlzaXMgd2FzIGNvbmR1Y3RlZCB1c2luZyBtb250aGx5IGRhdGEgZnJvbSAyMDAxIHRvIDIwMTksIGNvdmVyaW5nIGFsbCBmb3VyIHN1YnN5c3RlbXMgb2YgdGhlIE5hdGlvbmFsIEludGVyY29ubmVjdGVkIFN5c3RlbSAoU0lOKS4NCg0KVGhlIHN0dWR5IHByb2NlZWRzIHRocm91Z2ggdGhlIGZvbGxvd2luZyBzdGVwczoNCg0KMS4gIEh5ZHJvbG9naWNhbCBtb2RlbGxpbmcg4oCUIFdlIGVzdGltYXRlZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY2xpbWF0aWMgdmFyaWFibGVzIChwcmVjaXBpdGF0aW9uLCB0ZW1wZXJhdHVyZSwgaHVtaWRpdHksIHdpbmQpIGFuZCBzdG9yZWQgZW5lcmd5IChFQVIpIGFuZCBoeWRyb2VsZWN0cmljIGdlbmVyYXRpb24gdXNpbmcgR2VuZXJhbGl6ZWQgQWRkaXRpdmUgTW9kZWxzIChHQU1zKS4gVGhlc2UgbW9kZWxzIGNhcHR1cmUgbm9uLWxpbmVhciBjbGltYXRl4oCTaHlkcm9sb2d5IGludGVyYWN0aW9ucyBhbmQgc2Vhc29uYWwgZWZmZWN0cyBhdCB0aGUgc3Vic3lzdGVtIGxldmVsLg0KDQoyLiAgQ2xpbWF0aWMgY291bnRlcmZhY3R1YWxzIOKAlCBVc2luZyB0aGUgZml0dGVkIEdBTXMsIHdlIHNpbXVsYXRlZCBjb3VudGVyZmFjdHVhbCB0cmFqZWN0b3JpZXMgZml4aW5nIHRoZSBjbGltYXRpYyBjb3ZhcmlhdGVzIGF0IHRoZWlyIGhpc3RvcmljYWwgbWVhbiBsZXZlbHMgKGJhc2VsaW5lIDIwMDHigJMyMDA1KS4gVGhlIGRldmlhdGlvbiBiZXR3ZWVuIG9ic2VydmVkIGFuZCBjb3VudGVyZmFjdHVhbCB2YWx1ZXMgaXNvbGF0ZXMgdGhlIHNoYXJlIG9mIHZhcmlhdGlvbiBhdHRyaWJ1dGFibGUgZXhjbHVzaXZlbHkgdG8gY2xpbWF0ZSB2YXJpYWJpbGl0eS4NCg0KMy4gIENsaW1hdGUgcGVuYWx0eSAozpRFKSDigJQgVGhlIGNsaW1hdGUgcGVuYWx0eSB3YXMgZGVmaW5lZCBhcyAkzpRFPUVfe3ByZWRpY3RlZH3iiJJFX3tjZn0kIHJlcHJlc2VudGluZyB0aGUgbG9zcyAob3IgZ2Fpbikgb2YgaHlkcm8gZ2VuZXJhdGlvbiBkdWUgc29sZWx5IHRvIGNsaW1hdGljIGZsdWN0dWF0aW9ucy4NCg0KNC4gIEVsYXN0aWNpdGllcyDigJQgV2UgZGVyaXZlZCBlbGFzdGljaXRpZXMgbGlua2luZyBnZW5lcmF0aW9uIHRvIGh5ZHJvbG9naWNhbCBhbmQgY2xpbWF0aWMgY29uZGl0aW9ucywgYW5kIGRlbWFuZCB0byBwcmljZSBhbmQgaW5jb21lLCB0byBhc3Nlc3Mgc2Vuc2l0aXZpdHkgYW5kIHBvdGVudGlhbCB0cmFuc21pc3Npb24gY2hhbm5lbHMgb2YgY2xpbWF0aWMgc2hvY2tzLg0KDQo1LiAgQ29zdCB0cmFuc2xhdGlvbiDigJQgVGhlIGVzdGltYXRlZCBwZW5hbHRpZXMgd2VyZSBjb252ZXJ0ZWQgaW50byBtb25ldGFyeSB0ZXJtcyBhbG9uZyB0aHJlZSBjb3N0IGRpbWVuc2lvbnM6DQoNCjYuICBDb25zdW1lcnM6IGFkZGl0aW9uYWwgZXhwZW5kaXR1cmUgZHVlIHRvIHJlcGxhY2VtZW50IG9mIGNoZWFwZXIgaHlkcm8gZ2VuZXJhdGlvbiBieSBtb3JlIGV4cGVuc2l2ZSBzb3VyY2VzOw0KDQo3LiAgRWxlY3RyaWNpdHkgc2VjdG9yOiBoaWdoZXIgc3BvdCBtYXJrZXQgcHJpY2VzIChQTEQpIGFuZCBvcGVyYXRpb25hbCBjb3N0czsNCg0KVGhpcyBlbXBpcmljYWwgcGlwZWxpbmUgbGlua3MgY2xpbWF0ZSB2YXJpYWJpbGl0eSwgaHlkcm9sb2dpY2FsIHBlcmZvcm1hbmNlLCBhbmQgZWNvbm9taWMgb3V0Y29tZXMgdGhyb3VnaCBhIHVuaWZpZWQgc3RhdGlzdGljYWwgZnJhbWV3b3JrLCBlbmFibGluZyBhIG11bHRpZGltZW5zaW9uYWwgdmFsdWF0aW9uIG9mIGNsaW1hdGUtcmVsYXRlZCByaXNrcyBpbiBhIGh5ZHJvLWRlcGVuZGVudCBwb3dlciBzeXN0ZW0uDQoNCiMgMi4gRGF0YSBQcmVwYXJhdGlvbg0KDQpUaGlzIHNlY3Rpb24gZGVzY3JpYmVzIHRoZSBjb25zdHJ1Y3Rpb24gb2YgdGhlIGFuYWx5dGljYWwgZGF0YXNldCB1c2VkIHRvIGVzdGltYXRlIHRoZSBjbGltYXRpYyBwZW5hbHR5LlwNCkFsbCB2YXJpYWJsZXMgd2VyZSBoYXJtb25pemVkIGF0IHRoZSAqKnN1YnN5c3RlbeKAk2RheSoqIGxldmVsIGJldHdlZW4gMjAwMSBhbmQgMjAxOSwgaW50ZWdyYXRpbmcgaHlkcm9sb2dpY2FsLCBjbGltYXRpYywgYW5kIG1hcmtldCBpbmZvcm1hdGlvbi4NCg0KIyMjIDIuMSBEYXRhIFNvdXJjZXMNCg0KLSAgICAqKkh5ZHJvcG93ZXIgZ2VuZXJhdGlvbiAocGxhbnQtZGF5KToqKiBkYWlseSBnZW5lcmF0aW9uIGRhdGEgY29tcGlsZWQgZnJvbSBPTlMgcmVjb3JkcywgYWdncmVnYXRlZCBieSBzdWJzeXN0ZW0uDQoNCi0gICAqKlJlc2Vydm9pciBsZXZlbHMgYW5kIG5hdHVyYWwgaW5mbG93cyAoRUFSIGFuZCBFTkEpOioqIHN1YnN5c3RlbS1sZXZlbCBkYWlseSBkYXRhIGZyb20gT05TLg0KDQotICAgKipDbGltYXRpYyB2YXJpYWJsZXM6KiogcHJlY2lwaXRhdGlvbiBhbmQgdGVtcGVyYXR1cmUgb2J0YWluZWQgZnJvbSB0aGUgRUNNV0YvQ0FNUyByZWFuYWx5c2lzIGRhdGFzZXQsIGludGVycG9sYXRlZCB0byBtYXRjaCBzdWJzeXN0ZW0gY2VudHJvaWRzLg0KDQotICAgKipTcG90IHByaWNlIChQTEQpOioqIHdlZWtseSBzdWJzeXN0ZW0gZGF0YSBmcm9tIENDRUUuDQoNCi0gICAqKkRlbWFuZCBhbmQgZ2VuZXJhdGlvbiBkaXNwYXRjaCBieSBzb3VyY2U6KiogbW9udGhseSBvciB3ZWVrbHkgZGF0YSBmcm9tIE9OUyBhbmQgRVBFLg0KDQpBbGwgZGF0YXNldHMgd2VyZSBwcmUtcHJvY2Vzc2VkIHRvIGFsaWduIGRhdGUgZm9ybWF0cywgaGFybW9uaXplIHZhcmlhYmxlIG5hbWVzLCBhbmQgcmVtb3ZlIGluY29uc2lzdGVudCBvciBtaXNzaW5nIGlkZW50aWZpZXJzLg0KDQojIyMgMi4yIERhdGEgTG9hZGluZyBhbmQgQ2xlYW5pbmcNCg0KYGBge3IgZGF0YS1pbn0NCiMgTG9hZCBjb3JlIGRhdGFzZXRzDQpnZXIgICAgIDwtIHJlYWQuY3N2KCJiYXNlX2dlcmFfdHJhdGFkYV9zZXQuY3N2IikgICAgICMgcGxhbnQtZGF5IGdlbmVyYXRpb24NCnBsZCAgICAgPC0gcmVhZC5jc3YoInByZWNvX3NlbWFuYWwuY3N2IikgICAgICAgICAgICAgIyB3ZWVrbHkgc3BvdCBwcmljZSAoUExEKQ0KcmVzZXJ2ICA8LSByZWFkLmNzdigiZW5hX2Vhcl9oaWRyX2NlZ19hbWIuY3N2IikgICAgICAjIHJlc2Vydm9pciBsZXZlbHMgJiBpbmZsb3dzIChFQVIvRU5BKQ0KYGBgDQoNCg0KYGBge3IgZGF0YS1pbiAyIH0NCiMgQ29udmVydCBjaGFyYWN0ZXIgY29sdW1ucyB0byBmYWN0b3JzDQpnZXIgICAgPC0gZ2VyICAgICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQpyZXNlcnYgPC0gcmVzZXJ2ICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQpwbGQgICAgPC0gcGxkICAgICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQoNCiMgLS0tIERhdGUgcGFyc2luZyBhbmQgdGVtcG9yYWwgdmFyaWFibGVzIC0tLQ0KZ2VyJGRhdGUgICAgPC0gYXMuRGF0ZShnZXIkRGF0ZSkgICAgICAgICAgICAgICAjIGFkanVzdCBjb2x1bW4gbmFtZSBhcyBuZWVkZWQNCmdlciRkb3kgICAgIDwtIHlkYXkoZ2VyJGRhdGUpDQpnZXIkZG93ICAgICA8LSBsdWJyaWRhdGU6OndkYXkoZ2VyJGRhdGUsIGxhYmVsID0gVFJVRSwgYWJiciA9IFRSVUUpDQpnZXIkbW9udGggICA8LSBtb250aChnZXIkZGF0ZSkNCmdlciR0cmVuZCAgIDwtIGFzLm51bWVyaWMoZ2VyJGRhdGUpDQoNCnJlc2VydiRkYXRlIDwtIGFzLkRhdGUocmVzZXJ2JGVuYV9kYXRhKSAgICAgICAgIyBhZGp1c3QgY29sdW1uIG5hbWUgYXMgbmVlZGVkDQpyZXNlcnYkZG95ICA8LSB5ZGF5KHJlc2VydiRkYXRlKQ0KcmVzZXJ2JGRvdyAgPC0gbHVicmlkYXRlOjp3ZGF5KHJlc2VydiRkYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKQ0KcmVzZXJ2JG1vbnRoPC0gbW9udGgocmVzZXJ2JGRhdGUpDQpyZXNlcnYkdHJlbmQ8LSBhcy5udW1lcmljKHJlc2VydiRkYXRlKQ0KDQpwbGQkZGF0ZSAgICA8LSBhcy5EYXRlKHBsZCREQVRBX0lOSUNJTykgICAgICAgICMgYWRqdXN0IGNvbHVtbiBuYW1lIGFzIG5lZWRlZA0KcGxkJHdlZWsgICAgPC0gaXNvd2VlayhwbGQkZGF0ZSkNCnBsZCR5ZWFyICAgIDwtIHllYXIocGxkJGRhdGUpDQoNCmBgYA0KDQoNCg0KYGBge3IgY29uZmVyaXIgZSBsaW1wYXIgY29sdW5hcyBkdXBsaWNhZGFzfQ0KZHVwbGljYWRhcyA8LSBkdXBsaWNhdGVkKGFzLmxpc3QocmVzZXJ2KSkNCnJlc2VydlssZHVwbGljYWRhc10gJT4lIGNvbG5hbWVzKCkNCnJlc2VydjwtcmVzZXJ2ICU+JSBzZWxlY3QoLWlkX3N1YnNpc3RlbWEueC54LC1pZF9zdWJzaXN0ZW1hLnkueSwtbm9tX2JhY2lhLngsLW5vbV9iYWNpYS54LC1ub21fcmVlLngsLW5vbV9yZWUueSwtbm9tX3VzaW5hLngsLW5vbV9zdWJzaXN0ZW1hLnkueSwtbm9tX2JhY2lhLnkpDQpgYGANCg0KIyMjIDIuMyBUZW1wb3JhbCBTbW9vdGhpbmcgYW5kIFJvbGxpbmcgTWVhbnMNClRvIHJlZHVjZSBzaG9ydC10ZXJtIG5vaXNlIGFuZCBjYXB0dXJlIGN1bXVsYXRpdmUgY2xpbWF0aWMgZWZmZWN0cywgd2UgY29tcHV0ZWQgKipyb2xsaW5nIG1lYW5zICg3LCAxNCwgYW5kIDMwIGRheXMpKiogZm9yIGtleSBoeWRyb2xvZ2ljYWwgYW5kIGNsaW1hdGljIHZhcmlhYmxlcy4gIA0KDQoNCg0KYGBge3J9DQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoZHBseXIpDQoNCiMjZGlhZ19ncm91cHMgPC0gcmVzZXJ2ICU+JWZpbHRlcih0aXBfcmVzZXJ2YXRvcmlvPT0iUmVzZXJ2YXTDs3JpbyBjb20gVXNpbmEiKSAlPiUgDQojICBncm91cF9ieShub21fcmVzZXJ2YXRvcmlvLngsaWRfcmVzZXJ2YXRvcmlvLngsdGlwX3Jlc2VydmF0b3JpbykgJT4lDQojICBzdW1tYXJpc2UoDQojICAgIG5fdG90YWwgPSBuKCksDQojICAgIG5fbm9uX25hX3ByZWNpcCA9IHN1bSghaXMubmEocHJlY2lwdGF0aW9uKSksDQojICAgIG5fbm9uX25hX3RlbXAgICA9IHN1bSghaXMubmEodGVtcGVyYXR1cmUpKSwNCiMgICAgbl9ub25fbmFfZW5hICAgID0gc3VtKCFpcy5uYShlbmFfYnJ1dGFfcmVzX213bWVkKSksDQojICAgIG5fbm9uX25hX2VhciAgICA9IHN1bSghaXMubmEoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMpKSwNCiMgICAgbl9ub25fbmFfZ2VyICAgID0gc3VtKCFpcy5uYSh2YWxfZ2VyYWNhbykpLA0KIyAgICAuZ3JvdXBzID0gImRyb3AiDQojICApDQojIyBDcmlhciBtw6lkaWFzIG3Ds3ZlaXMgcGFyYSB2YXJpw6F2ZWlzIGFtYmllbnRhaXMgcHJpbmNpcGFpcw0KcmVzZXJ2IDwtIHJlc2VydiAlPiUgZmlsdGVyKHRpcF9yZXNlcnZhdG9yaW89PSJSZXNlcnZhdMOzcmlvIGNvbSBVc2luYSIpICU+JSANCiAgZ3JvdXBfYnkobm9tX3Jlc2VydmF0b3Jpby54KSAlPiUNCiAgYXJyYW5nZShkYXRlLCAuYnlfZ3JvdXAgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKA0KICAgICMgUHJlY2lwaXRhdGlvbiAodXNhIG5vbWUgJ3ByZWNpcHRhdGlvbicgY29tbyBlc3TDoSBuYSBzdWEgYmFzZSkNCiAgICAjcHJlY2lwX21tNyAgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAgNyksDQogICAgcHJlY2lwX21tMTQgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAxNCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQogICAgcHJlY2lwX21tMzAgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQoNCiAgICAjIFRlbXBlcmF0dXJlDQogICAgdGVtcF9tbTcgICAgID0gcm9sbG1lYW4odGVtcGVyYXR1cmUsICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICB0ZW1wX21tMTQgICAgPSByb2xsbWVhbih0ZW1wZXJhdHVyZSwgMTQsZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpLA0KICAgIHRlbXBfbW0zMCAgICA9IHJvbGxtZWFuKHRlbXBlcmF0dXJlLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQoNCiAgICAjIEVOQQ0KICAgIGVuYV9tdzcgICAgICA9IHJvbGxtZWFuKGVuYV9icnV0YV9yZXNfbXdtZWQsICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICAjZW5hX213MTQgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVuYV9icnV0YV9yZXNfbXdtZWQsIDE0KSwNCiAgICAjZW5hX213MzAgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVuYV9icnV0YV9yZXNfbXdtZWQsIDMwKSwNCg0KICAgICMgRUFSIChwcm9wcmlldMOhcmlvKSDigJQgcmVtb3ZldSBmaWxsPSJleHRlbmQiIChuw6NvIHN1cG9ydGFkbykNCiAgICMgZWFyX213NyAgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCA3KSwNCg0KICAgICMgR2VyYcOnw6NvDQogICAgZ2VyX213NyAgICAgID0gcm9sbG1lYW4odmFsX2dlcmFjYW8sICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICBnZXJfbXcxNCAgICAgPSByb2xsbWVhbih2YWxfZ2VyYWNhbywgMTQsZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpLA0KICAgIGdlcl9tdzMwICAgICA9IHJvbGxtZWFuKHZhbF9nZXJhY2FvLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IikNCiAgKSAlPiUNCiAgdW5ncm91cCgpDQoNCiNkaWFnX2dyb3VwcyAlPiUgZmlsdGVyKG5vbV9yZXNlcnZhdG9yaW8ueD09IkEuIFZFUk1FTEhBIikgDQojICANCiNyZXNlcnYgJT4lIGZpbHRlcihub21fcmVzZXJ2YXRvcmlvLng9PSJBLiBWRVJNRUxIQSIpICU+JSANCiMgIGdncGxvdChhZXMocHJlY2lwdGF0aW9uKSkrZ2VvbV9saW5lKGFlcyh4PWRhdGUseT1wcmVjaXB0YXRpb24pLGNvbD0ibGlnaHRibHVlIikNCiMgIHNlbGVjdChkYXRlLG5vbV9lc3RhZG8sdmFsX2dlcmFjYW8scHJlY2lwdGF0aW9uLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNlYXJtYXhfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfanVzYW50ZV9td21lcyxlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyxlYXJfbWF4aW1hX3RvdGFsX213bWVzKSAlPiUgc3VtbWFyeQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KIyAtLS0gQ29uZmVyaXIgY2hhdmVzIHByaW5jaXBhaXMgLS0tDQojIHZlcmlmaWNhciBzZSBkYXRhcyBlIHN1YnNpc3RlbWFzIGJhdGVtDQpjYXQoIkRhdGFzIGRpc3BvbsOtdmVpczpcbiIpDQpyYW5nZShnZXIkZGF0ZSwgbmEucm09VFJVRSkNCnJhbmdlKHJlc2VydiRkYXRlLCBuYS5ybT1UUlVFKQ0KcmFuZ2UocGxkJGRhdGUsIG5hLnJtPVRSVUUpDQpgYGANCg0KIyMjIDIuNCBEZXNjcmlwdGl2ZSBTdW1tYXJpZXMNCg0KYGBge3IgZGVzY3JpcHRpdmUtc3VtbWFyaWVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkoc3RyaW5ncikNCg0KIyBIZWxwZXI6IHNlbGVjaW9uYSBhcyB2YXJpw6F2ZWlzIGV4YXRhcyBwZWRpZGFzLCBzZSBleGlzdGlyZW0gbm8gZGF0YXNldA0Kc2VsZWN0X2Rlc2NfdmFycyA8LSBmdW5jdGlvbihkZil7DQogIHdhbnRlZCA8LSB0aWR5c2VsZWN0Ojp2YXJzX3NlbGVjdCgNCiAgICBuYW1lcyhkZiksDQogICAgc3RhcnRzX3dpdGgoImVhciIpLA0KICAgIHN0YXJ0c193aXRoKCJ0ZW0iKSwNCiAgICBzdGFydHNfd2l0aCgicHJlIiksDQogICAgc3RhcnRzX3dpdGgoImdlciIpLA0KICAgIHZhbF9nZXJhY2FvLA0KICAgIHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hLA0KICAgIGh1bWlkaXR5LA0KICAgIHdpbmRfc3BlZWQNCiAgKQ0KICBkZiAlPiUgZHBseXI6OnNlbGVjdChub21fc3Vic2lzdGVtYS54LCBkcGx5cjo6YWxsX29mKHdhbnRlZCkpDQp9DQoNCiMgSGVscGVyOiBzdW1hcml6YSBlc3RhdMOtc3RpY2FzIHBhcmEgdW0gZGF0YS5mcmFtZSBqw6EgZmlsdHJhZG8gcG9yIHN1YnNpc3RlbWENCnN1bW1hcmlzZV9zdGF0cyA8LSBmdW5jdGlvbihkZl9zdWIpew0KICBudW1fdmFycyA8LSBkZl9zdWIgJT4lIGRwbHlyOjpzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbnVtX3ZhcnMsDQogICAgZHBseXI6OmFjcm9zcygNCiAgICAgIC5jb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgLmZucyAgPSBsaXN0KA0KICAgICAgICBNZWFuID0gfm1lYW4oLiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgU0QgICA9IH5zZCguLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBNaW4gID0gfm1pbiguLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBNYXggID0gfm1heCguLCBuYS5ybSA9IFRSVUUpDQogICAgICApLA0KICAgICAgLm5hbWVzID0gInsuY29sfV9fey5mbn0iDQogICAgKQ0KICApICU+JQ0KICAgIHRpZHlyOjpwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLA0KICAgICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsInN0YXQiKSwNCiAgICAgIG5hbWVzX3NlcCA9ICJfXyIsDQogICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiDQogICAgKSAlPiUNCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHN0YXQsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JQ0KICAgIGRwbHlyOjphcnJhbmdlKHZhcmlhYmxlKQ0KfQ0KDQpgYGANCg0KYGBge3J9DQojIFRhYmVsYSBkZSBjb2JlcnR1cmEgdGVtcG9yYWwgcG9yIHN1YnNpc3RlbWENCmNvdmVyYWdlX3RibCA8LSByZXNlcnYgJT4lDQogIGRwbHlyOjpncm91cF9ieShub21fc3Vic2lzdGVtYS54KSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBvYnNlcnZhdGlvbnMgPSBkcGx5cjo6bl9kaXN0aW5jdChpZF9yZXNlcnZhdG9yaW8ueCksDQogICAgc3RhcnRfZGF0ZSAgPSBtaW4oZGF0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBlbmRfZGF0ZSAgICA9IG1heChkYXRlLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQp0YWJfY292IDwtIGd0X2FydGljbGUoDQogIGNvdmVyYWdlX3RibCwNCiAgdGl0bGUgPSAiKipUYWJsZSBBLiBUZW1wb3JhbCBjb3ZlcmFnZSBieSBzdWJzeXN0ZW0qKiIsDQogIHN1YnRpdGxlID0gIk9ic2VydmF0aW9uIGNvdW50cyBhbmQgZGF0ZSByYW5nZSIsDQogIG5vdGUgPSAiRGF0ZXMgaW4gWVlZWS1NTS1ERC4iDQopICU+JQ0KICBndDo6Y29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYS54ICAgPSAiU3Vic3lzdGVtIiwNCiAgICBvYnNlcnZhdGlvbnM9ICJOIG9mIFJlc2Vydm9pcnMiLA0KICAgIHN0YXJ0X2RhdGUgID0gIlN0YXJ0IiwNCiAgICBlbmRfZGF0ZSAgICA9ICJFbmQiDQogICkNCg0KZXhwb3J0X3RhYmxlKHRhYl9jb3YsICJUYWJBX0NvdmVyYWdlX2J5U3Vic3lzdGVtIikNCnRhYl9jb3YNCmBgYA0KDQpgYGB7cn0NCg0KIyBUYWJlbGEgZGUgY29iZXJ0dXJhIHRlbXBvcmFsIHBvciBzdWJzaXN0ZW1hDQojY292ZXJhZ2VfdGJsIDwtIA0KcmVzZXJ2ICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkobm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgTWVhbl9nZXJhY2FvPW1lYW4odmFsX2dlcmFjYW8sIG5hLnJtID0gVFJVRSksDQogICAgU0RfZ2VyYWNhbz1tZWFuKHZhbF9nZXJhY2FvLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9nZXJhY2FvICA9IG1pbih2YWxfZ2VyYWNhbywgbmEucm0gPSBUUlVFKSwNCiAgICBNYXhfZ2VyYWNhbyAgICA9IG1heCh2YWxfZ2VyYWNhbywgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICBNZWFuX0VBUj1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNEX0VBUj1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9FQVIgID0gbWluKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF9FQVIgICAgPSBtYXgoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMsIG5hLnJtID0gVFJVRSksDQogICAgDQogICAgTWVhbl9wcmVjaXBtbTMwPW1lYW4ocHJlY2lwX21tMzAsIG5hLnJtID0gVFJVRSksDQogICAgU0RfcHJlY2lwbW0zMD1tZWFuKHByZWNpcF9tbTMwLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9wcmVjaXBtbTMwICA9IG1pbihwcmVjaXBfbW0zMCwgbmEucm0gPSBUUlVFKSwNCiAgICBNYXhfcHJlY2lwbW0zMCAgICA9IG1heChwcmVjaXBfbW0zMCwgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICBNZWFuX3RlbXBtbTc9bWVhbih0ZW1wX21tNywgbmEucm0gPSBUUlVFKSwNCiAgICBTRF90ZW1wbW03PW1lYW4odGVtcF9tbTcsIG5hLnJtID0gVFJVRSksDQogICAgTWluX3RlbXBtbTcgID0gbWluKHRlbXBfbW03LCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF90ZW1wbW03ICAgID0gbWF4KHRlbXBfbW03LCBuYS5ybSA9IFRSVUUpLA0KICAgIA0KICAgIE1lYW5faHVtaWRpdHk9bWVhbihodW1pZGl0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBTRF9odW1pZGl0eT1tZWFuKGh1bWlkaXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9odW1pZGl0eSAgPSBtaW4oaHVtaWRpdHksIG5hLnJtID0gVFJVRSksDQogICAgTWF4X2h1bWlkaXR5ICAgID0gbWF4KGh1bWlkaXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIA0KICAgIE1lYW5fd2luZD1tZWFuKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgU0Rfd2luZD1tZWFuKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgTWluX3dpbmQgID0gbWluKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgTWF4X3dpbmQgICAgPSBtYXgod2luZF9zcGVlZCwgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGMoZW5kc193aXRoKCJnZXJhY2FvIiksZW5kc193aXRoKCJpbmQiKSxlbmRzX3dpdGgoIkVBUiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRzX3dpdGgoIml0eSIpLGVuZHNfd2l0aCgibW03IiksZW5kc193aXRoKCJtbTMwIikpLA0KICAgICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsInN0YXQiKSwNCiAgICAgIG5hbWVzX3NlcCA9ICJfIiwNCiAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSINCiAgICApICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsdmFsdWVzX2Zyb20gPXZhbHVlKSAlPiUgDQogIGFycmFuZ2Uoc3RhdCkgJT4lICMgLT4gdGFiX2Rlc2MNCiAgZ3RfYXJ0aWNsZSgNCiAgDQogIHRpdGxlID0gIioqVGFibGUgQi4gIERlc2NyaXB0aXZlIFN1bW1hcmllcyIsDQogIHN1YnRpdGxlID0gIk9ic2VydmF0aW9uIGNvdW50cyBhbmQgZGF0ZSByYW5nZSIsDQogIG5vdGUgPSAiRGF0ZXMgaW4gWVlZWS1NTS1ERC4iDQopICU+JQ0KICBndDo6Y29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYS54ICAgPSAiU3Vic3lzdGVtIiwNCiAgICBzdGF0PSAiVmFyaWFibGUiLA0KICAgIE1lYW4gID0gIk1lYW4iLA0KICAgIFNEICAgID0gIlNEIixNaW49ICJNaW4iLCJNYXgiPSAiTWF4Ig0KICApDQoNCiNleHBvcnRfdGFibGUodGFiX2NvdiwgIlRhYkFfQ292ZXJhZ2VfYnlTdWJzeXN0ZW0iKQ0KI3RhYl9jb3YNCg0KYGBgDQoNCmBgYHtyfQ0KDQoNCg0KcmVzZXJ2ICU+JSBzZWxlY3Qoc3RhcnRzX3dpdGgoImVuYSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoImVhciIpLHN0YXJ0c193aXRoKCJ0ZW0iKSxzdGFydHNfd2l0aCgicHJlIiksc3RhcnRzX3dpdGgoImdlciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsX2dlcmFjYW8sdmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEsaHVtaWRpdHksd2luZF9zcGVlZCkgJT4lIHN0YXJnYXplcjo6c3RhcmdhemVyKHR5cGU9InRleHQiKQ0KcGxkICU+JSBzdGFyZ2F6ZXI6OnN0YXJnYXplcih0eXBlPSJ0ZXh0IikNCmdlciAlPiUgc2VsZWN0KHZhbF9nZXJhY2FvLG5vbV90aXBvY29tYnVzdGl2ZWwsbm9tX3RpcG91c2luYT1hcy5mYWN0b3Iobm9tX3RpcG91c2luYSkpICU+JSBzdW1tYXJ5DQoNCmBgYA0KDQojIyMgW0dyw6FmaWNvcyByw6FwaWRvczogc8OpcmllcyBFTkEsIHByZWNpcGl0YcOnw6NvLCB0ZW1wZXJhdHVyYSwgRUFSLCBnZXJhw6fDo29dDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQ0KIyAtLS0gR3LDoWZpY29zIHLDoXBpZG9zIChFREEpIC0tLQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIFPDqXJpZSBFTkEvUmVzZXJ2YXTDs3Jpb3MNCnBsb3RfZW5hPC1yZXNlcnYgJT4lIGdyb3VwX2J5KGRhdGUpICU+JSBzdW1tYXJpc2UoZWFyX213Nz1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLG5hLnJtID0gVCkpICU+JSANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9ZWFyX213NykpICsNCiAgZ2VvbV9saW5lKGNvbG9yPSJzdGVlbGJsdWUiKSArZ2VvbV9zbW9vdGgoKSsNCiAgbGFicyh0aXRsZT0iRW5lcmdpYSBBcm1hemVuYWRhIChFQVIpIGJydXRhIChNV21lZCkiLCB4PSIiLCB5PSJNV21lZCIpDQoNCiMgU8OpcmllIEVBUg0KcGxvdF9lYXI8LXJlc2VydiAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lIHN1bW1hcmlzZShlbmFfbXc3PW1lYW4oZW5hX213NyxuYS5ybSA9IFQpKSAlPiUgDQogICAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9ZW5hX213NykpICsNCiAgZ2VvbV9saW5lKGNvbG9yPSJkYXJrZ3JlZW4iKSArZ2VvbV9zbW9vdGgoKSsNCiAgbGFicyh0aXRsZT0iRW5lcmdpYSBOYXR1cmFsIEFmbHVlbnRlIChFTkEpIHRvdGFsIChNV23DqnMpIiwgeD0iIiwgeT0iTVdtw6pzIikNCg0KIyBTw6lyaWUgZGUgZ2VyYcOnw6NvDQpwbG90X2dlcjwtcmVzZXJ2ICU+JSBncm91cF9ieShkYXRlKSAlPiUgc3VtbWFyaXNlKGdlcl9tdzc9bWVhbihnZXJfbXc3LG5hLnJtID0gVCkpICU+JSANCiAgICAgIGdncGxvdChhZXMoeD1kYXRlLCB5PWdlcl9tdzcpKSArDQogIGdlb21fbGluZShjb2xvcj0iZ3JleTMwIikgK2dlb21fc21vb3RoKCkrDQogIGxhYnModGl0bGU9IkdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhIChNV2gvZGlhKSIsIHg9IiIsIHk9Ik1XaCIpDQoNCiMgLS0tIENvcnJlbGHDp8O1ZXMgcsOhcGlkYXMgLS0tDQojIFtDaGVjYXIgY29ycmVsYcOnw6NvIGLDoXNpY2EgZW50cmUgY2xpbWEgKHByZWNpcCwgdGVtcCkgZSBFTkFdDQpjbGltYV92YXJzIDwtIHJlc2VydiAlPiUgDQogIGRwbHlyOjpzZWxlY3QoDQogICAgICAgICAgICAgICAgZ2VyX213X3N1YnNpc3RlbWE9dmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEsDQogICAgICAgICAgICAgICAgZ2VyX213PXZhbF9nZXJhY2FvLGdlcl9tdzcsZ2VyX213MTQsZ2VyX213MzAsDQogICAgICAgICAgICAgICAgZW5hX213PWVuYV9icnV0YV9yZXNfbXdtZWQsIGVuYV9tdzcsDQogICAgICAgICAgICAgICAgZWFyX213PWVhcl90b3RhbF9td21lcywgICNlYXJfbXcxNCwgZWFyX213MzAsDQogICAgICAgICAgICAgICAgcHJlY2lwdGF0aW9uLHByZWNpcF9tbTE0LHByZWNpcF9tbTMwLA0KICAgICAgICAgICAgICAgIHRlbXBlcmF0dXJlLHRlbXBfbW03LHRlbXBfbW0xNCx0ZW1wX21tMzAsDQogICAgICAgICAgICAgICAgd2luZF9zcGVlZCwgDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQ0KcGxvdF9nZXJ8cGxvdF9lYXIgLyBwbG90X2VuYQ0KDQpjb3JycGxvdDo6Y29ycnBsb3QoY29yKGNsaW1hX3ZhcnMsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKSxtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwNCiAgICAgICAgIGFkZENvZWYuY29sID0gImJsYWNrIiwgIyBtb3N0cmFyIGNvZWZpY2llbnRlcw0KICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gMzUsbnVtYmVyLmNleAkJID0uOCwNCiAgICAgICAgIGNvbD1jb2xvclJhbXBQYWxldHRlKGMoInJlZCIsIndoaXRlIiwiYmx1ZSIpKSgyMDApKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KGdncmVwZWwpDQpnZW9icjo6cmVhZF9yZWdpb24oKS0+Z2VvcmVnaW9uDQoNCnJlc2VydiAlPiUgZmlsdGVyKCJSZXNlcnZhdMOzcmlvIGNvbSBVc2luYSI9PXRpcF9yZXNlcnZhdG9yaW8pICU+JQ0KICBncm91cF9ieShub21fcmVzZXJ2YXRvcmlvLnksdmFsX2xhdGl0dWRlLHZhbF9sb25naXR1ZGUsbm9tX3N1YnNpc3RlbWEueCkgJT4lIA0KICBzdW1tYXJpc2UoZWFyX3Jlc2VydmF0b3Jpbz1zdW0oZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMgJT4lIGFzLm51bWVyaWMoKSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgKSAtPmENCmEgJT4lICAgZ2dwbG90KGFlcyh2YWxfbG9uZ2l0dWRlLHZhbF9sYXRpdHVkZSkpK2dlb21fcG9pbnQoKSsNCmdncGxvdChkYXRhPWdlb3JlZ2lvbikgK2dlb21fc2YoKQ0KYSRub21fc3Vic2lzdGVtYS54ICU+JSB1bmlxdWUNCmEgJT4lDQogIG11dGF0ZShub21fc3Vic2lzdGVtYS54PWNhc2Vfd2hlbihub21fc3Vic2lzdGVtYS54PT0iU1VMIn4iU291dGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9tX3N1YnNpc3RlbWEueD09IlNVREVTVEUifiJTb3V0aGVhc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9tX3N1YnNpc3RlbWEueD09Ik5PUkRFU1RFIn4iTm9ydGhlYXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hLng9PSJOT1JURSJ+Ik5vcnRoIixUUlVFfiIiKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGdlb3JlZ2lvbiwgY29sb3IgPSAid2hpdGUiLGZpbGw9ImxpZ2h0Z3JleSIsIHNpemUgPSAyKSsjZ2VvbV9saW5lKCkrDQogIGdlb21fcG9pbnQoYWVzKHZhbF9sb25naXR1ZGUsdmFsX2xhdGl0dWRlLGNvbD1ub21fc3Vic2lzdGVtYS54KSkgK3RoZW1lX3ZvaWQoKSsgI3NjYWxlX2NvbG9yX2Rpc2NyZXRlKHZhbHVlPSkNCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyh2YWxfbG9uZ2l0dWRlLHZhbF9sYXRpdHVkZSxjb2w9bm9tX3N1YnNpc3RlbWEueCxsYWJlbD1ub21fcmVzZXJ2YXRvcmlvLnkpLHNpemUgPSAyLG1heC5vdmVybGFwcz1ucm93KGEpLGZvcmNlX3B1bGwgID0yKSsNCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKC44LCAuOTUpLCxsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiKSsNCiAgbGFicyhjb2w9IkVsZXRyaWNhbCBTdWJzeXN0ZW1zIiktPm1hcA0KbWFwDQpgYGANCmBgYHtyfQ0KcmVzZXJ2IDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKA0KICAgIGRveSAgID0geWRheShkYXRlKSwNCiAgICBtb250aCA9IG1vbnRoKGRhdGUpLA0KICAgICMgdHJhbnNmb3JtYcOnw6NvIGxvZyBwYXJhIGludGVycHJldGHDp8OjbyBwZXJjZW50dWFsIChldml0YSBwcm9ibGVtYXMgY29tIHplcm8pDQogICAgbF9wcmVjaXAgPSBsb2cxcChwcmVjaXBfbW0zMCksDQogICAgbF90ZW1wICAgPSBsb2cxcCh0ZW1wX21tNyksICAgICAjIG9wY2lvbmFsOiBzZSBwcmVmZXJpciBtYW50ZXIgdGVtcCBubyBuw612ZWwsIHVzZSB0ZW1wX21tNyBlbSB2ZXogZGUgbF90ZW1wDQogICAgbF9odW1pZGl0eSA9bG9nMXAoaHVtaWRpdHkpLA0KICAgIGxfd2luZF9zcGVlZD1sb2cod2luZF9zcGVlZCkNCiAgKQ0KYGBgDQoNCiMgMy4xIE1vZGVsbyAxIOKAlCBHQU0g4oCcY2xpbWHigJFhcGVuYXPigJ0gKGJhc2VsaW5lKQ0KDQpNb2RlbG8gaGlkcm9sw7NnaWNvIHBhcnNpbW9uaW9zbyBubyBxdWFsIGEgRW5lcmdpYSBBcm1hemVuYWRhIChFQVIpIMOpIGV4cGxpY2FkYSBhcGVuYXMgcG9yIGNsaW1hIGUgY29udHJvbGVzIHNhem9uYWlzL3JlZ2lvbmFpcywgdXNhbmRvIGZ1bsOnw7VlcyBzdWF2ZXMgKHNwbGluZXMpIGVtIHVtIEdBTS4gTyBvYmpldGl2byDDqSBpc29sYXIgbyBzaW5hbCBwdXJhbWVudGUgY2xpbcOhdGljbyBzb2JyZSBvIGVzdG9xdWUgaMOtZHJpY28gZSBjb25zdHJ1aXIgdW0gY29udHJhZmFjdHVhbCBhdWRpdMOhdmVsLiBNYW50ZW1vcyBhIHJlc3Bvc3RhIG5vIG7DrXZlbCAoTVfCt23DqnMpIHBvciBjb2Vyw6puY2lhIGNvbSBhIGRlZmluacOnw6NvIGRlIHBlbmFsaWRhZGUgZSBtb25ldGl6YcOnw6NvLCBlIHRyYW5zZm9ybWFtb3MgcHJlZGl0b3JlcyBjbGltw6F0aWNvcyBxdWFuZG8gw7p0aWwgcGFyYSBpbnRlcnByZXRhw6fDo28gKHNlbWktZWxhc3RpY2lkYWRlcykuDQpgYGB7cn0NCiMgR0FNIChHYXVzc2lhbiwgZlJFTUwpLiBTcGxpbmVzIGNsaW3DoXRpY2FzICsgc2F6b25hbGlkYWRlIGPDrWNsaWNhICsgZWZlaXRvIGFsZWF0w7NyaW8gcG9yIHJlc2VydmF0w7NyaW8gKyBmaXhlZCBwb3Igc3Vic2lzdGVtYQ0KbTFfZ2FtIDwtIGJhbSgNCiAgZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMgfg0KICAgIHMobF9wcmVjaXAsIGsgPSA2KSArDQogICAgcyhsX3RlbXAsICAgayA9IDYpICsNCiAgICBzKGxfaHVtaWRpdHksIGsgPSA2KSArDQogICAgcyhsX3dpbmRfc3BlZWQsIGsgPSA2KSArDQogICAgcyhkb3ksIGJzID0gImNjIiwgayA9IDEyKSArICAgICAgICAgICAgIyBzYXpvbmFsaWRhZGUgY8OtY2xpY2Egbm8gYW5vDQogICAgcyhpZF9yZXNlcnZhdG9yaW8ueCwgYnMgPSAicmUiKSArICAgICAgIyBlZmVpdG8gYWxlYXTDs3JpbyBwb3IgcmVzZXJ2YXTDs3Jpbw0KICAgIG5vbV9zdWJzaXN0ZW1hLngsICAgICAgICAgICAgICAgICAgICAgICAjIGVmZWl0byBmaXhvIHBvciBzdWJzaXN0ZW1hDQogIGRhdGEgICAgID0gcmVzZXJ2LA0KICBtZXRob2QgICA9ICJmUkVNTCIsDQogIGRpc2NyZXRlID0gVFJVRSwNCiAgZmFtaWx5ICAgPSBnYXVzc2lhbigpLA0KICBuYS5hY3Rpb249IG5hLmV4Y2x1ZGUsDQogIGtub3RzICAgID0gbGlzdChkb3kgPSBjKDAuNSwgMzY2LjUpKSwNCiAgc2VsZWN0ICAgPSBUUlVFICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzaHJpbmthZ2UgcGFyYSBldml0YXIgd2lnZ2xlcw0KKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkobTFfZ2FtKQ0KZ3RzdW1tYXJ5Ojp0YmxfcmVncmVzc2lvbihtMV9nYW0pDQpzdW1tYXJ5KG0xX2dhbSkNCmdhbS5jaGVjayhtMV9nYW0pICAgICAgICAgICMgcmVzw61kdW9zLCBRUSwgay1pbmRleA0KY29uY3Vydml0eShtMV9nYW0sIGZ1bGw9VFJVRSkNCmBgYA0KDQojIyMgUmVzcG9zdGFzIG1hcmdpbmFpcyAocGxhdXNpYmlsaWRhZGUgZSBpbnRlcnByZXRhw6fDo28pDQpQYXJhIGludGVycHJldGFyIG8gY29tcG9ydGFtZW50byBmdW5jaW9uYWwgZSBhdmFsaWFyIHBsYXVzaWJpbGlkYWRlLCB1c2Ftb3MgZGVyaXZhZGFzIHBhcmNpYWlzLiBDb21vIGBsX3ByZWNpcCA9IGxvZyhwcmVjaXArMSlgLCBhIGRlcml2YWRhIGRlIFwoRVwpIGVtIHJlbGHDp8OjbyBhIGBsX3ByZWNpcGAgw6kgdW1hICoqc2VtaS1lbGFzdGljaWRhZGUgbm8gbsOtdmVsKio6IG8gZWZlaXRvIGRlICsxJSBlbSBwcmVjaXBpdGHDp8OjbyDDqSBhcHJveGltYWRhbWVudGUgXCgweyx9MDEgXHRpbWVzIFxwYXJ0aWFsIEUgLyBccGFydGlhbCBcbG4oXHRleHR7cHJlY2lwfSsxKVwpLg0KDQpgYGB7ciBtMS1kZXJpdmF0aXZlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBsb3QobTFfZ2FtLCBwYWdlcz00LCBzY2hlbWU9MSwgc2hhZGU9VFJVRSwgc2U9VFJVRSkNCg0KDQpgYGANCmBgYHtyfQ0KZF9wcmVjaXAgPC0gZGVyaXZhdGl2ZXMobTFfZ2FtLCB0ZXJtID0gInMobF9wcmVjaXApIiwgdHlwZSA9ICJjZW50cmFsIikNCmRfcHJlY2lwIDwtIGRfcHJlY2lwICU+JQ0KICBtdXRhdGUoZWZmZWN0X3Blcl8xcGN0ID0gMC4wMSAqIC5kZXJpdmF0aXZlKSANCiAgI3NlbGVjdChkYXRhLCAuZml0dGVkLCAuc2UsIGVmZmVjdF9wZXJfMXBjdCwgbG93ZXIsIHVwcGVyKQ0KDQpzdW1tYXJ5KGRfcHJlY2lwJGVmZmVjdF9wZXJfMXBjdCkNCmBgYA0KQ29tIGJhc2Ugbm9zIGdyw6FmaWNvcyBkZSBlZmVpdG9zIHBhcmNpYWlzLCBkaWFnbsOzc3RpY29zIGRlIHJlc8OtZHVvcyBlIHN1bcOhcmlvIGVzdGF0w61zdGljbyBkbyBHQU0gKGZSRU1MLCBSwrJhaj0wLjc0OyBkZXZpYW5jZSBleHBsYWluZWQ9NzQlKSwgw6kgcG9zc8OtdmVsIHNpbnRldGl6YXIgYSBxdWFsaWRhZGUgZG8gbW9kZWxvIGVtIHRyw6pzIHBhcsOhZ3JhZm9zIHTDqWNuaWNvcyBlIGludGVycHJldGF0aXZvcyDigJQgYWRlcXVhZG9zIHBhcmEgYSBzZcOnw6NvIGRlIHJlc3VsdGFkb3MgbWV0b2RvbMOzZ2ljb3M6DQpPIG1vZGVsbyBoaWRyb2zDs2dpY28g4oCcY2xpbWEtIGVhcuKAnSBhcHJlc2VudGEgZGVzZW1wZW5obyByb2J1c3RvIGUgY29lcmVudGUgY29tIGEgZGluw6JtaWNhIGbDrXNpY2EgZXNwZXJhZGEgZG8gc2lzdGVtYS4gTyBhanVzdGUgYWxjYW7Dp2EgUsKyIGFqdXN0YWRvIGRlIDAsNzQgZSBleHBsaWNhIDc0JSBkYSBkZXZpYW5jZSB0b3RhbCwgaW5kaWNhbmRvIHF1ZSBhcyB2YXJpw6F2ZWlzIGNsaW3DoXRpY2FzIOKAlCBwcmVjaXBpdGHDp8OjbywgdGVtcGVyYXR1cmEsIHVtaWRhZGUgZSB2ZW50byDigJQgY29tYmluYWRhcyDDoCBzYXpvbmFsaWRhZGUgZSBhb3MgZWZlaXRvcyByZWdpb25haXMsIGNhcHR1cmFtIGEgbWFpb3IgcGFydGUgZGEgdmFyaWFiaWxpZGFkZSBkYSBlbmVyZ2lhIGFybWF6ZW5hZGEgKEVBUikuIEEgc2lnbmlmaWPDom5jaWEgZXN0YXTDrXN0aWNhIGRvcyBzcGxpbmVzIMOpIGVsZXZhZGEgKHAgPCAwLjAwMSBwYXJhIHRvZG9zIG9zIHRlcm1vcyksIGUgYSBzdWF2aWRhZGUgZG9zIGVmZWl0b3MgbW9zdHJhIHBhZHLDtWVzIHJlYWxpc3RhczogcHJlY2lwaXRhw6fDo28gZXhlcmNlIGVmZWl0byBwb3NpdGl2byBtb25vdMO0bmljbyBzb2JyZSBhIEVBUjsgdGVtcGVyYXR1cmEgZXhpYmUgZm9ybWF0byBlbSBhcmNvIChlZmVpdG8gw7N0aW1vIHByw7N4aW1vIGEgMjAgwrBDLCBzZWd1aWRvIGRlIHF1ZWRhIG5vcyBleHRyZW1vcyk7IHVtaWRhZGUgZSB2ZW50byB0w6ptIGVmZWl0b3MgbW9kZXJhZG9zLCBtYXMgY29uc2lzdGVudGVzIGNvbSBtZWNhbmlzbW9zIGRlIGV2YXBvdHJhbnNwaXJhw6fDo28gZSByZWNhcmdhLiBPIHRlcm1vIHNhem9uYWwgKGRveSkgcmV2ZWxhIG8gY2ljbG8gaGlkcm9sw7NnaWNvIGFudWFsIGNhcmFjdGVyw61zdGljbyBkb3Mgc3Vic2lzdGVtYXMgYnJhc2lsZWlyb3MuDQoNCk9zIGRpYWduw7NzdGljb3MgZGUgcmVzw61kdW9zIGNvbmZpcm1hbSBxdWUgbyBtb2RlbG8gY2FwdHVyYSBhZGVxdWFkYW1lbnRlIGEgdGVuZMOqbmNpYSBtw6lkaWEgZSBhIHNhem9uYWxpZGFkZSwgbWFzIGV2aWRlbmNpYSBoZXRlcm9nZW5laWRhZGUgZXN0cnV0dXJhbCBlbnRyZSByZWdpbWVzIG9wZXJhY2lvbmFpcy4gTyBncsOhZmljbyBkZSByZXPDrWR1b3MgdmVyc3VzIHZhbG9yZXMgYWp1c3RhZG9zIG1vc3RyYSB0csOqcyBmYWl4YXMgZGVuc2FzLCBhc3NvY2lhZGFzIGEgZGlmZXJlbnRlcyBuw612ZWlzIGRlIGFybWF6ZW5hbWVudG8gKGJhaXhvLCBtw6lkaW8gZSBhbHRvKSwgc3VnZXJpbmRvIGEgcHJlc2Vuw6dhIGRlIGxpbWl0ZXMgZsOtc2ljb3MgZGUgb3BlcmHDp8OjbyBvdSB0cmFuc2nDp8O1ZXMgZW50cmUgZXN0w6FnaW9zIGRlIGVuY2hpbWVudG8gZSBlc3ZhemlhbWVudG8gZG9zIHJlc2VydmF0w7NyaW9zLiBPIGhpc3RvZ3JhbWEgZGUgcmVzw61kdW9zIMOpIGFwcm94aW1hZGFtZW50ZSBzaW3DqXRyaWNvIGUgY2VudHJhZG8gZW0gemVybywgZSBvIFFRLXBsb3QgaW5kaWNhIGxldmUgZGVzdmlvIG5hcyBjYXVkYXMsIG8gcXVlIMOpIGVzcGVyYWRvIGVtIHPDqXJpZXMgYW1iaWVudGFpcyBkZSBncmFuZGUgYW1wbGl0dWRlLiBBIGhvbW9nZW5laWRhZGUgZGUgdmFyacOibmNpYSDDqSBzYXRpc2ZhdMOzcmlhLCBzZW0gcGFkcsO1ZXMgc2lzdGVtw6F0aWNvcyBkZSBhdXRvY29ycmVsYcOnw6NvLCByZWZvcsOnYW5kbyBhIGFkZXF1YcOnw6NvIGRvIHVzbyBkYSBmYW3DrWxpYSBnYXVzc2lhbmEgY29tIGxpbmsgaWRlbnRpZGFkZS4NCg0KUG9yIGZpbSwgb3MgZWZlaXRvcyBhbGVhdMOzcmlvcyBwb3IgcmVzZXJ2YXTDs3JpbyBtb3N0cmFyYW0gYW1wbGEgZGlzcGVyc8OjbywgcmVmbGV0aW5kbyBkaWZlcmVuw6dhcyBlc3RydXR1cmFpcyBkZSBjYXBhY2lkYWRlIGUgb3BlcmHDp8OjbyBlbnRyZSB1c2luYXMuIEEgc3VhdmlkYWRlIGRvcyBzcGxpbmVzIGZvaSBhZGVxdWFkYSAoay1pbmRleCA+IDAuNiBwYXJhIHRvZG9zIG9zIHRlcm1vcyksIHNlbSBldmlkw6puY2lhcyBkZSBzdWJkaW1lbnNpb25hbWVudG8gZGUgY29tcGxleGlkYWRlLCBlIGEgYXVzw6puY2lhIGRlIGNvbmNvcnLDqm5jaWEgKGNvbmN1cnZpdHkpIHJlbGV2YW50ZSBpbmRpY2EgYmFpeGEgY29saW5lYXJpZGFkZSBlbnRyZSBvcyBlZmVpdG9zIGNsaW3DoXRpY29zLiBFbSBjb25qdW50bywgZXNzZXMgcmVzdWx0YWRvcyBzdXN0ZW50YW0gYSBwbGF1c2liaWxpZGFkZSBlc3RhdMOtc3RpY2EgZSBmw61zaWNhIGRvIG1vZGVsbyBjb21vIGJhc2VsaW5lIGNsaW3DoXRpY28gYXVkaXTDoXZlbC4gQXMgcHJpbmNpcGFpcyBsaW1pdGHDp8O1ZXMgcmVzaWRlbSBuYSBzdWF2aXphw6fDo28gZGUgZXh0cmVtb3MgaGlkcm9sw7NnaWNvcyBlIG5hIGxldmUgbsOjby1ub3JtYWxpZGFkZSBkb3MgcmVzw61kdW9zLCBhc3BlY3RvcyBjb211bnMgZW0gbW9kZWxvcyBhZ3JlZ2Fkb3MgZGUgZ3JhbmRlcyBzaXN0ZW1hcyBlIHF1ZSBwb2RlbSBzZXIgdHJhdGFkb3MgbmFzIGV0YXBhcyBzdWJzZXF1ZW50ZXMgY29tIGNvbnRyYWZhY3R1YWlzIGUgcHJvcGFnYcOnw6NvIGRlIGluY2VydGV6YS4NCg0KT3MgKiplZmVpdG9zIHBhcmNpYWlzKiogZXN0aW1hZG9zIHBlbG8gbW9kZWxvIGNvbmZpcm1hbSBwYWRyw7VlcyBjbGltw6F0aWNvcyBwbGF1c8OtdmVpcyBlIGZpc2ljYW1lbnRlIGNvZXJlbnRlcy4gQSBwcmVjaXBpdGHDp8OjbyBhcHJlc2VudGEgdW0gZWZlaXRvIG1vbm90b25pY2FtZW50ZSBjcmVzY2VudGUgc29icmUgYSBlbmVyZ2lhIGFybWF6ZW5hZGEsIGluZGljYW5kbyBxdWUgYXVtZW50b3MgYWN1bXVsYWRvcyBkZSBjaHV2YSB0w6ptIGltcGFjdG8gcG9zaXRpdm8gcXVhc2UgbGluZWFyIGF0w6kgbyBsaW1pdGUgc3VwZXJpb3Igb2JzZXJ2YWRvLCBzZW0gc2luYWlzIGRlIHNhdHVyYcOnw6NvIOKAlCB1bSByZXN1bHRhZG8gY29tcGF0w612ZWwgY29tIGEgcHJlZG9taW7Dom5jaWEgZGUgZ3JhbmRlcyByZXNlcnZhdMOzcmlvcyBkZSByZWd1bGFyaXphw6fDo28gbm8gc2lzdGVtYS4gQSB0ZW1wZXJhdHVyYSwgcG9yIHN1YSB2ZXosIGV4aWJlIHVtYSByZWxhw6fDo28gZW0gZm9ybWEgZGUgYXJjbzogb3MgbsOtdmVpcyBpbnRlcm1lZGnDoXJpb3MgKGVtIHRvcm5vIGRlIDIwIMKwQykgZXN0w6NvIGFzc29jaWFkb3MgYW8gbWFpb3IgYXJtYXplbmFtZW50bywgZW5xdWFudG8gdGVtcGVyYXR1cmFzIGV4dHJlbWFzIHJlZHV6ZW0gbyBzYWxkbyBlbmVyZ8OpdGljbywgcmVmbGV0aW5kbyBvIHBhcGVsIGRhIGV2YXBvcmHDp8OjbyBlIGRhIGVmaWNpw6puY2lhIGRvIGNpY2xvIGhpZHJvbMOzZ2ljby4gQSB1bWlkYWRlIG1vc3RyYSBsZXZlIGVmZWl0byBwb3NpdGl2byBhdMOpIGNlcnRvIHBvbnRvLCBzZWd1aWRvIGRlIHJldmVyc8Ojbywgc3VnZXJpbmRvIGludGVyYcOnw6NvIGNvbSByZWdpbWVzIGRlIGNodXZhIHBlcnNpc3RlbnRlLCBlbnF1YW50byBhIHZlbG9jaWRhZGUgZG8gdmVudG8gYXByZXNlbnRhIHVtIGVmZWl0byBuZWdhdGl2byBzdWF2ZSwgcG9zc2l2ZWxtZW50ZSBsaWdhZG8gw6AgbWFpb3IgcGVyZGEgcG9yIGV2YXBvdHJhbnNwaXJhw6fDo28gZSBhbyB0cmFuc3BvcnRlIGRlIG1hc3NhcyBzZWNhcy4gTyBjb21wb25lbnRlIHNhem9uYWwgKGRveSkgcmV2ZWxhIG8gY2ljbG8gYW51YWwgdMOtcGljbyBkbyByZWdpbWUgcGx1dmlhbCBicmFzaWxlaXJvLCBjb20gcGljb3MgZW50cmUgb3MgZGlhcyAxMDDigJMxNTAgKG91dG9ubykgZSBtw61uaW1vcyBwcsOzeGltb3MgYW8gZmluYWwgZG8gYW5vLiBQb3IgZmltLCBvcyBlZmVpdG9zIGFsZWF0w7NyaW9zIHBvciByZXNlcnZhdMOzcmlvIG1vc3RyYW0gaGV0ZXJvZ2VuZWlkYWRlIGV4cHJlc3NpdmEsIGluZGljYW5kbyBxdWUgZGlmZXJlbsOnYXMgZXN0cnV0dXJhaXMgZGUgY2FwYWNpZGFkZSBlIGxvY2FsaXphw6fDo28gY29uZGljaW9uYW0gYSByZXNwb3N0YSBjbGltw6F0aWNhIOKAlCB1bSBhY2hhZG8gcXVlIHJlZm9yw6dhIGEgbmVjZXNzaWRhZGUgZGUgYWJvcmRhZ2VucyByZWdpb25hbGl6YWRhcyBuYXMgZXRhcGFzIHNlZ3VpbnRlcyBkYSBtb2RlbGFnZW0uDQoNCg0KDQpgYGB7cn0NCiNzYXZlUkRTKG0xX2dhbSwgIm0xX2dhbS5yZHMiKQ0KI3JlYWRSRFMoIm0xX2dhbS5yZHMiKSAtPiBtMV9nYW0NCg0KYGBgDQoNCiMjIyMgUHJlZGnDp8O1ZXMgZmFjdHVhbCB2cy4gY29udHJhZmFjdHVhbCAoYmFzZWxpbmUgMjAwMeKAkzIwMDUpDQpDb25zdHJ1w61tb3MgbyBjb250cmFmYWN0dWFsIGNsaW3DoXRpY28gZml4YW5kbyBjbGltYSBubyAqKm3DqWRpbyBtZW5zYWwgMjAwMeKAkzIwMDUqKiBwb3IgcmVzZXJ2YXTDs3JpbyAob3UgcG9yIHN1YnNpc3RlbWEsIGNhc28gcHJlZmlyYSkgZSBtYW50ZW5kbyBvcyBkZW1haXMgY29udHJvbGVzIG9ic2VydmFkb3MuDQoNCg0KDQpgYGB7cn0NCiMgQmFzZWxpbmUgY2xpbcOhdGljbyBwb3IgcmVzZXJ2YXTDs3JpbyBlIG3DqnMgKDIwMDHigJMyMDA1KTsgYWp1c3RlIHNlIHByZWZlcmlyIHBvciBzdWJzaXN0ZW1hDQpjbGltX2Jhc2VsaW5lIDwtIHJlc2VydiAlPiUNCiAgZmlsdGVyKHllYXIoZGF0ZSkgPj0gMjAwMSwgeWVhcihkYXRlKSA8PSAyMDA1KSAlPiUNCiAgZ3JvdXBfYnkoaWRfcmVzZXJ2YXRvcmlvLngsIGRveSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBsX3ByZWNpcF9ibCA9IG1lYW4obF9wcmVjaXAsIG5hLnJtID0gVFJVRSksDQogICAgbF90ZW1wX2JsICAgPSBtZWFuKGxfdGVtcCwgICBuYS5ybSA9IFRSVUUpLA0KICAgIGxfaHVtaWRpdHlfYmwgPSBtZWFuKGxfaHVtaWRpdHksIG5hLnJtID0gVFJVRSksDQogICAgbF93aW5kX3NwZWVkX2JsICAgICA9IG1lYW4obF93aW5kX3NwZWVkLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIG5ld2RhdGEgZmFjdHVhbCAob2JzZXJ2YWRvKSBlIGNvbnRyYWZhY3R1YWwgKGNsaW1hIGZpeG8gbm8gYmFzZWxpbmUpDQpuZF9vYnMgPC0gcmVzZXJ2ICMlPiUgdW5ncm91cCgpICU+JSANCiAjc2VsZWN0KGlkX3Jlc2VydmF0b3Jpby54LCBub21fc3Vic2lzdGVtYS54LCBkYXRlLCBkb3ksIG1vbnRoLA0KICAjICAgICAgIGxfcHJlY2lwLCBsX3RlbXAsIGxfaHVtaWRpdHksIGxfd2luZF9zcGVlZCkNCg0KbmRfY2YgPC0gcmVzZXJ2ICU+JQ0KICBsZWZ0X2pvaW4oY2xpbV9iYXNlbGluZSwgYnkgPSBjKCJpZF9yZXNlcnZhdG9yaW8ueCIsImRveSIpKSAlPiUNCiAgbXV0YXRlKA0KICAgIGxfcHJlY2lwID0gbF9wcmVjaXBfYmwsDQogICAgbF90ZW1wICAgPSBsX3RlbXBfYmwsDQogICAgbF9odW1pZGl0eSA9IGxfaHVtaWRpdHlfYmwsDQogICAgbF93aW5kX3NwZWVkPSBsX3dpbmRfc3BlZWRfYmwNCiAgKSAjJT4lDQogICNzZWxlY3QobmFtZXMocmVzZXJ2KSkNCg0KIyBQcmVkacOnw7VlcyBubyBuw612ZWwgKE1Xwrdtw6pzKQ0KcmVzZXJ2JGVhcl9oYXRfb2JzIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gcmVzZXJ2LCB0eXBlID0gInJlc3BvbnNlIikNCnJlc2VydiRlYXJfaGF0X2NmICA8LSBwcmVkaWN0KG0xX2dhbSwgbmV3ZGF0YSA9IG5kX2NmLCAgdHlwZSA9ICJyZXNwb25zZSIpDQoNCiMgUGVuYWxpZGFkZSBjbGltw6F0aWNhIG5vIEVBUiAocG9udHVhbCkNCnJlc2VydiRkZWx0YV9lYXJfaGF0IDwtIHJlc2VydiRlYXJfaGF0X29icyAtIHJlc2VydiRlYXJfaGF0X2NmDQpkZWx0YV9lYXJfaGF0IDwtIHJlc2VydiRlYXJfaGF0X29icyAtIHJlc2VydiRlYXJfaGF0X2NmDQpgYGANCg0KIyMgMy4xLjUgUHJvcGFnYcOnw6NvIGRlIEluY2VydGV6YQ0KUGFyYSBxdWFudGlmaWNhciBhIGluY2VydGV6YSBhc3NvY2lhZGEgw6BzIGVzdGltYXRpdmFzIGRlIHBlbmFsaWRhZGUgY2xpbcOhdGljYSAozpRFQVIpLCBmb3JhbSBhcGxpY2Fkb3MgZG9pcyBtw6l0b2RvcyBjb21wbGVtZW50YXJlczogbyBEZWx0YSBNZXRob2QgYW5hbMOtdGljbyBlIGEgU2ltdWxhw6fDo28gUGFyYW3DqXRyaWNhIE11bHRpdmFyaWFkYS4gTyBwcmltZWlybyBmb3JuZWNlIGludGVydmFsb3MgZGUgY29uZmlhbsOnYSBwb250dWFpcyBiYXNlYWRvcyBuYSBtYXRyaXogZGUgY292YXJpw6JuY2lhIGRvcyBjb2VmaWNpZW50ZXMgZG8gbW9kZWxvOyBvIHNlZ3VuZG8gcGVybWl0ZSBwcm9wYWdhciBpbnRlZ3JhbG1lbnRlIGEgaW5jZXJ0ZXphIHBhcmFtw6l0cmljYSBhbyBsb25nbyBkYSBjYWRlaWEgZGUgZXN0aW1hw6fDo28sIGdlcmFuZG8gZGlzdHJpYnVpw6fDtWVzIGVtcMOtcmljYXMgcGFyYSBjYWRhIHN1YnNpc3RlbWEgZSBhbm8uDQoNCk5vIERlbHRhIE1ldGhvZCwgYSBpbmNlcnRlemEgw6kgY2FsY3VsYWRhIHBlbGEgbWF0cml6IGRlIGRlc2VuaG8gZG8gbW9kZWxvICggJCBYX3tvYnN9IC0gWF97Y2Z9JCksIG11bHRpcGxpY2FkYSBwZWxhIG1hdHJpeiBkZSBjb3ZhcmnDom5jaWEgZG9zIHBhcsOibWV0cm9zICgkVl/wnZu9JCksIGNvbmZvcm1lICRWYXIozpRFKT0gWChWX/Cdm70pWCckLiBFc3NhIGFib3JkYWdlbSBmb3JuZWNlIGVzdGltYXRpdmFzIGNvbnNpc3RlbnRlcyBwYXJhIGludGVydmFsb3MgZGUgOTUlIGRlIGNvbmZpYW7Dp2EgZSBwZXJtaXRlIGFncmVnYXIgcmVzdWx0YWRvcyBwcmVzZXJ2YW5kbyBhcyBjb3ZhcmnDom5jaWFzIGVudHJlIG9ic2VydmHDp8O1ZXMuIE8gbcOpdG9kbyDDqSBjb21wdXRhY2lvbmFsbWVudGUgZWZpY2llbnRlIGUgw7p0aWwgcGFyYSBnZXJhciBpbnRlcnZhbG9zIGFuYWzDrXRpY29zIGNvbXBhcsOhdmVpcyBlbnRyZSBzdWJzaXN0ZW1hcy4NCg0KQSBTaW11bGHDp8OjbyBQYXJhbcOpdHJpY2EgYW1wbGlhIGVzc2EgYWJvcmRhZ2VtIGFvIGFtb3N0cmFyIG1pbGhhcmVzIGRlIHZldG9yZXMgZGUgY29lZmljaWVudGVzICgNCiTwnZu9Xnso8J2RoCl94oi88J2RgShcaGF0e1xiZXRhfSzwnZGJ8J2bvSkkIGUgcmVjYWxjdWxhciAkzpQg8J2QuPCdkLTwnZGFXnso8J2RoCl9JCBwYXJhIGNhZGEgYW1vc3RyYS4gQSBhZ3JlZ2HDp8OjbyBkb3MgcmVzdWx0YWRvcyBwb3Igc3Vic2lzdGVtYSBlIGFubyBmb3JuZWNlIGRpc3RyaWJ1acOnw7VlcyBlbXDDrXJpY2FzIGRhIHBlbmFsaWRhZGUgY2xpbcOhdGljYSwgZXhwcmVzc2FzIHBvciBmYW4gY2hhcnRzIChGaWd1cmEgYWJhaXhvKS4gT3MgcmVzdWx0YWRvcyBpbmRpY2FtIHRlbmTDqm5jaWEgbmVnYXRpdmEgY3Jlc2NlbnRlIGRhIGVuZXJnaWEgYXJtYXplbmFkYSBhanVzdGFkYSBhbyBjbGltYSBtw6lkaW8sIGNvbSBmb3J0ZSBxdWVkYSBhcMOzcyAyMDEwIGUgcGljb3MgZGUgaW5jZXJ0ZXphIGVtIDIwMTTigJMyMDE2LiBBcyByZWdpw7VlcyBTdWRlc3RlIGUgU3VsIGNvbmNlbnRyYW0gb3MgbWFpb3JlcyBkw6lmaWNpdHMgbcOpZGlvcyAoYXTDqSDigJM1IGUg4oCTMSBtaWxow7VlcyBkZSBNV8K3bcOqcywgcmVzcGVjdGl2YW1lbnRlKSwgZW5xdWFudG8gTm9yZGVzdGUgZSBOb3J0ZSBhcHJlc2VudGFtIHBlbmFsaWRhZGVzIG1lbm9yZXMsIHBvcsOpbSBjb20gYXVtZW50byBwcm9ncmVzc2l2byBhbyBmaW5hbCBkYSBzw6lyaWUuIEVzc2EgY29uc2lzdMOqbmNpYSBlbnRyZSBvcyBkb2lzIG3DqXRvZG9zIGNvbmZpcm1hIGEgcm9idXN0ZXogZXN0YXTDrXN0aWNhIGRvIG1vZGVsbyBlIGVzdGFiZWxlY2UgdW1hIGJhc2UgY29uZmnDoXZlbCBwYXJhIGEgZXRhcGEgc2VndWludGUgZGUgcHJvcGFnYcOnw6NvIGRlIGluY2VydGV6YSBuYSBnZXJhw6fDo28gaGlkcmVsw6l0cmljYS4NCg0KDQoNCiMjIyMgSW5jZXJ0ZXphIChtw6l0b2RvIDQ6ICoqRGVsdGEgbWV0aG9kKiogYW5hbMOtdGljbykNCkVzdGltYW1vcyBJQ3MgcGFyYSBcKFxEZWx0YSBFQVJcKSB2aWEgbWF0cml6IGRlIGRlc2VuaG8gbm8gKipsaW5rKiogKGFxdWksIGlkZW50aXR5IOKHkiBqw6Egw6kgbsOtdmVsKS4gQWdyZWdhw6fDtWVzIHBvciBhbm8vc3Vic2lzdGVtYSBkZXZlbSBwcmVzZXJ2YXIgYSBjb3ZhcmnDom5jaWEuDQpgYGB7ciBtMS1kZWx0YS1tZXRob2QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpWcCAgICAgIDwtIHZjb3YobTFfZ2FtKSAgIyBjb3ZhcmnDom5jaWEgZG9zIGNvZWZpY2llbnRlcw0KWF9vYnMgICA8LSBwcmVkaWN0KG0xX2dhbSwgbmV3ZGF0YSA9IG5kX29icywgdHlwZSA9ICJscG1hdHJpeCIpDQpYX2NmICAgIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfY2YsICB0eXBlID0gImxwbWF0cml4IikNClhfZGlmZiAgPC0gWF9vYnMgLSBYX2NmDQoNCiMgRVAgcG9yIG9ic2VydmHDp8Ojbw0KdmFyX2RlbHRhIDwtIHJvd1N1bXMoKFhfZGlmZiAlKiUgVnApICogWF9kaWZmKQ0Kc2VfZGVsdGEgIDwtIHNxcnQocG1heCh2YXJfZGVsdGEsIDApKQ0KeiAgICAgICAgIDwtIHFub3JtKDAuOTc1KQ0KDQpkZWx0YV9sd3IgPC0gcmVzZXJ2JGRlbHRhX2Vhcl9oYXQgLSB6ICogc2VfZGVsdGENCmRlbHRhX3VwciA8LSByZXNlcnYkZGVsdGFfZWFyX2hhdCArIHogKiBzZV9kZWx0YQ0KcmVzZXJ2JGRlbHRhX2Vhcl91cHI8LWRlbHRhX3Vwcg0KcmVzZXJ2JGRlbHRhX2Vhcl9sd3I8LWRlbHRhX2x3cg0KbTFfZGVsdGEgPC0gbmRfb2JzICU+JQ0KICB0cmFuc211dGUoDQogICAgZGF0ZSwgbm9tX3N1YnNpc3RlbWEueCwNCiAgICBkZWx0YV9oYXQgPSBkZWx0YV9lYXJfaGF0LA0KICAgIGRlbHRhX3NlICA9IHNlX2RlbHRhLA0KICAgIGRlbHRhX2x3ciA9IGRlbHRhX2x3ciwNCiAgICBkZWx0YV91cHIgPSBkZWx0YV91cHINCiAgKQ0KDQojIEFncmVnYXIgcG9yIGFuby9zdWJzaXN0ZW1hIHByZXNlcnZhbmRvIGNvdmFyacOibmNpYSAoY29tYmluYcOnw6NvIGxpbmVhcikNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmR0IDwtIGFzLmRhdGEudGFibGUobmRfb2JzKVssIC4oZGF0ZSwgbm9tX3N1YnNpc3RlbWEueCldDQpkdFssIHllYXIgOj0geWVhcihkYXRlKV0NCg0KIyBWZXRvciBzX2cgPSBzb21hIGRhcyBsaW5oYXMgZGUgWF9kaWZmIG5vIGdydXBvIChhbm8sIHN1YnNpc3RlbWEpDQpncm91cHMgPC0gdW5pcXVlKGR0WywgLih5ZWFyLCBub21fc3Vic2lzdGVtYS54KV0pDQpTIDwtIGxhcHBseSgxOm5yb3coZ3JvdXBzKSwgZnVuY3Rpb24oZyl7DQogIGlkeCA8LSB3aGljaChkdCR5ZWFyID09IGdyb3VwcyR5ZWFyW2ddICYgZHQkbm9tX3N1YnNpc3RlbWEueCA9PSBncm91cHMkbm9tX3N1YnNpc3RlbWEueFtnXSkNCiAgY29sU3VtcyhYX2RpZmZbaWR4LCAsIGRyb3AgPSBGQUxTRV0pDQp9KQ0KDQphZ2dfbWVhbiA8LSBzYXBwbHkoMTpucm93KGdyb3VwcyksIGZ1bmN0aW9uKGcpew0KICBzdW0ocmVzZXJ2JGRlbHRhX2Vhcl9oYXRbZHQkeWVhciA9PSBncm91cHMkeWVhcltnXSAmIGR0JG5vbV9zdWJzaXN0ZW1hLnggPT0gZ3JvdXBzJG5vbV9zdWJzaXN0ZW1hLnhbZ11dLCBuYS5ybSA9IFRSVUUpDQp9KQ0KYWdnX3ZhciAgPC0gc2FwcGx5KFMsIGZ1bmN0aW9uKHN2KSBhcy5udW1lcmljKHQoc3YpICUqJSBWcCAlKiUgc3YpKQ0KYWdnX3NlICAgPC0gc3FydChwbWF4KGFnZ192YXIsIDApKQ0KDQptMV9kZWx0YV9hZ2cgPC0gY2JpbmQoZ3JvdXBzLA0KICBkZWx0YV9tZWFuID0gYWdnX21lYW4sDQogIGRlbHRhX2x3ciAgPSBhZ2dfbWVhbiAtIHogKiBhZ2dfc2UsDQogIGRlbHRhX3VwciAgPSBhZ2dfbWVhbiArIHogKiBhZ2dfc2UNCikNCmBgYA0KDQojIyMjIEluY2VydGV6YSAobcOpdG9kbyAxOiAqKlNpbXVsYcOnw6NvIHBhcmFtw6l0cmljYSoqIGVuY2FkZcOhdmVsKQ0KQW1vc3RyYW1vcyBvcyBjb2VmaWNpZW50ZXMgZGEgZGlzdHJpYnVpw6fDo28gbm9ybWFsIG11bHRpdmFyaWFkYSBlIHJlY2FsY3VsYW1vcyBcKFxEZWx0YSBFQVJeeyhzKX1cKS4gRXNzZSBvYmpldG8gc2Vyw6EgYSAqKmVudHJhZGEgcHJvYmFiaWzDrXN0aWNhKiogcGFyYSBvIEdBTSAxLg0KDQpgYGB7ciBtMS1tb250ZWNhcmxvLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShNQVNTKQ0KbnNpbSA8LSAyMDAwDQpzZXQuc2VlZCgyMDI1MTAxMCkNCg0KYmV0YV9kcmF3cyA8LSBNQVNTOjptdnJub3JtKG4gPSBuc2ltLCBtdSA9IGNvZWYobTFfZ2FtKSwgU2lnbWEgPSBWcCkNCg0KIyBQcsOpLWPDoWxjdWxvIHBhcmEgZWZpY2nDqm5jaWENCkQgPC0gWF9kaWZmICAgICAgICAgICAgICMgTiB4IHANCiMgzpRFQVIgcG9yIHNpbXVsYcOnw6NvOiBjYWRhIGNvbHVuYSDDqSB1bWEgc2ltLCBjYWRhIGxpbmhhIHVtYSBvYnNlcnZhw6fDo28NCmRlbHRhX3NpbXMgPC0gRCAlKiUgdChiZXRhX2RyYXdzKSAgICMgKE4geCBuc2ltKQ0KDQojIEFncmVnYXIgcG9yIGFuby9zdWJzaXN0ZW1hIGVtIGNhZGEgc2ltDQpkdCRnaWQgPC0gLkdSUDsgZHRbLCBnaWQgOj0gLkdSUCwgYnkgPSAuKHllYXIsIG5vbV9zdWJzaXN0ZW1hLngpXQ0KRyA8LSBtYXgoZHQkZ2lkKQ0KDQphZ2dfbWF0IDwtIG1hdHJpeChOQV9yZWFsXywgbnJvdyA9IEcsIG5jb2wgPSBuc2ltKQ0KZm9yIChnIGluIDE6Rykgew0KICBpZHggPC0gd2hpY2goZHQkZ2lkID09IGcpDQogIGFnZ19tYXRbZywgXSA8LSBjb2xTdW1zKGRlbHRhX3NpbXNbaWR4LCAsIGRyb3AgPSBGQUxTRV0sIG5hLnJtID0gVFJVRSkNCn0NCg0KbTFfc2ltX2FnZyA8LSBjYmluZChncm91cHMsDQogIG1lYW4gPSByb3dNZWFucyhhZ2dfbWF0KSwNCiAgbHdyICA9IGFwcGx5KGFnZ19tYXQsIDEsIHF1YW50aWxlLCAwLjAyNSksDQogIHVwciAgPSBhcHBseShhZ2dfbWF0LCAxLCBxdWFudGlsZSwgMC45NzUpDQopDQoNCmBgYA0KIyMjIyBWaXN1YWxpemHDp8OjbyByw6FwaWRhIChwdWJsaWNhw6fDo28pDQpSaWJib25zIChEZWx0YSkgZSBmYW4gY2hhcnRzIChNQykgcGFkcm9uaXphZG9zLg0KDQoNCmBgYHtyIG0xLXBsb3RzLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBSaWJib24gKERlbHRhKQ0KbTFfZGVsdGFfYWdnICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZGVsdGFfbWVhbi8xMDAwKSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IGRlbHRhX2x3ci8xMDAwLCB5bWF4ID0gZGVsdGFfdXByLzEwMDApLCBhbHBoYSA9IC4yNSwgZmlsbCA9ICJmaXJlYnJpY2siKSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJDbGltYXRlIHBlbmFsdHkgb24gc3RvcmVkIGVuZXJneSAozpRFQVIpIOKAlCBEZWx0YSBtZXRob2QiLA0KICAgICAgIHkgPSAizpRFQVIgKEdXwrdtb250aCkiLCB4ID0gIlllYXIiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIEZhbiBjaGFydCAoTUMpDQptMV9zaW1fYWdnICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbWVhbi8xMDAwKSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IGx3ci8xMDAwLCB5bWF4ID0gdXByLzEwMDApLCBhbHBoYSA9IC4yNSwgZmlsbCA9ICJzdGVlbGJsdWUiKSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJDbGltYXRlIHBlbmFsdHkgb24gc3RvcmVkIGVuZXJneSAozpRFQVIpIOKAlCBQYXJhbWV0cmljIHNpbXVsYXRpb24iLA0KICAgICAgIHkgPSAizpRFQVIgKEdXwrdtb250aCkiLCB4ID0gIlllYXIiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpQZW5hbGlkYWRlIGNsaW3DoXRpY2EgYWdyZWdhZGEgZSBpbnRlcnZhbG9zIGRlIGNvbmZpYW7Dp2ENCmBgYHtyfQ0KbTFfc3VtbWFyeSA8LSBtMV9zaW1fYWdnICU+JQ0KICBncm91cF9ieShub21fc3Vic2lzdGVtYS54KSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fcGVuYWx0eSA9IG1lYW4obWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgICBsd3JfOTUgPSBtZWFuKGx3ciwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHJfOTUgPSBtZWFuKHVwciwgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9wZW5hbHR5ID0gc2QobWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KIyBDb252ZXJ0ZW5kbyBwYXJhIEdXaC9hbm8gcGFyYSBpbnRlcnByZXRhw6fDo28NCm0xX3N1bW1hcnkgPC0gbTFfc3VtbWFyeSAlPiUNCiAgbXV0YXRlKA0KICAgIG1lYW5fR1doID0gbWVhbl9wZW5hbHR5IC8gMTAwMCwNCiAgICBsd3JfR1doICA9IGx3cl85NSAvIDEwMDAsDQogICAgdXByX0dXaCAgPSB1cHJfOTUgLyAxMDAwLA0KICApICMlPiUgc2VsZWN0KC1tZWFuX3BlbmFsdHksIC1sd3JfOTUsIC11cHJfOTUpDQoNCiMgVGFiZWxhIGZvcm1hdGFkYSAocHVibGljYcOnw6NvKQ0KbGlicmFyeShndCkNCm0xX3N1bW1hcnlbLGMoIm5vbV9zdWJzaXN0ZW1hLngiLCJtZWFuX0dXaCIsImx3cl9HV2giLCAidXByX0dXaCIpXSAlPiUgamFuaXRvcjo6YWRvcm5fdG90YWxzKCkgJT4lIA0KICBndCgpICU+JQ0KICBmbXRfbnVtYmVyKGNvbHVtbnMgPSAyOjQsIGRlY2ltYWxzID0gMSkgJT4lDQogIGNvbHNfbGFiZWwoDQogICAgbm9tX3N1YnNpc3RlbWEueCA9ICJTdWJzeXN0ZW0iLA0KICAgIG1lYW5fR1doID0gIk1lYW4gzpRFQVIgKEdXaCkiLA0KICAgIGx3cl9HV2ggID0gIkxvd2VyIDk1JSIsDQogICAgdXByX0dXaCAgPSAiVXBwZXIgOTUlIiwNCiAgKSAlPiUNCiAgdGFiX2hlYWRlcigNCiAgICB0aXRsZSA9IG1kKCIqKkFnZ3JlZ2F0ZSBjbGltYXRlIHBlbmFsdHkgb24gc3RvcmVkIGVuZXJneSAoMjAwMeKAkzIwMTgpKioiKSwNCiAgICBzdWJ0aXRsZSA9ICJTaW11bGF0ZWQgbWVhbiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHBlciBzdWJzeXN0ZW0iDQogICkNCmBgYA0KQSBUYWJlbGEgYXByZXNlbnRhIGEgKipwZW5hbGlkYWRlIGNsaW3DoXRpY2EgbcOpZGlhIHNvYnJlIGEgZW5lcmdpYSBhcm1hemVuYWRhICjOlEVBUikqKiBubyBwZXLDrW9kbyAyMDAx4oCTMjAxOCwgYWdyZWdhZGEgcG9yIHN1YnNpc3RlbWEuIE9zIHZhbG9yZXMgZm9yYW0gZXN0aW1hZG9zIGEgcGFydGlyIGRhcyBkaXN0cmlidWnDp8O1ZXMgb2J0aWRhcyB2aWEgc2ltdWxhw6fDo28gcGFyYW3DqXRyaWNhIGRlIDIuMDAwIHNvcnRlaW9zIGRhIG1hdHJpeiBkZSBjb3ZhcmnDom5jaWEgZG9zIGNvZWZpY2llbnRlcyBkbyBtb2RlbG8gaGlkcm9sw7NnaWNvLiBBcyBwZW5hbGlkYWRlcyBtw6lkaWFzIGZvcmFtIGV4cHJlc3NhcyBlbSBnaWdhd2F0dHMtbcOqcyAoR1dowrdtb250aCksIGNvbSBpbnRlcnZhbG9zIGRlIGNvbmZpYW7Dp2EgZGUgOTUlIGNvbSB1bSB0b3RhbCBkZSAqKuKAkzEsNjA2LjMgKElDOTUlOiDiiJIxLDc0Ni4yO+KIkjEsNDcwLjIpICBkZSBHV2guDQoNCk9zIHJlc3VsdGFkb3MgaW5kaWNhbSBxdWUgbyAqKnN1YnNpc3RlbWEgU3VkZXN0ZSoqIGNvbmNlbnRyYSBvIG1haW9yIGTDqWZpY2l0IG3DqWRpbyBkZSBhcm1hemVuYW1lbnRvLCBlc3RpbWFkbyBlbSBhcHJveGltYWRhbWVudGUgKiriiJIxLDE3OC40CSAoSUM5NSU64oiSMSwyNjIuNDviiJIxLDA5Ny40KSAgZGUgR1dowrdtw6pzKiosIHJlZmxldGluZG8gc3VhIHByZWRvbWluw6JuY2lhIG5vIHNpc3RlbWEgaW50ZXJsaWdhZG8gZSBzdWEgbWFpb3IgZXhwb3Npw6fDo28gYSBhbm9tYWxpYXMgZGUgcHJlY2lwaXRhw6fDo28uIE8gKipTdWwqKiBhcHJlc2VudGEgcGVuYWxpZGFkZSBpbnRlcm1lZGnDoXJpYSAoWFhYWFhYWFhYWFhYKSwgbWFzIGNvbSBtYWlvciB2YXJpYWJpbGlkYWRlIGludGVyYW51YWwsIGNvbXBhdMOtdmVsIGNvbSBzZXUgcmVnaW1lIHBsdXZpb23DqXRyaWNvIG1haXMgaXJyZWd1bGFyLiBObyAqKk5vcmRlc3RlKiosIGFzIHBlcmRhcyBtw6lkaWFzIHPDo28gbWVub3JlcyAoWFhYWFhYWFhYWFhYWFgpLCBlbWJvcmEgY29tIHRlbmTDqm5jaWEgbmVnYXRpdmEgYWNlbnR1YWRhIGFww7NzIDIwMTAuIErDoSBvICoqTm9ydGUqKiBhcHJlc2VudGEgdmFsb3JlcyBwcsOzeGltb3MgZGUgemVybywgY29tIGludGVydmFsb3MgZGUgY29uZmlhbsOnYSBxdWUgaW5jbHVlbSBhIG51bGlkYWRlLCBzdWdlcmluZG8gYXVzw6puY2lhIGRlIHBlbmFsaWRhZGUgbMOtcXVpZGEgc2lnbmlmaWNhdGl2YSBubyBwZXLDrW9kbyBhbmFsaXNhZG8uDQoNCkVzc2VzIHJlc3VsdGFkb3MgY29ycm9ib3JhbSBhIGhpcMOzdGVzZSBkZSBxdWUgYSAqKnBlbmFsaWRhZGUgY2xpbcOhdGljYSBzb2JyZSBvIGFybWF6ZW5hbWVudG8gaMOtZHJpY28gw6kgY29uY2VudHJhZGEgZSBlc3RydXR1cmFsbWVudGUgYXNzaW3DqXRyaWNhKiosIGFmZXRhbmRvIGNvbSBtYWlvciBpbnRlbnNpZGFkZSBvcyBzdWJzaXN0ZW1hcyBTdWRlc3RlIGUgU3VsIOKAlCBqdXN0YW1lbnRlIGFxdWVsZXMgY29tIG1haW9yIHBhcGVsIGRlIHJlZ3VsYcOnw6NvIGUgc3Vwb3J0ZSBlbmVyZ8OpdGljbyBwYXJhIG8gcmVzdGFudGUgZG8gcGHDrXMuIEVzc2EgaGV0ZXJvZ2VuZWlkYWRlIGVzcGFjaWFsIGZvcm5lY2UgbyBlbG8gZW1ww61yaWNvIHBhcmEgYSBwcsOzeGltYSBldGFwYSBkYSBtb2RlbGFnZW0sIGVtIHF1ZSBhcyB2YXJpYcOnw7VlcyBzaW11bGFkYXMgZGUgXCggXERlbHRhIEVBUiBcKSBzZXLDo28gcHJvcGFnYWRhcyDDoCBnZXJhw6fDo28gaGlkcmVsw6l0cmljYSAoR0FNIDEpLCDDoCBnZXJhw6fDo28gdMOpcm1pY2EgKEdBTSAyKSBlLCBwb3IgZmltLCBhbyBwcmXDp28gZGUgY3VydG8gcHJhem8gKEdBTSAzKS4NCg0KDQozLjIgTW9kZWxvIDIg4oCUIEdlcmHDp8OjbyBIaWRyZWzDqXRyaWNhIGNvbW8gRnVuw6fDo28gZG8gQXJtYXplbmFtZW50bw0KTyBzZWd1bmRvIG1vZGVsbyBkYSBjYWRlaWEgZXN0aW1hIGEgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2EgKEdfaGlkcm8pIGVtIGZ1bsOnw6NvIGRhIGVuZXJnaWEgYXJtYXplbmFkYSAoRUFSKSBlIGRlIGNvbnRyb2xlcyBvcGVyYWNpb25haXMgZSBzYXpvbmFpcy4gTyBvYmpldGl2byDDqSBjYXB0dXJhciBhIGVsYXN0aWNpZGFkZSBkYSBnZXJhw6fDo28gZW0gcmVsYcOnw6NvIGFvIGVzdG9xdWUgaMOtZHJpY28sIHBlcm1pdGluZG8gdHJhZHV6aXIgYXMgdmFyaWHDp8O1ZXMgc2ltdWxhZGFzIGRlIM6URUFSIChwZW5hbGlkYWRlIGNsaW3DoXRpY2EpIGVtIGltcGFjdG9zIHNvYnJlIGEgZ2VyYcOnw6NvIGVmZXRpdmEuIEFzc2ltIGNvbW8gbm8gbW9kZWxvIGNsaW3DoXRpY28sIGVtcHJlZ2Etc2UgdW0gR0FNIHBhcmEgY2FwdHVyYXIgcmVsYcOnw7VlcyBuw6NvIGxpbmVhcmVzIGVudHJlIHZhcmnDoXZlaXMgZsOtc2ljYXMgZSBvcGVyYWNpb25haXMsIG1hbnRlbmRvIHBhcmNpbcO0bmlhIGUgaW50ZXJwcmV0YWJpbGlkYWRlLg0KDQoNCg0KIyAzLjIgTW9kZWxvIDIg4oCUIEdlcmHDp8OjbyBIaWRyZWzDqXRyaWNhIGNvbW8gRnVuw6fDo28gZG8gQXJtYXplbmFtZW50bw0KDQpgYGB7cn0NCg0KbTJfaGlkcm8gPC0gYmFtKA0KICB2YWxfZ2VyYWNhbyB+ICBZZWFyKw0KICAgIHMoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMsIGsgPSA0KSsNCiAgICBzKHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hLCBrID0gNCkrDQogICAgcyhkb3ksIGJzID0gImNjIiwgayA9IDIpICsgICAgICMgc2F6b25hbGlkYWRlIGRvIGRpYSBkbyBhbm8gKGPDrWNsaWNhKQ0KICAgIHMoaWRfcmVzZXJ2YXRvcmlvLngsIGJzID0gInJlIikrIyBlZmVpdG8gYWxlYXTDs3JpbyBwb3IgcmVzZXJ2YXTDs3Jpbw0KICAgI3ModmFsX3ZhemFvZGVmbHVlbnRlLGsgPSAyKSsNCg0KICAgIG5vbV9zdWJzaXN0ZW1hLngNCiAgLA0KICBkYXRhICAgICA9IHJlc2VydiwNCiAgbWV0aG9kICAgPSAiZlJFTUwiLA0KICBkaXNjcmV0ZSA9IFRSVUUsDQogIGZhbWlseSAgID0gZ2F1c3NpYW4oKSwgICAgICAgICAgICAjIGZhbcOtbGlhOiBub3JtYWw7IGFqdXN0YXIgc2UgbmVjZXNzw6FyaW8NCiAgbmEuYWN0aW9uPSBuYS5leGNsdWRlLA0KICAja25vdHMgICAgPSBsaXN0KGRveSA9IGMoMC41LCAzNjYuNSkpDQopDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KG0yX2hpZHJvKQ0KZ2FtLmNoZWNrKG0yX2hpZHJvKQ0KY29uY3Vydml0eShtMl9oaWRybywgZnVsbD1UUlVFKQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KcGxvdChtMl9oaWRybywgcGFnZXM9Mywgc2NoZW1lPTEsIHNoYWRlPVRSVUUsIHNlPVRSVUUsIHNjYWxlcz0iZnJlZSIpDQpgYGANCk8gbW9kZWxvIGhpZHJlbMOpdHJpY28gKEdBTSAyKSBhcHJlc2VudG91IGZvcnRlIGRlc2VtcGVuaG8gZXhwbGljYXRpdm8sIGNvbSBSwrIgYWp1c3RhZG8gZGUgMCw4NSBlIGRldmlhbmNlIGV4cGxpY2FkYSBkZSA4NSwyJSwgbyBxdWUgY29uZmlybWEgc3VhIGFsdGEgY2FwYWNpZGFkZSBkZSByZXByb2R1emlyIGEgZ2VyYcOnw6NvIG9ic2VydmFkYSBhIHBhcnRpciBkYSBlbmVyZ2lhIGFybWF6ZW5hZGEgZSB2YXJpw6F2ZWlzIG9wZXJhY2lvbmFpcy4gTyB0ZXJtbyBsaW5lYXIgcGFyYSBvIGFubyDDqSBuZWdhdGl2byBlIGFsdGFtZW50ZSBzaWduaWZpY2F0aXZvICjigJMxMyw1IE1Xwrdtw6pzL2FubzsgcCA8IDAsMDAxKSwgcmVmbGV0aW5kbyBhIHRlbmTDqm5jaWEgZXN0cnV0dXJhbCBkZSByZWR1w6fDo28gZGEgcGFydGljaXBhw6fDo28gaMOtZHJpY2EgYW8gbG9uZ28gZG8gcGVyw61vZG8sIHBvc3NpdmVsbWVudGUgZW0gZnVuw6fDo28gZGEgZXhwYW5zw6NvIGRlIGZvbnRlcyB0w6lybWljYXMgZSByZW5vdsOhdmVpcyBuw6NvIGjDrWRyaWNhcy4gT3MgZWZlaXRvcyBmaXhvcyBwb3Igc3Vic2lzdGVtYSBpbmRpY2FtIGRpZmVyZW7Dp2FzIG1vZGVzdGFzLCBjb20gZ2VyYcOnw6NvIG3DqWRpYSBsaWdlaXJhbWVudGUgc3VwZXJpb3Igbm8gTm9ydGUgZSBpbmZlcmlvciBubyBTdWRlc3RlLCBjb25zaXN0ZW50ZXMgY29tIG8gcGFwZWwgZXN0cnV0dXJhbCBkZSBjYWRhIHJlZ2nDo28gbmEgb2ZlcnRhIGRlIGVuZXJnaWEgZSBubyBkZXNwYWNobyBkbyBzaXN0ZW1hLg0KDQpPcyBkaWFnbsOzc3RpY29zIGRlIHJlc8OtZHVvcyBldmlkZW5jaWFtIGFqdXN0ZSBhZGVxdWFkbywgY29tIGRpc3RyaWJ1acOnw6NvIGFwcm94aW1hZGFtZW50ZSBub3JtYWwgZSBhdXPDqm5jaWEgZGUgaGV0ZXJvY2VkYXN0aWNpZGFkZSBzaXN0ZW3DoXRpY2EuIE8gaGlzdG9ncmFtYSBkb3MgcmVzw61kdW9zIMOpIGNlbnRyYWRvIGVtIHplcm8sIGUgbyBRUS1wbG90IG1vc3RyYSBsZXZlIGN1cnZhdHVyYSBuYXMgY2F1ZGFzLCBpbmRpY2FuZG8gcGVxdWVuYSBhc3NpbWV0cmlhIGFzc29jaWFkYSBhIHJlZ2ltZXMgb3BlcmFjaW9uYWlzIGV4dHJlbW9zIChyZXNlcnZhdMOzcmlvcyBjaGVpb3Mgb3UgdmF6aW9zKS4gTyBncsOhZmljbyBkZSByZXPDrWR1b3MgdmVyc3VzIHByZWRpdG9zIGV4aWJlIGR1YXMgZmFpeGFzIGJlbSBkZWZpbmlkYXMsIGNvcnJlc3BvbmRlbnRlcyBhIGRpZmVyZW50ZXMgcmVnaW1lcyBkZSBvcGVyYcOnw6NvIGhpZHLDoXVsaWNhIOKAlCB1bSBkZSBiYWl4YSBnZXJhw6fDo28gY29tIEVBUiBsaW1pdGFkYSBlIG91dHJvIGRlIG9wZXJhw6fDo28gcGxlbmEgY29tIGFsdG9zIG7DrXZlaXMgZGUgZGVzcGFjaG8uIEVtYm9yYSBlc3NlcyByZWdpbWVzIGludHJvZHV6YW0gbGV2ZSBlc3RyYXRpZmljYcOnw6NvLCBuw6NvIGjDoSBpbmTDrWNpb3MgZGUgdmnDqXMgZGlyZWNpb25hbCBuZW0gYXV0b2NvcnJlbGHDp8OjbyByZWxldmFudGUsIG8gcXVlIHJlZm9yw6dhIGEgdmFsaWRhZGUgZG8gbW9kZWxvIGdhdXNzaWFubyBjb20gbGluayBpZGVudGlkYWRlLiBPIHRlc3RlIGRlIGRpbWVuc2lvbmFsaWRhZGUgZWZldGl2YSAoay1pbmRleCA+IDAuOSkgZSBvIGJhaXhvIG7DrXZlbCBkZSBjb25jb3Jyw6puY2lhIChjb25jdXJ2aXR5IDwgMC4zKSBjb25maXJtYW0gYSBlc3RhYmlsaWRhZGUgbnVtw6lyaWNhIGRvcyBzcGxpbmVzIGUgYSBhdXPDqm5jaWEgZGUgc29icmVhanVzdGUuDQoNCk9zIGVmZWl0b3MgcGFyY2lhaXMgaWx1c3RyYW0gZGUgZm9ybWEgY2xhcmEgYSBkaW7Dom1pY2EgZsOtc2ljYSBkbyBzaXN0ZW1hLiBPIHNwbGluZSBkYSBlbmVyZ2lhIGFybWF6ZW5hZGEgKEVBUikgYXByZXNlbnRhIHVtIGZvcm1hdG8gY3Jlc2NlbnRlIGNvbSBsZXZlIHNhdHVyYcOnw6NvLCBzdWdlcmluZG8gcmVuZGltZW50byBkZWNyZXNjZW50ZTogYXVtZW50b3MgaW5pY2lhaXMgZGUgYXJtYXplbmFtZW50byBwcm9kdXplbSBncmFuZGVzIGFjcsOpc2NpbW9zIGRlIGdlcmHDp8OjbywgbWFzIG8gZWZlaXRvIG1hcmdpbmFsIGRpbWludWkgw6AgbWVkaWRhIHF1ZSBvIHJlc2VydmF0w7NyaW8gc2UgYXByb3hpbWEgZGEgY2FwYWNpZGFkZSBtw6F4aW1hLiBPIHNwbGluZSBkYSBnZXJhw6fDo28gZGnDoXJpYSBkbyBzdWJzaXN0ZW1hIG1vc3RyYSByZWxhw6fDo28gcXVhc2UgbGluZWFyIHBvc2l0aXZhLCByZXByZXNlbnRhbmRvIG8gZWZlaXRvIGRlIGVzY2FsYSBlIGNvb3JkZW5hw6fDo28gZW50cmUgdXNpbmFzIGludGVybGlnYWRhcy4gQSBzYXpvbmFsaWRhZGUgYW51YWwgKGRveSkgw6kgZnJhY2EsIHJlZmxldGluZG8gbyBmYXRvIGRlIHF1ZSBhcyBvc2NpbGHDp8O1ZXMgc2F6b25haXMgasOhIHPDo28gaW50ZXJuYWxpemFkYXMgbm8gbsOtdmVsIGRlIGFybWF6ZW5hbWVudG8sIGVucXVhbnRvIG8gZWZlaXRvIGFsZWF0w7NyaW8gcG9yIHJlc2VydmF0w7NyaW8gaW5kaWNhIGFtcGxhIGhldGVyb2dlbmVpZGFkZSBlc3RydXR1cmFsIOKAlCBhbGd1bnMgcmVzZXJ2YXTDs3Jpb3Mgb3BlcmFtIGNvbW8gdXNpbmFzIGRlIGJhc2UsIGNvbSBlZmVpdG8gcHLDs3hpbW8gZGUgemVybywgZSBvdXRyb3MgY29tIGZvcnRlIHNlbnNpYmlsaWRhZGUgw6AgdmFyaWHDp8OjbyBkZSBFQVIuIEVtIGNvbmp1bnRvLCBlc3NlcyByZXN1bHRhZG9zIGNvbmZpcm1hbSBxdWUgbyBtb2RlbG8gY2FwdGEgYWRlcXVhZGFtZW50ZSBvIG1lY2FuaXNtbyBkZSBjb252ZXJzw6NvIGhpZHJvbMOzZ2ljYSBlbnRyZSBlc3RvcXVlIGUgZ2VyYcOnw6NvLCBvZmVyZWNlbmRvIGJhc2UgY29uc2lzdGVudGUgcGFyYSBhIGVzdGltYXRpdmEgY29udHJhZmFjdHVhbCBkYSBnZXJhw6fDo28gaMOtZHJpY2Egc29iIGRpZmVyZW50ZXMgY2Vuw6FyaW9zIGNsaW3DoXRpY29zLg0KDQoNCg0KIyNQcmVkacOnw7VlcyBmYWN0dWFsIHZzLiBjb250cmFmYWN0dWFsIGNvbSBpbmNlcnRlemEgKGJhc2VsaW5lIDIwMDHigJMyMDA1KQ0KTyBvYmpldGl2byDDqSBjb21wYXJhciBvIGFybWF6ZW5hbWVudG8gcHJldmlzdG8gcGVsbyBtb2RlbG8gc29iIGNvbmRpw6fDtWVzIGNsaW3DoXRpY2FzIG9ic2VydmFkYXMgZSBzb2IgY29uZGnDp8O1ZXMgbmV1dHJhcywgcmVwcmVzZW50YWRhcyBwZWxvIGNsaW1hIG3DqWRpbyBkbyBwZXLDrW9kbyAyMDAx4oCTMjAwNS4gQSBkaWZlcmVuw6dhIGVudHJlIGFzIGR1YXMgc8OpcmllcyAoJM6URUFSPUVee29ic33iiJJFXntjZn0kKSByZXByZXNlbnRhIGEgcGVuYWxpZGFkZSBjbGltw6F0aWNhIGzDrXF1aWRhLCBlIHN1YSBpbmNlcnRlemEgw6kgZXN0aW1hZGEgdmlhIHByb3BhZ2HDp8OjbyBkb3MgZXJyb3MgcGFyYW3DqXRyaWNvcyBkbyBHQU0uDQoNCmBgYHtyfQ0KIyAtLS0gUHJlZGnDp8O1ZXMgZmFjdHVhbCBlIGNvbnRyYWZhY3R1YWwgLS0tDQpyZXNlcnYkZWFyX2hhdF9vYnMgPC0gcHJlZGljdChtMV9nYW0sIG5ld2RhdGEgPSBuZF9vYnMsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcmVzZXJ2JGVhcl9oYXRfY2YgIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfY2YsICB0eXBlID0gInJlc3BvbnNlIikNCg0KIyBQZW5hbGlkYWRlIG3DqWRpYQ0KcmVzZXJ2IDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKGRlbHRhX2VhciA9IGVhcl9oYXRfb2JzIC0gZWFyX2hhdF9jZikNCg0KcmVzZXJ2JGdlcl9oYXRfZmFjdHVhbCA8LSBwcmVkaWN0KA0KICBtMl9oaWRybywgbmV3ZGF0YSA9IHJlc2VydiwNCiAgdHlwZSA9ICJyZXNwb25zZSINCikNCnJlc2VydiRnZXJfaGF0X2NvbnRyYWYgPC0gcHJlZGljdCgNCiAgbTJfaGlkcm8sIG5ld2RhdGEgPSByZXNlcnYgJT4lDQogICAgbXV0YXRlKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzID0gZWFyX2hhdF9jZiksDQogIHR5cGUgPSAicmVzcG9uc2UiDQopDQpyZXNlcnYgPC0gcmVzZXJ2ICU+JQ0KICBtdXRhdGUoZGVsdGFfR2hpZHJvID0gZ2VyX2hhdF9mYWN0dWFsIC0gZ2VyX2hhdF9jb250cmFmKQ0KcmVzZXJ2WyxjKCJkZWx0YV9HaGlkcm8iLCJnZXJfaGF0X2ZhY3R1YWwiLCJnZXJfaGF0X2NvbnRyYWYiLCJ2YWxfZ2VyYWNhbyIpXSAlPiUgc3VtbWFyeSgpDQpgYGANCiMgKDMpIEluY2VydGV6YSB2aWEgRGVsdGEgTWV0aG9kIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYGBge3J9DQpWcDIgPC0gdmNvdihtMl9oaWRybykNClhfZiA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gcmVzZXJ2ICwNCiAgICAgICAgICAgICAgIHR5cGUgPSAibHBtYXRyaXgiKQ0KWF9jIDwtIHByZWRpY3QobTJfaGlkcm8sIG5ld2RhdGEgPSByZXNlcnYgJT4lDQogICAgICAgICAgICAgICAgIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9oYXRfY2YpLA0KICAgICAgICAgICAgICAgdHlwZSA9ICJscG1hdHJpeCIpDQoNClhfZGlmZjIgPC0gWF9mIC0gWF9jDQp2YXJfZGVsdGEyIDwtIHJvd1N1bXMoKFhfZGlmZjIgJSolIFZwMikgKiBYX2RpZmYyKQ0Kc2VfZGVsdGEyICA8LSBzcXJ0KHBtYXgodmFyX2RlbHRhMiwgMCkpDQp6IDwtIHFub3JtKDAuOTc1KQ0KDQpyZXNlcnYgPC0gcmVzZXJ2ICU+JQ0KICBtdXRhdGUoDQogICAgZGVsdGFfbHdyX2dlciA9IGRlbHRhX0doaWRybyAtIHogKiBzZV9kZWx0YTIsDQogICAgZGVsdGFfdXByX2dlciA9IGRlbHRhX0doaWRybyArIHogKiBzZV9kZWx0YTINCiAgKQ0KDQpgYGANCg0KYGBge3J9DQojICg0KSBBZ3JlZ2HDp8OjbyBwb3IgYW5vIGUgc3Vic2lzdGVtYSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KbTJfZGVsdGFfYWdnIDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKFllYXIgPSB5ZWFyKGRhdGUpKSAlPiUNCiAgZ3JvdXBfYnkoWWVhciwgbm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX3BlbmFsdHkgPSBtZWFuKGRlbHRhX0doaWRybywgbmEucm0gPSBUUlVFKSwNCiAgICBsd3IgPSBtZWFuKGRlbHRhX2x3cl9nZXIsIG5hLnJtID0gVFJVRSksDQogICAgdXByID0gbWVhbihkZWx0YV91cHJfZ2VyLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KbTJfZGVsdGFfYWdnICU+JSBzdW1tYXJ5KCkNCiAgDQpgYGANCg0KIyMgUHJlZGnDp8O1ZXMgZG8gbW9kZWxvIEdlcmHDp8Ojbw0KDQpgYGB7cn0NCg0KbmV3ZGF0YV9tMSAlPiUgDQogIG11dGF0ZShnZXJfaGF0ID0gcHJlZGljdChtMl9oaWRybywgbmV3ZGF0YSA9IG5ld2RhdGFfbTEsIHR5cGU9InJlc3BvbnNlIixuYS5hY3Rpb24gPSBuYS5wYXNzKSkgLT4gbmV3ZGF0YV9tMQ0KDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9DQojIDEpIFPDqXJpZSB0ZW1wb3JhbDogRUFSIG9ic2VydmFkbyB2cyBwcmV2aXN0bw0KbmV3ZGF0YV9tMSAlPiUgDQogICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIikpICU+JSANCg0KICBncm91cF9ieShtZXMsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHZhbF9nZXJhY2FvID1tZWFuKHZhbF9nZXJhY2FvICAgLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXJfaGF0PW1lYW4oZ2VyX2hhdCxuYS5ybT1UKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IG1lcywpKSArDQogIGdlb21fbGluZShhZXMoeSA9IHZhbF9nZXJhY2FvLCBjb2xvciA9ICJPYnNlcnZhZG8iKSwgc2l6ZSA9IDAuNyxhbHBoYT0uNikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBnZXJfaGF0LCBjb2xvciA9ICJQcmV2aXN0byIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJFQVIgb2JzZXJ2YWRvIHZzIHByZXZpc3RvIChHQU0pIiwNCiAgICAgICB5ID0gIkVBUiAoTVdtw6pzKSIsIHggPSAiRGF0YSIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk9ic2VydmFkbyIgPSAiYmxhY2siLCAiUHJldmlzdG8iID0gInJlZCIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpuZXdkYXRhX20xICU+JSANCiAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpKSAlPiUgDQogIGdyb3VwX2J5KG1lcyxub21fc3Vic2lzdGVtYS54KSAlPiVzdW1tYXJpc2UocmVzaWQ9bWVhbih2YWxfZ2VyYWNhbyxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYXJfaGF0PW1lYW4oZ2VyX2hhdCxuYS5ybT1UKSkgJT4lDQogIA0KICBnZ3Bsb3QoIGFlcyh4ID0gbWVzLCkpICsNCiAgI2dlb21fcG9pbnQoYWVzKGNvbG9yPXJlc2lkX2NvbCkpKw0KICBmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGdlb21fbGluZShhZXMoeSA9IHJlc2lkKSxjb2w9InJlZCIpICsgIGdlb21fbGluZShhZXMoeT1lYXJfaGF0KSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj1yZXNpZCx5bWF4PWVhcl9oYXQpLGFscGhhPS40LGZpbGwgPSAiZmlyZWJyaWNrIiwpKw0KICBsYWJzKHRpdGxlID0gIlJlc8OtZHVvcyBkbyBtb2RlbG8gKG9ic2VydmFkbyAtIHByZXZpc3RvKSIsDQogICAgICAgeSA9ICJSZXPDrWR1byIsIHggPSAiRGF0YSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQojIyMgQWp1c3RlIGRvIEdBTTogc8OpcmllcyB0ZW1wb3JhaXMgZSBkaXNwZXJzw6NvDQoNCkEgRmlndXJhIDEgYXByZXNlbnRhIGEgY29tcGFyYcOnw6NvIGVudHJlIG9zIG7DrXZlaXMgZGUgRUFSIG9ic2VydmFkb3MgZSBvcyB2YWxvcmVzIHByZXZpc3RvcyBwZWxvIG1vZGVsbyBHQU0sIGRlc2FncmVnYWRvcyBwb3Igc3Vic2lzdGVtYS4NCg0KLSAgICoqTm9yZGVzdGUgZSBTdWRlc3RlOioqIG8gbW9kZWxvIGFjb21wYW5oYSByYXpvYXZlbG1lbnRlIGJlbSBhcyB0ZW5kw6puY2lhcyBkZSBsb25nbyBwcmF6bywgbWFzIHN1YmVzdGltYSBvcyBwZXLDrW9kb3MgZGUgc2VjYSBzZXZlcmEgKHDDs3MtMjAxMikgZSBzdXBlcmVzdGltYSBhbGd1bnMgcGljb3MgZGUgcmVjdXBlcmHDp8Ojby4NCg0KLSAgICoqTm9ydGU6KiogYSBwcmV2aXPDo28gdGVuZGUgYSBzdWF2aXphciBhIGFsdGEgdmFyaWFiaWxpZGFkZSBpbnRlcmFudWFsLCBjYXB0YW5kbyBtZWxob3IgYSBtw6lkaWEgZGUgbG9uZ28gcHJhem8gZG8gcXVlIG9zIGV4dHJlbW9zLg0KDQotICAgKipTdWw6KiogaMOhIG1haW9yIGFkZXLDqm5jaWEgZW50cmUgYXMgY3VydmFzLCBlbWJvcmEgb3MgY2hvcXVlcyBoaWRyb2zDs2dpY29zIG1haXMgaW50ZW5zb3Mgc2VqYW0gc3Vhdml6YWRvcyBwZWxvIG1vZGVsby4NCg0KRGUgZm9ybWEgZ2VyYWwsIG8gbW9kZWxvIMOpIGVmaWNheiBlbSBjYXB0dXJhciBvICoqbsOtdmVsIG3DqWRpbyBlIGEgc2F6b25hbGlkYWRlIGVzdHJ1dHVyYWwqKiwgbWFzIHRlbmRlIGEgKipzdWJlc3RpbWFyIGV2ZW50b3MgY3LDrXRpY29zKiogZGUgY2hlaWEgb3UgZGUgc2VjYS4NCg0KYGBge3J9DQoNCiMgMikgU2NhdHRlcnBsb3QgT2JzZXJ2YWRvIHZzIFByZXZpc3RvDQpuZXdkYXRhX20xICU+JSANCiAgIGdyb3VwX2J5KGRhdGUsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHZhbF9nZXJhY2FvPXN1bSh2YWxfZ2VyYWNhbyxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VyX2hhdD1zdW0oZ2VyX2hhdCxuYS5ybT1UKSkgJT4lDQogIGdncGxvdCggYWVzKHggPSB2YWxfZ2VyYWNhbywgeSA9IGdlcl9oYXQpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjEpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibHVlIikgICtmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGxhYnModGl0bGUgPSAiRGlzcGVyc8OjbyBFQVIgb2JzZXJ2YWRvIHZzIHByZXZpc3RvIiwNCiAgICAgICB4ID0gIlByZXZpc3RvIChHQU0pIiwgeSA9ICJPYnNlcnZhZG8iKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KDQpBIEZpZ3VyYSAyIG1vc3RyYSBvcyBkaWFncmFtYXMgZGUgZGlzcGVyc8OjbyBlbnRyZSBvcyB2YWxvcmVzIG9ic2VydmFkb3MgZSBwcmV2aXN0b3MgZGUgRUFSLCB0YW1iw6ltIHBvciBzdWJzaXN0ZW1hLCBjb20gYSBsaW5oYSB0cmFjZWphZGEgcmVwcmVzZW50YW5kbyBvIGFqdXN0ZSBwZXJmZWl0byAoNDXCsCkuDQoNCi0gICBBIG1haW9yIHBhcnRlIGRvcyBwb250b3Mgc2UgY29uY2VudHJhIHByw7N4aW1hIGRhIGxpbmhhIGRlIHJlZmVyw6puY2lhLCBjb25maXJtYW5kbyBhIGJvYSBjYXBhY2lkYWRlIGV4cGxpY2F0aXZhIGRvIG1vZGVsby4NCg0KLSAgIE8gKipTdWRlc3RlKiogY29uY2VudHJhIG1haW9yIGRpc3BlcnPDo28sIGNvZXJlbnRlIGNvbSBhIHN1YSByZWxldsOibmNpYSBlIG1haW9yIGhldGVyb2dlbmVpZGFkZSBoaWRyb2zDs2dpY2EuDQoNCi0gICBPICoqTm9yZGVzdGUqKiBtb3N0cmEgYm9tIGFsaW5oYW1lbnRvLCBtYXMgY29tIGFsZ3VucyBkZXN2aW9zIGVtIGJhaXhvcyBuw612ZWlzIGRlIEVBUi4NCg0KLSAgIE8gKipTdWwqKiBhcHJlc2VudGEgYSBtYWlvciBhZGVyw6puY2lhLCBjb20gbnV2ZW0gZGUgcG9udG9zIGZvcnRlbWVudGUgY29sYWRhIMOgIGxpbmhhIDQ1wrAuDQoNCkVzc2VzIHJlc3VsdGFkb3MgY29ycm9ib3JhbSBxdWUgbyBHQU0gw6kgYWRlcXVhZG8gcGFyYSBjYXB0dXJhciBhICoqZGluw6JtaWNhIG3DqWRpYSBlIGVzdHJ1dHVyYWwqKiBkbyBzaXN0ZW1hLCBtYXMgcXVlIG9zIHZhbG9yZXMgZXN0aW1hZG9zIGRldmVtIHNlciBpbnRlcnByZXRhZG9zIGNvbSBjYXV0ZWxhIGVtICoqY29uZGnDp8O1ZXMgZXh0cmVtYXMgZGUgZXNjYXNzZXogb3UgZXhjZXNzbyBow61kcmljbyoqLg0KDQojIyBDb250cmFmYWN0dXJhbCBHZXJhw6fDo28gVGVybWljYSBnYW0NCg0KYGBge3J9DQpuZXdkYXRhX20xICU+JSANCiAgbXV0YXRlKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzPWVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLWNsaW1faW4kcGVuYWxpZGFkZV9lYXIpLT5uZXdkYXRhX20yDQojbmV3ZGF0YV9tMSAlPiUgDQojICBtdXRhdGUoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXM9Y2xpbV9pbiRjbGltMjAyNl9oYXQpLT5uZXdkYXRhX20yDQpuZXdkYXRhX20yJGdlcl9oYXRfY2YgPC0gcHJlZGljdChtMl9oaWRybywgbmV3ZGF0YSA9IG5ld2RhdGFfbTIsIHR5cGU9InJlc3BvbnNlIixuYS5hY3Rpb24gPSBuYS5wYXNzKQ0KYGBgDQoNCmBgYHtyfQ0KIyAxKSBTw6lyaWUgdGVtcG9yYWw6IEVBUiBvYnNlcnZhZG8gdnMgcHJldmlzdG8NCm5ld2RhdGFfbTIgJT4lIA0KICAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpKSAlPiUgDQoNCiAgZ3JvdXBfYnkoLG5vbV9zdWJzaXN0ZW1hLngpICU+JXN1bW1hcmlzZShnZXJfaGF0X2NmID1tZWFuKGdlcl9oYXRfY2YgICAsbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlcl9oYXQ9bWVhbihnZXJfaGF0LG5hLnJtPVQpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbWVzLCkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZ2VyX2hhdF9jZiwgY29sb3IgPSAiUHJldmlzdG8gLSBSZWFsIiksIHNpemUgPSAwLjcsYWxwaGE9LjYpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZ2VyX2hhdCwgY29sb3IgPSAiUHJldmlzdG8gLSBDb250cmFmYWN0dWFsIiksIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCxzY2FsZXMgPSAiZnJlZSIpKw0KICBsYWJzKHRpdGxlID0gIkdlcmHDp8OjbyBQcmVkaXRvIHZzIHByZXZpc3RvIChDb250cmEtZmFjdHVhbCkiLA0KICAgICAgIHkgPSAiRUFSIChNV23DqnMpIiwgeCA9ICJEYXRhIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiUHJldmlzdG8gLSBSZWFsIiA9ICJibGFjayIsICJQcmV2aXN0byAtIENvbnRyYWZhY3R1YWwiID0gInJlZCIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KbmV3ZGF0YV9tMiAlPiUgDQogICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIikpICU+JSANCg0KICBncm91cF9ieShtZXMsKSAlPiVzdW1tYXJpc2UoZ2VyX2hhdF9jZiA9bWVhbihnZXJfaGF0X2NmICAgLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXJfaGF0PW1lYW4oZ2VyX2hhdCxuYS5ybT1UKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IG1lcywpKSArDQogIGdlb21fbGluZShhZXMoeSA9IGdlcl9oYXRfY2YsIGNvbG9yID0gIlByZXZpc3RvIC0gUmVhbCIpLCBzaXplID0gMC43LGFscGhhPS42KSArDQogIGdlb21fbGluZShhZXMoeSA9IGdlcl9oYXQsIGNvbG9yID0gIlByZXZpc3RvIC0gQ29udHJhZmFjdHVhbCIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyNmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGxhYnModGl0bGUgPSAiR2VyYcOnw6NvIFByZWRpdG8gdnMgcHJldmlzdG8gKENvbnRyYS1mYWN0dWFsKSIsDQogICAgICAgeSA9ICJFQVIgKE1XbcOqcykiLCB4ID0gIkRhdGEiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQcmV2aXN0byAtIFJlYWwiID0gImJsYWNrIiwgIlByZXZpc3RvIC0gQ29udHJhZmFjdHVhbCIgPSAicmVkIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KQSBmaWd1cmEgY29tcGFyYSwgcG9yIHN1YnNpc3RlbWEsIGEgKipnZXJhw6fDo28gaGlkcmVsw6l0cmljYSBwcmV2aXN0YSBjb20gY2xpbWEgb2JzZXJ2YWRvKiogZSBhICoqZ2VyYcOnw6NvIGNvbnRyYWZhY3R1YWwqKiBzaW11bGFkYSBhbyBzdWJzdGl0dWlyIG8gYXJtYXplbmFtZW50byAoRUFSKSBwZWxvIGJhc2VsaW5lIGNsaW3DoXRpY28gKDIwMDHigJMyMDEwKS4NCg0KLSAgICoqTm9yZGVzdGUgZSBTdWRlc3RlOioqIGEgc8OpcmllIGNvbSAqKmNsaW1hIG9ic2VydmFkbyoqIGFwcmVzZW50YSBxdWVkYXMgYWNlbnR1YWRhcyBhcMOzcyAyMDEyLCBlbnF1YW50byBvICoqY29udHJhZmFjdHVhbCoqIHNlIG1hbnTDqW0gZW0gcGF0YW1hcmVzIG1lbm9yZXMgZSBtYWlzIGVzdMOhdmVpcy4gQSBkaXZlcmfDqm5jaWEgY3Jlc2NlbnRlIHJlZmxldGUgYSAqKnBlbmFsaWRhZGUgY2xpbcOhdGljYSoqIHJlY2VudGUgc29icmUgYSBnZXJhw6fDo28uDQoNCi0gICAqKk5vcnRlOioqIG8gY29udHJhZmFjdHVhbCBhY29tcGFuaGEgZGUgcGVydG8gYSB0cmFqZXTDs3JpYSBtw6lkaWE7IGEgc8OpcmllIHJlYWwgbW9zdHJhIG9zY2lsYcOnw7VlcyBhZGljaW9uYWlzIGVtIGFub3MgZXNwZWPDrWZpY29zLCBzdWdlcmluZG8gY2hvcXVlcyBuw6NvIHJlcHJvZHV6aWRvcyBwZWxvIGNsaW1hIG3DqWRpby4NCg0KLSAgICoqU3VsOioqIGjDoSBmb3J0ZSB2YXJpYWJpbGlkYWRlIGludGVyYW51YWwgbmFzIGR1YXMgY3VydmFzOyBtZXNtbyBhc3NpbSwgYSBzw6lyaWUgcmVhbCB0ZW5kZSBhIGZpY2FyICoqYWJhaXhvKiogZG8gY29udHJhZmFjdHVhbCBlbSBhbm9zIHNlY29zLCBldmlkZW5jaWFuZG8gc3Vic3RpdHVpw6fDo28gcG9yIG91dHJhcyBmb250ZXMgbmVzc2VzIHBlcsOtb2Rvcy4NCg0KRW0gY29uanVudG8sIG9zIHJlc3VsdGFkb3MgaW5kaWNhbSBxdWUgKipvIGNsaW1hIHJlY2VudGUgcmVkdXppdSBhIGdlcmHDp8OjbyBow61kcmljYSoqIGVtIHJlbGHDp8OjbyBhbyBxdWUgc2VyaWEgZXNwZXJhZG8gc29iIHVtIHJlZ2ltZSBjbGltw6F0aWNvIG3DqWRpbywgY29tIGludGVuc2lkYWRlIG1haW9yIG5vIFN1ZGVzdGUgZSBOb3JkZXN0ZS4NCg0KYGBge3IgQ29udHJhZmFjdHVhbCBjbGltw6F0aWNvIDEoYmFzZWxpbmUgMjAwMeKAkzIwMDUpfQ0KbmV3ZGF0YV9tMiAlPiUgDQogICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIikpICU+JSANCg0KICBncm91cF9ieShZZWFyKSAlPiVzdW1tYXJpc2UoZW5hX213Nz1zdW0oZ2VyX2hhdCxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbTIwMjZfaGF0PXN1bShnZXJfaGF0X2NmLG5hLnJtPVQpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwpKSArDQogIGdlb21fbGluZShhZXMoeSA9IGVuYV9tdzcvMTAwMCwgY29sb3IgPSAiUHJldmlzdG8iKSwgc2l6ZSA9IDAuNyxhbHBoYT0uNikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBjbGltMjAyNl9oYXQvMTAwMCwgY29sb3IgPSAiQ29udHJhZmFjdHVhbCAyMDEwIiksIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArI2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJDb250cmFmYWN0dWFsIGJhc2VsaW5lIChjbGltYSBtw6lkaW8gMjAwMS0yMDEwKSIsDQogICAgICAgeSA9ICJHZXJhw6fDo28gKEdXbcOqcykiLCB4ID0gIkRhdGEiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQcmV2aXN0byIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDEwIiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpuZXdkYXRhX20yICU+JSANCiAgIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KDQogIGdyb3VwX2J5KFllYXIsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKGVuYV9tdzc9c3VtKGdlcl9oYXQsbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsaW0yMDI2X2hhdD1zdW0oZ2VyX2hhdF9jZixuYS5ybT1UKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBlbmFfbXc3LzEwMDAsIGNvbG9yID0gIlByZXZpc3RvIiksIHNpemUgPSAwLjcsYWxwaGE9LjYpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gY2xpbTIwMjZfaGF0LzEwMDAsIGNvbG9yID0gIkNvbnRyYWZhY3R1YWwgMjAxMCIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJDb250cmFmYWN0dWFsIGJhc2VsaW5lIChjbGltYSBtw6lkaW8gMjAwMS0yMDEwKSIsDQogICAgICAgeSA9ICJHZXJhw6fDo28gKEdXbcOqcykiLCB4ID0gIkRhdGEiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQcmV2aXN0byIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDEwIiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KQSBGaWd1cmEgMSBjb21wYXJhIGFzIHRyYWpldMOzcmlhcyBwcmV2aXN0YXMgZGUgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2Egc29iIGR1YXMgY29uZGnDp8O1ZXM6DQoNCi0gICAqKlByZXZpc3RvIOKAkyBSZWFsIChsaW5oYSBwcmV0YSk6KiogcmVzdWx0YWRvcyBkbyBHQU0gY29tIGNsaW1hIG9ic2VydmFkbyBubyBwZXLDrW9kbzsNCg0KICAgICoqUHJldmlzdG8g4oCTIENvbnRyYWZhY3R1YWwgKGxpbmhhIHZlcm1lbGhhIHRyYWNlamFkYSk6KiogcmVzdWx0YWRvcyBkbyBtZXNtbyBtb2RlbG8sIG1hcyBzdWJzdGl0dWluZG8gYXMgdmFyacOhdmVpcyBjbGltw6F0aWNhcyBwZWxhcyBtw6lkaWFzIGhpc3TDs3JpY2FzIChiYXNlbGluZSAyMDAx4oCTMjAxMCkuDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQ0KbmV3ZGF0YV9tMiAlPiUgDQogICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIikpICU+JSANCg0KICBncm91cF9ieShZZWFyLG5vbV9zdWJzaXN0ZW1hLngpICU+JXN1bW1hcmlzZShlbmFfbXc3PXN1bShnZXJfaGF0LG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGltMjAyNl9oYXQ9c3VtKGdlcl9oYXRfY2YsbmEucm09VCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZW5hX213Ny8xMDAwLCBjb2xvciA9ICJQcmV2aXN0byIpLCBzaXplID0gMC43LGFscGhhPS42KSArDQogIGdlb21fbGluZShhZXMoeSA9IGNsaW0yMDI2X2hhdC8xMDAwLCBjb2xvciA9ICJDb250cmFmYWN0dWFsIDIwMTAgLSBiYXNlbGluZSIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiLG5jb2wgPSAyKSsNCiAgbGFicyh0aXRsZSA9ICJDb250cmFmYWN0dWFsIGNsaW3DoXRpY28gcG9yIHN1YnNpc3RlbWEgKGJhc2VsaW5lIDIwMDHigJMyMDEwKSIsDQogICAgICAgeSA9ICJHZXJhw6fDo28gKEdXbcOqcykiLCB4ID0gIkRhdGEiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQcmV2aXN0byIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDEwIC0gYmFzZWxpbmUiID0gImJsdWUiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7ciB9DQpuZXdkYXRhX20yICU+JSANCiAgIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSwNCiAgICAgICAgICBwZW5hbGlkYWRlX2dlcmHDp8Ojb19oaWRybz1nZXJfaGF0LWdlcl9oYXRfY2YsDQogICAgICAgICAgI3BlbmFsaWRhZGUyPWVuYV9tdzctY2xpbTIwMjZfaGF0LA0KICAgICAgICAgICktPm5ld2RhdGFfbTINCm5ld2RhdGFfbTIgJT4lIA0KICAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpLA0KICAgICAgICAgIHBlbmFsaWRhZGUxPWdlcl9oYXQtZ2VyX2hhdF9jZiwNCiAgICAgICAgICAjcGVuYWxpZGFkZTI9ZW5hX213Ny1jbGltMjAyNl9oYXQsDQogICAgICAgICAgKSAlPiUgDQoNCiAgZ3JvdXBfYnkoWWVhcikgJT4lc3VtbWFyaXNlKGVuYV9tdzc9c3VtKHBlbmFsaWRhZGUxLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY2xpbTIwMjZfaGF0PXN1bShwZW5hbGlkYWRlMixuYS5ybT1UKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCkpICsNCiAgI2dlb21fbGluZShhZXMoeSA9IGVuYV9tdzcsIGNvbG9yID0gInByZXZpc3RvIC0gQ29udHJhZmFjdHVhbCIpLCBzaXplID0gMC43LGFscGhhPS42KSArDQogIGdlb21fbGluZShhZXMoeSA9IGVuYV9tdzcvMTAwMCwgY29sb3IgPSAiT2JzZXJ2YWRvIC0gQ29udHJhZmFjdHVhbCAyMDI2IiksIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArI2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJJbXBhY3RvIGzDrXF1aWRvIGRvIGNsaW1hIHJlY2VudGUgc29icmUgYSBHZXJhw6fDo28iLHN1YnRpdGxlID0gIk9ic2VydmFkbyAtIENvbnRyYWZhY3R1YWwgMjAyNiIsDQogICAgICAgeSA9ICJQZW5hbGlkYWRlIENsaW3DoXRpY2EgbmEgR2VyYcOnw6NvIEhpZHJvZWzDqXRpY2EgKE1XbcOqcykiLCB4ID0gIkRhdGEiKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW49ZW5hX213Ny8xMDAwLHltYXg9MCksYWxwaGE9LjQsZmlsbCA9ICJmaXJlYnJpY2siLCkrDQoNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk9ic2VydmFkbyIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDI2IiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpuZXdkYXRhX20yICU+JSANCiAgIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSwNCiAgICAgICAgICBwZW5hbGlkYWRlMT1nZXJfaGF0LWdlcl9oYXRfY2YsDQogICAgICAgICAgI3BlbmFsaWRhZGUyPWVuYV9tdzctY2xpbTIwMjZfaGF0LA0KICAgICAgICAgICkgJT4lIA0KDQogIGdyb3VwX2J5KFllYXIsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHBlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvPXN1bShwZW5hbGlkYWRlX2dlcmHDp8Ojb19oaWRybyxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NsaW0yMDI2X2hhdD1zdW0ocGVuYWxpZGFkZTIsbmEucm09VCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwpKSArDQogICNnZW9tX2xpbmUoYWVzKHkgPSBlbmFfbXc3LCBjb2xvciA9ICJwcmV2aXN0byAtIENvbnRyYWZhY3R1YWwiKSwgc2l6ZSA9IDAuNyxhbHBoYT0uNikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBwZW5hbGlkYWRlX2dlcmHDp8Ojb19oaWRyby8xMDAwLCBjb2xvciA9ICJPYnNlcnZhZG8gLSBDb250cmFmYWN0dWFsIDIwMjYiKSwgc2l6ZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIpICtmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGxhYnModGl0bGUgPSAiSW1wYWN0byBsw61xdWlkbyBkbyBjbGltYSByZWNlbnRlIHNvYnJlIGEgR2VyYcOnw6NvIHBvciBzdWJzaXN0ZW1hIixzdWJ0aXRsZSA9ICJPYnNlcnZhZG8gLSBDb250cmFmYWN0dWFsIDIwMjYiLA0KICAgICAgIHkgPSAiUGVuYWxpZGFkZSBDbGltw6F0aWNhIG5hIEdlcmHDp8OjbyBIaWRyb2Vsw6l0aWNhIChNV23DqnMpIiwgeCA9ICJEYXRhIikgKw0KICAgIGdlb21fcmliYm9uKGFlcyh5bWluPXBlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvLzEwMDAseW1heD0wKSxhbHBoYT0uNCxmaWxsID0gImZpcmVicmljayIsKSsNCg0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiT2JzZXJ2YWRvIiA9ICJibGFjayIsICJDb250cmFmYWN0dWFsIDIwMjYiID0gImJsdWUiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCm5ld2RhdGFfbTIgJT4lIA0KICAgbXV0YXRlKHBlbmFsaWRhZGUxPWdlcl9oYXQtZ2VyX2hhdF9jZiwNCiAgICAgICAgICBwZW5hbGlkYWRlX3BlcmM9Z2VyX2hhdC9nZXJfaGF0X2NmLA0KICAgICAgICAgICNwZW5hbGlkYWRlMj1lbmFfbXc3LWNsaW0yMDI2X2hhdCwNCiAgICAgICAgICApICU+JSANCg0KICBncm91cF9ieSgsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHBlbmFsaWRhZGUxPXN1bShwZW5hbGlkYWRlMSxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlcl9oYXQ9c3VtKGdlcl9oYXQsbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXJfaGF0X2NmPXN1bShnZXJfaGF0X2NmLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVuYWxpZGFkZV9wZXJjPW1lYW4ocGVuYWxpZGFkZV9wZXJjLG5hLnJtPVQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNjbGltMjAyNl9oYXQ9c3VtKHBlbmFsaWRhZGUyLG5hLnJtPVQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIG11dGF0ZShjdXN0b19maW5hbmNlaXJvX21hcmdpbmFsPXBlbmFsaWRhZGUxKjEwMCktPnBlbmFsaWRhZGVfaGlkcmljbw0KcGVuYWxpZGFkZV9oaWRyaWNvDQpgYGANCg0KQSBUYWJlbGEgcmVzdW1lIG9zIHJlc3VsdGFkb3MgcXVhbnRpdGF0aXZvcy4gQXMgY29sdW5hcyByZXBvcnRhbSBhIGdlcmHDp8OjbyBwcmV2aXN0YSByZWFsIChnZXJfaGF0KSwgbyBjb250cmFmYWN0dWFsIChnZXJfaGF0X2NmKSwgYSBwZW5hbGlkYWRlIGFic29sdXRhIChNV23DqnMpIGUgYSBwZW5hbGlkYWRlIHBlcmNlbnR1YWwgbcOpZGlhICglKS4gT3MgdmFsb3JlcyBpbmRpY2FtIHF1ZToNCg0KLSAgIE8gKipTdWRlc3RlKiogcmVnaXN0cm91IGEgbWFpb3IgcGVuYWxpZGFkZSBhYnNvbHV0YSAo4omIIOKAkzMsNSBtaWxow7VlcyBkZSBNV23DqnMpLCBjb20gcGVyZGEgbcOpZGlhIGRlICoqNCw0JSoqLg0KDQotICAgTyAqKk5vcmRlc3RlKiogcGVyZGV1IOKJiCDigJMxIG1pbGjDo28gZGUgTVdtw6pzICjigJMxMyw1JSksIGNvbmZpcm1hbmRvIHZ1bG5lcmFiaWxpZGFkZSBlc3RydXR1cmFsLg0KDQotICAgTyAqKlN1bCoqIGFwcmVzZW50b3UgcGVuYWxpZGFkZSBtZW5vciBlbSB0ZXJtb3MgcmVsYXRpdm9zICjigJM5LDIlKSwgbWFzIGNvbSBhbHRhIHZhcmlhYmlsaWRhZGUgaW50ZXJhbnVhbC4NCg0KLSAgIE8gKipOb3J0ZSoqIGZvaSBvIMO6bmljbyBzdWJzaXN0ZW1hIGEgbWFudGVyIG3DqWRpYSBjb250cmFmYWN0dWFsIHByw7N4aW1hIMOgIHJlYWwsIHJlZmxldGluZG8gZXF1aWzDrWJyaW8gbWFpcyBmYXZvcsOhdmVsIGVudHJlIGNsaW1hIGUgYXJtYXplbmFtZW50by4NCg0KYGBge3J9DQpuZXdkYXRhX20xJGdlcl9oYXRfY2YgPC0gbmV3ZGF0YV9tMiRnZXJfaGF0X2NmIA0KbmV3ZGF0YV9tMSRwZW5hbGlkYWRlX2dlcmHDp8Ojb19oaWRybyA8LSBuZXdkYXRhX20yJHBlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvIA0KDQpgYGANCg0KIyBNb2RlbG8gZGUgUHJvcGFnYcOnw6NvIHBhcmEgb3V0cmFzIGZvbnRlcyBkZSBlbmVyZ2lhDQoNCmBgYHtyfQ0KZ2VyJG5vbV90aXBvY29tYnVzdGl2ZWwgJT4lIHVuaXF1ZSgpDQpnZXIgJT4lbXV0YXRlKHVzaW5hX2ZvbnRlPXBhc3RlMCgiZ2VyXyIsbm9tX3RpcG91c2luYSkpICU+JSANCiAgZmlsdGVyKCFub21fc3Vic2lzdGVtYT09IlBBUkFHVUFJIikgJT4lICMsIl8iLG5vbV90aXBvdXNpbmEpKSAlPiUgDQogIG11dGF0ZSh1c2luYV9mb250ZT1jYXNlX3doZW4odXNpbmFfZm9udGU9PSJnZXJfQk9NQkVBTUVOVE8ifiJnZXJfSElEUk9FTMOJVFJJQ0EiLA0KICAgICAgICAgICAgICAgICAgIFRSVUV+dXNpbmFfZm9udGUpKSAlPiUgIywiXyIsbm9tX3RpcG91c2luYSkpICU+JSANCg0KICBncm91cF9ieShkYXRlLG5vbV9zdWJzaXN0ZW1hLHVzaW5hX2ZvbnRlLHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hKSAlPiUgDQogIHN1bW1hcmlzZShnZXI9c3VtKHZhbF9nZXJhY2FvLG5hLnJtID0gVCkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICBzcHJlYWQodXNpbmFfZm9udGUsZ2VyLGZpbGwgPSAwKSAlPiUgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgDQogIG11dGF0ZSgpLT5nZXJhX2VuZXJnX2RheQ0KZ2VyYV9lbmVyZ19kYXkkZG95ICAgIDwtIGx1YnJpZGF0ZTo6eWRheShnZXJhX2VuZXJnX2RheSRkYXRlKQ0KZ2VyYV9lbmVyZ19kYXkkZG93ICAgIDwtIGx1YnJpZGF0ZTo6d2RheShnZXJhX2VuZXJnX2RheSRkYXRlLCBsYWJlbD1UUlVFLCBhYmJyPVRSVUUpDQpnZXJhX2VuZXJnX2RheSRtb250aCAgPC0gbHVicmlkYXRlOjptb250aChnZXJhX2VuZXJnX2RheSRkYXRlKQ0KZ2VyYV9lbmVyZ19kYXkkdHJlbmQgIDwtIGx1YnJpZGF0ZTo6eWVhcihnZXJhX2VuZXJnX2RheSRkYXRlKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0xMH0NCmdlciAlPiUNCiAgbXV0YXRlKHVzaW5hX2ZvbnRlPXBhc3RlMCgiZ2VyXyIsbm9tX3RpcG91c2luYSksDQogICAgICAgICBtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIyBzZWxlY3QodXNpbmFfZm9udGUpICU+JSB1bmlxdWUoKQ0KICBtdXRhdGUodXNpbmFfZm9udGU9Y2FzZV93aGVuKHVzaW5hX2ZvbnRlPT0iZ2VyX0JPTUJFQU1FTlRPIn4iZ2VyX0hJRFJPRUzDiVRSSUNBIiwNCiAgICAgICAgICAgICAgICAgICBUUlVFfnVzaW5hX2ZvbnRlKSkgJT4lICMsIl8iLG5vbV90aXBvdXNpbmEpKSAlPiUgDQogIGdyb3VwX2J5KG1lcyx1c2luYV9mb250ZSxub21fc3Vic2lzdGVtYSkgJT4lICNub21fc3Vic2lzdGVtYQ0KICBzdW1tYXJpc2UoZ2VyPW1lYW4odmFsX2dlcmFjYW8sbmEucm0gPSBUKSkgJT4lIA0KICAgIGdncGxvdChhZXMoeCA9IG1lcyx5PWdlcixjb2w9bm9tX3N1YnNpc3RlbWEpKSArDQogICAgZ2VvbV9saW5lKCkgK2ZhY2V0X3dyYXAofnVzaW5hX2ZvbnRlLHNjYWxlcyA9ICJmcmVlIixuY29sID0gMikrDQogIGxhYnModGl0bGUgPSAiSW1wYWN0byBsw61xdWlkbyBkbyBjbGltYSByZWNlbnRlIHNvYnJlIGEgRU5BIHBvciBzdWJzaXN0ZW1hIixzdWJ0aXRsZSA9ICJPYnNlcnZhZG8gLSBDb250cmFmYWN0dWFsIDIwMjYiLA0KICAgICAgIHkgPSAiZ2VyIChHV23DqnMpIiwgeCA9ICJEYXRhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCnBsZF9mdWxsICU+JQ0KICAgICAgICAgICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICAgICAgZ2VyX2hpZHJvZWxldHJpY2EgPSBpZmVsc2UoZ2VyX2hpZHJvZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2hpZHJvZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9mb3Rvdm9sdGFpY2EgPSBpZmVsc2UoZ2VyX2ZvdG92b2x0YWljYSA9PSAwLCAxLCBnZXJfZm90b3ZvbHRhaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZW9saWVsZXRyaWNhID0gaWZlbHNlKGdlcl9lb2xpZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2VvbGllbGV0cmljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX3Rlcm1pY2EgPSBpZmVsc2UoZ2VyX3Rlcm1pY2EgPT0gMCwgMSwgZ2VyX3Rlcm1pY2EpLA0KICAgICAgICAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIsDQogICAgICAgICAgICAgICAgICkgJT4lIA0KICBnZ3Bsb3QoYWVzKGRhdGUsKSkrDQogICAgZ2VvbV9saW5lKGFlcyh5PURlbWFuZGEpLGNvbD0icmVkIikrDQogIGdlb21fbGluZShhZXMoeT12YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSxhbHBoYSA9IDAuMSksY29sPSJibGFjayIpK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWVfeSIpDQpgYGANCg0KYGBge3J9DQpnZXJhX2VuZXJnX2RheSAlPiUgc3RyKCkNCm9wdGlvbnMoc2NpcGVuID0gOCkNCmxtKGdlcl90ZXJtaWNhfg0KICAgICBnZXJfaGlkcm9lbGV0cmljYSsNCiAgICAgZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9udWNsZWFyKyAgICANCiAgICAgbm9tX3N1YnNpc3RlbWEueCswKw0KICAgICB0cmVuZCthcy5mYWN0b3IobW9udGgpLA0KICAgZGF0YSA9Z2VyYV9lbmVyZ19kYXkpICU+JSBzdW1tYXJ5KCkNCmBgYA0KDQpgYGB7cn0NCmxtKGxvZyhnZXJfdGVybWljYSl+DQogICAgIGxvZyhnZXJfaGlkcm9lbGV0cmljYSkrDQogICAgIGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfbnVjbGVhcisgICAgDQogICAgIG5vbV9zdWJzaXN0ZW1hLngrMCsNCiAgICB0cmVuZCthcy5mYWN0b3IobW9udGgpLA0KLA0KICAgZGF0YSA9Z2VyYV9lbmVyZ19kYXkgJT4lIA0KICAgICBtdXRhdGUoZ2VyX2hpZHJvZWxldHJpY2E9Y2FzZV93aGVuKGdlcl9oaWRyb2VsZXRyaWNhPDAuMDF+MSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUV+Z2VyX2hpZHJvZWxldHJpY2EpLA0KICAgICAgICAgICAgZ2VyX3Rlcm1pY2E9Y2FzZV93aGVuKGdlcl90ZXJtaWNhPDAuMDF+MSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUV+Z2VyX3Rlcm1pY2EpKQ0KICAgKSAlPiUgc3VtbWFyeSgpDQpgYGANCg0KYGBge3J9DQpnZXJhX2VuZXJnX2RheSRkYXRlICU+JSBzdW1tYXJ5KCkNCmxtKGdlcl90ZXJtaWNhfg0KICAgICBnZXJfaGlkcm9lbGV0cmljYSsNCiAgICAgZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9udWNsZWFyKyAgICANCiAgICAgbm9tX3N1YnNpc3RlbWEueCswKw0KICAgICB0cmVuZCthcy5mYWN0b3IobW9udGgpLA0KLA0KICAgZGF0YSA9Z2VyYV9lbmVyZ19kYXkgJT4lIGZpbHRlcihkYXRlPjIwMTgtMDEtMDEgKSkgJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCmBgYHtyfQ0KbG0oZ2VyX3Rlcm1pY2F+DQogICAgIGdlcl9oaWRyb2VsZXRyaWNhKw0KICAgICBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX251Y2xlYXIgKw0KICAgICB0cmVuZCthcy5mYWN0b3IobW9udGgpDQogICAgICNub21fc3Vic2lzdGVtYSswDQogICAgICwNCiAgIGRhdGEgPWdlcmFfZW5lcmdfZGF5KSAlPiUgc3VtbWFyeSgpDQpgYGANCg0KYGBge3J9DQpsbShnZXJfdGVybWljYX4NCiAgICAgZ2VyX2hpZHJvZWxldHJpY2Eqbm9tX3N1YnNpc3RlbWEueCsNCiAgICAgZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9udWNsZWFyICsNCiAgICAgdHJlbmQrYXMuZmFjdG9yKG1vbnRoKSwNCiAgICAgI25vbV9zdWJzaXN0ZW1hKzAsDQogICBkYXRhID1nZXJhX2VuZXJnX2RheSkgJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KG1nY3YpDQogICAgIyBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX251Y2xlYXIgKw0KICAgICMgdHJlbmQrYXMuZmFjdG9yKG1vbnRoKQ0KbV9nYW1fZm9udGVzIDwtIGJhbShnZXJfdGVybWljYSAgfiBzKGdlcl9oaWRyb2VsZXRyaWNhLCBrPTMpICsgcyhnZXJfZW9saWVsZXRyaWNhLCBrPTQpICsNCiAgICAgICAgICAgICAgICAgICAgICBzKGdlcl9mb3Rvdm9sdGFpY2EsIGs9MykgICArICAgICAgICAgICAgICsgcyhnZXJfbnVjbGVhciwgaz0zKSArDQogICAgICAgICAgICAgICAgICAgICAgcyh0cmVuZCwgaz0zKSArIHMobW9udGgsIGs9NCkgKw0KICAgICAgICAgICAgICAgICAgICAgICNzKERlbWFuZGEsIGs9NCkrDQogICAgICAgICAgICAgICAgICAgICAgcyhub21fc3Vic2lzdGVtYS54LCBicyA9ICJyZSIpLA0KICAgICAgICAgICAgIGRhdGEgPSBnZXJhX2VuZXJnX2RheSAlPiUgDQogICAgICAgICAgICAgICBtdXRhdGUoRGVtYW5kYSA9IGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfaGlkcm9lbGV0cmljYStnZXJfdGVybWljYStnZXJfbnVjbGVhciwNCikpDQpzdW1tYXJ5KG1fZ2FtX2ZvbnRlcykNCmBgYA0KDQpgYGB7cn0NCmdhbS5jaGVjayhtX2dhbV9mb250ZXMpICAgICAgICAgICAgICAgICAgICMgY2hlY2EgcmVzw61kdW9zLCBRUS1wbG90LCBrLWFkZXF1YcOnw6NvDQpgYGANCg0KYGBge3J9DQpjb25jdXJ2aXR5KG1fZ2FtX2ZvbnRlcywgZnVsbD1UUlVFKSAgICAgICAjIG11bHRpY29saW5lYXJpZGFkZSBuw6NvIGxpbmVhcg0KcGxvdChtX2dhbV9mb250ZXMsIHBhZ2VzPTQsIHNjaGVtZT0xLCBzaGFkZT1UUlVFLCBzZT1UUlVFLHNjYWxlcyA9ICJmcmVlIikNCmBgYA0KDQojIyMgQ29udHJhZmFjdHVhbCBPdXRyYXMgZm9udGVzIGRlIGVuZXJnaWENCg0KYGBge3J9DQojbmV3ZGF0YV9tMSRlYXJfaGF0X2NmPC1jbGltX2luJGNsaW0yMDI2X2hhdA0KDQpuZXdkYXRhX20xICU+JSANCiAgZ3JvdXBfYnkobm9tX3N1YnNpc3RlbWEueCxkYXRlKSAlPiUgDQogIHN1bW1hcmlzZShlYXI9c3VtKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLG5hLnJtID0gVCksDQogICAgICAgICAgICB2YWxfZ2VyYWNhbz1zdW0odmFsX2dlcmFjYW8pLA0KICAgICAgICAgICAgZWFyX2hhdD1zdW0oZWFyX2hhdCxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgZ2VyX2hhdD1zdW0oZ2VyX2hhdCxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgcGVuYWxpZGFkZV9nZXJhw6fDo29faGlkcm89c3VtKHBlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvLG5hLnJtID0gVCksDQogICAgICAgICAgICBnZXJfaGF0X2NmPXN1bShnZXJfaGF0X2NmLG5hLnJtID0gVCksDQogICAgICAgICAgICBlYXJfaGF0X2NmPXN1bShlYXJfaGF0X2NmLG5hLnJtID0gVCkpICU+JSANCiAgcmlnaHRfam9pbihnZXJhX2VuZXJnX2RheSxieSA9IGMoIm5vbV9zdWJzaXN0ZW1hLngiPSJub21fc3Vic2lzdGVtYSIsImRhdGUiPSJkYXRlIikpLT5nZXJhX2VuZXJnX2RheQ0KZ2VyYV9lbmVyZ19kYXkNCmBgYA0KDQpgYGB7cn0NCmdlcmFfZW5lcmdfZGF5ICU+JSANCiAgZ3JvdXBfYnkodHJlbmQpICU+JSBzdW1tYXJpc2UodmFsX2dlcmFjYW89c3VtKGdlcl9oYXQsbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VyX2hpZHJvZWxldHJpY2E9c3VtKGdlcl9oaWRyb2VsZXRyaWNhLG5hLnJtID0gVCkpICU+JSANCiAgZ2dwbG90KGFlcyh0cmVuZCkpKw0KICBnZW9tX2xpbmUoYWVzKHk9dmFsX2dlcmFjYW8pLGNvbD0iYmx1ZSIpKw0KICBnZW9tX2xpbmUoYWVzKHk9Z2VyX2hpZHJvZWxldHJpY2EpLGNvbD0icmVkIikrdGhlbWVfbWluaW1hbCgpDQpwcmVkaWN0KG1fZ2FtX2ZvbnRlcyxuZXdkYXRhID0gZ2VyICU+JSANCiAgbXV0YXRlKHZhbF9nZXJhY2FvPWdlcl9oYXQpICkNCg0KYGBgDQoNCmBgYHtyfQ0KZ2VyYV9lbmVyZ19kYXkkZ2VyX3Rlcm1pY2FfcHJldmlzdGE8LXByZWRpY3QobV9nYW1fZm9udGVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IGdlcmFfZW5lcmdfZGF5ICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub21fc3Vic2lzdGVtYT1ub21fc3Vic2lzdGVtYS54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVtYW5kYSA9IGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfaGlkcm9lbGV0cmljYStnZXJfdGVybWljYStnZXJfbnVjbGVhcikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCmdlcmFfZW5lcmdfZGF5JGdlcl90ZXJtaWNhX3ByZXZpc3RhX2NmPC1wcmVkaWN0KG1fZ2FtX2ZvbnRlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBnZXJhX2VuZXJnX2RheSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShnZXJfaGlkcm9lbGV0cmljYT1nZXJfaGlkcm9lbGV0cmljYStwZW5hbGlkYWRlX2dlcmHDp8Ojb19oaWRybywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hPW5vbV9zdWJzaXN0ZW1hLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZW1hbmRhID0gZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9oaWRyb2VsZXRyaWNhK2dlcl90ZXJtaWNhK2dlcl9udWNsZWFyKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIENvbnRyYWZhY3R1YWwgY2xpbcOhdGljbyAzKGJhc2VsaW5lIDIwMDHigJMyMDA1KX0NCmdlcmFfZW5lcmdfZGF5ICU+JSANCiAgIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KDQogIGdyb3VwX2J5KHRyZW5kKSAlPiVzdW1tYXJpc2UoZ2VyX3Rlcm1pY2FfcHJldmlzdGE9c3VtKGdlcl90ZXJtaWNhX3ByZXZpc3RhLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXJfdGVybWljYV9wcmV2aXN0YV9jZj1zdW0oZ2VyX3Rlcm1pY2FfcHJldmlzdGFfY2YsbmEucm09VCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB0cmVuZCwpKSArDQogIGdlb21fbGluZShhZXMoeSA9IGdlcl90ZXJtaWNhX3ByZXZpc3RhLzEwMDAsIGNvbG9yID0gIlByZXZpc3RvIiksIHNpemUgPSAwLjcsYWxwaGE9LjYpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZ2VyX3Rlcm1pY2FfcHJldmlzdGFfY2YvMTAwMCwgY29sb3IgPSAiQ29udHJhZmFjdHVhbCAyMDEwIiksIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArI2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW49Z2VyX3Rlcm1pY2FfcHJldmlzdGEvMTAwMCx5bWF4PWdlcl90ZXJtaWNhX3ByZXZpc3RhX2NmLzEwMDApLGFscGhhPS40LGZpbGwgPSAiZmlyZWJyaWNrIiwpKw0KDQogIGxhYnModGl0bGUgPSAiQ29udHJhZmFjdHVhbCBiYXNlbGluZSAoY2xpbWEgbcOpZGlvIDIwMDEtMjAxMCkiLA0KICAgICAgIHkgPSAiR2VyYcOnw6NvIFRlcm1pY2EgKEdXbcOqcykiLCB4ID0gIkRhdGEiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQcmV2aXN0byIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDEwIiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCg0KZ2VyYV9lbmVyZ19kYXkgJT4lIA0KICAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpKSAlPiUgDQoNCiAgZ3JvdXBfYnkodHJlbmQsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKGVuYV9tdzc9c3VtKGdlcl90ZXJtaWNhX3ByZXZpc3RhLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGltMjAyNl9oYXQ9c3VtKGdlcl90ZXJtaWNhX3ByZXZpc3RhX2NmLG5hLnJtPVQpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gdHJlbmQsKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBlbmFfbXc3LzEwMDAsIGNvbG9yID0gIlByZXZpc3RvIiksIHNpemUgPSAwLjcsYWxwaGE9LjYpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gY2xpbTIwMjZfaGF0LzEwMDAsIGNvbG9yID0gIkNvbnRyYWZhY3R1YWwgMjAxMCIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJDb250cmFmYWN0dWFsIGJhc2VsaW5lIChjbGltYSBtw6lkaW8gMjAwMS0yMDEwKSIsDQogICAgICAgeSA9ICJHZXJhw6fDo28gVGVybWljYSAoR1dtw6pzKSIsIHggPSAiRGF0YSIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlByZXZpc3RvIiA9ICJibGFjayIsICJDb250cmFmYWN0dWFsIDIwMTAiID0gImJsdWUiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7ciB9DQpnZXJhX2VuZXJnX2RheSAlPiUgDQogICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIiksDQogICAgICAgICAgcGVuYWxpZGFkZV90ZXJtaWNvPWdlcl90ZXJtaWNhX3ByZXZpc3RhX2NmLWdlcl90ZXJtaWNhX3ByZXZpc3RhLA0KICAgICAgICAgICNwZW5hbGlkYWRlMj1lbmFfbXc3LWNsaW0yMDI2X2hhdCwNCiAgICAgICAgICApLT5nZXJhX2VuZXJnX2RheQ0KZ2VyYV9lbmVyZ19kYXkgJT4lIA0KICAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpLA0KICAgICAgICAgIHBlbmFsaWRhZGUxPWdlcl90ZXJtaWNhX3ByZXZpc3RhX2NmLWdlcl90ZXJtaWNhX3ByZXZpc3RhLA0KICAgICAgICAgICNwZW5hbGlkYWRlMj1lbmFfbXc3LWNsaW0yMDI2X2hhdCwNCiAgICAgICAgICApICU+JSANCg0KICBncm91cF9ieSh0cmVuZCkgJT4lc3VtbWFyaXNlKGVuYV9tdzc9c3VtKHBlbmFsaWRhZGUxLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY2xpbTIwMjZfaGF0PXN1bShwZW5hbGlkYWRlMixuYS5ybT1UKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB0cmVuZCwpKSArDQogICNnZW9tX2xpbmUoYWVzKHkgPSBlbmFfbXc3LCBjb2xvciA9ICJwcmV2aXN0byAtIENvbnRyYWZhY3R1YWwiKSwgc2l6ZSA9IDAuNyxhbHBoYT0uNikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBlbmFfbXc3LzEwMDAsIGNvbG9yID0gIk9ic2VydmFkbyAtIENvbnRyYWZhY3R1YWwgMjAyNiIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyNmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGxhYnModGl0bGUgPSAiSW1wYWN0byBsw61xdWlkbyBkbyBjbGltYSByZWNlbnRlIHNvYnJlIGEgR2VyYcOnw6NvIixzdWJ0aXRsZSA9ICJPYnNlcnZhZG8gLSBDb250cmFmYWN0dWFsIDIwMjYiLA0KICAgICAgIHkgPSAiUGVuYWxpZGFkZSBDbGltw6F0aWNhIG5hIFRlcm1pY2EgKE1XbcOqcykiLCB4ID0gIkRhdGEiKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW49ZW5hX213Ny8xMDAwLHltYXg9MCksYWxwaGE9LjQsZmlsbCA9ICJmaXJlYnJpY2siLCkrDQoNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk9ic2VydmFkbyIgPSAiYmxhY2siLCAiQ29udHJhZmFjdHVhbCAyMDI2IiA9ICJibHVlIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdlcmFfZW5lcmdfZGF5ICU+JSANCiAgIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSwNCiAgICAgICAgICBwZW5hbGlkYWRlX3Rlcm1pY2E9Z2VyX3Rlcm1pY2FfcHJldmlzdGFfY2YtZ2VyX3Rlcm1pY2FfcHJldmlzdGEsDQogICAgICAgICAgI3BlbmFsaWRhZGUyPWVuYV9tdzctY2xpbTIwMjZfaGF0LA0KICAgICAgICAgICkgJT4lIA0KDQogIGdyb3VwX2J5KHRyZW5kLG5vbV9zdWJzaXN0ZW1hLngpICU+JXN1bW1hcmlzZShwZW5hbGlkYWRlX3Rlcm1pY2E9c3VtKHBlbmFsaWRhZGVfdGVybWljYSxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NsaW0yMDI2X2hhdD1zdW0ocGVuYWxpZGFkZTIsbmEucm09VCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gdHJlbmQsKSkgKw0KICAjZ2VvbV9saW5lKGFlcyh5ID0gZW5hX213NywgY29sb3IgPSAicHJldmlzdG8gLSBDb250cmFmYWN0dWFsIiksIHNpemUgPSAwLjcsYWxwaGE9LjYpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcGVuYWxpZGFkZV90ZXJtaWNhLzEwMDAsIGNvbG9yID0gIk9ic2VydmFkbyAtIENvbnRyYWZhY3R1YWwgMjAyNiIpLCBzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZSA9ICJJbXBhY3RvIGzDrXF1aWRvIGRvIGNsaW1hIHJlY2VudGUgc29icmUgYSBHZXJhw6fDo28iLHN1YnRpdGxlID0gIk9ic2VydmFkbyAtIENvbnRyYWZhY3R1YWwgMjAyNiIsDQogICAgICAgeSA9ICJQZW5hbGlkYWRlIENsaW3DoXRpY2EgbmEgVGVybWljYSAoTVdtw6pzKSIsIHggPSAiRGF0YSIpICsNCiAgICBnZW9tX3JpYmJvbihhZXMoeW1pbj1wZW5hbGlkYWRlX3Rlcm1pY2EvMTAwMCx5bWF4PTApLGFscGhhPS40LGZpbGwgPSAiZmlyZWJyaWNrIiwpKw0KDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJPYnNlcnZhZG8iID0gImJsYWNrIiwgIkNvbnRyYWZhY3R1YWwgMjAyNiIgPSAiYmx1ZSIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmFtIG1haW9yIHZvbGF0aWxpZGFkZS4gRXNzYSBkZWNvbXBvc2nDp8OjbyByZWdpb25hbCDDqSBjcnVjaWFsIHBhcmEgYXZhbGlhciBhIGVsYXN0aWNpZGFkZSBkYSBlc2Nhc3NleiBlIG8gcmVkaXJlY2lvbmFtZW50byBkYSBwcmVzc8OjbyBwYXJhIG91dHJhcyBmb250ZXMgZGUgZ2VyYcOnw6NvLg0KDQpgYGB7cn0NCmdlcmFfZW5lcmdfZGF5ICU+JSANCiAgIG11dGF0ZShwZW5hbGlkYWRlMT1nZXJfdGVybWljYV9wcmV2aXN0YV9jZi1nZXJfdGVybWljYV9wcmV2aXN0YSwNCiAgICAgICAgICBwZW5hbGlkYWRlX3BlcmM9Z2VyX3Rlcm1pY2FfcHJldmlzdGFfY2YvZ2VyX3Rlcm1pY2FfcHJldmlzdGEsDQogICAgICAgICAgI3BlbmFsaWRhZGUyPWVuYV9tdzctY2xpbTIwMjZfaGF0LA0KICAgICAgICAgICkgJT4lIA0KDQogIGdyb3VwX2J5KCxub21fc3Vic2lzdGVtYS54KSAlPiVzdW1tYXJpc2UocGVuYWxpZGFkZTE9c3VtKHBlbmFsaWRhZGUxLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VyX2hhdD1zdW0oZ2VyX2hhdCxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlcl9oYXRfY2Y9c3VtKGdlcl9oYXRfY2YsbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZW5hbGlkYWRlX3BlcmM9bWVhbihwZW5hbGlkYWRlX3BlcmMsbmEucm09VCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NsaW0yMDI2X2hhdD1zdW0ocGVuYWxpZGFkZTIsbmEucm09VCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgbXV0YXRlKGN1c3RvX2ZpbmFuY2Vpcm9fdXNvdGVybWljbz1wZW5hbGlkYWRlMSozMDApLT5wZW5hbGlkYWRlX3Rlcm1pY28NCg0KYGBgDQoNCmBgYHtyfQ0KYmluZF9yb3dzKHBlbmFsaWRhZGVfaGlkcmljbyAlPiUgbXV0YXRlKGVzdGltYT0iSGlkcm8iKSxwZW5hbGlkYWRlX3Rlcm1pY28gJT4lIG11dGF0ZShlc3RpbWE9IlTDqXJtaWNvIikpICU+JSANCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgiY3VzdG8iKSkgJT4lIA0KICBtdXRhdGUoY3VzdG9fUmVhaXM9Y2FzZV93aGVuKGVzdGltYT09IkhpZHJvIn5wZW5hbGlkYWRlMSotMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFfnBlbmFsaWRhZGUxKjMwMCksDQogICAgICAgICBjdXN0b19VU0Q9Y3VzdG9fUmVhaXMvNS4yDQogICAgICAgICApIA0KYGBgDQoNCmBgYHtyfQ0KYmluZF9yb3dzKHBlbmFsaWRhZGVfaGlkcmljbyAlPiUgbXV0YXRlKGVzdGltYT0iSGlkcm8iKSxwZW5hbGlkYWRlX3Rlcm1pY28gJT4lIG11dGF0ZShlc3RpbWE9IlTDqXJtaWNvIikpICU+JSANCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgiY3VzdG8iKSkgJT4lIA0KICBtdXRhdGUoY3VzdG9fUmVhaXM9Y2FzZV93aGVuKGVzdGltYT09IkhpZHJvIn5wZW5hbGlkYWRlMSotMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFfnBlbmFsaWRhZGUxKjMwMCksDQogICAgICAgICBjdXN0b19VU0Q9Y3VzdG9fUmVhaXMvNS4yDQogICAgICAgICApICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vbV9zdWJzaXN0ZW1hLngseT1jdXN0b19VU0QvMTAwMDAwMCxmaWxsPWVzdGltYSkpK2dlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrDQogIGdlb21fdGV4dChhZXMoeT1jdXN0b19VU0QvMTAwMDAwMCsyLGxhYmVsID0gcm91bmQoY3VzdG9fVVNELzEwMDAsIDEpKSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MSksIHNpemUgPSAzLGNoZWNrX292ZXJsYXA9RikrY29vcmRfZmxpcCgpKw0KICBsYWJzKHRpdGxlID0gIkN1c3RvIGVjb27DtG1pY28gZXN0aW1hZG8gZGEgcGVuYWxpZGFkZSBjbGltw6F0aWNhICgyMDEwLTIwMjMpIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJDdXN0byBmaW5hbmNlaXJvIGFwcm94aW1hZG8gZG8gaW1wYWN0byBjbGltw6F0aWNvIHNvYnJlIGEgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2EgZSB0w6lybWljYSIsDQogICAgICAgeSA9ICJDdXN0byAoVVMkIG1pbCkiLCB4ID0gIlN1YnNpc3RlbWEiKSArdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQojIyBQTEQ6IEN1c3RvIHBhcmEgbyBzaXN0ZW1hDQoNCmBgYHtyfQ0KcGxkICAgICA8LSByZWFkLmNzdigicHJlY29fc2VtYW5hbC5jc3YiKSAgICAgICAgICAgIyBQTEQgc2VtYW5hbA0KcGxkJGRhdGUgPC0gYXMuRGF0ZShwbGQkZGF0YXMpICAgIyBpZGVtIHBhcmEgYSBiYXNlIGRlIFBMRA0KcGxkJHdlZWsgIDwtIGx1YnJpZGF0ZTo6aXNvd2VlayhwbGQkZGF0YXMpDQpwbGQkeWVhciAgPC0gbHVicmlkYXRlOjp5ZWFyKHBsZCRkYXRhcykNCmBgYA0KDQpgYGB7cn0NCg0KI3BsZCRkYXRlPC1wbGQkREFUQV9JTklDSU8gJT4lIGFzX2RhdGUoKSANCnBsZCAlPiUgc3ByZWFkKFN1Ym1lcmNhZG8scHJlY28pLT5wbGQNCnBsZCRkYXRlICU+JSBtaW4oKS0+aW5pY2lvDQpwbGQgJT4lIGZpbHRlcihEQVRBX0lOSUNJTz09aW5pY2lvKQ0KZGF0YXM8LWdlcmFfZW5lcmdfZGF5JGRhdGUgJT4lIHVuaXF1ZQ0KZGF0YS5mcmFtZShkYXRhcykgJT4lIGZpbHRlcihkYXRhcz5pbmljaW8tMSkgJT4lIGFycmFuZ2UoZGF0YXMpICU+JSBsZWZ0X2pvaW4ocGxkLGJ5ID0gYygiZGF0YXMiPSJkYXRlIikpLT5kYWFzX2NvbXBsZXRhcw0KZGFhc19jb21wbGV0YXMNCmk9Mg0KZm9yIChpIGluIDE6bGVuZ3RoKGRhYXNfY29tcGxldGFzJEFOTykpIHsjbGVuZ3RoKGRhYXNfY29tcGxldGFzJEFOTykNCiAgcHJpbnQoaSkNCiAgaWYgKGlzLm5hKGRhYXNfY29tcGxldGFzJEFOT1tpXSkpIHsNCiAgICBkYWFzX2NvbXBsZXRhcyRBTk9baV08LWRhYXNfY29tcGxldGFzJEFOT1tpLTFdDQogICAgZGFhc19jb21wbGV0YXMkTUVTW2ldPC1kYWFzX2NvbXBsZXRhcyRNRVNbaS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJFNFTUFOQVtpXTwtZGFhc19jb21wbGV0YXMkU0VNQU5BW2ktMV0NCiAgICBkYWFzX2NvbXBsZXRhcyREQVRBX0ZJTVtpXTwtZGFhc19jb21wbGV0YXMkREFUQV9GSU1baS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJFNVREVTVEVbaV08LWRhYXNfY29tcGxldGFzJFNVREVTVEVbaS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJFNVTFtpXTwtZGFhc19jb21wbGV0YXMkU1VMW2ktMV0NCiAgICBkYWFzX2NvbXBsZXRhcyROT1JERVNURVtpXTwtZGFhc19jb21wbGV0YXMkTk9SREVTVEVbaS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJE5PUlRFW2ldPC1kYWFzX2NvbXBsZXRhcyROT1JURVtpLTFdDQoNCiAgICANCiAgfQ0KICANCn0gIA0KZGFhc19jb21wbGV0YXMgJT4lIGdhdGhlcihrZXkgPSAibm9tX3N1YnNpdGVtYSIsdmFsdWUgPSAicHJlY28iLGMoIk5PUkRFU1RFIiwiU1VERVNURSIsIlNVTCIsIk5PUlRFIikpLT5wbGQNCmBgYA0KDQpgYGB7cn0NCnNlcmllIDwtIGRhYXNfY29tcGxldGFzICU+JQ0KICBwdWxsKE5PUkRFU1RFKSAlPiUNCiAgdHMoc3RhcnQgPSAgYygyMDAxLCAxODEpLCBmcmVxdWVuY3kgPSAzNjUpDQpzdGwoc2VyaWUscy53aW5kb3cgPSAicGVyaW9kaWMiKSAlPiUgcGxvdA0KDQpzZXJpZSA8LSBkYWFzX2NvbXBsZXRhcyAlPiUNCiAgcHVsbChTVUwpICU+JQ0KICB0cyhzdGFydCA9ICBjKDIwMDEsIDE4MSksIGZyZXF1ZW5jeSA9IDM2NSkNCnN0bChzZXJpZSxzLndpbmRvdyA9ICJwZXJpb2RpYyIpICU+JSBwbG90DQoNCnNlcmllIDwtIGRhYXNfY29tcGxldGFzICU+JQ0KICBwdWxsKFNVREVTVEUpICU+JQ0KICB0cyhzdGFydCA9ICBjKDIwMDEsIDE4MSksIGZyZXF1ZW5jeSA9IDM2NSkNCnN0bChzZXJpZSxzLndpbmRvdyA9ICJwZXJpb2RpYyIpICU+JSBwbG90DQoNCnNlcmllIDwtIGRhYXNfY29tcGxldGFzICU+JQ0KICBwdWxsKE5PUlRFKSAlPiUNCiAgdHMoc3RhcnQgPSAgYygyMDAxLCAxODEpLCBmcmVxdWVuY3kgPSAzNjUpDQpzdGwoc2VyaWUscy53aW5kb3cgPSAicGVyaW9kaWMiKSAlPiUgcGxvdA0KDQoNCmBgYA0KDQpgYGB7cn0NCnBsZCRTdWJtZXJjYWRvICU+JSB1bmlxdWUoKQ0KZ2VyYV9lbmVyZ19kYXkkbm9tX3N1YnNpc3RlbWEueCAlPiUgdW5pcXVlDQoNCiNuZXdkYXRhX20xICU+JSB3cml0ZS5jc3YoImJhc2UgdmFsb3JlcyBwcmV2aXN0b3MuY3N2IikNCiNnZXJhX2VuZXJnX2RheSAlPiUgd3JpdGUuY3N2KCJ2YWxvcmVzX3ByZXZpc3Rvc19kYXkuY3N2IikNCmBgYA0KDQpgYGB7cn0NCmdlcmFfZW5lcmdfZGF5ICU+JSBpbm5lcl9qb2luKHBsZCxieT1jKCJkYXRlIiwibm9tX3N1YnNpc3RlbWEueCI9Im5vbV9zdWJzaXRlbWEiKSktPnBsZF9mdWxsDQpwbGRfZnVsbCAlPiUgc3VtbWFyeSgpDQoNCmBgYA0KDQpgYGB7cn0NCnBsZF9mdWxsICU+JSBncm91cF9ieShkYXRlKSAlPiUgc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKGRhdGUscHJlY28pKStnZW9tX2xpbmUoKQ0KcGxkX2Z1bGwgJT4lIA0KICBncm91cF9ieSh0cmVuZCkgJT4lIHN1bW1hcmlzZShwcmVjbz1tZWFuKHByZWNvLG5hLnJtID0gVCkpICU+JSANCiAgZ2dwbG90KGFlcyh0cmVuZCxwcmVjbykpK2dlb21fbGluZSgpDQpwbGRfZnVsbCAlPiUgDQogIGdyb3VwX2J5KG1vbnRoKSAlPiUgc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKG1vbnRoLHByZWNvKSkrZ2VvbV9saW5lKCkNCnBsZF9mdWxsICU+JSANCiAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpKSAlPiUgDQoNCiAgZ3JvdXBfYnkobWVzKSAlPiUgc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKG1lcyxwcmVjbykpK2dlb21fbGluZSgpDQpgYGANCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUgDQogIGdncGxvdChhZXMoZGF0ZSxwcmVjbyxub21fc3Vic2lzdGVtYS54KSkrZ2VvbV9saW5lKCkrZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCkNCg0KcGxkX2Z1bGwgJT4lIA0KICBncm91cF9ieSh0cmVuZCxub21fc3Vic2lzdGVtYS54KSAlPiUgc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHRyZW5kLHByZWNvKSkrZ2VvbV9saW5lKCkrZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCkNCnBsZF9mdWxsICU+JSANCiAgZ3JvdXBfYnkobW9udGgsbm9tX3N1YnNpc3RlbWEueCkgJT4lIHN1bW1hcmlzZShwcmVjbz1tZWFuKHByZWNvLG5hLnJtID0gVCkpICU+JSANCiAgZ2dwbG90KGFlcyhtb250aCxwcmVjbykpK2dlb21fbGluZSgpK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngpDQpwbGRfZnVsbCAlPiUgDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KDQogIGdyb3VwX2J5KG1lcyxub21fc3Vic2lzdGVtYS54KSAlPiUgc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKG1lcyxwcmVjbykpK2dlb21fbGluZSgpK2ZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngpDQpgYGANCg0KIyMjIG1vZGVsb3MgaW5nZW51b3MNCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUgc3RyKCkNCmBgYA0KDQpgYGB7cn0NCmxtKGxvZyhwcmVjbyl+bG9nKGdlcl9oaWRyb2VsZXRyaWNhKStsb2coZ2VyX2VvbGllbGV0cmljYSkrbG9nKGdlcl9mb3Rvdm9sdGFpY2EpK2xvZyhnZXJfdGVybWljYSkrDQogICAgIGxvZyhEZW1hbmRhKStub21fc3Vic2lzdGVtYS54LA0KICAgZGF0YT1wbGRfZnVsbCAlPiUNCiAgICAgbXV0YXRlKGdlcl9oaWRyb2VsZXRyaWNhPWlmZWxzZShnZXJfaGlkcm9lbGV0cmljYT09MCwxLGdlcl9oaWRyb2VsZXRyaWNhKSwNCiAgICAgICAgICAgIGdlcl9mb3Rvdm9sdGFpY2E9aWZlbHNlKGdlcl9mb3Rvdm9sdGFpY2E9PTAsMSxnZXJfZm90b3ZvbHRhaWNhKSwNCiAgICAgICAgICAgIGdlcl9lb2xpZWxldHJpY2E9aWZlbHNlKGdlcl9lb2xpZWxldHJpY2E9PTAsMSxnZXJfZW9saWVsZXRyaWNhKSwNCiAgICAgICAgICAgIGdlcl90ZXJtaWNhPWlmZWxzZShnZXJfdGVybWljYT09MCwxLGdlcl90ZXJtaWNhKSwNCiAgICAgICAgICAgICNEZW1hbmRhPWlmZWxzZSh2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYT09MCwxLHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hKSwNCiAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIsDQoNCiAgICAgICAgICAgICkpICU+JSBzdW1tYXJ5KCkNCnBsZF9mdWxsJGdlcl9oaWRyb2VsZXRyaWNhICU+JSBzdW1tYXJ5KCkNCmBgYA0KDQotICAgQXVtZW50byBkZSAxJSBuYSBnZXJhw6fDo28gaMOtZHJpY2EgcmVkdXogbyBwcmXDp28gZW0gMSw3JS4NCg0KLSAgICsxJSBlbSBlw7NsaWNhIOKGkiArMCwyMSUgbm8gcHJlw6dvLg0KDQotICAgQXVtZW50byBkZSAxJSBuYSBzb2xhciByZWR1eiBwcmXDp28gZW0gMCw0MCUuDQoNCi0gICBFbGFzdGljaWRhZGUgZm9ydGU6ICsxJSBuYSBkZW1hbmRhIOKGkiArMSw5NSUgbm8gcHJlw6dvLg0KDQotICAgUsKyID0gMC4zNDYgKFx+MzUlKQ0KDQogICAgIyMjIEdBTSBQcmXDp28gUExEDQoNCmBgYHtyfQ0KZ2FtX21vZCA8LSBnYW0ocHJlY28gfiAjdHJlbmQrDQogICAgICAgICAgICAgICAgIHMobG9nKGdlcl9oaWRyb2VsZXRyaWNhKSkgKyANCiAgICAgICAgICAgICAgICAgcyhsb2codHJlbmQpKSArICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBzKGxvZyhkb3kpKSsNCiAgICAgICAgICAgICAgICAgcyhsb2coZ2VyX2VvbGllbGV0cmljYSkpICsgDQogICAgICAgICAgICAgICAgIHMobG9nKGdlcl9mb3Rvdm9sdGFpY2EpKSArIA0KICAgICAgICAgICAgICAgICBzKGxvZyhEZW1hbmRhKSkgKyANCiAgICAgICAgICAgICAgICAgcyhsb2coZ2VyX3Rlcm1pY2EpKSsNCiAgICAgICAgICAgICAgICAgI3Mobm9tX3N1YnNpc3RlbWEueCwgYnMgPSAicmUiKSwjIGVmZWl0byBhbGVhdMOzcmlvIHBvciByZXNlcnZhdMOzcmlvDQogICAgICAgICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hLngsDQogICAgICAgICAgICAgICBkYXRhID0gcGxkX2Z1bGwgJT4lDQogICAgICAgICAgICAgICAgIG11dGF0ZSgNCiAgICAgICAgICAgICAgICAgICBnZXJfaGlkcm9lbGV0cmljYSA9IGlmZWxzZShnZXJfaGlkcm9lbGV0cmljYSA9PSAwLCAxLCBnZXJfaGlkcm9lbGV0cmljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX2ZvdG92b2x0YWljYSA9IGlmZWxzZShnZXJfZm90b3ZvbHRhaWNhID09IDAsIDEsIGdlcl9mb3Rvdm9sdGFpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9lb2xpZWxldHJpY2EgPSBpZmVsc2UoZ2VyX2VvbGllbGV0cmljYSA9PSAwLCAxLCBnZXJfZW9saWVsZXRyaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfdGVybWljYSA9IGlmZWxzZShnZXJfdGVybWljYSA9PSAwLCAxLCBnZXJfdGVybWljYSksDQogICAgICAgICAgICAgICAgICAgI0RlbWFuZGEgPSBpZmVsc2UodmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEgPT0gMCwgMSwgdmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEpDQogICAgICAgICAgICAgICAgICAgRGVtYW5kYSA9IGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfaGlkcm9lbGV0cmljYStnZXJfdGVybWljYStnZXJfbnVjbGVhciwNCiAgICAgICAgICAgICAgICAgKSkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoZ2FtX21vZCkNCnBsb3QoZ2FtX21vZCwgcGFnZXMgPSAzLCBzaGFkZSA9IFRSVUUpDQoNCmBgYA0KDQotICAgKipSwrIgYWp1c3RhZG8gPSAwLjUwKiog4oaSIG8gR0FNIGV4cGxpY291ICoqbWV0YWRlIGRhIHZhcmnDom5jaWEqKiBkb3MgcHJlw6dvcywgY29udHJhIFx+MC4zNSBkbyBtb2RlbG8gbGluZWFyIGFudGVyaW9yLg0KDQogICAgLSAgICoqRGV2aWFuY2UgZXhwbGFpbmVkID0gNTAlKiog4oaSIG11aXRvIG1haXMgYWRlcsOqbmNpYS4NCg0KLSAgICoqSGlkcmVsw6l0cmljYSAoYHMobG9nKGdlcl9oaWRybykpYCkqKg0KDQogICAgLSAgIE8gZWZlaXRvIMOpICoqZm9ydGUgYXTDqSBjZXJ0byBwb250byoqIGUgZGVwb2lzICoqc2F0dXJhKioNCg0KLSAgIEXDs2xpY2ENCg0KICAgIC0gICBMaW5oYSByZWxhdGl2YW1lbnRlIHBsYW5hLCBsZXZlbWVudGUgbmVnYXRpdmEgZW0gdmFsb3JlcyBhbHRvcy4NCg0KICAgIC0gICBNb3N0cmEgcXVlIGEgZcOzbGljYSB0ZW0gZWZlaXRvIGZyYWNvIG91IGF0w6kgbmV1dHJvIGVtIGZhaXhhcyBub3JtYWlzIGRlIG9wZXJhw6fDo28sIG1hcyBwb2RlIGFqdWRhciBhIGJhaXhhciBwcmXDp29zIGVtIGNvbmRpw6fDtWVzIGV4dHJlbWFzLg0KDQotICAgU29sYXINCg0KICAgIC0gICBFZmVpdG8gcHJhdGljYW1lbnRlICoqbGluZWFyIGUgbmVnYXRpdm8qKiwgbWFzIGZyYWNvIChlZGYg4omIIDEg4oaSIHF1YXNlIGxpbmVhcikNCg0KLSAgIERlbWFuZGENCg0KYGBgICAgICAgICAgDQotICAgQ2xhcmFtZW50ZSBjcmVzY2VudGUsIGUgbWFpcyDDrW5ncmVtZSBlbSB2YWxvcmVzIGFsdG9zLiBJc3NvIG1vc3RyYSBxdWUgbyBwcmXDp28gcmVzcG9uZGUgZGUgZm9ybWEgbsOjbyBsaW5lYXI6DQoNCiAgICAtICAgZW0gZGVtYW5kYXMgYmFpeGFzL23DqWRpYXMsIGVmZWl0byBzdWF2ZSwNCg0KLSAgIGVtIGRlbWFuZGFzIG11aXRvIGFsdGFzLCBwcmXDp28gZGlzcGFyYQ0KDQotICAgRXhhdGFtZW50ZSBvIGNvbXBvcnRhbWVudG8gZXNwZXJhZG8gZW0gc2lzdGVtYXMgY29tIGRlc3BhY2hvIHBvciBvcmRlbSBkZSBtw6lyaXRvLg0KYGBgDQoNCiMjIyBQcmV2aXN0byBQTEQNCg0KYGBge3J9DQoNCiNwbGRfZnVsbCRwcmVjX3ByZXZpc3RvPC1wcmVkaWN0KGdhbV9tb2QsKQ0KDQpwcmVkaWN0KGdhbV9tb2QsbmV3ZGF0YT1wbGRfZnVsbCAlPiUNCiAgICAgICAgICAgICAgICAgbXV0YXRlKA0KICAgICAgICAgICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhID0gaWZlbHNlKGdlcl9oaWRyb2VsZXRyaWNhID09IDAsIDEsIGdlcl9oaWRyb2VsZXRyaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZm90b3ZvbHRhaWNhID0gaWZlbHNlKGdlcl9mb3Rvdm9sdGFpY2EgPT0gMCwgMSwgZ2VyX2ZvdG92b2x0YWljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX2VvbGllbGV0cmljYSA9IGlmZWxzZShnZXJfZW9saWVsZXRyaWNhID09IDAsIDEsIGdlcl9lb2xpZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXJfdGVybWljYSA9IGlmZWxzZShnZXJfdGVybWljYSA9PSAwLCAxLCBnZXJfdGVybWljYSksDQogICAgICAgICAgICAgICAgICAgRGVtYW5kYSA9IGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfaGlkcm9lbGV0cmljYStnZXJfdGVybWljYStnZXJfbnVjbGVhciwNCg0KICAgICAgICAgICAgICAgICAgICNEZW1hbmRhID0gaWZlbHNlKHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hID09IDAsIDEsIHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hKQ0KICAgICAgICAgICAgICAgICApLHR5cGU9InJlc3BvbnNlIikgLT4gcGxkX2Z1bGwkcHJlY19wcmV2aXN0bw0KYGBgDQoNCmBgYHtyfQ0KcGxkX2Z1bGwgJT4lIA0KDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KICBncm91cF9ieShtZXMsbm9tX3N1YnNpc3RlbWEueCkgJT4lIHN1bW1hcmlzZShwcmVjX3ByZXZpc3RvPW1lYW4ocHJlY19wcmV2aXN0byxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSANCiAgZ2dwbG90KGFlcyhtZXMscHJlY19wcmV2aXN0bykpKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsY29sPSJyZWQiKSArDQogIGdlb21fbGluZShhZXMoeT1wcmVjbyksY29sID0gImJsYWNrIikrDQogIGxhYnMoeT0iJCIseD0iWWVhciIpK3RoZW1lX21pbmltYWwoKSsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCxzY2FsZXMgPSAiZnJlZSIpDQoNCnBsZF9mdWxsICU+JSANCiAgbXV0YXRlKG1lcyA9IGZsb29yX2RhdGUoZGF0ZSwgdW5pdCA9ICJtb250aCIpKSAlPiUgDQogIGdyb3VwX2J5KG1lcyxub21fc3Vic2lzdGVtYS54KSAlPiVzdW1tYXJpc2UocHJlY289bWVhbihwcmVjbyxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVjX3ByZXZpc3RvPW1lYW4ocHJlY19wcmV2aXN0byxuYS5ybT1UKSkgJT4lDQogIGdncGxvdCggYWVzKHggPSBtZXMsKSkgKw0KICAjZ2VvbV9wb2ludChhZXMoY29sb3I9cmVzaWRfY29sKSkrDQogIGZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKSsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcHJlY19wcmV2aXN0byksY29sPSJyZWQiKSArICAjZ2VvbV9saW5lKGFlcyh5PWV4cChwcmVjX3ByZXZpc3RvKSkpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW49cHJlY19wcmV2aXN0byx5bWF4PXByZWNvKSxhbHBoYT0uNCxmaWxsID0gImZpcmVicmljayIsKSsNCiAgbGFicyh0aXRsZSA9ICJSZXPDrWR1b3MgZG8gbW9kZWxvIChvYnNlcnZhZG8gLSBwcmV2aXN0bykiLA0KICAgICAgIHkgPSAiUmVzw61kdW8iLCB4ID0gIkRhdGEiKSArDQoNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUgDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KICBncm91cF9ieShtZXMsbm9tX3N1YnNpc3RlbWEueCkgJT4lIHN1bW1hcmlzZShwcmVjX3ByZXZpc3RvPW1lYW4ocHJlY19wcmV2aXN0byxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWNvPW1lYW4ocHJlY28sbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSANCiAgZ2dwbG90KGFlcyhtZXMscHJlY19wcmV2aXN0bykpKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsY29sPSJyZWQiKSArDQogIGdlb21fbGluZShhZXMoeT1wcmVjbyksY29sID0gImJsYWNrIikrDQogIGxhYnMoeT0iJCIseD0iWWVhciIpK3RoZW1lX21pbmltYWwoKSsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCxzY2FsZXMgPSAiZnJlZSIpDQpwbGRfZnVsbCAlPiUgDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KICBncm91cF9ieShtZXMsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHByZWNvPW1lYW4ocHJlY28sbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlY19wcmV2aXN0bz1tZWFuKHByZWNfcHJldmlzdG8sbmEucm09VCkpICU+JQ0KICBnZ3Bsb3QoIGFlcyh4ID0gbWVzLCkpICsNCiAgI2dlb21fcG9pbnQoYWVzKGNvbG9yPXJlc2lkX2NvbCkpKw0KICBmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogIGdlb21fbGluZShhZXMoeSA9IHByZWNfcHJldmlzdG8pLGNvbD0icmVkIikgKyAgZ2VvbV9saW5lKGFlcyh5PXByZWNfcHJldmlzdG8pKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluPXByZWNfcHJldmlzdG8seW1heD1wcmVjbyksYWxwaGE9LjQsZmlsbCA9ICJmaXJlYnJpY2siLCkrDQogIGxhYnModGl0bGUgPSAiUmVzw61kdW9zIGRvIG1vZGVsbyAob2JzZXJ2YWRvIC0gcHJldmlzdG8pIiwNCiAgICAgICB5ID0gIlJlc8OtZHVvIiwgeCA9ICJEYXRhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiMjIyBDb250cmFmYWN0dWFsIFBMRA0KDQpgYGB7cn0NCmdlcmFfZW5lcmdfZGF5JGdlcl90ZXJtaWNhX3ByZXZpc3RhPC1wcmVkaWN0KG1fZ2FtX2ZvbnRlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBnZXJhX2VuZXJnX2RheSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9tX3N1YnNpc3RlbWE9bm9tX3N1YnNpc3RlbWEueCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpnZXJhX2VuZXJnX2RheSRnZXJfdGVybWljYV9wcmV2aXN0YV9jZjwtcHJlZGljdChtX2dhbV9mb250ZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gZ2VyYV9lbmVyZ19kYXkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZ2VyX2hpZHJvZWxldHJpY2E9Z2VyX2hpZHJvZWxldHJpY2ErcGVuYWxpZGFkZV9nZXJhw6fDo29faGlkcm8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub21fc3Vic2lzdGVtYT1ub21fc3Vic2lzdGVtYS54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlcl90ZXJtaWNhPWdlcl90ZXJtaWNhLXBlbmFsaWRhZGVfdGVybWljbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpgYGANCg0KYGBge3J9DQoNCnByZWRpY3QoZ2FtX21vZCxuZXdkYXRhPXBsZF9mdWxsICU+JQ0KICAgICAgICAgICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICAgICBEZW1hbmRhID0gZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9oaWRyb2VsZXRyaWNhK2dlcl90ZXJtaWNhK2dlcl9udWNsZWFyLA0KICAgICAgICAgICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhID0gaWZlbHNlKGlzLm5hKGdlcl9oaWRyb2VsZXRyaWNhK3BlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhK3BlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfaGlkcm9lbGV0cmljYSA9IGlmZWxzZShnZXJfaGlkcm9lbGV0cmljYTwxICwgMSwgZ2VyX2hpZHJvZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9mb3Rvdm9sdGFpY2EgPSBpZmVsc2UoZ2VyX2ZvdG92b2x0YWljYSA9PSAwLCAxLCBnZXJfZm90b3ZvbHRhaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZW9saWVsZXRyaWNhID0gaWZlbHNlKGdlcl9lb2xpZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2VvbGllbGV0cmljYSksDQogICAgICAgICAgICAgICAgICBnZXJfdGVybWljYSA9IGlmZWxzZShnZXJfdGVybWljYStwZW5hbGlkYWRlX3Rlcm1pY288IDAuMSwgMSwgZ2VyX3Rlcm1pY2ErcGVuYWxpZGFkZV90ZXJtaWNvKSwNCg0KICAgICAgICAgICAgICAgICApLHR5cGU9InJlc3BvbnNlIikgLT4gcGxkX2Z1bGwkcHJlY19wcmV2aXN0b19jZg0KDQpwbGRfZnVsbCAlPiUgdW5ncm91cCgpICU+JSANCiAgI211dGF0ZShwZW5hbGlkYWRlX3Rlcm1pY28pDQogIHNlbGVjdChwcmVjX3ByZXZpc3RvLHByZWNfcHJldmlzdG9fY2YscHJlY28sZ2VyX3Rlcm1pY2EscGVuYWxpZGFkZV90ZXJtaWNvLHBlbmFsaWRhZGVfZ2VyYcOnw6NvX2hpZHJvKSAlPiUgc3VtbWFyeSgpDQoNCiAgICAgICAgICAgICAgICAgDQpgYGANCg0KYGBge3J9DQoNCg0KcGxkX2Z1bGwgJT4lIA0KICBtdXRhdGUobWVzID0gZmxvb3JfZGF0ZShkYXRlLCB1bml0ID0gIm1vbnRoIikpICU+JSANCiAgZ3JvdXBfYnkobWVzLG5vbV9zdWJzaXN0ZW1hLngpICU+JSBzdW1tYXJpc2UocHJlY19wcmV2aXN0bz1tZWFuKHByZWNfcHJldmlzdG8sbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVjbz1tZWFuKHByZWNvLG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlY19wcmV2aXN0b19jZj1tZWFuKHByZWNfcHJldmlzdG9fY2YsbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSANCiAgZ2dwbG90KGFlcyhtZXMsKHByZWNfcHJldmlzdG8pKSkrDQogIGdlb21fbGluZShzaXplID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIixjb2w9InJlZCIpICsNCiAgI2dlb21fbGluZShhZXMoeT1wcmVjbyksY29sID0gImJsYWNrIikrDQogICAgZ2VvbV9saW5lKGFlcyh5PShwcmVjX3ByZXZpc3RvX2NmKSksY29sID0gImJsdWUiKSsNCg0KICBsYWJzKHk9IiQiLHg9IlllYXIiKSt0aGVtZV9taW5pbWFsKCkrDQogIGZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsc2NhbGVzID0gImZyZWUiKQ0KDQpgYGANCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUgDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KICBncm91cF9ieShtZXMsbm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHByZWNfcHJldmlzdG9fY2Y9bWVhbihwcmVjX3ByZXZpc3RvX2NmLG5hLnJtPVQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWNfcHJldmlzdG89bWVhbihwcmVjX3ByZXZpc3RvLG5hLnJtPVQpKSAlPiUNCiAgZ2dwbG90KCBhZXMoeCA9IG1lcywpKSArDQogICNnZW9tX3BvaW50KGFlcyhjb2xvcj1yZXNpZF9jb2wpKSsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCxzY2FsZXMgPSAiZnJlZSIpKw0KICAjZ2VvbV9saW5lKGFlcyh5ID0gZXhwKHByZWNfcHJldmlzdG9fY2YpKSxjb2w9InJlZCIpICsgDQogIGdlb21fbGluZShhZXMoeT0ocHJlY19wcmV2aXN0b19jZiktKHByZWNfcHJldmlzdG8pKSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj0wLHltYXg9KHByZWNfcHJldmlzdG9fY2YpLShwcmVjX3ByZXZpc3RvKSksYWxwaGE9LjQsZmlsbCA9ICJmaXJlYnJpY2siLCkrDQogIGxhYnModGl0bGUgPSAiUGVuYWxpZGFkZSAoQ29udHJhZmFjdHVhbC0gUHJlZGl0bykiLA0KICAgICAgIHkgPSAiUGVuYWxpZGFkZSBDbGltw6F0aWNhIG5vIFByZcOnbyIsIHggPSAiRGF0YSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUgDQogIG11dGF0ZShtZXMgPSBmbG9vcl9kYXRlKGRhdGUsIHVuaXQgPSAibW9udGgiKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyLG5vbV9zdWJzaXN0ZW1hLngpICU+JXN1bW1hcmlzZShwcmVjX3ByZXZpc3RvX2NmPW1lYW4ocHJlY19wcmV2aXN0b19jZixuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVjX3ByZXZpc3RvPW1lYW4ocHJlY19wcmV2aXN0byxuYS5ybT1UKSkgJT4lDQogIGdncGxvdCggYWVzKHggPSB5ZWFyLCkpICsNCiAgI2dlb21fcG9pbnQoYWVzKGNvbG9yPXJlc2lkX2NvbCkpKw0KICBmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LHNjYWxlcyA9ICJmcmVlIikrDQogICNnZW9tX2xpbmUoYWVzKHkgPSBleHAocHJlY19wcmV2aXN0b19jZikpLGNvbD0icmVkIikgKyANCiAgZ2VvbV9saW5lKGFlcyh5PShwcmVjX3ByZXZpc3RvX2NmKS0ocHJlY19wcmV2aXN0bykpKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluPTAseW1heD0ocHJlY19wcmV2aXN0b19jZiktKHByZWNfcHJldmlzdG8pKSxhbHBoYT0uNCxmaWxsID0gImZpcmVicmljayIsKSsNCiAgbGFicyh0aXRsZSA9ICJQZW5hbGlkYWRlIChDb250cmFmYWN0dWFsLSBQcmVkaXRvKSIsDQogICAgICAgeSA9ICJQZW5hbGlkYWRlIENsaW3DoXRpY2Egbm8gUHJlw6dvIiwgeCA9ICJEYXRhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCnBsZF9mdWxsICU+JSANCiAgIG11dGF0ZShwZW5hbGlkYWRlMT1wcmVjX3ByZXZpc3RvX2NmLXByZWNfcHJldmlzdG8sDQogICAgICAgICAgcGVuYWxpZGFkZV9wZXJjPXByZWNfcHJldmlzdG9fY2YvcHJlY19wcmV2aXN0bywNCiAgICAgICAgICAjcGVuYWxpZGFkZTI9ZW5hX213Ny1jbGltMjAyNl9oYXQsDQogICAgICAgICAgKSAlPiUgDQoNCiAgZ3JvdXBfYnkobm9tX3N1YnNpc3RlbWEueCkgJT4lc3VtbWFyaXNlKHBlbmFsaWRhZGUxPXN1bShwZW5hbGlkYWRlMSxuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWNfcHJldmlzdG89c3VtKHByZWNfcHJldmlzdG8sbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVjX3ByZXZpc3RvX2NmPXN1bShwcmVjX3ByZXZpc3RvX2NmKjEwMDAsbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVjPW1lYW4ocHJlY28sbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlbmFsaWRhZGVfcGVyYz1tZWFuKHBlbmFsaWRhZGVfcGVyYyxuYS5ybT1UKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY2xpbTIwMjZfaGF0PXN1bShwZW5hbGlkYWRlMixuYS5ybT1UKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSBtdXRhdGUoY3VzdG9fZmluYW5jZWlyb19wbGQ9cGVuYWxpZGFkZTEpLT5wZW5hbGlkYWRlX3BsZA0KcGVuYWxpZGFkZV9wbGQNCmBgYA0KDQpkZHNhZA0KDQpkc2ENCg0KYGBge3J9DQoNCmJpbmRfcm93cyhwZW5hbGlkYWRlX2hpZHJpY28gJT4lIG11dGF0ZShlc3RpbWE9IkhpZHJvKiIpLA0KDQogICAgICAgICAgcGVuYWxpZGFkZV90ZXJtaWNvICU+JSBtdXRhdGUoZXN0aW1hPSJUw6lybWljbyoqIiksDQogICAgICAgICAgcGVuYWxpZGFkZV9wbGQgJT4lIG11dGF0ZShlc3RpbWE9Ik9wZXJhY2lvbmFsKioqIikpICU+JSANCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgiY3VzdG8iKSkgJT4lIA0KICBtdXRhdGUoY3VzdG9fUmVhaXM9Y2FzZV93aGVuKGVzdGltYT09IkhpZHJvKiJ+KC1wZW5hbGlkYWRlMSkqKDI5Ni44KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWE9PSJUw6lybWljbyoqIn5wZW5hbGlkYWRlMSoJNDc4LjksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUV+cGVuYWxpZGFkZTEqMTAwMDAvNyksDQogICAgICAgICBjdXN0b19VU0Q9Y3VzdG9fUmVhaXMvNS4yDQogICAgICAgICApICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vbV9zdWJzaXN0ZW1hLngseT0oY3VzdG9fVVNELzEwMDAwMCksZmlsbD1lc3RpbWEpKStnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoY3VzdG9fVVNELzEwMDAwMCwgMikpLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0xKSwgc2l6ZSA9IDMsY2hlY2tfb3ZlcmxhcD1GKStjb29yZF9mbGlwKCkrDQogIGxhYnModGl0bGUgPSAiQ3VzdG8gZWNvbsO0bWljbyBlc3RpbWFkbyBkYSBwZW5hbGlkYWRlIGNsaW3DoXRpY2EgKDIwMDEtMjAxOSkiLA0KICAgICAgIHN1YnRpdGxlID0gIkN1c3RvIGZpbmFuY2Vpcm8gYXByb3hpbWFkbyBkbyBpbXBhY3RvIGNsaW3DoXRpY28gc29icmUgYSBnZXJhw6fDo28gaGlkcmVsw6l0cmljYSBlIHTDqXJtaWNhIiwNCiAgICAgICBjYXB0aW9uID0gIioyOTYsOCBSJC9NV2gNCioqNDc4LDkgUiQvTVdoDQoqKiogRXN0aW1hZG8gZW0gMTAgR1doIHBvciBzZW1hbmEiLA0KICAgICAgIHkgPSAiQ3VzdG8gKFVTJCBtaWxow7VlcykiLCB4ID0gIlN1YnNpc3RlbWEiKSArdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpiaW5kX3Jvd3MocGVuYWxpZGFkZV9oaWRyaWNvICU+JSBtdXRhdGUoZXN0aW1hPSJIaWRybyoiKSwNCg0KICAgICAgICAgIHBlbmFsaWRhZGVfdGVybWljbyAlPiUgbXV0YXRlKGVzdGltYT0iVMOpcm1pY28qKiIpLA0KICAgICAgICAgIHBlbmFsaWRhZGVfcGxkICU+JSBtdXRhdGUoZXN0aW1hPSJPcGVyYWNpb25hbCoqKiIpKSAlPiUgDQogIHNlbGVjdCgtc3RhcnRzX3dpdGgoImN1c3RvIikpICU+JSANCiAgbXV0YXRlKGN1c3RvX1JlYWlzPWNhc2Vfd2hlbihlc3RpbWE9PSJIaWRybyoifigtcGVuYWxpZGFkZTEpKigyOTYuOCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hPT0iVMOpcm1pY28qKiJ+cGVuYWxpZGFkZTEqCTQ3OC45LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFfnBlbmFsaWRhZGUxKjEwMDAwLzcpLA0KICAgICAgICAgY3VzdG9fVVNEPWN1c3RvX1JlYWlzLzUuMg0KICAgICAgICAgKSAlPiUgDQogIGdyb3VwX2J5KGVzdGltYSkgJT4lIHN1bW1hcmlzZShjdXN0b19VU0Q9c3VtKGN1c3RvX1VTRCkpICU+JSANCiAgZ2dwbG90KGFlcyh4PWVzdGltYSx5PShjdXN0b19VU0QvMTAwMDAwKSxmaWxsPWVzdGltYSkpK2dlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrDQogIGdlb21fdGV4dChhZXMoeT1jdXN0b19VU0QvMjAwMDAwLGxhYmVsID0gcm91bmQoY3VzdG9fVVNELzEwMDAwMCwgMSkpLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0xKSwgc2l6ZSA9IDMsY2hlY2tfb3ZlcmxhcD1GKStjb29yZF9mbGlwKCkrDQogIGxhYnModGl0bGUgPSAiQ3VzdG8gZWNvbsO0bWljbyBlc3RpbWFkbyBkYSBwZW5hbGlkYWRlIGNsaW3DoXRpY2EgKDIwMDAtMjAxOSkiLA0KICAgICAgIHN1YnRpdGxlID0gIkN1c3RvIGZpbmFuY2Vpcm8gYXByb3hpbWFkbyBkbyBpbXBhY3RvIGNsaW3DoXRpY28gc29icmUgYSBnZXJhw6fDo28gaGlkcmVsw6l0cmljYSBlIHTDqXJtaWNhIiwNCiAgICAgICBjYXB0aW9uID0gIioyOTYsOCBSJC9NV2gNCioqNDc4LDkgUiQvTVdoDQoqKiogRXN0aW1hZG8gZW0gMTAgR1doIHBvciBzZW1hbmEiLA0KICAgICAgIHkgPSAiQ3VzdG8gKFVTJCBNaWxob2VzKSIsIHggPSAiU3Vic2lzdGVtYSIpICt0aGVtZV9taW5pbWFsKCkNCmBgYA0K