Pacotes
# Carregar pacotes-base do projeto
# Manipulação e datas
library(tidyverse);library(data.table);library(lubridate);library(patchwork);library(Hmisc)
# Modelagem
library(mgcv);library(gratia);library(lubridate);library(modelsummary);library(gt);library(glue);library(scales);library(broom);library(broom.helpers);library(geobr)
# Utilidades
library(scales);library(patchwork);library(knitr);library(kableExtra)
# 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
pld <- read.csv("pld_diario_completo.csv") # weekly spot price (PLD)
Aviso em file(file, "rt") :
não foi possível abrir o arquivo 'pld_diario_completo.csv': No such file or directory
Error in file(file, "rt") : não é possível abrir a conexão
# 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)
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")
range(ger$date, na.rm=TRUE)
range(reserv$date, na.rm=TRUE)
range(pld$date, na.rm=TRUE)
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")
tab_cov
# 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"
)
#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
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
a %>% ggplot(aes(val_longitude,val_latitude))+geom_point()+
ggplot(data=georegion) +geom_sf()
a$nom_subsistema.x %>% unique
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)
gtsummary::tbl_regression(m1_gam)
summary(m1_gam)
gam.check(m1_gam) # resíduos, QQ, k-index
concurvity(m1_gam, full=TRUE)
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)
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)
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
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)
nsim <- 500
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 <- as.data.table(nd_obs)[, .(date, year = year(date), nom_subsistema.x)]
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),
sd = apply(agg_mat, 1, sd)
)
m1_sim_agg %>% mutate(sd_up=mean+z*sd, sd_lwr=mean-z*sd)->m1_sim_agg
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_ribbon(aes(ymin = 0, ymax = upr/1000), fill = "red3", alpha = 0.1) +
geom_line() +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Climate penalty on stored energy (ΔEAR) — Parametric simulation quartile",
y = "ΔEAR (GW·month)", x = "Year") +
theme_minimal()

m1_sim_agg %>%
ggplot(aes(x = year, y = mean/1000)) +
geom_ribbon(aes(ymin = sd_lwr/1000, ymax = sd_up/1000), alpha = .25, fill = "steelblue") +
geom_ribbon(aes(ymin = 0, ymax = sd_up/1000), fill = "red3", alpha = 0.1) +
geom_line() +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Climate penalty on stored energy (ΔEAR) — Parametric simulation sd",
y = "ΔEAR (GW·month)", x = "Year") +
theme_minimal()
Error in `geom_ribbon()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error:
! objeto 'sd_lwr' não encontrado
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.

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 = mean_penalty-z*sd_penalty / 1000,
upr_GWh = mean_penalty+z*sd_penalty / 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"
)
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))
)
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)
C <- reserv %>%
mutate(
delta_lwr_ger = delta_Ghidro - z * se_delta2,
delta_upr_ger = delta_Ghidro + z * se_delta2
)
C[,c("delta_Ghidro","delta_lwr_ger","delta_upr_ger","val_geracao")] %>% summary()
# (4) Agregação por ano e subsistema -----------------------------------------
m2_delta_agg <- C %>%
mutate(Year = year(date)) %>%
group_by(Year, nom_subsistema.x) %>%
summarise(
mean_penalty = sum(delta_Ghidro, na.rm = TRUE),
lwr = sum(delta_lwr_ger, na.rm = TRUE),
upr = sum(delta_upr_ger, na.rm = TRUE),
.groups = "drop"
)
m2_delta_agg
library(ggplot2)
m2_delta_agg %>%
ggplot(aes(x = Year, y = mean_penalty/1000)) +
geom_ribbon(aes(ymin = lwr/1000, ymax = upr/1000), fill = "steelblue", alpha = 0.8) +
geom_ribbon(aes(ymin = 0, ymax = upr/1000), fill = "red3", alpha = 0.1) +
geom_line(color = "black") +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Propagated climate penalty on hydropower generation (ΔG_hidro)",
subtitle = "Baseline climate: mean 2001–2005",
y = "ΔG_hidro (GW·month)", x = "Year") +
theme_minimal()

m2_summary <- C %>%
mutate(Year = year(date)) %>% ungroup() %>%
group_by( nom_subsistema.x) %>%
summarise(
mean_penalty = sum(delta_Ghidro, na.rm = TRUE),
lwr = sum(delta_lwr_ger, na.rm = TRUE),
upr = sum(delta_upr_ger, na.rm = TRUE),
.groups = "drop"
)
library(gt)
m2_summary[,c("nom_subsistema.x","mean_penalty","lwr", "upr")] %>% janitor::adorn_totals() %>%
gt() %>%
fmt_number(columns = 2:4, decimals = 1) %>%
cols_label(
nom_subsistema.x = "Subsystem",
mean_penalty = "Sum Δger (MWh)",
lwr = "Lower 95%",
upr = "Upper 95%",
) %>%
tab_header(
title = md("**Aggregate climate penalty on hidropower energy (2001–2018)**"),
subtitle = "Simulated mean and 95% confidence intervals per subsystem"
)
A Figura apresenta o resultado da propagação da penalidade
climática sobre a geração hidrelétrica (ΔG_hidro), obtida pela
substituição do clima observado pelo clima médio histórico (2001–2005)
no modelo de armazenamento e pela aplicação desses valores
contrafactuais no modelo de geração. O gráfico mostra a diferença entre
a geração prevista sob clima efetivo e o cenário contrafactual neutro,
com intervalos de confiança calculados por duas abordagens: o método
analítico (Delta) e a simulação paramétrica.
Os resultados indicam que a penalidade climática média sobre a
geração hidrelétrica segue o mesmo padrão espacial observado na energia
armazenada, mas com magnitude amplificada devido à resposta elástica do
despacho hídrico. O Sudeste apresenta o maior déficit
médio, com reduções acumuladas superiores a –4 milhões de
MW·mês em anos secos, refletindo a forte dependência da geração
ao nível de reservatórios. O Sul mostra penalidades
intermediárias (entre –1 e –2 milhões de MW·mês), com alta variabilidade
interanual. O Nordeste e o Norte
apresentam oscilações menores, mas com tendência negativa acentuada após
2012, compatível com períodos de estiagem prolongada.
Os intervalos de confiança revelam aumento
expressivo da incerteza após 2010, quando as condições climáticas se
tornaram mais voláteis e os reservatórios passaram a operar próximos de
limites críticos. Esse padrão reforça a interpretação de que a
penalidade climática propagada à geração representa não
apenas a perda de estoque hídrico, mas também a diminuição da
flexibilidade operativa do sistema, um dos principais canais de
transmissão dos efeitos climáticos para os custos do setor elétrico.
3.2.5 Propagação conjunta de incerteza (ΔEAR → ΔG_hidro) Este bloco
realiza uma simulação Monte Carlo encadeada: cada sorteio inclui
simultaneamente os coeficientes do modelo climático (m1_gam) e do modelo
hidrelétrico (m2_hidro). Assim, as incertezas da previsão do
armazenamento (EAR) são transmitidas integralmente para as previsões de
geração, produzindo uma distribuição conjunta para \(Δ𝐺_{ℎ𝑖𝑑𝑟𝑜}\).
3.2.6 Resultados — Propagação integral de incerteza (ΔG_hidro
conjunto) partindo do m2——————–
library(MASS)
library(dplyr)
library(lubridate)
set.seed(20251011)
nsim <- 500 # pode aumentar depois para 1000, mas teste com 500 primeiro
# --- 1. Covariâncias e sorteios dos coeficientes ----------------------------
Vp1 <- vcov(m1_gam)
Vp2 <- vcov(m2_hidro)
beta_draws_1 <- MASS::mvrnorm(n = nsim, mu = coef(m1_gam), Sigma = Vp1)
beta_draws_2 <- MASS::mvrnorm(n = nsim, mu = coef(m2_hidro), Sigma = Vp2)
# --- 2. Matrizes do modelo 1 (EAR ~ clima) ----------------------------------
X_obs_ear <- predict(m1_gam, newdata = nd_obs, type = "lpmatrix")
X_cf_ear <- predict(m1_gam, newdata = nd_cf, type = "lpmatrix")
# --- 3. Propagação Monte Carlo encadeada -----------------------------------
delta_G_joint <- matrix(NA_real_, nrow = nrow(nd_obs), ncol = nsim)
for (s in seq_len(nsim)) {
# 1. EAR factual e contrafactual simulados
ear_f <- as.numeric(X_obs_ear %*% beta_draws_1[s, ])
ear_c <- as.numeric(X_cf_ear %*% beta_draws_1[s, ])
# 2. Atualizar inputs do modelo de geração
nd_f <- nd_obs %>%
mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_f)
nd_c <- nd_obs %>%
mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_c)
# 3. Predições completas do modelo de geração (não linear)
g_f <- predict(m2_hidro, newdata = nd_f, type = "response")
g_c <- predict(m2_hidro, newdata = nd_c, type = "response")
# 4. Penalidade propagada
delta_G_joint[, s] <- g_f - g_c
print(s)
}
write_rds(delta_G_joint, "delta_G_joint.rds")
delta_G_joint<-read_rds("data/delta_G_joint.rds")
Error in readRDS(con, refhook = refhook) : não é possível abrir a conexão
# --- 4. Agregar por subsistema e ano ----------------------------------------
nd_obs$Year
dt <- nd_obs %>% select(Year, nom_subsistema.x)
dt$Year<-nd_obs$Year
library(data.table)
dt <- as.data.table(dt)
groups <- unique(dt[, .(Year, nom_subsistema.x)])
agg_joint <- lapply(seq_len(nrow(groups)), function(g){
idx <- which(dt$Year == groups$Year[g] & dt$nom_subsistema.x == groups$nom_subsistema.x[g])
colSums(delta_G_joint[idx, , drop = FALSE], na.rm = TRUE)
})
agg_joint <- do.call(rbind, agg_joint)
colnames(agg_joint) <- paste0("sim_", 1:nsim)
agg_df <- cbind(groups, agg_joint)
# --- 5. Estatísticas resumo -------------------------------------------------
m2_joint_summary <- agg_df %>%
tidyr::pivot_longer(cols = starts_with("sim_"), values_to = "delta_G") %>%
group_by(Year, nom_subsistema.x) %>%
summarise(
mean = mean(delta_G, na.rm = TRUE),
lwr = quantile(delta_G, 0.025, na.rm = TRUE),
upr = quantile(delta_G, 0.975, na.rm = TRUE),
.groups = "drop"
)
library(ggplot2)
m2_joint_summary %>%
ggplot(aes(x = Year, y = mean)) +
geom_ribbon(aes(ymin = lwr, ymax = upr), fill = "firebrick", alpha = 0.3) +
geom_line(color = "black") +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Joint propagated climate penalty on hydropower generation (ΔG_hidro)",
subtitle = "Uncertainty fully propagated from climate → storage → generation",
y = "ΔG_hidro (MW·month)", x = "Year") +
theme_minimal()
library(ggplot2)
m2_joint_summary %>%
ggplot(aes(x = Year, y = mean/1000)) +
geom_ribbon(aes(ymin = lwr/1000, ymax = upr/1000), fill = "steelblue", alpha = 1) +
geom_ribbon(aes(ymin = 0, ymax = upr/1000), fill = "firebrick", alpha = 0.1) +
geom_line(color = "black") +
facet_wrap(~nom_subsistema.x, scales = "free_y") +
labs(title = "Joint propagated climate penalty on hydropower generation (ΔG_hidro)",
subtitle = "Uncertainty fully propagated from climate → storage → generation",
y = "ΔG_hidro (GW·month)", x = "Year") +
theme_minimal()

A Figura apresenta a penalidade climática sobre a geração
hidrelétrica (ΔG_hidro) estimada com propagação
conjunta de incerteza ao longo de toda a cadeia
climato-hidrológica. Diferentemente das abordagens que tratam os modelos
de forma independente, esta simulação incorpora simultaneamente a
incerteza dos coeficientes do modelo climático (EAR ~ clima) e do modelo
hidrelétrico (geração ~ EAR), gerando uma distribuição conjunta de
resultados. Cada trajetória Monte Carlo representa uma combinação
plausível de parâmetros e condições climáticas, permitindo capturar a
variabilidade estrutural e climática do sistema.
Os resultados mostram que a incerteza propagada amplia os intervalos
de confiança das estimativas anuais de ΔG_hidro, principalmente após
2010, quando a variabilidade climática e operacional aumenta
significativamente. O subsistema Sudeste concentra as
maiores perdas médias (até –4,5 × 10⁶ MW·mês) e a maior dispersão
interanual, refletindo tanto a magnitude de sua capacidade de
armazenamento quanto sua exposição a secas prolongadas. O
Sul apresenta penalidades menores, mas com amplitudes
de incerteza elevadas, coerentes com sua instabilidade hidrológica.
Nordeste e Norte mostram menores
déficits absolutos, mas com tendência negativa contínua.
Esses resultados representam a estimativa mais completa de
impacto climático propagado no sistema elétrico, pois
integram incertezas climáticas, hidrológicas e operacionais dentro de
uma mesma estrutura probabilística.
m2_summary <- m2_joint_summary %>%
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
m2_summary <- m2_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)
m2_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 ΔG_hidro (GWh)",
lwr_GWh = "Lower 95%",
upr_GWh = "Upper 95%",
) %>%
tab_header(
title = md("**Aggregate climate penalty on Hidric Generation (2001–2018)**"),
subtitle = "Simulated mean and 95% confidence intervals per subsystem"
)
| Aggregate climate penalty on Hidric Generation (2001–2018) |
| Simulated mean and 95% confidence intervals per subsystem |
| Subsystem |
Mean ΔG_hidro (GWh) |
Lower 95% |
Upper 95% |
| NORDESTE |
−6.8 |
−7.0 |
−6.6 |
| NORTE |
−1.9 |
−2.1 |
−1.6 |
| SUDESTE |
−79.0 |
−82.5 |
−76.0 |
| SUL |
−16.7 |
−17.8 |
−15.9 |
| Total |
−104.4 |
−109.4 |
−100.1 |
3.3 Modelo 3 — Geração Termica como Função da Geração
Hidrelétrica
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)
O Modelo 3 estima a resposta da geração térmica às variações na
geração hidrelétrica, incorporando a competição com outras fontes e o
ciclo sazonal de demanda. O modelo aditivo generalizado (GAM) foi
ajustado para o período 2000–2019, com estrutura semiparamétrica que
permite capturar relações não lineares entre as fontes de geração e seus
determinantes temporais. Os resultados indicam uma relação negativa e
estatisticamente significativa entre geração hidrelétrica e térmica,
evidenciando o papel da térmica como mecanismo de compensação durante
períodos de escassez hídrica. O efeito marginal de ger_hidroeletrica é
fortemente não linear, com respostas mais intensas em faixas
intermediárias de redução, o que sugere que o despacho térmico atinge
limites estruturais de expansão em anos de seca severa.
library(mgcv)
library(dplyr)
# --- Preparação dos dados ---------------------------------------------------
gera_energ_day <- gera_energ_day %>%
mutate(
Demanda = ger_eolieletrica + ger_fotovoltaica + ger_hidroeletrica + ger_termica + ger_nuclear,
month = as.numeric(format(date, "%m")),
trend = as.numeric(date - min(date)) / 30 # tendência linear em meses
)
# --- Modelo GAM 3: Geração Térmica como função da Hidro + outras fontes -----
m3_gam_termica <- bam(
ger_termica ~
s(ger_hidroeletrica, k = 4) + # principal efeito substitutivo
s(ger_eolieletrica, k = 4) +
s(ger_fotovoltaica, k = 4) +
s(ger_nuclear, k = 3) +
s(trend, k = 3) +
s(month, bs = "cc", k = 4) + # padrão sazonal
s(nom_subsistema, bs = "re"), # efeito aleatório por subsistema
data = gera_energ_day,
method = "fREML",
discrete = TRUE,
family = gaussian(),
na.action = na.exclude
)
summary(m3_gam_termica)
summary(m3_gam_termica)
gtsummary::tbl_regression(m3_gam_termica)
summary(m3_gam_termica)
gam.check(m3_gam_termica) # resíduos, QQ, k-index
concurvity(m3_gam_termica, full=TRUE)
plot(m3_gam_termica, pages=4, scheme=1, shade=TRUE, se=TRUE)
\(𝑔𝑒𝑟
𝑡𝑒𝑟𝑚𝑖𝑐𝑎_𝑡=𝑓_1(𝑔𝑒_h𝑖𝑑𝑟𝑜_𝑡)+𝑓_2(𝑔𝑒𝑟_𝑒𝑜𝑙𝑖𝑐𝑎_𝑡)+𝑓_3(𝑔𝑒𝑟_𝑠𝑜𝑙𝑎𝑟_𝑡)+_𝑓_4(𝑔𝑒𝑟_𝑛𝑢𝑐𝑙𝑒𝑎𝑟𝑡)+𝑓_5(𝑡𝑟𝑒𝑛𝑑_𝑡)+𝑓_6(𝑚𝑜𝑛𝑡ℎ_𝑡)+𝑢𝑠𝑢𝑏𝑠𝑖𝑠𝑡𝑒𝑚𝑎+𝜀\)
Qualidade do ajuste
O modelo apresenta R² ajustado de 0,64 e deviance explicada de 64,1%,
indicando boa capacidade preditiva diante da alta variabilidade
interdiária. Todos os efeitos suaves são altamente significativos (p
< 0.001), com exceção do intercepto. O histograma e o QQ-plot dos
resíduos mostram distribuição aproximadamente normal, com leve
assimetria nas caudas — reflexo de picos de despacho térmico em períodos
de seca severa.
O gráfico “Resíduos vs. Valores Ajustados” revela dispersão crescente
com o aumento da geração prevista, sugerindo heterocedasticidade
moderada associada a regimes distintos de operação (base × pico). Ainda
assim, os resíduos são centrados e sem padrão sistemático, confirmando a
adequação geral da especificação.
Efeitos parciais
Os efeitos marginais estimados exibem comportamentos coerentes com a
lógica física do sistema:
- s(ger_hidroeletrica) → forte relação inversa e não linear: reduções
na geração hídrica aumentam a geração térmica, especialmente em faixas
intermediárias de operação (substituição estrutural). Em níveis
extremos, o efeito se estabiliza, indicando limite de despacho
térmico.
-s(ger_eolieletrica) e s(ger_fotovoltaica) → ambas apresentam efeitos
substitutivos negativos, evidenciando o papel das renováveis na
mitigação do uso térmico.
s(ger_nuclear) → relação levemente côncava, estável, refletindo
despacho praticamente fixo.
s(trend) → tendência ascendente, indicando aumento gradual da
base térmica no longo prazo, coerente com a expansão de termelétricas
entre 2005–2015.
s(month) → padrão quase plano, com fraca sazonalidade residual
após o controle hidrológico.
Efeito aleatório (nom_subsistema) → o ajuste confirma diferenças
estruturais regionais: subsistemas do Sudeste e Sul exibem maior
intensidade térmica relativa que Norte e Nordeste.
Síntese O modelo confirma o papel contracíclico da geração
térmica no sistema elétrico brasileiro: quando o clima reduz a geração
hídrica, a resposta térmica compensa parte do déficit, com sensibilidade
não linear e limites operacionais definidos.
A estrutura suavizada dos efeitos permite quantificar a elasticidade
marginal entre fontes, que será usada na próxima etapa para estimar a
penalidade térmica propagada (ΔG_term) resultante da penalidade hídrica
(ΔG_hidro) obtida no Modelo
Predições factual vs. contrafactual (propagação de incerteza)
# --- 5. Loop principal de propagação Monte Carlo -----------------------------
for (s in seq_len(nsim)) {
# ===== (1) EAR factual e contrafactual (M1) no nível de reservatório×dia
ear_f <- as.numeric(X1_obs %*% b1[s, ])
ear_c <- as.numeric(X1_cf %*% b1[s, ])
# ===== (2) Predição de G_hidro factual e cf (M2) no nível de reservatório×dia
nd2_f <- reserv %>% mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_f)
nd2_c <- reserv %>% mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_c)
X2_f <- predict(m2_hidro, newdata = nd2_f, type = "lpmatrix")
X2_c <- predict(m2_hidro, newdata = nd2_c, type = "lpmatrix")
g_h_f_res <- as.numeric(X2_f %*% b2[s, ]) # por reservatório×dia
g_h_c_res <- as.numeric(X2_c %*% b2[s, ])
# ===== (3) Agregar G_hidro por subsistema×dia (para alimentar M3)
df_h <- data.frame(date = keys_m2$date,
subs = keys_m2$nom_subsistema.x,
g_h_f = g_h_f_res,
g_h_c = g_h_c_res)
g_h_agg <- df_h |>
group_by(date, subs) |>
summarise(g_h_f = sum(g_h_f, na.rm = TRUE),
g_h_c = sum(g_h_c, na.rm = TRUE), .groups = "drop")
# ΔG_hidro_clima (subsistema×dia)
g_h_agg <- g_h_agg |>
mutate(delta_g_hidro_clima = g_h_f - g_h_c)
# ===== (4) Construir input do M3
# factual: usa a hidrelétrica observada (gera_energ_day$ger_hidroeletrica)
# contrafactual: obs − ΔG_hidro_clima
nd3 <- gera_energ_day |>
left_join(g_h_agg,
by = c("date" = "date", "nom_subsistema" = "subs"))
# se faltar subsistema em algum dia, trata NA como 0 delta
nd3$delta_g_hidro_clima[is.na(nd3$delta_g_hidro_clima)] <- 0
g_h_obs <- nd3$ger_hidroeletrica
g_h_cfM3 <- g_h_obs - nd3$delta_g_hidro_clima# clipping em 0
nd3_f <- nd3 %>% mutate(ger_hidroeletrica = g_h_obs) # factual (observado)
nd3_c <- nd3 %>% mutate(ger_hidroeletrica = g_h_cfM3) # contrafactual (obs − Δclima)
# ===== (5) Predição térmica factual e cf (M3) no nível subsistema×dia
X3_f <- predict(m3_gam_termica, newdata = nd3_f, type = "lpmatrix")
X3_c <- predict(m3_gam_termica, newdata = nd3_c, type = "lpmatrix")
g_t_f <- as.numeric(X3_f %*% b3[s, ])
g_t_c <- as.numeric(X3_c %*% b3[s, ])
delta_Gterm_mat[, s] <- g_t_f - g_t_c
print(s)
}

| Aggregate climate penalty on stored energy (2001–2018) |
| Simulated mean and 95% confidence intervals per subsystem |
| Subsystem |
Sum Δger Term (MWh) |
Lower 95% |
Upper 95% |
| NORDESTE |
−35,567.9 |
−37,124.3 |
−34,109.4 |
| NORTE |
7,159.6 |
−172.2 |
11,126.5 |
| SUDESTE |
195,864.3 |
171,174.0 |
213,723.0 |
| SUL |
567,160.8 |
539,040.6 |
587,110.0 |
| Total |
734,616.8 |
672,918.1 |
777,850.2 |
#3.4 Modelo 3 PLD: Custo para o sistema
pld <- read.csv("preco_semanal.csv") # PLD semanal
pld$date <- as.Date(pld$DATA_INICIO) # idem para a base de PLD
pld$week <- lubridate::isoweek(pld$date)
pld$year <- lubridate::year(pld$date)
#pld$date<-pld$DATA_INICIO %>% as_date()
pld %>% spread(Submercado,preco)->pld
Error in `spread()`:
Caused by error:
! objeto 'Submercado' não encontrado
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.
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

NA
NA
pld$Submercado %>% unique()
NULL
gera_energ_day$nom_subsistema.x %>% unique
Aviso: Unknown or uninitialised column: `nom_subsistema.x`.
NULL
#newdata_m1 %>% write.csv("base valores previstos.csv")
#gera_energ_day %>% write.csv("valores_previstos_day.csv")
pld_full %>% summary()
date nom_subsistema val_geracao_day_subsistema ger_eolieletrica ger_fotovoltaica ger_hidroeletrica
Min. :2001-06-30 Length:25536 Min. : 0 Min. : 0.00 Min. : 0.000 Min. : 0
1st Qu.:2005-11-12 Class :character 1st Qu.: 5109 1st Qu.: 0.00 1st Qu.: 0.000 1st Qu.: 3736
Median :2010-03-27 Mode :character Median : 7269 Median : 0.00 Median : 0.000 Median : 6233
Mean :2010-03-29 Mean :10564 Mean : 257.88 Mean : 5.367 Mean :10019
3rd Qu.:2014-08-11 3rd Qu.:11367 3rd Qu.: 69.93 3rd Qu.: 0.000 3rd Qu.:13023
Max. :2018-12-31 Max. :40055 Max. :7863.72 Max. :375.152 Max. :35712
NA's :2078
ger_nuclear ger_termica doy dow month trend Demanda ANO
Min. : 0.0 Min. : 0.0 Min. : 1.0 dom:3650 Min. : 1.000 Min. : 18.20 Min. : 0 Min. :2001
1st Qu.: 0.0 1st Qu.: 235.0 1st Qu.: 94.0 seg:3649 1st Qu.: 4.000 1st Qu.: 71.42 1st Qu.: 5308 1st Qu.:2005
Median : 0.0 Median : 974.5 Median :188.0 ter:3646 Median : 7.000 Median :124.62 Median : 7653 Median :2010
Mean : 403.9 Mean :1428.6 Mean :185.8 qua:3646 Mean : 6.612 Mean :124.67 Mean :12115 Mean :2010
3rd Qu.: 0.0 3rd Qu.:1933.6 3rd Qu.:277.0 qui:3646 3rd Qu.:10.000 3rd Qu.:177.87 3rd Qu.:14941 3rd Qu.:2014
Max. :2026.2 Max. :8117.4 Max. :366.0 sex:3649 Max. :12.000 Max. :231.30 Max. :40688 Max. :2018
sáb:3650
MES SEMANA DATA_INICIO DATA_FIM week year preco
Min. : 1.000 Min. : 1.0 Length:25536 Length:25536 Min. : 1 Min. :2001 Min. : 4.00
1st Qu.: 4.000 1st Qu.:232.0 Class :character Class :character 1st Qu.:14 1st Qu.:2005 1st Qu.: 18.59
Median : 7.000 Median :460.0 Mode :character Mode :character Median :27 Median :2010 Median : 79.16
Mean : 6.612 Mean :459.9 Mean :27 Mean :2010 Mean :159.29
3rd Qu.:10.000 3rd Qu.:688.0 3rd Qu.:40 3rd Qu.:2014 3rd Qu.:213.52
Max. :12.000 Max. :919.0 Max. :53 Max. :2018 Max. :822.83
NA's :21866 NA's :21866
Modelo 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,
))
Error in eval(predvars, data, env) :
objeto 'nom_subsistema.x' não encontrado
summary(gam_3_pld)
Family: gaussian
Link function: identity
Formula:
preco ~ 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)) + nom_subsistema
Parametric coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 123.845 5.255 23.565 <2e-16 ***
nom_subsistemaNORTE 56.400 6.080 9.276 <2e-16 ***
nom_subsistemaSUDESTE 42.572 17.231 2.471 0.0135 *
nom_subsistemaSUL 42.793 3.838 11.149 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Approximate significance of smooth terms:
edf Ref.df F p-value
s(log(ger_hidroeletrica)) 9.000 9.000 171.44 <2e-16 ***
s(log(trend)) 8.985 9.000 680.45 <2e-16 ***
s(log(doy)) 8.881 8.996 13.21 <2e-16 ***
s(log(ger_eolieletrica)) 8.479 8.922 66.83 <2e-16 ***
s(log(ger_fotovoltaica)) 8.627 8.956 60.52 <2e-16 ***
s(log(Demanda)) 8.952 8.999 204.85 <2e-16 ***
s(log(ger_termica)) 8.963 9.000 158.85 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
R-sq.(adj) = 0.614 Deviance explained = 61.5%
GCV = 14797 Scale est. = 14759 n = 25536
summary(gam_3_pld)
Family: gaussian
Link function: identity
Formula:
preco ~ 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)) + nom_subsistema
Parametric coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 123.845 5.255 23.565 <2e-16 ***
nom_subsistemaNORTE 56.400 6.080 9.276 <2e-16 ***
nom_subsistemaSUDESTE 42.572 17.231 2.471 0.0135 *
nom_subsistemaSUL 42.793 3.838 11.149 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Approximate significance of smooth terms:
edf Ref.df F p-value
s(log(ger_hidroeletrica)) 9.000 9.000 171.44 <2e-16 ***
s(log(trend)) 8.985 9.000 680.45 <2e-16 ***
s(log(doy)) 8.881 8.996 13.21 <2e-16 ***
s(log(ger_eolieletrica)) 8.479 8.922 66.83 <2e-16 ***
s(log(ger_fotovoltaica)) 8.627 8.956 60.52 <2e-16 ***
s(log(Demanda)) 8.952 8.999 204.85 <2e-16 ***
s(log(ger_termica)) 8.963 9.000 158.85 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
R-sq.(adj) = 0.614 Deviance explained = 61.5%
GCV = 14797 Scale est. = 14759 n = 25536
gtsummary::tbl_regression(gam_3_pld)
| Characteristic |
Beta |
95% CI |
p-value |
| nom_subsistema |
|
|
|
| NORDESTE |
— |
— |
|
| NORTE |
56 |
44, 68 |
<0.001 |
| SUDESTE |
43 |
8.8, 76 |
0.013 |
| SUL |
43 |
35, 50 |
<0.001 |
| s(log(ger_hidroeletrica)) |
|
|
<0.001 |
| s(log(trend)) |
|
|
<0.001 |
| s(log(doy)) |
|
|
<0.001 |
| s(log(ger_eolieletrica)) |
|
|
<0.001 |
| s(log(ger_fotovoltaica)) |
|
|
<0.001 |
| s(log(Demanda)) |
|
|
<0.001 |
| s(log(ger_termica)) |
|
|
<0.001 |
summary(gam_3_pld)
Family: gaussian
Link function: identity
Formula:
preco ~ 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)) + nom_subsistema
Parametric coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 123.845 5.255 23.565 <2e-16 ***
nom_subsistemaNORTE 56.400 6.080 9.276 <2e-16 ***
nom_subsistemaSUDESTE 42.572 17.231 2.471 0.0135 *
nom_subsistemaSUL 42.793 3.838 11.149 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Approximate significance of smooth terms:
edf Ref.df F p-value
s(log(ger_hidroeletrica)) 9.000 9.000 171.44 <2e-16 ***
s(log(trend)) 8.985 9.000 680.45 <2e-16 ***
s(log(doy)) 8.881 8.996 13.21 <2e-16 ***
s(log(ger_eolieletrica)) 8.479 8.922 66.83 <2e-16 ***
s(log(ger_fotovoltaica)) 8.627 8.956 60.52 <2e-16 ***
s(log(Demanda)) 8.952 8.999 204.85 <2e-16 ***
s(log(ger_termica)) 8.963 9.000 158.85 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
R-sq.(adj) = 0.614 Deviance explained = 61.5%
GCV = 14797 Scale est. = 14759 n = 25536
gam.check(gam_3_pld) # resíduos, QQ, k-index



Method: GCV Optimizer: magic
Smoothing parameter selection converged after 23 iterations.
The RMS GCV score gradient at convergence was 0.001482978 .
The Hessian was positive definite.
Model rank = 67 / 67
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(log(ger_hidroeletrica)) 9.00 9.00 1.00 0.34
s(log(trend)) 9.00 8.99 0.34 <2e-16 ***
s(log(doy)) 9.00 8.88 0.99 0.32
s(log(ger_eolieletrica)) 9.00 8.48 0.98 0.07 .
s(log(ger_fotovoltaica)) 9.00 8.63 0.98 0.11
s(log(Demanda)) 9.00 8.95 1.01 0.66
s(log(ger_termica)) 9.00 8.96 0.98 0.12
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

concurvity(gam_3_pld, full=TRUE)
para s(log(ger_hidroeletrica)) s(log(trend)) s(log(doy)) s(log(ger_eolieletrica)) s(log(ger_fotovoltaica))
worst 0.9792992 0.9994989 0.8701883 0.16445905 0.9702436 0.7582099
observed 0.9792992 0.9973993 0.4043606 0.03943132 0.9065618 0.4626105
estimate 0.9792992 0.9742579 0.6596454 0.03892563 0.8213786 0.4134559
s(log(Demanda)) s(log(ger_termica))
worst 0.9996432 0.9847597
observed 0.9966872 0.7688939
estimate 0.9727015 0.8624509
plot(gam_3_pld, pages=4, scheme=1, shade=TRUE, se=TRUE)




# --- 2. Matrizes de design do M1 (clima → EAR) -------------------------------
X1_obs <- predict(m1_gam, newdata = nd_obs, type = "lpmatrix")
X1_cf <- predict(m1_gam, newdata = nd_cf, type = "lpmatrix")
# --- 3. Preparação de bases e matrizes de saída ------------------------------
delta_PLD_mat <- matrix(NA_real_, nrow = nrow(preco_day), ncol = nsim)
Erro: objeto 'preco_day' não encontrado
# ==========================================================
# --- 4. Loop principal de propagação Monte Carlo ----------
# ==========================================================
for (s in seq_len(nsim)) {
# ===== (1) EAR factual e contrafactual (M1) por reservatório×dia ===========
ear_f <- as.numeric(X1_obs %*% b1[s, ])
ear_c <- as.numeric(X1_cf %*% b1[s, ])
# ===== (2) Predição de G_hidro factual e cf (M2) ===========================
nd2_f <- reserv %>% mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_f)
nd2_c <- reserv %>% mutate(ear_reservatorio_subsistema_proprio_mwmes = ear_c)
X2_f <- predict(m2_hidro, newdata = nd2_f, type = "lpmatrix")
X2_c <- predict(m2_hidro, newdata = nd2_c, type = "lpmatrix")
g_h_f_res <- as.numeric(X2_f %*% b2[s, ]) # geração hídrica por reservatório×dia
g_h_c_res <- as.numeric(X2_c %*% b2[s, ])
# ===== (3) Agregar G_hidro para subsistema×dia =============================
df_h <- data.frame(date = keys_m2$date,
subs = keys_m2$nom_subsistema.x,
g_h_f = g_h_f_res,
g_h_c = g_h_c_res)
g_h_agg <- df_h |>
group_by(date, subs) |>
summarise(g_h_f = sum(g_h_f, na.rm = TRUE),
g_h_c = sum(g_h_c, na.rm = TRUE), .groups = "drop") |>
mutate(delta_g_hidro_clima = g_h_f - g_h_c)
# ===== (4) Construir input do M3 (subsistema×dia) ==========================
nd3 <- gera_energ_day |>
left_join(g_h_agg, by = c("date" = "date", "nom_subsistema" = "subs"))
nd3$delta_g_hidro_clima[is.na(nd3$delta_g_hidro_clima)] <- 0
g_h_obs <- nd3$ger_hidroeletrica
g_h_cfM3 <- g_h_obs - nd3$delta_g_hidro_clima # sem truncagem
nd3_f <- nd3 %>% mutate(ger_hidroeletrica = g_h_obs)%>%
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,
)
nd3_c <- nd3 %>% mutate(ger_hidroeletrica = g_h_cfM3)%>%
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,
)
# ===== (5) Predição térmica factual e cf (M3) ==============================
X3_f <- predict(m3_gam_termica, newdata = nd3_f, type = "lpmatrix")
X3_c <- predict(m3_gam_termica, newdata = nd3_c, type = "lpmatrix")
g_t_f <- as.numeric(X3_f %*% b3[s, ])
g_t_c <- as.numeric(X3_c %*% b3[s, ])
delta_g_term_clima <- g_t_f - g_t_c
# ===== (6) Preparar input para M4 (preço) ==================================
nd4 <- pld_full2 |>
left_join(
nd3 %>% select(date, nom_subsistema, ger_hidroeletrica) %>%
mutate(g_t_f=g_t_f,g_h_cfM3=g_h_cfM3,
g_t_c=g_t_c,g_h_obs=g_h_obs,
),
by = c("date", "nom_subsistema")
) |>
mutate(ger_termica_f = g_t_f,
ger_termica_c = g_t_c,
ger_hidroeletrica_c = g_h_cfM3,
ger_hidroeletrica_f = g_h_obs)
# factual
nd4_f <- nd4 %>% mutate(
ger_termica = ger_termica_f,
ger_hidroeletrica = ger_hidroeletrica_f
)%>%
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,
)
# contrafactual (com penalidade climática propagada)
nd4_c <- nd4 %>% mutate(
ger_termica = ger_termica_c,
ger_hidroeletrica = ger_hidroeletrica_c
)%>%
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,
)
# ===== (7) Predição de preço factual e cf (M4) =============================
X4_f <- predict(gam_4_pld, newdata = nd4_f, type = "lpmatrix")
X4_c <- predict(gam_4_pld, newdata = nd4_c, type = "lpmatrix")
pld_f <- as.numeric(X4_f %*% b4[s, ])
pld_c <- as.numeric(X4_c %*% b4[s, ])
delta_PLD_mat[, s] <- pld_f - pld_c # penalidade climática em preço (R$/MWh)
print(s)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
— 6. Visualização: Fan Chart do impacto no PLD ———-

| Aggregate climate penalty on stored energy (2001–2018) |
| Simulated mean and 95% confidence intervals per subsystem |
| Subsystem |
mean Δpld Term (MWh) |
Lower 95% |
Upper 95% |
| NORDESTE |
0.7 |
0.6 |
0.9 |
| NORTE |
1.1 |
0.9 |
1.2 |
| SUDESTE |
3.0 |
2.5 |
3.6 |
| SUL |
13.5 |
12.4 |
14.7 |
| Total |
18.4 |
16.5 |
20.3 |
LS0tDQp0aXRsZTogIkNsaW1hdGUgUGVuYWx0aWVzIGFuZCBTY2FyY2l0eSBQcmVzc3VyZSBpbiBCcmF6aWzigJlzIFBvd2VyIFNlY3RvciINCmF1dGhvcjogIlRoaWFnbyBHYXJkaW4gJiBEYW5pZWwgRGFubmEiDQpkYXRlOiAiMjAyNS0xMC0wNiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRoZW1lOiBqb3VybmFsDQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCiMgUGFjb3Rlcw0KDQpgYGB7ciBDYXJyZWdhciBwYWNvdGVzLWJhc2UgZG8gcHJvamV0bzsgZGVmaW5pciBvcMOnw7VlcyBnbG9iYWlzfQ0KIyBDYXJyZWdhciBwYWNvdGVzLWJhc2UgZG8gcHJvamV0bw0KIyBNYW5pcHVsYcOnw6NvIGUgZGF0YXMNCmxpYnJhcnkodGlkeXZlcnNlKTtsaWJyYXJ5KGRhdGEudGFibGUpO2xpYnJhcnkobHVicmlkYXRlKTtsaWJyYXJ5KHBhdGNod29yayk7bGlicmFyeShIbWlzYykNCg0KIyBNb2RlbGFnZW0NCmxpYnJhcnkobWdjdik7bGlicmFyeShncmF0aWEpO2xpYnJhcnkobHVicmlkYXRlKTtsaWJyYXJ5KG1vZGVsc3VtbWFyeSk7bGlicmFyeShndCk7bGlicmFyeShnbHVlKTtsaWJyYXJ5KHNjYWxlcyk7bGlicmFyeShicm9vbSk7bGlicmFyeShicm9vbS5oZWxwZXJzKTtsaWJyYXJ5KGdlb2JyKQ0KIyBVdGlsaWRhZGVzDQpsaWJyYXJ5KHNjYWxlcyk7bGlicmFyeShwYXRjaHdvcmspO2xpYnJhcnkoa25pdHIpO2xpYnJhcnkoa2FibGVFeHRyYSkNCg0KIyBEZWZpbmlyIG9ww6fDtWVzIGdsb2JhaXMgZGUga25pdHINCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyAgICAgICA9IFRSVUUsDQogIG1lc3NhZ2UgICAgPSBUUlVFLA0KICB3YXJuaW5nICAgID0gVFJVRSwNCiAgZHBpICAgICAgICA9IDEyMCwNCiAgZmlnLmFsaWduICA9ICJjZW50ZXIiLA0KICBmaWcud2lkdGggID0gMTIsDQogIGZpZy5oZWlnaHQgPSA4DQopDQoNCiMgVGVtYSB2aXN1YWwgcGFkcsOjbyANCnRoZW1lX2FydGljbGUgPC0gZnVuY3Rpb24oKXsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMSkgKw0KICAgIHRoZW1lKA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4oYj02KSksDQogICAgICBwbG90LmNhcHRpb24gID0gZWxlbWVudF90ZXh0KHNpemU9OSwgY29sb3I9ImdyZXkzMCIpLA0KICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLA0KICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgKQ0KfQ0KdGhlbWVfc2V0KHRoZW1lX2FydGljbGUoKSkNCnNldC5zZWVkKDEyMzQpDQpgYGANCg0KYGBge3IgaGVscGVyc30NCnByZWRpY3RfZ2FtX2NpIDwtIGZ1bmN0aW9uKG1vZGVsLCBuZXdkYXRhLCB0eXBlID0gImxpbmsiLCBsZXZlbCA9IDAuOTUpew0KICBzdG9waWZub3QoaW5oZXJpdHMobW9kZWwsICJnYW0iKSkNCiAgcHIgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IG5ld2RhdGEsIHR5cGUgPSB0eXBlLCBzZS5maXQgPSBUUlVFKQ0KICBhbHBoYSA8LSAxIC0gbGV2ZWwNCiAgY3JpdCAgPC0gcW5vcm0oMSAtIGFscGhhLzIpDQogIHRpYmJsZSgNCiAgICAuZml0dGVkID0gYXMubnVtZXJpYyhwciRmaXQpLA0KICAgIC5zZSAgICAgPSBhcy5udW1lcmljKHByJHNlLmZpdCksDQogICAgLmxvd2VyICA9IC5maXR0ZWQgLSBjcml0Ki5zZSwNCiAgICAudXBwZXIgID0gLmZpdHRlZCArIGNyaXQqLnNlDQogICkNCn0NCmV4cG9ydF9maWd1cmUgPC0gZnVuY3Rpb24ocCwgZmlsZW5hbWUsIHdpZHRoID0gNywgaGVpZ2h0ID0gNC4yKXsNCiAgZ2dzYXZlKGdsdWUoImZpZ3VyZXMve2ZpbGVuYW1lfS5wZGYiKSwgcGxvdCA9IHAsIHdpZHRoID0gd2lkdGgsIGhlaWdodCA9IGhlaWdodCwgZHBpID0gMzAwLCBkZXZpY2UgPSBjYWlyb19wZGYpDQogIGdnc2F2ZShnbHVlKCJmaWd1cmVzL3tmaWxlbmFtZX0uZXBzIiksIHBsb3QgPSBwLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIGRwaSA9IDMwMCwgZGV2aWNlID0gImVwcyIpDQogIGdnc2F2ZShnbHVlKCJmaWd1cmVzL3tmaWxlbmFtZX0udGlmZiIpLHBsb3QgPSBwLCB3aWR0aCA9IHdpZHRoLCBoZWlnaHQgPSBoZWlnaHQsIGRwaSA9IDYwMCwgY29tcHJlc3Npb24gPSAibHp3IikNCiAgaW52aXNpYmxlKE5VTEwpDQp9DQpleHBvcnRfdGFibGUgPC0gZnVuY3Rpb24oZ3Rfb2JqLCBmaWxlbmFtZSl7DQogIGd0c2F2ZShndF9vYmosIGZpbGVuYW1lID0gZ2x1ZSgidGFibGVzL3tmaWxlbmFtZX0uaHRtbCIpKQ0KICAjIFBORyAocHJlY2lzYSB3ZWJzaG90MiBpbnN0YWxhZG8vY29uZmlndXJhZG8pDQogIHRyeShndHNhdmUoZ3Rfb2JqLCBmaWxlbmFtZSA9IGdsdWUoInRhYmxlcy97ZmlsZW5hbWV9LnBuZyIpKSkNCiAgIyBMYVRlWA0KICB0cnkoZ3RzYXZlKGd0X29iaiwgZmlsZW5hbWUgPSBnbHVlKCJ0YWJsZXMve2ZpbGVuYW1lfS50ZXgiKSkpDQogIGludmlzaWJsZShOVUxMKQ0KfQ0KDQojIEVzdGlsbyBwYWRyw6NvIGRlIHRhYmVsYQ0KZ3RfYXJ0aWNsZSA8LSBmdW5jdGlvbihkYXQsIHRpdGxlID0gTlVMTCwgc3VidGl0bGUgPSBOVUxMLCBub3RlID0gTlVMTCl7DQogIGRhdCAlPiUNCiAgICBndCgpICU+JQ0KICAgIHRhYl9oZWFkZXIodGl0bGUgPSBtZCh0aXRsZSAlfHwlICIiKSwgc3VidGl0bGUgPSBtZChzdWJ0aXRsZSAlfHwlICIiKSkgJT4lDQogICAgZm10X251bWJlcih3aGVyZShpcy5udW1lcmljKSwgZGVjaW1hbHMgPSAyKSAlPiUNCiAgICB0YWJfb3B0aW9ucyh0YWJsZS5mb250LnNpemUgPSBweCgxMikpICU+JQ0KICAgIG9wdF9ob3Jpem9udGFsX3BhZGRpbmcoc2NhbGUgPSAxLjEpICU+JQ0KICAgIG9wdF92ZXJ0aWNhbF9wYWRkaW5nKHNjYWxlID0gMS4xKSAlPiUNCiAgICB0YWJfc291cmNlX25vdGUobWQobm90ZSAlfHwlICJOb3RlczogQXV0aG9y4oCZcyBjYWxjdWxhdGlvbnMuIikpDQp9DQpgYGANCg0KIyAxLiBJbnRyb2R1Y3Rpb24NCg0KVGhpcyByZXBvcnQgZG9jdW1lbnRzIHRoZSBhbmFseXRpY2FsIHBpcGVsaW5lIGRldmVsb3BlZCB0byBlc3RpbWF0ZSB0aGUgY2xpbWF0aWMgcGVuYWx0eSAocGVuYWxpZGFkZSBjbGltw6F0aWNhKSBvbiBCcmF6aWzigJlzIGVsZWN0cmljaXR5IHNlY3RvciBhbmQgdG8gdHJhbnNsYXRlIHRoZXNlIGVmZmVjdHMgaW50byBtZWFzdXJhYmxlIGVjb25vbWljIGNvc3RzLiBUaGUgYW5hbHlzaXMgd2FzIGNvbmR1Y3RlZCB1c2luZyBtb250aGx5IGRhdGEgZnJvbSAyMDAxIHRvIDIwMTksIGNvdmVyaW5nIGFsbCBmb3VyIHN1YnN5c3RlbXMgb2YgdGhlIE5hdGlvbmFsIEludGVyY29ubmVjdGVkIFN5c3RlbSAoU0lOKS4NCg0KVGhlIHN0dWR5IHByb2NlZWRzIHRocm91Z2ggdGhlIGZvbGxvd2luZyBzdGVwczoNCg0KMS4gIEh5ZHJvbG9naWNhbCBtb2RlbGxpbmcg4oCUIFdlIGVzdGltYXRlZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY2xpbWF0aWMgdmFyaWFibGVzIChwcmVjaXBpdGF0aW9uLCB0ZW1wZXJhdHVyZSwgaHVtaWRpdHksIHdpbmQpIGFuZCBzdG9yZWQgZW5lcmd5IChFQVIpIGFuZCBoeWRyb2VsZWN0cmljIGdlbmVyYXRpb24gdXNpbmcgR2VuZXJhbGl6ZWQgQWRkaXRpdmUgTW9kZWxzIChHQU1zKS4gVGhlc2UgbW9kZWxzIGNhcHR1cmUgbm9uLWxpbmVhciBjbGltYXRl4oCTaHlkcm9sb2d5IGludGVyYWN0aW9ucyBhbmQgc2Vhc29uYWwgZWZmZWN0cyBhdCB0aGUgc3Vic3lzdGVtIGxldmVsLg0KDQoyLiAgQ2xpbWF0aWMgY291bnRlcmZhY3R1YWxzIOKAlCBVc2luZyB0aGUgZml0dGVkIEdBTXMsIHdlIHNpbXVsYXRlZCBjb3VudGVyZmFjdHVhbCB0cmFqZWN0b3JpZXMgZml4aW5nIHRoZSBjbGltYXRpYyBjb3ZhcmlhdGVzIGF0IHRoZWlyIGhpc3RvcmljYWwgbWVhbiBsZXZlbHMgKGJhc2VsaW5lIDIwMDHigJMyMDA1KS4gVGhlIGRldmlhdGlvbiBiZXR3ZWVuIG9ic2VydmVkIGFuZCBjb3VudGVyZmFjdHVhbCB2YWx1ZXMgaXNvbGF0ZXMgdGhlIHNoYXJlIG9mIHZhcmlhdGlvbiBhdHRyaWJ1dGFibGUgZXhjbHVzaXZlbHkgdG8gY2xpbWF0ZSB2YXJpYWJpbGl0eS4NCg0KMy4gIENsaW1hdGUgcGVuYWx0eSAozpRFKSDigJQgVGhlIGNsaW1hdGUgcGVuYWx0eSB3YXMgZGVmaW5lZCBhcyAkzpRFPUVfe3ByZWRpY3RlZH3iiJJFX3tjZn0kIHJlcHJlc2VudGluZyB0aGUgbG9zcyAob3IgZ2Fpbikgb2YgaHlkcm8gZ2VuZXJhdGlvbiBkdWUgc29sZWx5IHRvIGNsaW1hdGljIGZsdWN0dWF0aW9ucy4NCg0KNC4gIEVsYXN0aWNpdGllcyDigJQgV2UgZGVyaXZlZCBlbGFzdGljaXRpZXMgbGlua2luZyBnZW5lcmF0aW9uIHRvIGh5ZHJvbG9naWNhbCBhbmQgY2xpbWF0aWMgY29uZGl0aW9ucywgYW5kIGRlbWFuZCB0byBwcmljZSBhbmQgaW5jb21lLCB0byBhc3Nlc3Mgc2Vuc2l0aXZpdHkgYW5kIHBvdGVudGlhbCB0cmFuc21pc3Npb24gY2hhbm5lbHMgb2YgY2xpbWF0aWMgc2hvY2tzLg0KDQo1LiAgQ29zdCB0cmFuc2xhdGlvbiDigJQgVGhlIGVzdGltYXRlZCBwZW5hbHRpZXMgd2VyZSBjb252ZXJ0ZWQgaW50byBtb25ldGFyeSB0ZXJtcyBhbG9uZyB0aHJlZSBjb3N0IGRpbWVuc2lvbnM6DQoNCjYuICBDb25zdW1lcnM6IGFkZGl0aW9uYWwgZXhwZW5kaXR1cmUgZHVlIHRvIHJlcGxhY2VtZW50IG9mIGNoZWFwZXIgaHlkcm8gZ2VuZXJhdGlvbiBieSBtb3JlIGV4cGVuc2l2ZSBzb3VyY2VzOw0KDQo3LiAgRWxlY3RyaWNpdHkgc2VjdG9yOiBoaWdoZXIgc3BvdCBtYXJrZXQgcHJpY2VzIChQTEQpIGFuZCBvcGVyYXRpb25hbCBjb3N0czsNCg0KVGhpcyBlbXBpcmljYWwgcGlwZWxpbmUgbGlua3MgY2xpbWF0ZSB2YXJpYWJpbGl0eSwgaHlkcm9sb2dpY2FsIHBlcmZvcm1hbmNlLCBhbmQgZWNvbm9taWMgb3V0Y29tZXMgdGhyb3VnaCBhIHVuaWZpZWQgc3RhdGlzdGljYWwgZnJhbWV3b3JrLCBlbmFibGluZyBhIG11bHRpZGltZW5zaW9uYWwgdmFsdWF0aW9uIG9mIGNsaW1hdGUtcmVsYXRlZCByaXNrcyBpbiBhIGh5ZHJvLWRlcGVuZGVudCBwb3dlciBzeXN0ZW0uDQoNCiMgMi4gRGF0YSBQcmVwYXJhdGlvbg0KDQpUaGlzIHNlY3Rpb24gZGVzY3JpYmVzIHRoZSBjb25zdHJ1Y3Rpb24gb2YgdGhlIGFuYWx5dGljYWwgZGF0YXNldCB1c2VkIHRvIGVzdGltYXRlIHRoZSBjbGltYXRpYyBwZW5hbHR5LlwNCkFsbCB2YXJpYWJsZXMgd2VyZSBoYXJtb25pemVkIGF0IHRoZSAqKnN1YnN5c3RlbeKAk2RheSoqIGxldmVsIGJldHdlZW4gMjAwMSBhbmQgMjAxOSwgaW50ZWdyYXRpbmcgaHlkcm9sb2dpY2FsLCBjbGltYXRpYywgYW5kIG1hcmtldCBpbmZvcm1hdGlvbi4NCg0KIyMjIDIuMSBEYXRhIFNvdXJjZXMNCg0KLSAgICAqKkh5ZHJvcG93ZXIgZ2VuZXJhdGlvbiAocGxhbnQtZGF5KToqKiBkYWlseSBnZW5lcmF0aW9uIGRhdGEgY29tcGlsZWQgZnJvbSBPTlMgcmVjb3JkcywgYWdncmVnYXRlZCBieSBzdWJzeXN0ZW0uDQoNCi0gICAqKlJlc2Vydm9pciBsZXZlbHMgYW5kIG5hdHVyYWwgaW5mbG93cyAoRUFSIGFuZCBFTkEpOioqIHN1YnN5c3RlbS1sZXZlbCBkYWlseSBkYXRhIGZyb20gT05TLg0KDQotICAgKipDbGltYXRpYyB2YXJpYWJsZXM6KiogcHJlY2lwaXRhdGlvbiBhbmQgdGVtcGVyYXR1cmUgb2J0YWluZWQgZnJvbSB0aGUgRUNNV0YvQ0FNUyByZWFuYWx5c2lzIGRhdGFzZXQsIGludGVycG9sYXRlZCB0byBtYXRjaCBzdWJzeXN0ZW0gY2VudHJvaWRzLg0KDQotICAgKipTcG90IHByaWNlIChQTEQpOioqIHdlZWtseSBzdWJzeXN0ZW0gZGF0YSBmcm9tIENDRUUuDQoNCi0gICAqKkRlbWFuZCBhbmQgZ2VuZXJhdGlvbiBkaXNwYXRjaCBieSBzb3VyY2U6KiogbW9udGhseSBvciB3ZWVrbHkgZGF0YSBmcm9tIE9OUyBhbmQgRVBFLg0KDQpBbGwgZGF0YXNldHMgd2VyZSBwcmUtcHJvY2Vzc2VkIHRvIGFsaWduIGRhdGUgZm9ybWF0cywgaGFybW9uaXplIHZhcmlhYmxlIG5hbWVzLCBhbmQgcmVtb3ZlIGluY29uc2lzdGVudCBvciBtaXNzaW5nIGlkZW50aWZpZXJzLg0KDQojIyMgMi4yIERhdGEgTG9hZGluZyBhbmQgQ2xlYW5pbmcNCg0KYGBge3IgZGF0YS1pbn0NCiMgTG9hZCBjb3JlIGRhdGFzZXRzDQpnZXIgICAgIDwtIHJlYWQuY3N2KCJiYXNlX2dlcmFfdHJhdGFkYV9zZXQuY3N2IikgICAgICMgcGxhbnQtZGF5IGdlbmVyYXRpb24NCnBsZCAgICAgPC0gcmVhZC5jc3YoInBsZF9kaWFyaW9fY29tcGxldG8uY3N2IikgICAgICAgICAgICAgIyB3ZWVrbHkgc3BvdCBwcmljZSAoUExEKQ0KcmVzZXJ2ICA8LSByZWFkLmNzdigiZW5hX2Vhcl9oaWRyX2NlZ19hbWIuY3N2IikgICAgICAjIHJlc2Vydm9pciBsZXZlbHMgJiBpbmZsb3dzIChFQVIvRU5BKQ0KYGBgDQoNCg0KYGBge3IgZGF0YS1pbiAyIH0NCiMgQ29udmVydCBjaGFyYWN0ZXIgY29sdW1ucyB0byBmYWN0b3JzDQpnZXIgICAgPC0gZ2VyICAgICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQpyZXNlcnYgPC0gcmVzZXJ2ICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQpwbGQgICAgPC0gcGxkICAgICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIGFzLmZhY3RvcikpDQoNCiMgLS0tIERhdGUgcGFyc2luZyBhbmQgdGVtcG9yYWwgdmFyaWFibGVzIC0tLQ0KZ2VyJGRhdGUgICAgPC0gYXMuRGF0ZShnZXIkRGF0ZSkgICAgICAgICAgICAgICAjIGFkanVzdCBjb2x1bW4gbmFtZSBhcyBuZWVkZWQNCmdlciRkb3kgICAgIDwtIHlkYXkoZ2VyJGRhdGUpDQpnZXIkZG93ICAgICA8LSBsdWJyaWRhdGU6OndkYXkoZ2VyJGRhdGUsIGxhYmVsID0gVFJVRSwgYWJiciA9IFRSVUUpDQpnZXIkbW9udGggICA8LSBtb250aChnZXIkZGF0ZSkNCmdlciR0cmVuZCAgIDwtIGFzLm51bWVyaWMoZ2VyJGRhdGUpDQoNCnJlc2VydiRkYXRlIDwtIGFzLkRhdGUocmVzZXJ2JGVuYV9kYXRhKSAgICAgICAgIyBhZGp1c3QgY29sdW1uIG5hbWUgYXMgbmVlZGVkDQpyZXNlcnYkZG95ICA8LSB5ZGF5KHJlc2VydiRkYXRlKQ0KcmVzZXJ2JGRvdyAgPC0gbHVicmlkYXRlOjp3ZGF5KHJlc2VydiRkYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKQ0KcmVzZXJ2JG1vbnRoPC0gbW9udGgocmVzZXJ2JGRhdGUpDQpyZXNlcnYkdHJlbmQ8LSBhcy5udW1lcmljKHJlc2VydiRkYXRlKQ0KDQpwbGQkZGF0ZSAgICA8LSBhcy5EYXRlKHBsZCREQVRBX0lOSUNJTykgICAgICAgICMgYWRqdXN0IGNvbHVtbiBuYW1lIGFzIG5lZWRlZA0KcGxkJHdlZWsgICAgPC0gaXNvd2VlayhwbGQkZGF0ZSkNCnBsZCR5ZWFyICAgIDwtIHllYXIocGxkJGRhdGUpDQoNCmBgYA0KDQoNCg0KYGBge3IgY29uZmVyaXIgZSBsaW1wYXIgY29sdW5hcyBkdXBsaWNhZGFzfQ0KZHVwbGljYWRhcyA8LSBkdXBsaWNhdGVkKGFzLmxpc3QocmVzZXJ2KSkNCnJlc2VydlssZHVwbGljYWRhc10gJT4lIGNvbG5hbWVzKCkNCnJlc2VydjwtcmVzZXJ2ICU+JSBzZWxlY3QoLWlkX3N1YnNpc3RlbWEueC54LC1pZF9zdWJzaXN0ZW1hLnkueSwtbm9tX2JhY2lhLngsLW5vbV9iYWNpYS54LC1ub21fcmVlLngsLW5vbV9yZWUueSwtbm9tX3VzaW5hLngsLW5vbV9zdWJzaXN0ZW1hLnkueSwtbm9tX2JhY2lhLnkpDQpgYGANCg0KIyMjIDIuMyBUZW1wb3JhbCBTbW9vdGhpbmcgYW5kIFJvbGxpbmcgTWVhbnMNClRvIHJlZHVjZSBzaG9ydC10ZXJtIG5vaXNlIGFuZCBjYXB0dXJlIGN1bXVsYXRpdmUgY2xpbWF0aWMgZWZmZWN0cywgd2UgY29tcHV0ZWQgKipyb2xsaW5nIG1lYW5zICg3LCAxNCwgYW5kIDMwIGRheXMpKiogZm9yIGtleSBoeWRyb2xvZ2ljYWwgYW5kIGNsaW1hdGljIHZhcmlhYmxlcy4gIA0KDQoNCg0KYGBge3J9DQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoZHBseXIpDQoNCiMjZGlhZ19ncm91cHMgPC0gcmVzZXJ2ICU+JWZpbHRlcih0aXBfcmVzZXJ2YXRvcmlvPT0iUmVzZXJ2YXTDs3JpbyBjb20gVXNpbmEiKSAlPiUgDQojICBncm91cF9ieShub21fcmVzZXJ2YXRvcmlvLngsaWRfcmVzZXJ2YXRvcmlvLngsdGlwX3Jlc2VydmF0b3JpbykgJT4lDQojICBzdW1tYXJpc2UoDQojICAgIG5fdG90YWwgPSBuKCksDQojICAgIG5fbm9uX25hX3ByZWNpcCA9IHN1bSghaXMubmEocHJlY2lwdGF0aW9uKSksDQojICAgIG5fbm9uX25hX3RlbXAgICA9IHN1bSghaXMubmEodGVtcGVyYXR1cmUpKSwNCiMgICAgbl9ub25fbmFfZW5hICAgID0gc3VtKCFpcy5uYShlbmFfYnJ1dGFfcmVzX213bWVkKSksDQojICAgIG5fbm9uX25hX2VhciAgICA9IHN1bSghaXMubmEoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMpKSwNCiMgICAgbl9ub25fbmFfZ2VyICAgID0gc3VtKCFpcy5uYSh2YWxfZ2VyYWNhbykpLA0KIyAgICAuZ3JvdXBzID0gImRyb3AiDQojICApDQojIyBDcmlhciBtw6lkaWFzIG3Ds3ZlaXMgcGFyYSB2YXJpw6F2ZWlzIGFtYmllbnRhaXMgcHJpbmNpcGFpcw0KcmVzZXJ2IDwtIHJlc2VydiAlPiUgZmlsdGVyKHRpcF9yZXNlcnZhdG9yaW89PSJSZXNlcnZhdMOzcmlvIGNvbSBVc2luYSIpICU+JSANCiAgZ3JvdXBfYnkobm9tX3Jlc2VydmF0b3Jpby54KSAlPiUNCiAgYXJyYW5nZShkYXRlLCAuYnlfZ3JvdXAgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKA0KICAgICMgUHJlY2lwaXRhdGlvbiAodXNhIG5vbWUgJ3ByZWNpcHRhdGlvbicgY29tbyBlc3TDoSBuYSBzdWEgYmFzZSkNCiAgICAjcHJlY2lwX21tNyAgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAgNyksDQogICAgcHJlY2lwX21tMTQgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAxNCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQogICAgcHJlY2lwX21tMzAgID0gcm9sbG1lYW4ocHJlY2lwdGF0aW9uLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQoNCiAgICAjIFRlbXBlcmF0dXJlDQogICAgdGVtcF9tbTcgICAgID0gcm9sbG1lYW4odGVtcGVyYXR1cmUsICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICB0ZW1wX21tMTQgICAgPSByb2xsbWVhbih0ZW1wZXJhdHVyZSwgMTQsZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpLA0KICAgIHRlbXBfbW0zMCAgICA9IHJvbGxtZWFuKHRlbXBlcmF0dXJlLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksDQoNCiAgICAjIEVOQQ0KICAgIGVuYV9tdzcgICAgICA9IHJvbGxtZWFuKGVuYV9icnV0YV9yZXNfbXdtZWQsICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICAjZW5hX213MTQgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVuYV9icnV0YV9yZXNfbXdtZWQsIDE0KSwNCiAgICAjZW5hX213MzAgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVuYV9icnV0YV9yZXNfbXdtZWQsIDMwKSwNCg0KICAgICMgRUFSIChwcm9wcmlldMOhcmlvKSDigJQgcmVtb3ZldSBmaWxsPSJleHRlbmQiIChuw6NvIHN1cG9ydGFkbykNCiAgICMgZWFyX213NyAgICAgID0gcm9sbF9tZWFuX3JpZ2h0KGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCA3KSwNCg0KICAgICMgR2VyYcOnw6NvDQogICAgZ2VyX213NyAgICAgID0gcm9sbG1lYW4odmFsX2dlcmFjYW8sICA3LGZpbGwgPSBOQSwgYWxpZ24gPSAicmlnaHQiKSwNCiAgICBnZXJfbXcxNCAgICAgPSByb2xsbWVhbih2YWxfZ2VyYWNhbywgMTQsZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpLA0KICAgIGdlcl9tdzMwICAgICA9IHJvbGxtZWFuKHZhbF9nZXJhY2FvLCAzMCxmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IikNCiAgKSAlPiUNCiAgdW5ncm91cCgpDQoNCiNkaWFnX2dyb3VwcyAlPiUgZmlsdGVyKG5vbV9yZXNlcnZhdG9yaW8ueD09IkEuIFZFUk1FTEhBIikgDQojICANCiNyZXNlcnYgJT4lIGZpbHRlcihub21fcmVzZXJ2YXRvcmlvLng9PSJBLiBWRVJNRUxIQSIpICU+JSANCiMgIGdncGxvdChhZXMocHJlY2lwdGF0aW9uKSkrZ2VvbV9saW5lKGFlcyh4PWRhdGUseT1wcmVjaXB0YXRpb24pLGNvbD0ibGlnaHRibHVlIikNCiMgIHNlbGVjdChkYXRlLG5vbV9lc3RhZG8sdmFsX2dlcmFjYW8scHJlY2lwdGF0aW9uLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNlYXJtYXhfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfanVzYW50ZV9td21lcyxlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyxlYXJfbWF4aW1hX3RvdGFsX213bWVzKSAlPiUgc3VtbWFyeQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KIyAtLS0gQ29uZmVyaXIgY2hhdmVzIHByaW5jaXBhaXMgLS0tDQojIHZlcmlmaWNhciBzZSBkYXRhcyBlIHN1YnNpc3RlbWFzIGJhdGVtDQpjYXQoIkRhdGFzIGRpc3BvbsOtdmVpczpcbiIpDQpyYW5nZShnZXIkZGF0ZSwgbmEucm09VFJVRSkNCnJhbmdlKHJlc2VydiRkYXRlLCBuYS5ybT1UUlVFKQ0KcmFuZ2UocGxkJGRhdGUsIG5hLnJtPVRSVUUpDQpgYGANCg0KIyMjIDIuNCBEZXNjcmlwdGl2ZSBTdW1tYXJpZXMNCg0KYGBge3IgZGVzY3JpcHRpdmUtc3VtbWFyaWVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkoc3RyaW5ncikNCg0KIyBIZWxwZXI6IHNlbGVjaW9uYSBhcyB2YXJpw6F2ZWlzIGV4YXRhcyBwZWRpZGFzLCBzZSBleGlzdGlyZW0gbm8gZGF0YXNldA0Kc2VsZWN0X2Rlc2NfdmFycyA8LSBmdW5jdGlvbihkZil7DQogIHdhbnRlZCA8LSB0aWR5c2VsZWN0Ojp2YXJzX3NlbGVjdCgNCiAgICBuYW1lcyhkZiksDQogICAgc3RhcnRzX3dpdGgoImVhciIpLA0KICAgIHN0YXJ0c193aXRoKCJ0ZW0iKSwNCiAgICBzdGFydHNfd2l0aCgicHJlIiksDQogICAgc3RhcnRzX3dpdGgoImdlciIpLA0KICAgIHZhbF9nZXJhY2FvLA0KICAgIHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hLA0KICAgIGh1bWlkaXR5LA0KICAgIHdpbmRfc3BlZWQNCiAgKQ0KICBkZiAlPiUgZHBseXI6OnNlbGVjdChub21fc3Vic2lzdGVtYS54LCBkcGx5cjo6YWxsX29mKHdhbnRlZCkpDQp9DQoNCiMgSGVscGVyOiBzdW1hcml6YSBlc3RhdMOtc3RpY2FzIHBhcmEgdW0gZGF0YS5mcmFtZSBqw6EgZmlsdHJhZG8gcG9yIHN1YnNpc3RlbWENCnN1bW1hcmlzZV9zdGF0cyA8LSBmdW5jdGlvbihkZl9zdWIpew0KICBudW1fdmFycyA8LSBkZl9zdWIgJT4lIGRwbHlyOjpzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbnVtX3ZhcnMsDQogICAgZHBseXI6OmFjcm9zcygNCiAgICAgIC5jb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgLmZucyAgPSBsaXN0KA0KICAgICAgICBNZWFuID0gfm1lYW4oLiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgU0QgICA9IH5zZCguLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBNaW4gID0gfm1pbiguLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBNYXggID0gfm1heCguLCBuYS5ybSA9IFRSVUUpDQogICAgICApLA0KICAgICAgLm5hbWVzID0gInsuY29sfV9fey5mbn0iDQogICAgKQ0KICApICU+JQ0KICAgIHRpZHlyOjpwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLA0KICAgICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsInN0YXQiKSwNCiAgICAgIG5hbWVzX3NlcCA9ICJfXyIsDQogICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiDQogICAgKSAlPiUNCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHN0YXQsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JQ0KICAgIGRwbHlyOjphcnJhbmdlKHZhcmlhYmxlKQ0KfQ0KDQpgYGANCg0KYGBge3J9DQojIFRhYmVsYSBkZSBjb2JlcnR1cmEgdGVtcG9yYWwgcG9yIHN1YnNpc3RlbWENCmNvdmVyYWdlX3RibCA8LSByZXNlcnYgJT4lDQogIGRwbHlyOjpncm91cF9ieShub21fc3Vic2lzdGVtYS54KSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBvYnNlcnZhdGlvbnMgPSBkcGx5cjo6bl9kaXN0aW5jdChpZF9yZXNlcnZhdG9yaW8ueCksDQogICAgc3RhcnRfZGF0ZSAgPSBtaW4oZGF0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBlbmRfZGF0ZSAgICA9IG1heChkYXRlLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQp0YWJfY292IDwtIGd0X2FydGljbGUoDQogIGNvdmVyYWdlX3RibCwNCiAgdGl0bGUgPSAiKipUYWJsZSBBLiBUZW1wb3JhbCBjb3ZlcmFnZSBieSBzdWJzeXN0ZW0qKiIsDQogIHN1YnRpdGxlID0gIk9ic2VydmF0aW9uIGNvdW50cyBhbmQgZGF0ZSByYW5nZSIsDQogIG5vdGUgPSAiRGF0ZXMgaW4gWVlZWS1NTS1ERC4iDQopICU+JQ0KICBndDo6Y29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYS54ICAgPSAiU3Vic3lzdGVtIiwNCiAgICBvYnNlcnZhdGlvbnM9ICJOIG9mIFJlc2Vydm9pcnMiLA0KICAgIHN0YXJ0X2RhdGUgID0gIlN0YXJ0IiwNCiAgICBlbmRfZGF0ZSAgICA9ICJFbmQiDQogICkNCg0KZXhwb3J0X3RhYmxlKHRhYl9jb3YsICJUYWJBX0NvdmVyYWdlX2J5U3Vic3lzdGVtIikNCnRhYl9jb3YNCmBgYA0KDQpgYGB7cn0NCg0KIyBUYWJlbGEgZGUgY29iZXJ0dXJhIHRlbXBvcmFsIHBvciBzdWJzaXN0ZW1hDQojY292ZXJhZ2VfdGJsIDwtIA0KcmVzZXJ2ICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkobm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgTWVhbl9nZXJhY2FvPW1lYW4odmFsX2dlcmFjYW8sIG5hLnJtID0gVFJVRSksDQogICAgU0RfZ2VyYWNhbz1tZWFuKHZhbF9nZXJhY2FvLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9nZXJhY2FvICA9IG1pbih2YWxfZ2VyYWNhbywgbmEucm0gPSBUUlVFKSwNCiAgICBNYXhfZ2VyYWNhbyAgICA9IG1heCh2YWxfZ2VyYWNhbywgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICBNZWFuX0VBUj1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNEX0VBUj1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9FQVIgID0gbWluKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF9FQVIgICAgPSBtYXgoZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMsIG5hLnJtID0gVFJVRSksDQogICAgDQogICAgTWVhbl9wcmVjaXBtbTMwPW1lYW4ocHJlY2lwX21tMzAsIG5hLnJtID0gVFJVRSksDQogICAgU0RfcHJlY2lwbW0zMD1tZWFuKHByZWNpcF9tbTMwLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9wcmVjaXBtbTMwICA9IG1pbihwcmVjaXBfbW0zMCwgbmEucm0gPSBUUlVFKSwNCiAgICBNYXhfcHJlY2lwbW0zMCAgICA9IG1heChwcmVjaXBfbW0zMCwgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICBNZWFuX3RlbXBtbTc9bWVhbih0ZW1wX21tNywgbmEucm0gPSBUUlVFKSwNCiAgICBTRF90ZW1wbW03PW1lYW4odGVtcF9tbTcsIG5hLnJtID0gVFJVRSksDQogICAgTWluX3RlbXBtbTcgID0gbWluKHRlbXBfbW03LCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF90ZW1wbW03ICAgID0gbWF4KHRlbXBfbW03LCBuYS5ybSA9IFRSVUUpLA0KICAgIA0KICAgIE1lYW5faHVtaWRpdHk9bWVhbihodW1pZGl0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBTRF9odW1pZGl0eT1tZWFuKGh1bWlkaXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIE1pbl9odW1pZGl0eSAgPSBtaW4oaHVtaWRpdHksIG5hLnJtID0gVFJVRSksDQogICAgTWF4X2h1bWlkaXR5ICAgID0gbWF4KGh1bWlkaXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIA0KICAgIE1lYW5fd2luZD1tZWFuKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgU0Rfd2luZD1tZWFuKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgTWluX3dpbmQgID0gbWluKHdpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgTWF4X3dpbmQgICAgPSBtYXgod2luZF9zcGVlZCwgbmEucm0gPSBUUlVFKSwNCiAgICANCiAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGMoZW5kc193aXRoKCJnZXJhY2FvIiksZW5kc193aXRoKCJpbmQiKSxlbmRzX3dpdGgoIkVBUiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRzX3dpdGgoIml0eSIpLGVuZHNfd2l0aCgibW03IiksZW5kc193aXRoKCJtbTMwIikpLA0KICAgICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsInN0YXQiKSwNCiAgICAgIG5hbWVzX3NlcCA9ICJfIiwNCiAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSINCiAgICApICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsdmFsdWVzX2Zyb20gPXZhbHVlKSAlPiUgDQogIGFycmFuZ2Uoc3RhdCkgJT4lICMgLT4gdGFiX2Rlc2MNCiAgZ3RfYXJ0aWNsZSgNCiAgDQogIHRpdGxlID0gIioqVGFibGUgQi4gIERlc2NyaXB0aXZlIFN1bW1hcmllcyIsDQogIHN1YnRpdGxlID0gIk9ic2VydmF0aW9uIGNvdW50cyBhbmQgZGF0ZSByYW5nZSIsDQogIG5vdGUgPSAiRGF0ZXMgaW4gWVlZWS1NTS1ERC4iDQopICU+JQ0KICBndDo6Y29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYS54ICAgPSAiU3Vic3lzdGVtIiwNCiAgICBzdGF0PSAiVmFyaWFibGUiLA0KICAgIE1lYW4gID0gIk1lYW4iLA0KICAgIFNEICAgID0gIlNEIixNaW49ICJNaW4iLCJNYXgiPSAiTWF4Ig0KICApDQoNCiNleHBvcnRfdGFibGUodGFiX2NvdiwgIlRhYkFfQ292ZXJhZ2VfYnlTdWJzeXN0ZW0iKQ0KI3RhYl9jb3YNCg0KYGBgDQoNCmBgYHtyfQ0KDQoNCg0KcmVzZXJ2ICU+JSBzZWxlY3Qoc3RhcnRzX3dpdGgoImVuYSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoImVhciIpLHN0YXJ0c193aXRoKCJ0ZW0iKSxzdGFydHNfd2l0aCgicHJlIiksc3RhcnRzX3dpdGgoImdlciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsX2dlcmFjYW8sdmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEsaHVtaWRpdHksd2luZF9zcGVlZCkgJT4lIHN0YXJnYXplcjo6c3RhcmdhemVyKHR5cGU9InRleHQiKQ0KcGxkICU+JSBzdGFyZ2F6ZXI6OnN0YXJnYXplcih0eXBlPSJ0ZXh0IikNCmdlciAlPiUgc2VsZWN0KHZhbF9nZXJhY2FvLG5vbV90aXBvY29tYnVzdGl2ZWwsbm9tX3RpcG91c2luYT1hcy5mYWN0b3Iobm9tX3RpcG91c2luYSkpICU+JSBzdW1tYXJ5DQoNCmBgYA0KDQojIyMgW0dyw6FmaWNvcyByw6FwaWRvczogc8OpcmllcyBFTkEsIHByZWNpcGl0YcOnw6NvLCB0ZW1wZXJhdHVyYSwgRUFSLCBnZXJhw6fDo29dDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQ0KIyAtLS0gR3LDoWZpY29zIHLDoXBpZG9zIChFREEpIC0tLQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIFPDqXJpZSBFTkEvUmVzZXJ2YXTDs3Jpb3MNCnBsb3RfZW5hPC1yZXNlcnYgJT4lIGdyb3VwX2J5KGRhdGUpICU+JSBzdW1tYXJpc2UoZWFyX213Nz1tZWFuKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLG5hLnJtID0gVCkpICU+JSANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9ZWFyX213NykpICsNCiAgZ2VvbV9saW5lKGNvbG9yPSJzdGVlbGJsdWUiKSArZ2VvbV9zbW9vdGgoKSsNCiAgbGFicyh0aXRsZT0iRW5lcmdpYSBBcm1hemVuYWRhIChFQVIpIGJydXRhIChNV21lZCkiLCB4PSIiLCB5PSJNV21lZCIpDQoNCiMgU8OpcmllIEVBUg0KcGxvdF9lYXI8LXJlc2VydiAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lIHN1bW1hcmlzZShlbmFfbXc3PW1lYW4oZW5hX213NyxuYS5ybSA9IFQpKSAlPiUgDQogICAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9ZW5hX213NykpICsNCiAgZ2VvbV9saW5lKGNvbG9yPSJkYXJrZ3JlZW4iKSArZ2VvbV9zbW9vdGgoKSsNCiAgbGFicyh0aXRsZT0iRW5lcmdpYSBOYXR1cmFsIEFmbHVlbnRlIChFTkEpIHRvdGFsIChNV23DqnMpIiwgeD0iIiwgeT0iTVdtw6pzIikNCg0KIyBTw6lyaWUgZGUgZ2VyYcOnw6NvDQpwbG90X2dlcjwtcmVzZXJ2ICU+JSBncm91cF9ieShkYXRlKSAlPiUgc3VtbWFyaXNlKGdlcl9tdzc9bWVhbihnZXJfbXc3LG5hLnJtID0gVCkpICU+JSANCiAgICAgIGdncGxvdChhZXMoeD1kYXRlLCB5PWdlcl9tdzcpKSArDQogIGdlb21fbGluZShjb2xvcj0iZ3JleTMwIikgK2dlb21fc21vb3RoKCkrDQogIGxhYnModGl0bGU9IkdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhIChNV2gvZGlhKSIsIHg9IiIsIHk9Ik1XaCIpDQoNCiMgLS0tIENvcnJlbGHDp8O1ZXMgcsOhcGlkYXMgLS0tDQojIFtDaGVjYXIgY29ycmVsYcOnw6NvIGLDoXNpY2EgZW50cmUgY2xpbWEgKHByZWNpcCwgdGVtcCkgZSBFTkFdDQpjbGltYV92YXJzIDwtIHJlc2VydiAlPiUgDQogIGRwbHlyOjpzZWxlY3QoDQogICAgICAgICAgICAgICAgZ2VyX213X3N1YnNpc3RlbWE9dmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEsDQogICAgICAgICAgICAgICAgZ2VyX213PXZhbF9nZXJhY2FvLGdlcl9tdzcsZ2VyX213MTQsZ2VyX213MzAsDQogICAgICAgICAgICAgICAgZW5hX213PWVuYV9icnV0YV9yZXNfbXdtZWQsIGVuYV9tdzcsDQogICAgICAgICAgICAgICAgZWFyX213PWVhcl90b3RhbF9td21lcywgICNlYXJfbXcxNCwgZWFyX213MzAsDQogICAgICAgICAgICAgICAgcHJlY2lwdGF0aW9uLHByZWNpcF9tbTE0LHByZWNpcF9tbTMwLA0KICAgICAgICAgICAgICAgIHRlbXBlcmF0dXJlLHRlbXBfbW03LHRlbXBfbW0xNCx0ZW1wX21tMzAsDQogICAgICAgICAgICAgICAgd2luZF9zcGVlZCwgDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQ0KcGxvdF9nZXJ8cGxvdF9lYXIgLyBwbG90X2VuYQ0KDQpjb3JycGxvdDo6Y29ycnBsb3QoY29yKGNsaW1hX3ZhcnMsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKSxtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwNCiAgICAgICAgIGFkZENvZWYuY29sID0gImJsYWNrIiwgIyBtb3N0cmFyIGNvZWZpY2llbnRlcw0KICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gMzUsbnVtYmVyLmNleAkJID0uOCwNCiAgICAgICAgIGNvbD1jb2xvclJhbXBQYWxldHRlKGMoInJlZCIsIndoaXRlIiwiYmx1ZSIpKSgyMDApKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KGdncmVwZWwpDQpnZW9icjo6cmVhZF9yZWdpb24oKS0+Z2VvcmVnaW9uDQoNCnJlc2VydiAlPiUgZmlsdGVyKCJSZXNlcnZhdMOzcmlvIGNvbSBVc2luYSI9PXRpcF9yZXNlcnZhdG9yaW8pICU+JQ0KICBncm91cF9ieShub21fcmVzZXJ2YXRvcmlvLnksdmFsX2xhdGl0dWRlLHZhbF9sb25naXR1ZGUsbm9tX3N1YnNpc3RlbWEueCkgJT4lIA0KICBzdW1tYXJpc2UoZWFyX3Jlc2VydmF0b3Jpbz1zdW0oZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMgJT4lIGFzLm51bWVyaWMoKSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgKSAtPmENCmEgJT4lICAgZ2dwbG90KGFlcyh2YWxfbG9uZ2l0dWRlLHZhbF9sYXRpdHVkZSkpK2dlb21fcG9pbnQoKSsNCmdncGxvdChkYXRhPWdlb3JlZ2lvbikgK2dlb21fc2YoKQ0KYSRub21fc3Vic2lzdGVtYS54ICU+JSB1bmlxdWUNCmEgJT4lDQogIG11dGF0ZShub21fc3Vic2lzdGVtYS54PWNhc2Vfd2hlbihub21fc3Vic2lzdGVtYS54PT0iU1VMIn4iU291dGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9tX3N1YnNpc3RlbWEueD09IlNVREVTVEUifiJTb3V0aGVhc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9tX3N1YnNpc3RlbWEueD09Ik5PUkRFU1RFIn4iTm9ydGhlYXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hLng9PSJOT1JURSJ+Ik5vcnRoIixUUlVFfiIiKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGdlb3JlZ2lvbiwgY29sb3IgPSAid2hpdGUiLGZpbGw9ImxpZ2h0Z3JleSIsIHNpemUgPSAyKSsjZ2VvbV9saW5lKCkrDQogIGdlb21fcG9pbnQoYWVzKHZhbF9sb25naXR1ZGUsdmFsX2xhdGl0dWRlLGNvbD1ub21fc3Vic2lzdGVtYS54KSkgK3RoZW1lX3ZvaWQoKSsgI3NjYWxlX2NvbG9yX2Rpc2NyZXRlKHZhbHVlPSkNCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyh2YWxfbG9uZ2l0dWRlLHZhbF9sYXRpdHVkZSxjb2w9bm9tX3N1YnNpc3RlbWEueCxsYWJlbD1ub21fcmVzZXJ2YXRvcmlvLnkpLHNpemUgPSAyLG1heC5vdmVybGFwcz1ucm93KGEpLGZvcmNlX3B1bGwgID0yKSsNCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKC44LCAuOTUpLCxsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiKSsNCiAgbGFicyhjb2w9IkVsZXRyaWNhbCBTdWJzeXN0ZW1zIiktPm1hcA0KbWFwDQpgYGANCmBgYHtyfQ0KcmVzZXJ2IDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKA0KICAgIGRveSAgID0geWRheShkYXRlKSwNCiAgICBtb250aCA9IG1vbnRoKGRhdGUpLA0KICAgICMgdHJhbnNmb3JtYcOnw6NvIGxvZyBwYXJhIGludGVycHJldGHDp8OjbyBwZXJjZW50dWFsIChldml0YSBwcm9ibGVtYXMgY29tIHplcm8pDQogICAgbF9wcmVjaXAgPSBsb2cxcChwcmVjaXBfbW0zMCksDQogICAgbF90ZW1wICAgPSBsb2cxcCh0ZW1wX21tNyksICAgICAjIG9wY2lvbmFsOiBzZSBwcmVmZXJpciBtYW50ZXIgdGVtcCBubyBuw612ZWwsIHVzZSB0ZW1wX21tNyBlbSB2ZXogZGUgbF90ZW1wDQogICAgbF9odW1pZGl0eSA9bG9nMXAoaHVtaWRpdHkpLA0KICAgIGxfd2luZF9zcGVlZD1sb2cod2luZF9zcGVlZCkNCiAgKQ0KYGBgDQoNCiMgMy4xIE1vZGVsbyAxIOKAlCBHQU0g4oCcY2xpbWHigJFhcGVuYXPigJ0gKGJhc2VsaW5lKQ0KDQpNb2RlbG8gaGlkcm9sw7NnaWNvIHBhcnNpbW9uaW9zbyBubyBxdWFsIGEgRW5lcmdpYSBBcm1hemVuYWRhIChFQVIpIMOpIGV4cGxpY2FkYSBhcGVuYXMgcG9yIGNsaW1hIGUgY29udHJvbGVzIHNhem9uYWlzL3JlZ2lvbmFpcywgdXNhbmRvIGZ1bsOnw7VlcyBzdWF2ZXMgKHNwbGluZXMpIGVtIHVtIEdBTS4gTyBvYmpldGl2byDDqSBpc29sYXIgbyBzaW5hbCBwdXJhbWVudGUgY2xpbcOhdGljbyBzb2JyZSBvIGVzdG9xdWUgaMOtZHJpY28gZSBjb25zdHJ1aXIgdW0gY29udHJhZmFjdHVhbCBhdWRpdMOhdmVsLiBNYW50ZW1vcyBhIHJlc3Bvc3RhIG5vIG7DrXZlbCAoTVfCt23DqnMpIHBvciBjb2Vyw6puY2lhIGNvbSBhIGRlZmluacOnw6NvIGRlIHBlbmFsaWRhZGUgZSBtb25ldGl6YcOnw6NvLCBlIHRyYW5zZm9ybWFtb3MgcHJlZGl0b3JlcyBjbGltw6F0aWNvcyBxdWFuZG8gw7p0aWwgcGFyYSBpbnRlcnByZXRhw6fDo28gKHNlbWktZWxhc3RpY2lkYWRlcykuDQpgYGB7cn0NCiMgR0FNIChHYXVzc2lhbiwgZlJFTUwpLiBTcGxpbmVzIGNsaW3DoXRpY2FzICsgc2F6b25hbGlkYWRlIGPDrWNsaWNhICsgZWZlaXRvIGFsZWF0w7NyaW8gcG9yIHJlc2VydmF0w7NyaW8gKyBmaXhlZCBwb3Igc3Vic2lzdGVtYQ0KbTFfZ2FtIDwtIGJhbSgNCiAgZWFyX3Jlc2VydmF0b3Jpb19zdWJzaXN0ZW1hX3Byb3ByaW9fbXdtZXMgfg0KICAgIHMobF9wcmVjaXAsIGsgPSA2KSArDQogICAgcyhsX3RlbXAsICAgayA9IDYpICsNCiAgICBzKGxfaHVtaWRpdHksIGsgPSA2KSArDQogICAgcyhsX3dpbmRfc3BlZWQsIGsgPSA2KSArDQogICAgcyhkb3ksIGJzID0gImNjIiwgayA9IDEyKSArICAgICAgICAgICAgIyBzYXpvbmFsaWRhZGUgY8OtY2xpY2Egbm8gYW5vDQogICAgcyhpZF9yZXNlcnZhdG9yaW8ueCwgYnMgPSAicmUiKSArICAgICAgIyBlZmVpdG8gYWxlYXTDs3JpbyBwb3IgcmVzZXJ2YXTDs3Jpbw0KICAgIG5vbV9zdWJzaXN0ZW1hLngsICAgICAgICAgICAgICAgICAgICAgICAjIGVmZWl0byBmaXhvIHBvciBzdWJzaXN0ZW1hDQogIGRhdGEgICAgID0gcmVzZXJ2LA0KICBtZXRob2QgICA9ICJmUkVNTCIsDQogIGRpc2NyZXRlID0gVFJVRSwNCiAgZmFtaWx5ICAgPSBnYXVzc2lhbigpLA0KICBuYS5hY3Rpb249IG5hLmV4Y2x1ZGUsDQogIGtub3RzICAgID0gbGlzdChkb3kgPSBjKDAuNSwgMzY2LjUpKSwNCiAgc2VsZWN0ICAgPSBUUlVFICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzaHJpbmthZ2UgcGFyYSBldml0YXIgd2lnZ2xlcw0KKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkobTFfZ2FtKQ0KZ3RzdW1tYXJ5Ojp0YmxfcmVncmVzc2lvbihtMV9nYW0pDQpzdW1tYXJ5KG0xX2dhbSkNCmdhbS5jaGVjayhtMV9nYW0pICAgICAgICAgICMgcmVzw61kdW9zLCBRUSwgay1pbmRleA0KY29uY3Vydml0eShtMV9nYW0sIGZ1bGw9VFJVRSkNCmBgYA0KDQojIyMgUmVzcG9zdGFzIG1hcmdpbmFpcyAocGxhdXNpYmlsaWRhZGUgZSBpbnRlcnByZXRhw6fDo28pDQpQYXJhIGludGVycHJldGFyIG8gY29tcG9ydGFtZW50byBmdW5jaW9uYWwgZSBhdmFsaWFyIHBsYXVzaWJpbGlkYWRlLCB1c2Ftb3MgZGVyaXZhZGFzIHBhcmNpYWlzLiBDb21vIGBsX3ByZWNpcCA9IGxvZyhwcmVjaXArMSlgLCBhIGRlcml2YWRhIGRlIFwoRVwpIGVtIHJlbGHDp8OjbyBhIGBsX3ByZWNpcGAgw6kgdW1hICoqc2VtaS1lbGFzdGljaWRhZGUgbm8gbsOtdmVsKio6IG8gZWZlaXRvIGRlICsxJSBlbSBwcmVjaXBpdGHDp8OjbyDDqSBhcHJveGltYWRhbWVudGUgXCgweyx9MDEgXHRpbWVzIFxwYXJ0aWFsIEUgLyBccGFydGlhbCBcbG4oXHRleHR7cHJlY2lwfSsxKVwpLg0KDQpgYGB7ciBtMS1kZXJpdmF0aXZlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KcGxvdChtMV9nYW0sIHBhZ2VzPTQsIHNjaGVtZT0xLCBzaGFkZT1UUlVFLCBzZT1UUlVFKQ0KDQoNCmBgYA0KYGBge3J9DQpkX3ByZWNpcCA8LSBkZXJpdmF0aXZlcyhtMV9nYW0sIHRlcm0gPSAicyhsX3ByZWNpcCkiLCB0eXBlID0gImNlbnRyYWwiKQ0KZF9wcmVjaXAgPC0gZF9wcmVjaXAgJT4lDQogIG11dGF0ZShlZmZlY3RfcGVyXzFwY3QgPSAwLjAxICogLmRlcml2YXRpdmUpIA0KICAjc2VsZWN0KGRhdGEsIC5maXR0ZWQsIC5zZSwgZWZmZWN0X3Blcl8xcGN0LCBsb3dlciwgdXBwZXIpDQoNCnN1bW1hcnkoZF9wcmVjaXAkZWZmZWN0X3Blcl8xcGN0KQ0KYGBgDQpDb20gYmFzZSBub3MgZ3LDoWZpY29zIGRlIGVmZWl0b3MgcGFyY2lhaXMsIGRpYWduw7NzdGljb3MgZGUgcmVzw61kdW9zIGUgc3Vtw6FyaW8gZXN0YXTDrXN0aWNvIGRvIEdBTSAoZlJFTUwsIFLCsmFqPTAuNzQ7IGRldmlhbmNlIGV4cGxhaW5lZD03NCUpLCDDqSBwb3Nzw612ZWwgc2ludGV0aXphciBhIHF1YWxpZGFkZSBkbyBtb2RlbG8gZW0gdHLDqnMgcGFyw6FncmFmb3MgdMOpY25pY29zIGUgaW50ZXJwcmV0YXRpdm9zIOKAlCBhZGVxdWFkb3MgcGFyYSBhIHNlw6fDo28gZGUgcmVzdWx0YWRvcyBtZXRvZG9sw7NnaWNvczoNCk8gbW9kZWxvIGhpZHJvbMOzZ2ljbyDigJxjbGltYS0gZWFy4oCdIGFwcmVzZW50YSBkZXNlbXBlbmhvIHJvYnVzdG8gZSBjb2VyZW50ZSBjb20gYSBkaW7Dom1pY2EgZsOtc2ljYSBlc3BlcmFkYSBkbyBzaXN0ZW1hLiBPIGFqdXN0ZSBhbGNhbsOnYSBSwrIgYWp1c3RhZG8gZGUgMCw3NCBlIGV4cGxpY2EgNzQlIGRhIGRldmlhbmNlIHRvdGFsLCBpbmRpY2FuZG8gcXVlIGFzIHZhcmnDoXZlaXMgY2xpbcOhdGljYXMg4oCUIHByZWNpcGl0YcOnw6NvLCB0ZW1wZXJhdHVyYSwgdW1pZGFkZSBlIHZlbnRvIOKAlCBjb21iaW5hZGFzIMOgIHNhem9uYWxpZGFkZSBlIGFvcyBlZmVpdG9zIHJlZ2lvbmFpcywgY2FwdHVyYW0gYSBtYWlvciBwYXJ0ZSBkYSB2YXJpYWJpbGlkYWRlIGRhIGVuZXJnaWEgYXJtYXplbmFkYSAoRUFSKS4gQSBzaWduaWZpY8OibmNpYSBlc3RhdMOtc3RpY2EgZG9zIHNwbGluZXMgw6kgZWxldmFkYSAocCA8IDAuMDAxIHBhcmEgdG9kb3Mgb3MgdGVybW9zKSwgZSBhIHN1YXZpZGFkZSBkb3MgZWZlaXRvcyBtb3N0cmEgcGFkcsO1ZXMgcmVhbGlzdGFzOiBwcmVjaXBpdGHDp8OjbyBleGVyY2UgZWZlaXRvIHBvc2l0aXZvIG1vbm90w7RuaWNvIHNvYnJlIGEgRUFSOyB0ZW1wZXJhdHVyYSBleGliZSBmb3JtYXRvIGVtIGFyY28gKGVmZWl0byDDs3RpbW8gcHLDs3hpbW8gYSAyMCDCsEMsIHNlZ3VpZG8gZGUgcXVlZGEgbm9zIGV4dHJlbW9zKTsgdW1pZGFkZSBlIHZlbnRvIHTDqm0gZWZlaXRvcyBtb2RlcmFkb3MsIG1hcyBjb25zaXN0ZW50ZXMgY29tIG1lY2FuaXNtb3MgZGUgZXZhcG90cmFuc3BpcmHDp8OjbyBlIHJlY2FyZ2EuIE8gdGVybW8gc2F6b25hbCAoZG95KSByZXZlbGEgbyBjaWNsbyBoaWRyb2zDs2dpY28gYW51YWwgY2FyYWN0ZXLDrXN0aWNvIGRvcyBzdWJzaXN0ZW1hcyBicmFzaWxlaXJvcy4NCg0KT3MgZGlhZ27Ds3N0aWNvcyBkZSByZXPDrWR1b3MgY29uZmlybWFtIHF1ZSBvIG1vZGVsbyBjYXB0dXJhIGFkZXF1YWRhbWVudGUgYSB0ZW5kw6puY2lhIG3DqWRpYSBlIGEgc2F6b25hbGlkYWRlLCBtYXMgZXZpZGVuY2lhIGhldGVyb2dlbmVpZGFkZSBlc3RydXR1cmFsIGVudHJlIHJlZ2ltZXMgb3BlcmFjaW9uYWlzLiBPIGdyw6FmaWNvIGRlIHJlc8OtZHVvcyB2ZXJzdXMgdmFsb3JlcyBhanVzdGFkb3MgbW9zdHJhIHRyw6pzIGZhaXhhcyBkZW5zYXMsIGFzc29jaWFkYXMgYSBkaWZlcmVudGVzIG7DrXZlaXMgZGUgYXJtYXplbmFtZW50byAoYmFpeG8sIG3DqWRpbyBlIGFsdG8pLCBzdWdlcmluZG8gYSBwcmVzZW7Dp2EgZGUgbGltaXRlcyBmw61zaWNvcyBkZSBvcGVyYcOnw6NvIG91IHRyYW5zacOnw7VlcyBlbnRyZSBlc3TDoWdpb3MgZGUgZW5jaGltZW50byBlIGVzdmF6aWFtZW50byBkb3MgcmVzZXJ2YXTDs3Jpb3MuIE8gaGlzdG9ncmFtYSBkZSByZXPDrWR1b3Mgw6kgYXByb3hpbWFkYW1lbnRlIHNpbcOpdHJpY28gZSBjZW50cmFkbyBlbSB6ZXJvLCBlIG8gUVEtcGxvdCBpbmRpY2EgbGV2ZSBkZXN2aW8gbmFzIGNhdWRhcywgbyBxdWUgw6kgZXNwZXJhZG8gZW0gc8OpcmllcyBhbWJpZW50YWlzIGRlIGdyYW5kZSBhbXBsaXR1ZGUuIEEgaG9tb2dlbmVpZGFkZSBkZSB2YXJpw6JuY2lhIMOpIHNhdGlzZmF0w7NyaWEsIHNlbSBwYWRyw7VlcyBzaXN0ZW3DoXRpY29zIGRlIGF1dG9jb3JyZWxhw6fDo28sIHJlZm9yw6dhbmRvIGEgYWRlcXVhw6fDo28gZG8gdXNvIGRhIGZhbcOtbGlhIGdhdXNzaWFuYSBjb20gbGluayBpZGVudGlkYWRlLg0KDQpQb3IgZmltLCBvcyBlZmVpdG9zIGFsZWF0w7NyaW9zIHBvciByZXNlcnZhdMOzcmlvIG1vc3RyYXJhbSBhbXBsYSBkaXNwZXJzw6NvLCByZWZsZXRpbmRvIGRpZmVyZW7Dp2FzIGVzdHJ1dHVyYWlzIGRlIGNhcGFjaWRhZGUgZSBvcGVyYcOnw6NvIGVudHJlIHVzaW5hcy4gQSBzdWF2aWRhZGUgZG9zIHNwbGluZXMgZm9pIGFkZXF1YWRhIChrLWluZGV4ID4gMC42IHBhcmEgdG9kb3Mgb3MgdGVybW9zKSwgc2VtIGV2aWTDqm5jaWFzIGRlIHN1YmRpbWVuc2lvbmFtZW50byBkZSBjb21wbGV4aWRhZGUsIGUgYSBhdXPDqm5jaWEgZGUgY29uY29ycsOqbmNpYSAoY29uY3Vydml0eSkgcmVsZXZhbnRlIGluZGljYSBiYWl4YSBjb2xpbmVhcmlkYWRlIGVudHJlIG9zIGVmZWl0b3MgY2xpbcOhdGljb3MuIEVtIGNvbmp1bnRvLCBlc3NlcyByZXN1bHRhZG9zIHN1c3RlbnRhbSBhIHBsYXVzaWJpbGlkYWRlIGVzdGF0w61zdGljYSBlIGbDrXNpY2EgZG8gbW9kZWxvIGNvbW8gYmFzZWxpbmUgY2xpbcOhdGljbyBhdWRpdMOhdmVsLiBBcyBwcmluY2lwYWlzIGxpbWl0YcOnw7VlcyByZXNpZGVtIG5hIHN1YXZpemHDp8OjbyBkZSBleHRyZW1vcyBoaWRyb2zDs2dpY29zIGUgbmEgbGV2ZSBuw6NvLW5vcm1hbGlkYWRlIGRvcyByZXPDrWR1b3MsIGFzcGVjdG9zIGNvbXVucyBlbSBtb2RlbG9zIGFncmVnYWRvcyBkZSBncmFuZGVzIHNpc3RlbWFzIGUgcXVlIHBvZGVtIHNlciB0cmF0YWRvcyBuYXMgZXRhcGFzIHN1YnNlcXVlbnRlcyBjb20gY29udHJhZmFjdHVhaXMgZSBwcm9wYWdhw6fDo28gZGUgaW5jZXJ0ZXphLg0KDQpPcyAqKmVmZWl0b3MgcGFyY2lhaXMqKiBlc3RpbWFkb3MgcGVsbyBtb2RlbG8gY29uZmlybWFtIHBhZHLDtWVzIGNsaW3DoXRpY29zIHBsYXVzw612ZWlzIGUgZmlzaWNhbWVudGUgY29lcmVudGVzLiBBIHByZWNpcGl0YcOnw6NvIGFwcmVzZW50YSB1bSBlZmVpdG8gbW9ub3RvbmljYW1lbnRlIGNyZXNjZW50ZSBzb2JyZSBhIGVuZXJnaWEgYXJtYXplbmFkYSwgaW5kaWNhbmRvIHF1ZSBhdW1lbnRvcyBhY3VtdWxhZG9zIGRlIGNodXZhIHTDqm0gaW1wYWN0byBwb3NpdGl2byBxdWFzZSBsaW5lYXIgYXTDqSBvIGxpbWl0ZSBzdXBlcmlvciBvYnNlcnZhZG8sIHNlbSBzaW5haXMgZGUgc2F0dXJhw6fDo28g4oCUIHVtIHJlc3VsdGFkbyBjb21wYXTDrXZlbCBjb20gYSBwcmVkb21pbsOibmNpYSBkZSBncmFuZGVzIHJlc2VydmF0w7NyaW9zIGRlIHJlZ3VsYXJpemHDp8OjbyBubyBzaXN0ZW1hLiBBIHRlbXBlcmF0dXJhLCBwb3Igc3VhIHZleiwgZXhpYmUgdW1hIHJlbGHDp8OjbyBlbSBmb3JtYSBkZSBhcmNvOiBvcyBuw612ZWlzIGludGVybWVkacOhcmlvcyAoZW0gdG9ybm8gZGUgMjAgwrBDKSBlc3TDo28gYXNzb2NpYWRvcyBhbyBtYWlvciBhcm1hemVuYW1lbnRvLCBlbnF1YW50byB0ZW1wZXJhdHVyYXMgZXh0cmVtYXMgcmVkdXplbSBvIHNhbGRvIGVuZXJnw6l0aWNvLCByZWZsZXRpbmRvIG8gcGFwZWwgZGEgZXZhcG9yYcOnw6NvIGUgZGEgZWZpY2nDqm5jaWEgZG8gY2ljbG8gaGlkcm9sw7NnaWNvLiBBIHVtaWRhZGUgbW9zdHJhIGxldmUgZWZlaXRvIHBvc2l0aXZvIGF0w6kgY2VydG8gcG9udG8sIHNlZ3VpZG8gZGUgcmV2ZXJzw6NvLCBzdWdlcmluZG8gaW50ZXJhw6fDo28gY29tIHJlZ2ltZXMgZGUgY2h1dmEgcGVyc2lzdGVudGUsIGVucXVhbnRvIGEgdmVsb2NpZGFkZSBkbyB2ZW50byBhcHJlc2VudGEgdW0gZWZlaXRvIG5lZ2F0aXZvIHN1YXZlLCBwb3NzaXZlbG1lbnRlIGxpZ2FkbyDDoCBtYWlvciBwZXJkYSBwb3IgZXZhcG90cmFuc3BpcmHDp8OjbyBlIGFvIHRyYW5zcG9ydGUgZGUgbWFzc2FzIHNlY2FzLiBPIGNvbXBvbmVudGUgc2F6b25hbCAoZG95KSByZXZlbGEgbyBjaWNsbyBhbnVhbCB0w61waWNvIGRvIHJlZ2ltZSBwbHV2aWFsIGJyYXNpbGVpcm8sIGNvbSBwaWNvcyBlbnRyZSBvcyBkaWFzIDEwMOKAkzE1MCAob3V0b25vKSBlIG3DrW5pbW9zIHByw7N4aW1vcyBhbyBmaW5hbCBkbyBhbm8uIFBvciBmaW0sIG9zIGVmZWl0b3MgYWxlYXTDs3Jpb3MgcG9yIHJlc2VydmF0w7NyaW8gbW9zdHJhbSBoZXRlcm9nZW5laWRhZGUgZXhwcmVzc2l2YSwgaW5kaWNhbmRvIHF1ZSBkaWZlcmVuw6dhcyBlc3RydXR1cmFpcyBkZSBjYXBhY2lkYWRlIGUgbG9jYWxpemHDp8OjbyBjb25kaWNpb25hbSBhIHJlc3Bvc3RhIGNsaW3DoXRpY2Eg4oCUIHVtIGFjaGFkbyBxdWUgcmVmb3LDp2EgYSBuZWNlc3NpZGFkZSBkZSBhYm9yZGFnZW5zIHJlZ2lvbmFsaXphZGFzIG5hcyBldGFwYXMgc2VndWludGVzIGRhIG1vZGVsYWdlbS4NCg0KDQoNCmBgYHtyfQ0KI3NhdmVSRFMobTFfZ2FtLCAibTFfZ2FtLnJkcyIpDQojcmVhZFJEUygibTFfZ2FtLnJkcyIpIC0+IG0xX2dhbQ0KDQpgYGANCg0KIyMjIyBQcmVkacOnw7VlcyBmYWN0dWFsIHZzLiBjb250cmFmYWN0dWFsIChiYXNlbGluZSAyMDAx4oCTMjAwNSkNCkNvbnN0cnXDrW1vcyBvIGNvbnRyYWZhY3R1YWwgY2xpbcOhdGljbyBmaXhhbmRvIGNsaW1hIG5vICoqbcOpZGlvIG1lbnNhbCAyMDAx4oCTMjAwNSoqIHBvciByZXNlcnZhdMOzcmlvIChvdSBwb3Igc3Vic2lzdGVtYSwgY2FzbyBwcmVmaXJhKSBlIG1hbnRlbmRvIG9zIGRlbWFpcyBjb250cm9sZXMgb2JzZXJ2YWRvcy4NCg0KDQoNCmBgYHtyfQ0KIyBCYXNlbGluZSBjbGltw6F0aWNvIHBvciByZXNlcnZhdMOzcmlvIGUgbcOqcyAoMjAwMeKAkzIwMDUpOyBhanVzdGUgc2UgcHJlZmVyaXIgcG9yIHN1YnNpc3RlbWENCmNsaW1fYmFzZWxpbmUgPC0gcmVzZXJ2ICU+JQ0KICBmaWx0ZXIoeWVhcihkYXRlKSA+PSAyMDAxLCB5ZWFyKGRhdGUpIDw9IDIwMDUpICU+JQ0KICBncm91cF9ieShpZF9yZXNlcnZhdG9yaW8ueCwgZG95KSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGxfcHJlY2lwX2JsID0gbWVhbihsX3ByZWNpcCwgbmEucm0gPSBUUlVFKSwNCiAgICBsX3RlbXBfYmwgICA9IG1lYW4obF90ZW1wLCAgIG5hLnJtID0gVFJVRSksDQogICAgbF9odW1pZGl0eV9ibCA9IG1lYW4obF9odW1pZGl0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBsX3dpbmRfc3BlZWRfYmwgICAgID0gbWVhbihsX3dpbmRfc3BlZWQsIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQoNCiMgbmV3ZGF0YSBmYWN0dWFsIChvYnNlcnZhZG8pIGUgY29udHJhZmFjdHVhbCAoY2xpbWEgZml4byBubyBiYXNlbGluZSkNCm5kX29icyA8LSByZXNlcnYgIyU+JSB1bmdyb3VwKCkgJT4lIA0KICNzZWxlY3QoaWRfcmVzZXJ2YXRvcmlvLngsIG5vbV9zdWJzaXN0ZW1hLngsIGRhdGUsIGRveSwgbW9udGgsDQogICMgICAgICAgbF9wcmVjaXAsIGxfdGVtcCwgbF9odW1pZGl0eSwgbF93aW5kX3NwZWVkKQ0KDQpuZF9jZiA8LSByZXNlcnYgJT4lDQogIGxlZnRfam9pbihjbGltX2Jhc2VsaW5lLCBieSA9IGMoImlkX3Jlc2VydmF0b3Jpby54IiwiZG95IikpICU+JQ0KICBtdXRhdGUoDQogICAgbF9wcmVjaXAgPSBsX3ByZWNpcF9ibCwNCiAgICBsX3RlbXAgICA9IGxfdGVtcF9ibCwNCiAgICBsX2h1bWlkaXR5ID0gbF9odW1pZGl0eV9ibCwNCiAgICBsX3dpbmRfc3BlZWQ9IGxfd2luZF9zcGVlZF9ibA0KICApICMlPiUNCiAgI3NlbGVjdChuYW1lcyhyZXNlcnYpKQ0KDQojIFByZWRpw6fDtWVzIG5vIG7DrXZlbCAoTVfCt23DqnMpDQpyZXNlcnYkZWFyX2hhdF9vYnMgPC0gcHJlZGljdChtMV9nYW0sIG5ld2RhdGEgPSByZXNlcnYsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcmVzZXJ2JGVhcl9oYXRfY2YgIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfY2YsICB0eXBlID0gInJlc3BvbnNlIikNCg0KIyBQZW5hbGlkYWRlIGNsaW3DoXRpY2Egbm8gRUFSIChwb250dWFsKQ0KcmVzZXJ2JGRlbHRhX2Vhcl9oYXQgPC0gcmVzZXJ2JGVhcl9oYXRfb2JzIC0gcmVzZXJ2JGVhcl9oYXRfY2YNCmRlbHRhX2Vhcl9oYXQgPC0gcmVzZXJ2JGVhcl9oYXRfb2JzIC0gcmVzZXJ2JGVhcl9oYXRfY2YNCmBgYA0KDQojIyAzLjEuNSBQcm9wYWdhw6fDo28gZGUgSW5jZXJ0ZXphDQpQYXJhIHF1YW50aWZpY2FyIGEgaW5jZXJ0ZXphIGFzc29jaWFkYSDDoHMgZXN0aW1hdGl2YXMgZGUgcGVuYWxpZGFkZSBjbGltw6F0aWNhICjOlEVBUiksIGZvcmFtIGFwbGljYWRvcyBkb2lzIG3DqXRvZG9zIGNvbXBsZW1lbnRhcmVzOiBvIERlbHRhIE1ldGhvZCBhbmFsw610aWNvIGUgYSBTaW11bGHDp8OjbyBQYXJhbcOpdHJpY2EgTXVsdGl2YXJpYWRhLiBPIHByaW1laXJvIGZvcm5lY2UgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIHBvbnR1YWlzIGJhc2VhZG9zIG5hIG1hdHJpeiBkZSBjb3ZhcmnDom5jaWEgZG9zIGNvZWZpY2llbnRlcyBkbyBtb2RlbG87IG8gc2VndW5kbyBwZXJtaXRlIHByb3BhZ2FyIGludGVncmFsbWVudGUgYSBpbmNlcnRlemEgcGFyYW3DqXRyaWNhIGFvIGxvbmdvIGRhIGNhZGVpYSBkZSBlc3RpbWHDp8OjbywgZ2VyYW5kbyBkaXN0cmlidWnDp8O1ZXMgZW1ww61yaWNhcyBwYXJhIGNhZGEgc3Vic2lzdGVtYSBlIGFuby4NCg0KTm8gRGVsdGEgTWV0aG9kLCBhIGluY2VydGV6YSDDqSBjYWxjdWxhZGEgcGVsYSBtYXRyaXogZGUgZGVzZW5obyBkbyBtb2RlbG8gKCAkIFhfe29ic30gLSBYX3tjZn0kKSwgbXVsdGlwbGljYWRhIHBlbGEgbWF0cml6IGRlIGNvdmFyacOibmNpYSBkb3MgcGFyw6JtZXRyb3MgKCRWX/Cdm70kKSwgY29uZm9ybWUgJFZhcijOlEUpPSBYKFZf8J2bvSlYJyQuIEVzc2EgYWJvcmRhZ2VtIGZvcm5lY2UgZXN0aW1hdGl2YXMgY29uc2lzdGVudGVzIHBhcmEgaW50ZXJ2YWxvcyBkZSA5NSUgZGUgY29uZmlhbsOnYSBlIHBlcm1pdGUgYWdyZWdhciByZXN1bHRhZG9zIHByZXNlcnZhbmRvIGFzIGNvdmFyacOibmNpYXMgZW50cmUgb2JzZXJ2YcOnw7Vlcy4gTyBtw6l0b2RvIMOpIGNvbXB1dGFjaW9uYWxtZW50ZSBlZmljaWVudGUgZSDDunRpbCBwYXJhIGdlcmFyIGludGVydmFsb3MgYW5hbMOtdGljb3MgY29tcGFyw6F2ZWlzIGVudHJlIHN1YnNpc3RlbWFzLg0KDQpBIFNpbXVsYcOnw6NvIFBhcmFtw6l0cmljYSBhbXBsaWEgZXNzYSBhYm9yZGFnZW0gYW8gYW1vc3RyYXIgbWlsaGFyZXMgZGUgdmV0b3JlcyBkZSBjb2VmaWNpZW50ZXMgKA0KJPCdm71eeyjwnZGgKX3iiLzwnZGBKFxoYXR7XGJldGF9LPCdkYnwnZu9KSQgZSByZWNhbGN1bGFyICTOlCDwnZC48J2QtPCdkYVeeyjwnZGgKX0kIHBhcmEgY2FkYSBhbW9zdHJhLiBBIGFncmVnYcOnw6NvIGRvcyByZXN1bHRhZG9zIHBvciBzdWJzaXN0ZW1hIGUgYW5vIGZvcm5lY2UgZGlzdHJpYnVpw6fDtWVzIGVtcMOtcmljYXMgZGEgcGVuYWxpZGFkZSBjbGltw6F0aWNhLCBleHByZXNzYXMgcG9yIGZhbiBjaGFydHMgKEZpZ3VyYSBhYmFpeG8pLiBPcyByZXN1bHRhZG9zIGluZGljYW0gdGVuZMOqbmNpYSBuZWdhdGl2YSBjcmVzY2VudGUgZGEgZW5lcmdpYSBhcm1hemVuYWRhIGFqdXN0YWRhIGFvIGNsaW1hIG3DqWRpbywgY29tIGZvcnRlIHF1ZWRhIGFww7NzIDIwMTAgZSBwaWNvcyBkZSBpbmNlcnRlemEgZW0gMjAxNOKAkzIwMTYuIEFzIHJlZ2nDtWVzIFN1ZGVzdGUgZSBTdWwgY29uY2VudHJhbSBvcyBtYWlvcmVzIGTDqWZpY2l0cyBtw6lkaW9zIChhdMOpIOKAkzUgZSDigJMxIG1pbGjDtWVzIGRlIE1Xwrdtw6pzLCByZXNwZWN0aXZhbWVudGUpLCBlbnF1YW50byBOb3JkZXN0ZSBlIE5vcnRlIGFwcmVzZW50YW0gcGVuYWxpZGFkZXMgbWVub3JlcywgcG9yw6ltIGNvbSBhdW1lbnRvIHByb2dyZXNzaXZvIGFvIGZpbmFsIGRhIHPDqXJpZS4gRXNzYSBjb25zaXN0w6puY2lhIGVudHJlIG9zIGRvaXMgbcOpdG9kb3MgY29uZmlybWEgYSByb2J1c3RleiBlc3RhdMOtc3RpY2EgZG8gbW9kZWxvIGUgZXN0YWJlbGVjZSB1bWEgYmFzZSBjb25macOhdmVsIHBhcmEgYSBldGFwYSBzZWd1aW50ZSBkZSBwcm9wYWdhw6fDo28gZGUgaW5jZXJ0ZXphIG5hIGdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhLg0KDQoNCg0KIyMjIyBJbmNlcnRlemEgKG3DqXRvZG8gNDogKipEZWx0YSBtZXRob2QqKiBhbmFsw610aWNvKQ0KRXN0aW1hbW9zIElDcyBwYXJhIFwoXERlbHRhIEVBUlwpIHZpYSBtYXRyaXogZGUgZGVzZW5obyBubyAqKmxpbmsqKiAoYXF1aSwgaWRlbnRpdHkg4oeSIGrDoSDDqSBuw612ZWwpLiBBZ3JlZ2HDp8O1ZXMgcG9yIGFuby9zdWJzaXN0ZW1hIGRldmVtIHByZXNlcnZhciBhIGNvdmFyacOibmNpYS4NCmBgYHtyIG0xLWRlbHRhLW1ldGhvZCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NClZwICAgICAgPC0gdmNvdihtMV9nYW0pICAjIGNvdmFyacOibmNpYSBkb3MgY29lZmljaWVudGVzDQpYX29icyAgIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfb2JzLCB0eXBlID0gImxwbWF0cml4IikNClhfY2YgICAgPC0gcHJlZGljdChtMV9nYW0sIG5ld2RhdGEgPSBuZF9jZiwgIHR5cGUgPSAibHBtYXRyaXgiKQ0KWF9kaWZmICA8LSBYX29icyAtIFhfY2YNCg0KIyBFUCBwb3Igb2JzZXJ2YcOnw6NvDQp2YXJfZGVsdGEgPC0gcm93U3VtcygoWF9kaWZmICUqJSBWcCkgKiBYX2RpZmYpDQpzZV9kZWx0YSAgPC0gc3FydChwbWF4KHZhcl9kZWx0YSwgMCkpDQp6ICAgICAgICAgPC0gcW5vcm0oMC45NzUpDQoNCmRlbHRhX2x3ciA8LSByZXNlcnYkZGVsdGFfZWFyX2hhdCAtIHogKiBzZV9kZWx0YQ0KZGVsdGFfdXByIDwtIHJlc2VydiRkZWx0YV9lYXJfaGF0ICsgeiAqIHNlX2RlbHRhDQpyZXNlcnYkZGVsdGFfZWFyX3VwcjwtZGVsdGFfdXByDQpyZXNlcnYkZGVsdGFfZWFyX2x3cjwtZGVsdGFfbHdyDQptMV9kZWx0YSA8LSBuZF9vYnMgJT4lDQogIHRyYW5zbXV0ZSgNCiAgICBkYXRlLCBub21fc3Vic2lzdGVtYS54LA0KICAgIGRlbHRhX2hhdCA9IGRlbHRhX2Vhcl9oYXQsDQogICAgZGVsdGFfc2UgID0gc2VfZGVsdGEsDQogICAgZGVsdGFfbHdyID0gZGVsdGFfbHdyLA0KICAgIGRlbHRhX3VwciA9IGRlbHRhX3Vwcg0KICApDQoNCiMgQWdyZWdhciBwb3IgYW5vL3N1YnNpc3RlbWEgcHJlc2VydmFuZG8gY292YXJpw6JuY2lhIChjb21iaW5hw6fDo28gbGluZWFyKQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KZHQgPC0gYXMuZGF0YS50YWJsZShuZF9vYnMpWywgLihkYXRlLCBub21fc3Vic2lzdGVtYS54KV0NCmR0WywgeWVhciA6PSB5ZWFyKGRhdGUpXQ0KDQojIFZldG9yIHNfZyA9IHNvbWEgZGFzIGxpbmhhcyBkZSBYX2RpZmYgbm8gZ3J1cG8gKGFubywgc3Vic2lzdGVtYSkNCmdyb3VwcyA8LSB1bmlxdWUoZHRbLCAuKHllYXIsIG5vbV9zdWJzaXN0ZW1hLngpXSkNClMgPC0gbGFwcGx5KDE6bnJvdyhncm91cHMpLCBmdW5jdGlvbihnKXsNCiAgaWR4IDwtIHdoaWNoKGR0JHllYXIgPT0gZ3JvdXBzJHllYXJbZ10gJiBkdCRub21fc3Vic2lzdGVtYS54ID09IGdyb3VwcyRub21fc3Vic2lzdGVtYS54W2ddKQ0KICBjb2xTdW1zKFhfZGlmZltpZHgsICwgZHJvcCA9IEZBTFNFXSkNCn0pDQoNCmFnZ19tZWFuIDwtIHNhcHBseSgxOm5yb3coZ3JvdXBzKSwgZnVuY3Rpb24oZyl7DQogIHN1bShyZXNlcnYkZGVsdGFfZWFyX2hhdFtkdCR5ZWFyID09IGdyb3VwcyR5ZWFyW2ddICYgZHQkbm9tX3N1YnNpc3RlbWEueCA9PSBncm91cHMkbm9tX3N1YnNpc3RlbWEueFtnXV0sIG5hLnJtID0gVFJVRSkNCn0pDQphZ2dfdmFyICA8LSBzYXBwbHkoUywgZnVuY3Rpb24oc3YpIGFzLm51bWVyaWModChzdikgJSolIFZwICUqJSBzdikpDQphZ2dfc2UgICA8LSBzcXJ0KHBtYXgoYWdnX3ZhciwgMCkpDQoNCm0xX2RlbHRhX2FnZyA8LSBjYmluZChncm91cHMsDQogIGRlbHRhX21lYW4gPSBhZ2dfbWVhbiwNCiAgZGVsdGFfbHdyICA9IGFnZ19tZWFuIC0geiAqIGFnZ19zZSwNCiAgZGVsdGFfdXByICA9IGFnZ19tZWFuICsgeiAqIGFnZ19zZQ0KKQ0KYGBgDQoNCiMjIyMgSW5jZXJ0ZXphIChtw6l0b2RvIDE6ICoqU2ltdWxhw6fDo28gcGFyYW3DqXRyaWNhKiogZW5jYWRlw6F2ZWwpDQpBbW9zdHJhbW9zIG9zIGNvZWZpY2llbnRlcyBkYSBkaXN0cmlidWnDp8OjbyBub3JtYWwgbXVsdGl2YXJpYWRhIGUgcmVjYWxjdWxhbW9zIFwoXERlbHRhIEVBUl57KHMpfVwpLiBFc3NlIG9iamV0byBzZXLDoSBhICoqZW50cmFkYSBwcm9iYWJpbMOtc3RpY2EqKiBwYXJhIG8gR0FNIDEuDQoNCmBgYHtyIG0xLW1vbnRlY2FybG8sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KE1BU1MpDQpuc2ltIDwtIDUwMA0Kc2V0LnNlZWQoMjAyNTEwMTApDQoNCmJldGFfZHJhd3MgPC0gTUFTUzo6bXZybm9ybShuID0gbnNpbSwgbXUgPSBjb2VmKG0xX2dhbSksIFNpZ21hID0gVnApDQoNCiMgUHLDqS1jw6FsY3VsbyBwYXJhIGVmaWNpw6puY2lhDQpEIDwtIFhfZGlmZiAgICAgICAgICAgICAjIE4geCBwDQojIM6URUFSIHBvciBzaW11bGHDp8OjbzogY2FkYSBjb2x1bmEgw6kgdW1hIHNpbSwgY2FkYSBsaW5oYSB1bWEgb2JzZXJ2YcOnw6NvDQpkZWx0YV9zaW1zIDwtIEQgJSolIHQoYmV0YV9kcmF3cykgICAjIChOIHggbnNpbSkNCg0KIyBBZ3JlZ2FyIHBvciBhbm8vc3Vic2lzdGVtYSBlbSBjYWRhIHNpbQ0KZHQgPC0gYXMuZGF0YS50YWJsZShuZF9vYnMpWywgLihkYXRlLCB5ZWFyID0geWVhcihkYXRlKSwgbm9tX3N1YnNpc3RlbWEueCldDQoNCmR0JGdpZCA8LSAuR1JQOyBkdFssIGdpZCA6PSAuR1JQLCBieSA9IC4oeWVhciwgbm9tX3N1YnNpc3RlbWEueCldDQpHIDwtIG1heChkdCRnaWQpDQoNCmFnZ19tYXQgPC0gbWF0cml4KE5BX3JlYWxfLCBucm93ID0gRywgbmNvbCA9IG5zaW0pDQpmb3IgKGcgaW4gMTpHKSB7DQogIGlkeCA8LSB3aGljaChkdCRnaWQgPT0gZykNCiAgYWdnX21hdFtnLCBdIDwtIGNvbFN1bXMoZGVsdGFfc2ltc1tpZHgsICwgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKQ0KfQ0KDQptMV9zaW1fYWdnIDwtIGNiaW5kKGdyb3VwcywNCiAgbWVhbiA9IHJvd01lYW5zKGFnZ19tYXQpLA0KICBsd3IgID0gYXBwbHkoYWdnX21hdCwgMSwgcXVhbnRpbGUsIDAuMDI1KSwNCiAgdXByICA9IGFwcGx5KGFnZ19tYXQsIDEsIHF1YW50aWxlLCAwLjk3NSksDQogIHNkICA9IGFwcGx5KGFnZ19tYXQsIDEsIHNkKQ0KDQopDQoNCmBgYA0KYGBge3J9DQptMV9zaW1fYWdnICU+JSBtdXRhdGUoc2RfdXA9bWVhbit6KnNkLCBzZF9sd3I9bWVhbi16KnNkKS0+bTFfc2ltX2FnZw0KYGBgDQoNCiMjIyMgVmlzdWFsaXphw6fDo28gcsOhcGlkYSAocHVibGljYcOnw6NvKQ0KUmliYm9ucyAoRGVsdGEpIGUgZmFuIGNoYXJ0cyAoTUMpIHBhZHJvbml6YWRvcy4NCg0KDQpgYGB7ciBtMS1wbG90cywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgUmliYm9uIChEZWx0YSkNCm0xX2RlbHRhX2FnZyAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGRlbHRhX21lYW4vMTAwMCkpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBkZWx0YV9sd3IvMTAwMCwgeW1heCA9IGRlbHRhX3Vwci8xMDAwKSwgYWxwaGEgPSAuMjUsIGZpbGwgPSAiZmlyZWJyaWNrIikgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnModGl0bGUgPSAiQ2xpbWF0ZSBwZW5hbHR5IG9uIHN0b3JlZCBlbmVyZ3kgKM6URUFSKSDigJQgRGVsdGEgbWV0aG9kIiwNCiAgICAgICB5ID0gIs6URUFSIChHV8K3bW9udGgpIiwgeCA9ICJZZWFyIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBGYW4gY2hhcnQgKE1DKQ0KbTFfc2ltX2FnZyAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IG1lYW4vMTAwMCkpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBsd3IvMTAwMCwgeW1heCA9IHVwci8xMDAwKSwgYWxwaGEgPSAuMjUsIGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IDAsIHltYXggPSB1cHIvMTAwMCksIGZpbGwgPSAicmVkMyIsIGFscGhhID0gMC4xKSArDQoNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKHRpdGxlID0gIkNsaW1hdGUgcGVuYWx0eSBvbiBzdG9yZWQgZW5lcmd5ICjOlEVBUikg4oCUIFBhcmFtZXRyaWMgc2ltdWxhdGlvbiBxdWFydGlsZSIsDQogICAgICAgeSA9ICLOlEVBUiAoR1fCt21vbnRoKSIsIHggPSAiWWVhciIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQptMV9zaW1fYWdnICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbWVhbi8xMDAwKSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IHNkX2x3ci8xMDAwLCB5bWF4ID0gc2RfdXAvMTAwMCksIGFscGhhID0gLjI1LCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSAwLCB5bWF4ID0gc2RfdXAvMTAwMCksIGZpbGwgPSAicmVkMyIsIGFscGhhID0gMC4xKSArDQoNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH5ub21fc3Vic2lzdGVtYS54LCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKHRpdGxlID0gIkNsaW1hdGUgcGVuYWx0eSBvbiBzdG9yZWQgZW5lcmd5ICjOlEVBUikg4oCUIFBhcmFtZXRyaWMgc2ltdWxhdGlvbiBzZCIsDQogICAgICAgeSA9ICLOlEVBUiAoR1fCt21vbnRoKSIsIHggPSAiWWVhciIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KUGVuYWxpZGFkZSBjbGltw6F0aWNhIGFncmVnYWRhIGUgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhDQoNCmBgYHtyfQ0KbTFfc3VtbWFyeSA8LSBtMV9zaW1fYWdnICU+JQ0KICBncm91cF9ieShub21fc3Vic2lzdGVtYS54KSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fcGVuYWx0eSA9IG1lYW4obWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgICBsd3JfOTUgPSBtZWFuKGx3ciwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHJfOTUgPSBtZWFuKHVwciwgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9wZW5hbHR5ID0gc2QobWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KIyBDb252ZXJ0ZW5kbyBwYXJhIEdXaC9hbm8gcGFyYSBpbnRlcnByZXRhw6fDo28NCm0xX3N1bW1hcnkgPC0gbTFfc3VtbWFyeSAlPiUNCiAgbXV0YXRlKA0KICAgIG1lYW5fR1doID0gbWVhbl9wZW5hbHR5IC8gMTAwMCwNCiAgICBsd3JfR1doICA9IG1lYW5fcGVuYWx0eS16KnNkX3BlbmFsdHkgLyAxMDAwLA0KICAgIHVwcl9HV2ggID0gbWVhbl9wZW5hbHR5K3oqc2RfcGVuYWx0eSAvIDEwMDAsDQogICkgIyU+JSBzZWxlY3QoLW1lYW5fcGVuYWx0eSwgLWx3cl85NSwgLXVwcl85NSkNCg0KIyBUYWJlbGEgZm9ybWF0YWRhIChwdWJsaWNhw6fDo28pDQpsaWJyYXJ5KGd0KQ0KbTFfc3VtbWFyeVssYygibm9tX3N1YnNpc3RlbWEueCIsIm1lYW5fR1doIiwibHdyX0dXaCIsICJ1cHJfR1doIildICU+JSBqYW5pdG9yOjphZG9ybl90b3RhbHMoKSAlPiUgDQogIGd0KCkgJT4lDQogIGZtdF9udW1iZXIoY29sdW1ucyA9IDI6NCwgZGVjaW1hbHMgPSAxKSAlPiUNCiAgY29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYS54ID0gIlN1YnN5c3RlbSIsDQogICAgbWVhbl9HV2ggPSAiTWVhbiDOlEVBUiAoR1doKSIsDQogICAgbHdyX0dXaCAgPSAiTG93ZXIgOTUlIiwNCiAgICB1cHJfR1doICA9ICJVcHBlciA5NSUiLA0KICApICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gbWQoIioqQWdncmVnYXRlIGNsaW1hdGUgcGVuYWx0eSBvbiBzdG9yZWQgZW5lcmd5ICgyMDAx4oCTMjAxOCkqKiIpLA0KICAgIHN1YnRpdGxlID0gIlNpbXVsYXRlZCBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgcGVyIHN1YnN5c3RlbSINCiAgKQ0KYGBgDQpBIFRhYmVsYSBhcHJlc2VudGEgYSAqKnBlbmFsaWRhZGUgY2xpbcOhdGljYSBtw6lkaWEgc29icmUgYSBlbmVyZ2lhIGFybWF6ZW5hZGEgKM6URUFSKSoqIG5vIHBlcsOtb2RvIDIwMDHigJMyMDE4LCBhZ3JlZ2FkYSBwb3Igc3Vic2lzdGVtYS4gT3MgdmFsb3JlcyBmb3JhbSBlc3RpbWFkb3MgYSBwYXJ0aXIgZGFzIGRpc3RyaWJ1acOnw7VlcyBvYnRpZGFzIHZpYSBzaW11bGHDp8OjbyBwYXJhbcOpdHJpY2EgZGUgMi4wMDAgc29ydGVpb3MgZGEgbWF0cml6IGRlIGNvdmFyacOibmNpYSBkb3MgY29lZmljaWVudGVzIGRvIG1vZGVsbyBoaWRyb2zDs2dpY28uIEFzIHBlbmFsaWRhZGVzIG3DqWRpYXMgZm9yYW0gZXhwcmVzc2FzIGVtIGdpZ2F3YXR0cy1tw6pzIChHV2jCt21vbnRoKSwgY29tIGludGVydmFsb3MgZGUgY29uZmlhbsOnYSBkZSA5NSUgY29tIHVtIHRvdGFsIGRlICoq4oCTMSw2MDYuMyAoSUM5NSU6IOKIkjEsNzQ2LjI74oiSMSw0NzAuMikgIGRlIEdXaC4NCg0KT3MgcmVzdWx0YWRvcyBpbmRpY2FtIHF1ZSBvICoqc3Vic2lzdGVtYSBTdWRlc3RlKiogY29uY2VudHJhIG8gbWFpb3IgZMOpZmljaXQgbcOpZGlvIGRlIGFybWF6ZW5hbWVudG8sIGVzdGltYWRvIGVtIGFwcm94aW1hZGFtZW50ZSAqKuKIkjEsMTc4LjQJIChJQzk1JTriiJIxLDI2Mi40O+KIkjEsMDk3LjQpICBkZSBHV2jCt23DqnMqKiwgcmVmbGV0aW5kbyBzdWEgcHJlZG9taW7Dom5jaWEgbm8gc2lzdGVtYSBpbnRlcmxpZ2FkbyBlIHN1YSBtYWlvciBleHBvc2nDp8OjbyBhIGFub21hbGlhcyBkZSBwcmVjaXBpdGHDp8Ojby4gTyAqKlN1bCoqIGFwcmVzZW50YSBwZW5hbGlkYWRlIGludGVybWVkacOhcmlhIChYWFhYWFhYWFhYWFgpLCBtYXMgY29tIG1haW9yIHZhcmlhYmlsaWRhZGUgaW50ZXJhbnVhbCwgY29tcGF0w612ZWwgY29tIHNldSByZWdpbWUgcGx1dmlvbcOpdHJpY28gbWFpcyBpcnJlZ3VsYXIuIE5vICoqTm9yZGVzdGUqKiwgYXMgcGVyZGFzIG3DqWRpYXMgc8OjbyBtZW5vcmVzIChYWFhYWFhYWFhYWFhYWCksIGVtYm9yYSBjb20gdGVuZMOqbmNpYSBuZWdhdGl2YSBhY2VudHVhZGEgYXDDs3MgMjAxMC4gSsOhIG8gKipOb3J0ZSoqIGFwcmVzZW50YSB2YWxvcmVzIHByw7N4aW1vcyBkZSB6ZXJvLCBjb20gaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIHF1ZSBpbmNsdWVtIGEgbnVsaWRhZGUsIHN1Z2VyaW5kbyBhdXPDqm5jaWEgZGUgcGVuYWxpZGFkZSBsw61xdWlkYSBzaWduaWZpY2F0aXZhIG5vIHBlcsOtb2RvIGFuYWxpc2Fkby4NCg0KRXNzZXMgcmVzdWx0YWRvcyBjb3Jyb2JvcmFtIGEgaGlww7N0ZXNlIGRlIHF1ZSBhICoqcGVuYWxpZGFkZSBjbGltw6F0aWNhIHNvYnJlIG8gYXJtYXplbmFtZW50byBow61kcmljbyDDqSBjb25jZW50cmFkYSBlIGVzdHJ1dHVyYWxtZW50ZSBhc3NpbcOpdHJpY2EqKiwgYWZldGFuZG8gY29tIG1haW9yIGludGVuc2lkYWRlIG9zIHN1YnNpc3RlbWFzIFN1ZGVzdGUgZSBTdWwg4oCUIGp1c3RhbWVudGUgYXF1ZWxlcyBjb20gbWFpb3IgcGFwZWwgZGUgcmVndWxhw6fDo28gZSBzdXBvcnRlIGVuZXJnw6l0aWNvIHBhcmEgbyByZXN0YW50ZSBkbyBwYcOtcy4gRXNzYSBoZXRlcm9nZW5laWRhZGUgZXNwYWNpYWwgZm9ybmVjZSBvIGVsbyBlbXDDrXJpY28gcGFyYSBhIHByw7N4aW1hIGV0YXBhIGRhIG1vZGVsYWdlbSwgZW0gcXVlIGFzIHZhcmlhw6fDtWVzIHNpbXVsYWRhcyBkZSBcKCBcRGVsdGEgRUFSIFwpIHNlcsOjbyBwcm9wYWdhZGFzIMOgIGdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhIChHQU0gMSksIMOgIGdlcmHDp8OjbyB0w6lybWljYSAoR0FNIDIpIGUsIHBvciBmaW0sIGFvIHByZcOnbyBkZSBjdXJ0byBwcmF6byAoR0FNIDMpLg0KDQoNCjMuMiBNb2RlbG8gMiDigJQgR2VyYcOnw6NvIEhpZHJlbMOpdHJpY2EgY29tbyBGdW7Dp8OjbyBkbyBBcm1hemVuYW1lbnRvDQpPIHNlZ3VuZG8gbW9kZWxvIGRhIGNhZGVpYSBlc3RpbWEgYSBnZXJhw6fDo28gaGlkcmVsw6l0cmljYSAoR19oaWRybykgZW0gZnVuw6fDo28gZGEgZW5lcmdpYSBhcm1hemVuYWRhIChFQVIpIGUgZGUgY29udHJvbGVzIG9wZXJhY2lvbmFpcyBlIHNhem9uYWlzLiBPIG9iamV0aXZvIMOpIGNhcHR1cmFyIGEgZWxhc3RpY2lkYWRlIGRhIGdlcmHDp8OjbyBlbSByZWxhw6fDo28gYW8gZXN0b3F1ZSBow61kcmljbywgcGVybWl0aW5kbyB0cmFkdXppciBhcyB2YXJpYcOnw7VlcyBzaW11bGFkYXMgZGUgzpRFQVIgKHBlbmFsaWRhZGUgY2xpbcOhdGljYSkgZW0gaW1wYWN0b3Mgc29icmUgYSBnZXJhw6fDo28gZWZldGl2YS4gQXNzaW0gY29tbyBubyBtb2RlbG8gY2xpbcOhdGljbywgZW1wcmVnYS1zZSB1bSBHQU0gcGFyYSBjYXB0dXJhciByZWxhw6fDtWVzIG7Do28gbGluZWFyZXMgZW50cmUgdmFyacOhdmVpcyBmw61zaWNhcyBlIG9wZXJhY2lvbmFpcywgbWFudGVuZG8gcGFyY2ltw7RuaWEgZSBpbnRlcnByZXRhYmlsaWRhZGUuDQoNCg0KDQojIDMuMiBNb2RlbG8gMiDigJQgR2VyYcOnw6NvIEhpZHJlbMOpdHJpY2EgY29tbyBGdW7Dp8OjbyBkbyBBcm1hemVuYW1lbnRvLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYGBge3J9DQoNCm0yX2hpZHJvIDwtIGJhbSgNCiAgdmFsX2dlcmFjYW8gfiAgWWVhcisNCiAgICBzKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzLCBrID0gNCkrDQogICAgcyh2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSwgayA9IDQpKw0KICAgIHMoZG95LCBicyA9ICJjYyIsIGsgPSAyKSArICAgICAjIHNhem9uYWxpZGFkZSBkbyBkaWEgZG8gYW5vIChjw61jbGljYSkNCiAgICBzKGlkX3Jlc2VydmF0b3Jpby54LCBicyA9ICJyZSIpKyMgZWZlaXRvIGFsZWF0w7NyaW8gcG9yIHJlc2VydmF0w7NyaW8NCiAgICNzKHZhbF92YXphb2RlZmx1ZW50ZSxrID0gMikrDQoNCiAgICBub21fc3Vic2lzdGVtYS54DQogICwNCiAgZGF0YSAgICAgPSByZXNlcnYsDQogIG1ldGhvZCAgID0gImZSRU1MIiwNCiAgZGlzY3JldGUgPSBUUlVFLA0KICBmYW1pbHkgICA9IGdhdXNzaWFuKCksICAgICAgICAgICAgIyBmYW3DrWxpYTogbm9ybWFsOyBhanVzdGFyIHNlIG5lY2Vzc8OhcmlvDQogIG5hLmFjdGlvbj0gbmEuZXhjbHVkZSwNCiAgI2tub3RzICAgID0gbGlzdChkb3kgPSBjKDAuNSwgMzY2LjUpKQ0KKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShtMl9oaWRybykNCmdhbS5jaGVjayhtMl9oaWRybykNCmNvbmN1cnZpdHkobTJfaGlkcm8sIGZ1bGw9VFJVRSkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCnBsb3QobTJfaGlkcm8sIHBhZ2VzPTMsIHNjaGVtZT0xLCBzaGFkZT1UUlVFLCBzZT1UUlVFLCBzY2FsZXM9ImZyZWUiKQ0KYGBgDQpPIG1vZGVsbyBoaWRyZWzDqXRyaWNvIChHQU0gMikgYXByZXNlbnRvdSBmb3J0ZSBkZXNlbXBlbmhvIGV4cGxpY2F0aXZvLCBjb20gUsKyIGFqdXN0YWRvIGRlIDAsODUgZSBkZXZpYW5jZSBleHBsaWNhZGEgZGUgODUsMiUsIG8gcXVlIGNvbmZpcm1hIHN1YSBhbHRhIGNhcGFjaWRhZGUgZGUgcmVwcm9kdXppciBhIGdlcmHDp8OjbyBvYnNlcnZhZGEgYSBwYXJ0aXIgZGEgZW5lcmdpYSBhcm1hemVuYWRhIGUgdmFyacOhdmVpcyBvcGVyYWNpb25haXMuIE8gdGVybW8gbGluZWFyIHBhcmEgbyBhbm8gw6kgbmVnYXRpdm8gZSBhbHRhbWVudGUgc2lnbmlmaWNhdGl2byAo4oCTMTMsNSBNV8K3bcOqcy9hbm87IHAgPCAwLDAwMSksIHJlZmxldGluZG8gYSB0ZW5kw6puY2lhIGVzdHJ1dHVyYWwgZGUgcmVkdcOnw6NvIGRhIHBhcnRpY2lwYcOnw6NvIGjDrWRyaWNhIGFvIGxvbmdvIGRvIHBlcsOtb2RvLCBwb3NzaXZlbG1lbnRlIGVtIGZ1bsOnw6NvIGRhIGV4cGFuc8OjbyBkZSBmb250ZXMgdMOpcm1pY2FzIGUgcmVub3bDoXZlaXMgbsOjbyBow61kcmljYXMuIE9zIGVmZWl0b3MgZml4b3MgcG9yIHN1YnNpc3RlbWEgaW5kaWNhbSBkaWZlcmVuw6dhcyBtb2Rlc3RhcywgY29tIGdlcmHDp8OjbyBtw6lkaWEgbGlnZWlyYW1lbnRlIHN1cGVyaW9yIG5vIE5vcnRlIGUgaW5mZXJpb3Igbm8gU3VkZXN0ZSwgY29uc2lzdGVudGVzIGNvbSBvIHBhcGVsIGVzdHJ1dHVyYWwgZGUgY2FkYSByZWdpw6NvIG5hIG9mZXJ0YSBkZSBlbmVyZ2lhIGUgbm8gZGVzcGFjaG8gZG8gc2lzdGVtYS4NCg0KT3MgZGlhZ27Ds3N0aWNvcyBkZSByZXPDrWR1b3MgZXZpZGVuY2lhbSBhanVzdGUgYWRlcXVhZG8sIGNvbSBkaXN0cmlidWnDp8OjbyBhcHJveGltYWRhbWVudGUgbm9ybWFsIGUgYXVzw6puY2lhIGRlIGhldGVyb2NlZGFzdGljaWRhZGUgc2lzdGVtw6F0aWNhLiBPIGhpc3RvZ3JhbWEgZG9zIHJlc8OtZHVvcyDDqSBjZW50cmFkbyBlbSB6ZXJvLCBlIG8gUVEtcGxvdCBtb3N0cmEgbGV2ZSBjdXJ2YXR1cmEgbmFzIGNhdWRhcywgaW5kaWNhbmRvIHBlcXVlbmEgYXNzaW1ldHJpYSBhc3NvY2lhZGEgYSByZWdpbWVzIG9wZXJhY2lvbmFpcyBleHRyZW1vcyAocmVzZXJ2YXTDs3Jpb3MgY2hlaW9zIG91IHZhemlvcykuIE8gZ3LDoWZpY28gZGUgcmVzw61kdW9zIHZlcnN1cyBwcmVkaXRvcyBleGliZSBkdWFzIGZhaXhhcyBiZW0gZGVmaW5pZGFzLCBjb3JyZXNwb25kZW50ZXMgYSBkaWZlcmVudGVzIHJlZ2ltZXMgZGUgb3BlcmHDp8OjbyBoaWRyw6F1bGljYSDigJQgdW0gZGUgYmFpeGEgZ2VyYcOnw6NvIGNvbSBFQVIgbGltaXRhZGEgZSBvdXRybyBkZSBvcGVyYcOnw6NvIHBsZW5hIGNvbSBhbHRvcyBuw612ZWlzIGRlIGRlc3BhY2hvLiBFbWJvcmEgZXNzZXMgcmVnaW1lcyBpbnRyb2R1emFtIGxldmUgZXN0cmF0aWZpY2HDp8OjbywgbsOjbyBow6EgaW5kw61jaW9zIGRlIHZpw6lzIGRpcmVjaW9uYWwgbmVtIGF1dG9jb3JyZWxhw6fDo28gcmVsZXZhbnRlLCBvIHF1ZSByZWZvcsOnYSBhIHZhbGlkYWRlIGRvIG1vZGVsbyBnYXVzc2lhbm8gY29tIGxpbmsgaWRlbnRpZGFkZS4gTyB0ZXN0ZSBkZSBkaW1lbnNpb25hbGlkYWRlIGVmZXRpdmEgKGstaW5kZXggPiAwLjkpIGUgbyBiYWl4byBuw612ZWwgZGUgY29uY29ycsOqbmNpYSAoY29uY3Vydml0eSA8IDAuMykgY29uZmlybWFtIGEgZXN0YWJpbGlkYWRlIG51bcOpcmljYSBkb3Mgc3BsaW5lcyBlIGEgYXVzw6puY2lhIGRlIHNvYnJlYWp1c3RlLg0KDQpPcyBlZmVpdG9zIHBhcmNpYWlzIGlsdXN0cmFtIGRlIGZvcm1hIGNsYXJhIGEgZGluw6JtaWNhIGbDrXNpY2EgZG8gc2lzdGVtYS4gTyBzcGxpbmUgZGEgZW5lcmdpYSBhcm1hemVuYWRhIChFQVIpIGFwcmVzZW50YSB1bSBmb3JtYXRvIGNyZXNjZW50ZSBjb20gbGV2ZSBzYXR1cmHDp8Ojbywgc3VnZXJpbmRvIHJlbmRpbWVudG8gZGVjcmVzY2VudGU6IGF1bWVudG9zIGluaWNpYWlzIGRlIGFybWF6ZW5hbWVudG8gcHJvZHV6ZW0gZ3JhbmRlcyBhY3LDqXNjaW1vcyBkZSBnZXJhw6fDo28sIG1hcyBvIGVmZWl0byBtYXJnaW5hbCBkaW1pbnVpIMOgIG1lZGlkYSBxdWUgbyByZXNlcnZhdMOzcmlvIHNlIGFwcm94aW1hIGRhIGNhcGFjaWRhZGUgbcOheGltYS4gTyBzcGxpbmUgZGEgZ2VyYcOnw6NvIGRpw6FyaWEgZG8gc3Vic2lzdGVtYSBtb3N0cmEgcmVsYcOnw6NvIHF1YXNlIGxpbmVhciBwb3NpdGl2YSwgcmVwcmVzZW50YW5kbyBvIGVmZWl0byBkZSBlc2NhbGEgZSBjb29yZGVuYcOnw6NvIGVudHJlIHVzaW5hcyBpbnRlcmxpZ2FkYXMuIEEgc2F6b25hbGlkYWRlIGFudWFsIChkb3kpIMOpIGZyYWNhLCByZWZsZXRpbmRvIG8gZmF0byBkZSBxdWUgYXMgb3NjaWxhw6fDtWVzIHNhem9uYWlzIGrDoSBzw6NvIGludGVybmFsaXphZGFzIG5vIG7DrXZlbCBkZSBhcm1hemVuYW1lbnRvLCBlbnF1YW50byBvIGVmZWl0byBhbGVhdMOzcmlvIHBvciByZXNlcnZhdMOzcmlvIGluZGljYSBhbXBsYSBoZXRlcm9nZW5laWRhZGUgZXN0cnV0dXJhbCDigJQgYWxndW5zIHJlc2VydmF0w7NyaW9zIG9wZXJhbSBjb21vIHVzaW5hcyBkZSBiYXNlLCBjb20gZWZlaXRvIHByw7N4aW1vIGRlIHplcm8sIGUgb3V0cm9zIGNvbSBmb3J0ZSBzZW5zaWJpbGlkYWRlIMOgIHZhcmlhw6fDo28gZGUgRUFSLiBFbSBjb25qdW50bywgZXNzZXMgcmVzdWx0YWRvcyBjb25maXJtYW0gcXVlIG8gbW9kZWxvIGNhcHRhIGFkZXF1YWRhbWVudGUgbyBtZWNhbmlzbW8gZGUgY29udmVyc8OjbyBoaWRyb2zDs2dpY2EgZW50cmUgZXN0b3F1ZSBlIGdlcmHDp8Ojbywgb2ZlcmVjZW5kbyBiYXNlIGNvbnNpc3RlbnRlIHBhcmEgYSBlc3RpbWF0aXZhIGNvbnRyYWZhY3R1YWwgZGEgZ2VyYcOnw6NvIGjDrWRyaWNhIHNvYiBkaWZlcmVudGVzIGNlbsOhcmlvcyBjbGltw6F0aWNvcy4NCg0KDQoNCiMjUHJlZGnDp8O1ZXMgZmFjdHVhbCB2cy4gY29udHJhZmFjdHVhbCBjb20gaW5jZXJ0ZXphIChiYXNlbGluZSAyMDAx4oCTMjAwNSkNCk8gb2JqZXRpdm8gw6kgY29tcGFyYXIgbyBhcm1hemVuYW1lbnRvIHByZXZpc3RvIHBlbG8gbW9kZWxvIHNvYiBjb25kacOnw7VlcyBjbGltw6F0aWNhcyBvYnNlcnZhZGFzIGUgc29iIGNvbmRpw6fDtWVzIG5ldXRyYXMsIHJlcHJlc2VudGFkYXMgcGVsbyBjbGltYSBtw6lkaW8gZG8gcGVyw61vZG8gMjAwMeKAkzIwMDUuIEEgZGlmZXJlbsOnYSBlbnRyZSBhcyBkdWFzIHPDqXJpZXMgKCTOlEVBUj1FXntvYnN94oiSRV57Y2Z9JCkgcmVwcmVzZW50YSBhIHBlbmFsaWRhZGUgY2xpbcOhdGljYSBsw61xdWlkYSwgZSBzdWEgaW5jZXJ0ZXphIMOpIGVzdGltYWRhIHZpYSBwcm9wYWdhw6fDo28gZG9zIGVycm9zIHBhcmFtw6l0cmljb3MgZG8gR0FNLg0KDQpgYGB7cn0NCiMgLS0tIFByZWRpw6fDtWVzIGZhY3R1YWwgZSBjb250cmFmYWN0dWFsIC0tLQ0KcmVzZXJ2JGVhcl9oYXRfb2JzIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfb2JzLCB0eXBlID0gInJlc3BvbnNlIikNCnJlc2VydiRlYXJfaGF0X2NmICA8LSBwcmVkaWN0KG0xX2dhbSwgbmV3ZGF0YSA9IG5kX2NmLCAgdHlwZSA9ICJyZXNwb25zZSIpDQoNCiMgUGVuYWxpZGFkZSBtw6lkaWENCnJlc2VydiA8LSByZXNlcnYgJT4lDQogIG11dGF0ZShkZWx0YV9lYXIgPSBlYXJfaGF0X29icyAtIGVhcl9oYXRfY2YpDQoNCnJlc2VydiRnZXJfaGF0X2ZhY3R1YWwgPC0gcHJlZGljdCgNCiAgbTJfaGlkcm8sIG5ld2RhdGEgPSByZXNlcnYsDQogIHR5cGUgPSAicmVzcG9uc2UiDQopDQpyZXNlcnYkZ2VyX2hhdF9jb250cmFmIDwtIHByZWRpY3QoDQogIG0yX2hpZHJvLCBuZXdkYXRhID0gcmVzZXJ2ICU+JQ0KICAgIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9oYXRfY2YpLA0KICB0eXBlID0gInJlc3BvbnNlIg0KKQ0KcmVzZXJ2IDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKGRlbHRhX0doaWRybyA9IGdlcl9oYXRfZmFjdHVhbCAtIGdlcl9oYXRfY29udHJhZikNCnJlc2VydlssYygiZGVsdGFfR2hpZHJvIiwiZ2VyX2hhdF9mYWN0dWFsIiwiZ2VyX2hhdF9jb250cmFmIiwidmFsX2dlcmFjYW8iKV0gJT4lIHN1bW1hcnkoKQ0KYGBgDQojICgzKSBJbmNlcnRlemEgdmlhIERlbHRhIE1ldGhvZCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYGBge3J9DQpWcDIgPC0gdmNvdihtMl9oaWRybykNClhfZiA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gcmVzZXJ2ICwNCiAgICAgICAgICAgICAgIHR5cGUgPSAibHBtYXRyaXgiKQ0KWF9jIDwtIHByZWRpY3QobTJfaGlkcm8sIG5ld2RhdGEgPSByZXNlcnYgJT4lDQogICAgICAgICAgICAgICAgIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9oYXRfY2YpLA0KICAgICAgICAgICAgICAgdHlwZSA9ICJscG1hdHJpeCIpDQoNClhfZGlmZjIgPC0gWF9mIC0gWF9jDQp2YXJfZGVsdGEyIDwtIHJvd1N1bXMoKFhfZGlmZjIgJSolIFZwMikgKiBYX2RpZmYyKQ0Kc2VfZGVsdGEyICA8LSBzcXJ0KHBtYXgodmFyX2RlbHRhMiwgMCkpDQp6IDwtIHFub3JtKDAuOTc1KQ0KDQpDIDwtIHJlc2VydiAlPiUNCiAgbXV0YXRlKA0KICAgIGRlbHRhX2x3cl9nZXIgPSBkZWx0YV9HaGlkcm8gLSB6ICogc2VfZGVsdGEyLA0KICAgIGRlbHRhX3Vwcl9nZXIgPSBkZWx0YV9HaGlkcm8gKyB6ICogc2VfZGVsdGEyDQogICkNCkNbLGMoImRlbHRhX0doaWRybyIsImRlbHRhX2x3cl9nZXIiLCJkZWx0YV91cHJfZ2VyIiwidmFsX2dlcmFjYW8iKV0gJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCmBgYHtyfQ0KIyAoNCkgQWdyZWdhw6fDo28gcG9yIGFubyBlIHN1YnNpc3RlbWEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCm0yX2RlbHRhX2FnZyA8LSBDICU+JQ0KICBtdXRhdGUoWWVhciA9IHllYXIoZGF0ZSkpICU+JQ0KICBncm91cF9ieShZZWFyLCBub21fc3Vic2lzdGVtYS54KSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fcGVuYWx0eSA9IHN1bShkZWx0YV9HaGlkcm8sIG5hLnJtID0gVFJVRSksDQogICAgbHdyID0gc3VtKGRlbHRhX2x3cl9nZXIsIG5hLnJtID0gVFJVRSksDQogICAgdXByID0gc3VtKGRlbHRhX3Vwcl9nZXIsIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQptMl9kZWx0YV9hZ2cNCmBgYA0KDQoNCmBgYHtyIG0yLXBsb3QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbTJfZGVsdGFfYWdnICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gbWVhbl9wZW5hbHR5LzEwMDApKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gbHdyLzEwMDAsIHltYXggPSB1cHIvMTAwMCksIGZpbGwgPSAic3RlZWxibHVlIiwgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSAwLCB5bWF4ID0gdXByLzEwMDApLCBmaWxsID0gInJlZDMiLCBhbHBoYSA9IDAuMSkgKw0KDQogIGdlb21fbGluZShjb2xvciA9ICJibGFjayIpICsNCiAgZmFjZXRfd3JhcCh+bm9tX3N1YnNpc3RlbWEueCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJQcm9wYWdhdGVkIGNsaW1hdGUgcGVuYWx0eSBvbiBoeWRyb3Bvd2VyIGdlbmVyYXRpb24gKM6UR19oaWRybykiLA0KICAgICAgIHN1YnRpdGxlID0gIkJhc2VsaW5lIGNsaW1hdGU6IG1lYW4gMjAwMeKAkzIwMDUiLA0KICAgICAgIHkgPSAizpRHX2hpZHJvIChHV8K3bW9udGgpIiwgeCA9ICJZZWFyIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KYGBge3J9DQogDQptMl9zdW1tYXJ5ICA8LSBDICU+JQ0KICBtdXRhdGUoWWVhciA9IHllYXIoZGF0ZSkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICBncm91cF9ieSggbm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX3BlbmFsdHkgPSBzdW0oZGVsdGFfR2hpZHJvLCBuYS5ybSA9IFRSVUUpLA0KICAgIGx3ciA9IHN1bShkZWx0YV9sd3JfZ2VyLCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwciA9IHN1bShkZWx0YV91cHJfZ2VyLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQpsaWJyYXJ5KGd0KQ0KbTJfc3VtbWFyeVssYygibm9tX3N1YnNpc3RlbWEueCIsIm1lYW5fcGVuYWx0eSIsImx3ciIsICJ1cHIiKV0gJT4lIGphbml0b3I6OmFkb3JuX3RvdGFscygpICU+JSANCiAgZ3QoKSAlPiUNCiAgZm10X251bWJlcihjb2x1bW5zID0gMjo0LCBkZWNpbWFscyA9IDEpICU+JQ0KICBjb2xzX2xhYmVsKA0KICAgIG5vbV9zdWJzaXN0ZW1hLnggPSAiU3Vic3lzdGVtIiwNCiAgICBtZWFuX3BlbmFsdHkgPSAiU3VtIM6UZ2VyIChNV2gpIiwNCiAgICBsd3IgID0gIkxvd2VyIDk1JSIsDQogICAgdXByICA9ICJVcHBlciA5NSUiLA0KICApICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gbWQoIioqQWdncmVnYXRlIGNsaW1hdGUgcGVuYWx0eSBvbiBoaWRyb3Bvd2VyIGVuZXJneSAoMjAwMeKAkzIwMTgpKioiKSwNCiAgICBzdWJ0aXRsZSA9ICJTaW11bGF0ZWQgbWVhbiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHBlciBzdWJzeXN0ZW0iDQogICkNCmBgYA0KDQpBIEZpZ3VyYSBhcHJlc2VudGEgbyByZXN1bHRhZG8gZGEgKipwcm9wYWdhw6fDo28gZGEgcGVuYWxpZGFkZSBjbGltw6F0aWNhIHNvYnJlIGEgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2EgKM6UR1xfaGlkcm8pKiosIG9idGlkYSBwZWxhIHN1YnN0aXR1acOnw6NvIGRvIGNsaW1hIG9ic2VydmFkbyBwZWxvIGNsaW1hIG3DqWRpbyBoaXN0w7NyaWNvICgyMDAx4oCTMjAwNSkgbm8gbW9kZWxvIGRlIGFybWF6ZW5hbWVudG8gZSBwZWxhIGFwbGljYcOnw6NvIGRlc3NlcyB2YWxvcmVzIGNvbnRyYWZhY3R1YWlzIG5vIG1vZGVsbyBkZSBnZXJhw6fDo28uIE8gZ3LDoWZpY28gbW9zdHJhIGEgZGlmZXJlbsOnYSBlbnRyZSBhIGdlcmHDp8OjbyBwcmV2aXN0YSBzb2IgY2xpbWEgZWZldGl2byBlIG8gY2Vuw6FyaW8gY29udHJhZmFjdHVhbCBuZXV0cm8sIGNvbSBpbnRlcnZhbG9zIGRlIGNvbmZpYW7Dp2EgY2FsY3VsYWRvcyBwb3IgZHVhcyBhYm9yZGFnZW5zOiBvIG3DqXRvZG8gYW5hbMOtdGljbyAoRGVsdGEpIGUgYSBzaW11bGHDp8OjbyBwYXJhbcOpdHJpY2EuDQoNCk9zIHJlc3VsdGFkb3MgaW5kaWNhbSBxdWUgYSBwZW5hbGlkYWRlIGNsaW3DoXRpY2EgbcOpZGlhIHNvYnJlIGEgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2Egc2VndWUgbyBtZXNtbyBwYWRyw6NvIGVzcGFjaWFsIG9ic2VydmFkbyBuYSBlbmVyZ2lhIGFybWF6ZW5hZGEsIG1hcyBjb20gbWFnbml0dWRlIGFtcGxpZmljYWRhIGRldmlkbyDDoCByZXNwb3N0YSBlbMOhc3RpY2EgZG8gZGVzcGFjaG8gaMOtZHJpY28uIE8gKipTdWRlc3RlKiogYXByZXNlbnRhIG8gbWFpb3IgZMOpZmljaXQgbcOpZGlvLCBjb20gcmVkdcOnw7VlcyBhY3VtdWxhZGFzIHN1cGVyaW9yZXMgYSAqKuKAkzQgbWlsaMO1ZXMgZGUgTVfCt23DqnMqKiBlbSBhbm9zIHNlY29zLCByZWZsZXRpbmRvIGEgZm9ydGUgZGVwZW5kw6puY2lhIGRhIGdlcmHDp8OjbyBhbyBuw612ZWwgZGUgcmVzZXJ2YXTDs3Jpb3MuIE8gKipTdWwqKiBtb3N0cmEgcGVuYWxpZGFkZXMgaW50ZXJtZWRpw6FyaWFzIChlbnRyZSDigJMxIGUg4oCTMiBtaWxow7VlcyBkZSBNV8K3bcOqcyksIGNvbSBhbHRhIHZhcmlhYmlsaWRhZGUgaW50ZXJhbnVhbC4gTyAqKk5vcmRlc3RlKiogZSBvICoqTm9ydGUqKiBhcHJlc2VudGFtIG9zY2lsYcOnw7VlcyBtZW5vcmVzLCBtYXMgY29tIHRlbmTDqm5jaWEgbmVnYXRpdmEgYWNlbnR1YWRhIGFww7NzIDIwMTIsIGNvbXBhdMOtdmVsIGNvbSBwZXLDrW9kb3MgZGUgZXN0aWFnZW0gcHJvbG9uZ2FkYS4gIA0KDQpPcyAqKmludGVydmFsb3MgZGUgY29uZmlhbsOnYSoqIHJldmVsYW0gYXVtZW50byBleHByZXNzaXZvIGRhIGluY2VydGV6YSBhcMOzcyAyMDEwLCBxdWFuZG8gYXMgY29uZGnDp8O1ZXMgY2xpbcOhdGljYXMgc2UgdG9ybmFyYW0gbWFpcyB2b2zDoXRlaXMgZSBvcyByZXNlcnZhdMOzcmlvcyBwYXNzYXJhbSBhIG9wZXJhciBwcsOzeGltb3MgZGUgbGltaXRlcyBjcsOtdGljb3MuIEVzc2UgcGFkcsOjbyByZWZvcsOnYSBhIGludGVycHJldGHDp8OjbyBkZSBxdWUgYSAqKnBlbmFsaWRhZGUgY2xpbcOhdGljYSBwcm9wYWdhZGEgw6AgZ2VyYcOnw6NvKiogcmVwcmVzZW50YSBuw6NvIGFwZW5hcyBhIHBlcmRhIGRlIGVzdG9xdWUgaMOtZHJpY28sIG1hcyB0YW1iw6ltIGEgKipkaW1pbnVpw6fDo28gZGEgZmxleGliaWxpZGFkZSBvcGVyYXRpdmEqKiBkbyBzaXN0ZW1hLCB1bSBkb3MgcHJpbmNpcGFpcyBjYW5haXMgZGUgdHJhbnNtaXNzw6NvIGRvcyBlZmVpdG9zIGNsaW3DoXRpY29zIHBhcmEgb3MgY3VzdG9zIGRvIHNldG9yIGVsw6l0cmljby4NCg0KMy4yLjUgUHJvcGFnYcOnw6NvIGNvbmp1bnRhIGRlIGluY2VydGV6YSAozpRFQVIg4oaSIM6UR19oaWRybykNCkVzdGUgYmxvY28gcmVhbGl6YSB1bWEgc2ltdWxhw6fDo28gTW9udGUgQ2FybG8gZW5jYWRlYWRhOiBjYWRhIHNvcnRlaW8gaW5jbHVpIHNpbXVsdGFuZWFtZW50ZSBvcyBjb2VmaWNpZW50ZXMgZG8gbW9kZWxvIGNsaW3DoXRpY28gKG0xX2dhbSkgZSBkbyBtb2RlbG8gaGlkcmVsw6l0cmljbyAobTJfaGlkcm8pLg0KQXNzaW0sIGFzIGluY2VydGV6YXMgZGEgcHJldmlzw6NvIGRvIGFybWF6ZW5hbWVudG8gKEVBUikgc8OjbyB0cmFuc21pdGlkYXMgaW50ZWdyYWxtZW50ZSBwYXJhIGFzIHByZXZpc8O1ZXMgZGUgZ2VyYcOnw6NvLCBwcm9kdXppbmRvIHVtYSBkaXN0cmlidWnDp8OjbyBjb25qdW50YSBwYXJhICTOlPCdkLpfe+KEjvCdkZbwnZGR8J2Rn/CdkZx9JC4gDQoNCg0KIyMjIDMuMi42IFJlc3VsdGFkb3Mg4oCUIFByb3BhZ2HDp8OjbyBpbnRlZ3JhbCBkZSBpbmNlcnRlemEgKM6UR1xfaGlkcm8gY29uanVudG8pIHBhcnRpbmRvIGRvIG0yLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KDQoNCmBgYHtyIHJld20xbTItam9pbnQtc2ltdWxhdGlvbiAxLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KDQpzZXQuc2VlZCgyMDI1MTAxMSkNCm5zaW0gPC0gNTAwICAjIHBvZGUgYXVtZW50YXIgZGVwb2lzIHBhcmEgMTAwMCwgbWFzIHRlc3RlIGNvbSA1MDAgcHJpbWVpcm8NCg0KDQojIC0tLSAxLiBDb3ZhcmnDom5jaWFzIGUgc29ydGVpb3MgZG9zIGNvZWZpY2llbnRlcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpWcDEgPC0gdmNvdihtMV9nYW0pDQpWcDIgPC0gdmNvdihtMl9oaWRybykNCmJldGFfZHJhd3NfMSA8LSBNQVNTOjptdnJub3JtKG4gPSBuc2ltLCBtdSA9IGNvZWYobTFfZ2FtKSwgU2lnbWEgPSBWcDEpDQpiZXRhX2RyYXdzXzIgPC0gTUFTUzo6bXZybm9ybShuID0gbnNpbSwgbXUgPSBjb2VmKG0yX2hpZHJvKSwgU2lnbWEgPSBWcDIpDQoNCiMgLS0tIDIuIE1hdHJpemVzIGRvIG1vZGVsbyAxIChFQVIgfiBjbGltYSkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KWF9vYnNfZWFyIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfb2JzLCB0eXBlID0gImxwbWF0cml4IikNClhfY2ZfZWFyICA8LSBwcmVkaWN0KG0xX2dhbSwgbmV3ZGF0YSA9IG5kX2NmLCAgdHlwZSA9ICJscG1hdHJpeCIpDQoNCiMgLS0tIDMuIFByb3BhZ2HDp8OjbyBNb250ZSBDYXJsbyBlbmNhZGVhZGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmRlbHRhX0dfam9pbnQgPC0gbWF0cml4KE5BX3JlYWxfLCBucm93ID0gbnJvdyhuZF9vYnMpLCBuY29sID0gbnNpbSkNCg0KZm9yIChzIGluIHNlcV9sZW4obnNpbSkpIHsNCiAgIyAxLiBFQVIgZmFjdHVhbCBlIGNvbnRyYWZhY3R1YWwgc2ltdWxhZG9zDQogIGVhcl9mIDwtIGFzLm51bWVyaWMoWF9vYnNfZWFyICUqJSBiZXRhX2RyYXdzXzFbcywgXSkNCiAgZWFyX2MgPC0gYXMubnVtZXJpYyhYX2NmX2VhciAgJSolIGJldGFfZHJhd3NfMVtzLCBdKQ0KICANCiAgIyAyLiBBdHVhbGl6YXIgaW5wdXRzIGRvIG1vZGVsbyBkZSBnZXJhw6fDo28NCiAgbmRfZiA8LSBuZF9vYnMgJT4lDQogICAgbXV0YXRlKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzID0gZWFyX2YpDQogIG5kX2MgPC0gbmRfb2JzICU+JQ0KICAgIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9jKQ0KICANCiAgIyAzLiBQcmVkacOnw7VlcyBjb21wbGV0YXMgZG8gbW9kZWxvIGRlIGdlcmHDp8OjbyAobsOjbyBsaW5lYXIpDQogIGdfZiA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gbmRfZiwgdHlwZSA9ICJyZXNwb25zZSIpDQogIGdfYyA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gbmRfYywgdHlwZSA9ICJyZXNwb25zZSIpDQogIA0KICAjIDQuIFBlbmFsaWRhZGUgcHJvcGFnYWRhDQogIGRlbHRhX0dfam9pbnRbLCBzXSA8LSBnX2YgLSBnX2MNCiAgcHJpbnQocykNCn0NCg0KDQp3cml0ZV9yZHMoZGVsdGFfR19qb2ludCwgImRlbHRhX0dfam9pbnQucmRzIikNCmBgYA0KDQoNCmBgYHtyIHJld20xbTItam9pbnQtc2ltdWxhdGlvbiAyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGVsdGFfR19qb2ludDwtcmVhZF9yZHMoImRlbHRhX0dfam9pbnQucmRzIikNCmRlbHRhX0dfam9pbnQgJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCg0KYGBge3IgcmV3bTFtMi1qb2ludC1zaW11bGF0aW9uIDMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIC0tLSA0LiBBZ3JlZ2FyIHBvciBzdWJzaXN0ZW1hIGUgYW5vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCm5kX29icyRZZWFyDQpkdCA8LSBuZF9vYnMgJT4lIHNlbGVjdChZZWFyLCBub21fc3Vic2lzdGVtYS54KQ0KZHQkWWVhcjwtbmRfb2JzJFllYXINCg0KDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpkdCA8LSBhcy5kYXRhLnRhYmxlKGR0KQ0KZ3JvdXBzIDwtIHVuaXF1ZShkdFssIC4oWWVhciwgbm9tX3N1YnNpc3RlbWEueCldKQ0KDQphZ2dfam9pbnQgPC0gbGFwcGx5KHNlcV9sZW4obnJvdyhncm91cHMpKSwgZnVuY3Rpb24oZyl7DQogIGlkeCA8LSB3aGljaChkdCRZZWFyID09IGdyb3VwcyRZZWFyW2ddICYgZHQkbm9tX3N1YnNpc3RlbWEueCA9PSBncm91cHMkbm9tX3N1YnNpc3RlbWEueFtnXSkNCiAgY29sU3VtcyhkZWx0YV9HX2pvaW50W2lkeCwgLCBkcm9wID0gRkFMU0VdLCBuYS5ybSA9IFRSVUUpDQp9KQ0KYWdnX2pvaW50IDwtIGRvLmNhbGwocmJpbmQsIGFnZ19qb2ludCkNCmNvbG5hbWVzKGFnZ19qb2ludCkgPC0gcGFzdGUwKCJzaW1fIiwgMTpuc2ltKQ0KICBhZ2dfZGYgPC0gY2JpbmQoZ3JvdXBzLCBhZ2dfam9pbnQpDQojIC0tLSA1LiBFc3RhdMOtc3RpY2FzIHJlc3VtbyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQptMl9qb2ludF9zdW1tYXJ5IDwtIGFnZ19kZiAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoInNpbV8iKSwgdmFsdWVzX3RvID0gImRlbHRhX0ciKSAlPiUNCiAgZ3JvdXBfYnkoWWVhciwgbm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuID0gbWVhbihkZWx0YV9HLCBuYS5ybSA9IFRSVUUpLA0KICAgIGx3ciAgPSBxdWFudGlsZShkZWx0YV9HLCAwLjAyNSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHIgID0gcXVhbnRpbGUoZGVsdGFfRywgMC45NzUsIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQoNCmBgYA0KDQoNCmBgYHtyIG0yLWpvaW50LXBsb3QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbTJfam9pbnRfc3VtbWFyeSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IG1lYW4pKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gbHdyLCB5bWF4ID0gdXByKSwgZmlsbCA9ICJmaXJlYnJpY2siLCBhbHBoYSA9IDAuMykgKw0KICBnZW9tX2xpbmUoY29sb3IgPSAiYmxhY2siKSArDQogIGZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnModGl0bGUgPSAiSm9pbnQgcHJvcGFnYXRlZCBjbGltYXRlIHBlbmFsdHkgb24gaHlkcm9wb3dlciBnZW5lcmF0aW9uICjOlEdfaGlkcm8pIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJVbmNlcnRhaW50eSBmdWxseSBwcm9wYWdhdGVkIGZyb20gY2xpbWF0ZSDihpIgc3RvcmFnZSDihpIgZ2VuZXJhdGlvbiIsDQogICAgICAgeSA9ICLOlEdfaGlkcm8gKE1Xwrdtb250aCkiLCB4ID0gIlllYXIiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KYGBge3IgbTItam8gZ2lnaW50LXBsb3QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbTJfam9pbnRfc3VtbWFyeSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IG1lYW4vMTAwMCkpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBsd3IvMTAwMCwgeW1heCA9IHVwci8xMDAwKSwgZmlsbCA9ICJzdGVlbGJsdWUiLCBhbHBoYSA9IDEpICsNCiAgICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IDAsIHltYXggPSB1cHIvMTAwMCksIGZpbGwgPSAiZmlyZWJyaWNrIiwgYWxwaGEgPSAwLjEpICsNCg0KICBnZW9tX2xpbmUoY29sb3IgPSAiYmxhY2siKSArDQogIGZhY2V0X3dyYXAofm5vbV9zdWJzaXN0ZW1hLngsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnModGl0bGUgPSAiSm9pbnQgcHJvcGFnYXRlZCBjbGltYXRlIHBlbmFsdHkgb24gaHlkcm9wb3dlciBnZW5lcmF0aW9uICjOlEdfaGlkcm8pIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJVbmNlcnRhaW50eSBmdWxseSBwcm9wYWdhdGVkIGZyb20gY2xpbWF0ZSDihpIgc3RvcmFnZSDihpIgZ2VuZXJhdGlvbiIsDQogICAgICAgeSA9ICLOlEdfaGlkcm8gKEdXwrdtb250aCkiLCB4ID0gIlllYXIiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkEgRmlndXJhIGFwcmVzZW50YSBhICoqcGVuYWxpZGFkZSBjbGltw6F0aWNhIHNvYnJlIGEgZ2VyYcOnw6NvIGhpZHJlbMOpdHJpY2EgKM6UR1xfaGlkcm8pKiogZXN0aW1hZGEgY29tICoqcHJvcGFnYcOnw6NvIGNvbmp1bnRhIGRlIGluY2VydGV6YSoqIGFvIGxvbmdvIGRlIHRvZGEgYSBjYWRlaWEgY2xpbWF0by1oaWRyb2zDs2dpY2EuIERpZmVyZW50ZW1lbnRlIGRhcyBhYm9yZGFnZW5zIHF1ZSB0cmF0YW0gb3MgbW9kZWxvcyBkZSBmb3JtYSBpbmRlcGVuZGVudGUsIGVzdGEgc2ltdWxhw6fDo28gaW5jb3Jwb3JhIHNpbXVsdGFuZWFtZW50ZSBhIGluY2VydGV6YSBkb3MgY29lZmljaWVudGVzIGRvIG1vZGVsbyBjbGltw6F0aWNvIChFQVIgfiBjbGltYSkgZSBkbyBtb2RlbG8gaGlkcmVsw6l0cmljbyAoZ2VyYcOnw6NvIH4gRUFSKSwgZ2VyYW5kbyB1bWEgZGlzdHJpYnVpw6fDo28gY29uanVudGEgZGUgcmVzdWx0YWRvcy4gQ2FkYSB0cmFqZXTDs3JpYSBNb250ZSBDYXJsbyByZXByZXNlbnRhIHVtYSBjb21iaW5hw6fDo28gcGxhdXPDrXZlbCBkZSBwYXLDom1ldHJvcyBlIGNvbmRpw6fDtWVzIGNsaW3DoXRpY2FzLCBwZXJtaXRpbmRvIGNhcHR1cmFyIGEgdmFyaWFiaWxpZGFkZSBlc3RydXR1cmFsIGUgY2xpbcOhdGljYSBkbyBzaXN0ZW1hLg0KDQpPcyByZXN1bHRhZG9zIG1vc3RyYW0gcXVlIGEgaW5jZXJ0ZXphIHByb3BhZ2FkYSBhbXBsaWEgb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIGRhcyBlc3RpbWF0aXZhcyBhbnVhaXMgZGUgzpRHXF9oaWRybywgcHJpbmNpcGFsbWVudGUgYXDDs3MgMjAxMCwgcXVhbmRvIGEgdmFyaWFiaWxpZGFkZSBjbGltw6F0aWNhIGUgb3BlcmFjaW9uYWwgYXVtZW50YSBzaWduaWZpY2F0aXZhbWVudGUuIE8gKipzdWJzaXN0ZW1hIFN1ZGVzdGUqKiBjb25jZW50cmEgYXMgbWFpb3JlcyBwZXJkYXMgbcOpZGlhcyAoYXTDqSDigJM0LDUgw5cgMTDigbYgTVfCt23DqnMpIGUgYSBtYWlvciBkaXNwZXJzw6NvIGludGVyYW51YWwsIHJlZmxldGluZG8gdGFudG8gYSBtYWduaXR1ZGUgZGUgc3VhIGNhcGFjaWRhZGUgZGUgYXJtYXplbmFtZW50byBxdWFudG8gc3VhIGV4cG9zacOnw6NvIGEgc2VjYXMgcHJvbG9uZ2FkYXMuIE8gKipTdWwqKiBhcHJlc2VudGEgcGVuYWxpZGFkZXMgbWVub3JlcywgbWFzIGNvbSBhbXBsaXR1ZGVzIGRlIGluY2VydGV6YSBlbGV2YWRhcywgY29lcmVudGVzIGNvbSBzdWEgaW5zdGFiaWxpZGFkZSBoaWRyb2zDs2dpY2EuICoqTm9yZGVzdGUqKiBlICoqTm9ydGUqKiBtb3N0cmFtIG1lbm9yZXMgZMOpZmljaXRzIGFic29sdXRvcywgbWFzIGNvbSB0ZW5kw6puY2lhIG5lZ2F0aXZhIGNvbnTDrW51YS4gIA0KRXNzZXMgcmVzdWx0YWRvcyByZXByZXNlbnRhbSBhIGVzdGltYXRpdmEgbWFpcyBjb21wbGV0YSBkZSAqKmltcGFjdG8gY2xpbcOhdGljbyBwcm9wYWdhZG8gbm8gc2lzdGVtYSBlbMOpdHJpY28qKiwgcG9pcyBpbnRlZ3JhbSBpbmNlcnRlemFzIGNsaW3DoXRpY2FzLCBoaWRyb2zDs2dpY2FzIGUgb3BlcmFjaW9uYWlzIGRlbnRybyBkZSB1bWEgbWVzbWEgZXN0cnV0dXJhIHByb2JhYmlsw61zdGljYS4NCg0KDQpgYGB7cn0NCm0yX3N1bW1hcnkgPC0gbTJfam9pbnRfc3VtbWFyeSAlPiUNCiAgZ3JvdXBfYnkobm9tX3N1YnNpc3RlbWEueCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX3BlbmFsdHkgPSBtZWFuKG1lYW4sIG5hLnJtID0gVFJVRSksDQogICAgbHdyXzk1ID0gbWVhbihsd3IsIG5hLnJtID0gVFJVRSksDQogICAgdXByXzk1ID0gbWVhbih1cHIsIG5hLnJtID0gVFJVRSksDQogICAgc2RfcGVuYWx0eSA9IHNkKG1lYW4sIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQoNCiMgQ29udmVydGVuZG8gcGFyYSBHV2gvYW5vIHBhcmEgaW50ZXJwcmV0YcOnw6NvDQptMl9zdW1tYXJ5IDwtIG0yX3N1bW1hcnkgJT4lDQogIG11dGF0ZSgNCiAgICBtZWFuX0dXaCA9IG1lYW5fcGVuYWx0eSAvIDEwMDAsDQogICAgbHdyX0dXaCAgPSBsd3JfOTUgLyAxMDAwLA0KICAgIHVwcl9HV2ggID0gdXByXzk1IC8gMTAwMCwNCiAgKSAjJT4lIHNlbGVjdCgtbWVhbl9wZW5hbHR5LCAtbHdyXzk1LCAtdXByXzk1KQ0KDQojIFRhYmVsYSBmb3JtYXRhZGEgKHB1YmxpY2HDp8OjbykNCmxpYnJhcnkoZ3QpDQptMl9zdW1tYXJ5WyxjKCJub21fc3Vic2lzdGVtYS54IiwibWVhbl9HV2giLCJsd3JfR1doIiwgInVwcl9HV2giKV0gJT4lIGphbml0b3I6OmFkb3JuX3RvdGFscygpICU+JSANCiAgZ3QoKSAlPiUNCiAgZm10X251bWJlcihjb2x1bW5zID0gMjo0LCBkZWNpbWFscyA9IDEpICU+JQ0KICBjb2xzX2xhYmVsKA0KICAgIG5vbV9zdWJzaXN0ZW1hLnggPSAiU3Vic3lzdGVtIiwNCiAgICBtZWFuX0dXaCA9ICJNZWFuIM6UR19oaWRybyAoR1doKSIsDQogICAgbHdyX0dXaCAgPSAiTG93ZXIgOTUlIiwNCiAgICB1cHJfR1doICA9ICJVcHBlciA5NSUiLA0KICApICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gbWQoIioqQWdncmVnYXRlIGNsaW1hdGUgcGVuYWx0eSBvbiBIaWRyaWMgR2VuZXJhdGlvbiAoMjAwMeKAkzIwMTgpKioiKSwNCiAgICBzdWJ0aXRsZSA9ICJTaW11bGF0ZWQgbWVhbiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHBlciBzdWJzeXN0ZW0iDQogICkNCmBgYA0KDQoNCiMgMy4zIE1vZGVsbyAzIOKAlCBHZXJhw6fDo28gVGVybWljYSAgY29tbyBGdW7Dp8OjbyBkYSBHZXJhw6fDo28gSGlkcmVsw6l0cmljYQ0KDQpgYGB7cn0NCmdlciAlPiVtdXRhdGUodXNpbmFfZm9udGU9cGFzdGUwKCJnZXJfIixub21fdGlwb3VzaW5hKSkgJT4lIA0KICBmaWx0ZXIoIW5vbV9zdWJzaXN0ZW1hPT0iUEFSQUdVQUkiKSAlPiUgIywiXyIsbm9tX3RpcG91c2luYSkpICU+JSANCiAgbXV0YXRlKHVzaW5hX2ZvbnRlPWNhc2Vfd2hlbih1c2luYV9mb250ZT09Imdlcl9CT01CRUFNRU5UTyJ+Imdlcl9ISURST0VMw4lUUklDQSIsDQogICAgICAgICAgICAgICAgICAgVFJVRX51c2luYV9mb250ZSkpICU+JSAjLCJfIixub21fdGlwb3VzaW5hKSkgJT4lIA0KDQogIGdyb3VwX2J5KGRhdGUsbm9tX3N1YnNpc3RlbWEsdXNpbmFfZm9udGUsdmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEpICU+JSANCiAgc3VtbWFyaXNlKGdlcj1zdW0odmFsX2dlcmFjYW8sbmEucm0gPSBUKSkgJT4lIHVuZ3JvdXAoKSAlPiUgDQogIHNwcmVhZCh1c2luYV9mb250ZSxnZXIsZmlsbCA9IDApICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSANCiAgbXV0YXRlKCktPmdlcmFfZW5lcmdfZGF5DQpnZXJhX2VuZXJnX2RheSRkb3kgICAgPC0gbHVicmlkYXRlOjp5ZGF5KGdlcmFfZW5lcmdfZGF5JGRhdGUpDQpnZXJhX2VuZXJnX2RheSRkb3cgICAgPC0gbHVicmlkYXRlOjp3ZGF5KGdlcmFfZW5lcmdfZGF5JGRhdGUsIGxhYmVsPVRSVUUsIGFiYnI9VFJVRSkNCmdlcmFfZW5lcmdfZGF5JG1vbnRoICA8LSBsdWJyaWRhdGU6Om1vbnRoKGdlcmFfZW5lcmdfZGF5JGRhdGUpDQpnZXJhX2VuZXJnX2RheSR0cmVuZCAgPC0gbHVicmlkYXRlOjp5ZWFyKGdlcmFfZW5lcmdfZGF5JGRhdGUpDQpgYGANCg0KTyBNb2RlbG8gMyBlc3RpbWEgYSByZXNwb3N0YSBkYSBnZXJhw6fDo28gdMOpcm1pY2Egw6BzIHZhcmlhw6fDtWVzIG5hIGdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhLCBpbmNvcnBvcmFuZG8gYSBjb21wZXRpw6fDo28gY29tIG91dHJhcyBmb250ZXMgZSBvIGNpY2xvIHNhem9uYWwgZGUgZGVtYW5kYS4gTyBtb2RlbG8gYWRpdGl2byBnZW5lcmFsaXphZG8gKEdBTSkgZm9pIGFqdXN0YWRvIHBhcmEgbyBwZXLDrW9kbyAyMDAw4oCTMjAxOSwgY29tIGVzdHJ1dHVyYSBzZW1pcGFyYW3DqXRyaWNhIHF1ZSBwZXJtaXRlIGNhcHR1cmFyIHJlbGHDp8O1ZXMgbsOjbyBsaW5lYXJlcyBlbnRyZSBhcyBmb250ZXMgZGUgZ2VyYcOnw6NvIGUgc2V1cyBkZXRlcm1pbmFudGVzIHRlbXBvcmFpcy4NCk9zIHJlc3VsdGFkb3MgaW5kaWNhbSB1bWEgcmVsYcOnw6NvIG5lZ2F0aXZhIGUgZXN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIGVudHJlIGdlcmHDp8OjbyBoaWRyZWzDqXRyaWNhIGUgdMOpcm1pY2EsIGV2aWRlbmNpYW5kbyBvIHBhcGVsIGRhIHTDqXJtaWNhIGNvbW8gbWVjYW5pc21vIGRlIGNvbXBlbnNhw6fDo28gZHVyYW50ZSBwZXLDrW9kb3MgZGUgZXNjYXNzZXogaMOtZHJpY2EuIE8gZWZlaXRvIG1hcmdpbmFsIGRlIGdlcl9oaWRyb2VsZXRyaWNhIMOpIGZvcnRlbWVudGUgbsOjbyBsaW5lYXIsIGNvbSByZXNwb3N0YXMgbWFpcyBpbnRlbnNhcyBlbSBmYWl4YXMgaW50ZXJtZWRpw6FyaWFzIGRlIHJlZHXDp8OjbywgbyBxdWUgc3VnZXJlIHF1ZSBvIGRlc3BhY2hvIHTDqXJtaWNvIGF0aW5nZSBsaW1pdGVzIGVzdHJ1dHVyYWlzIGRlIGV4cGFuc8OjbyBlbSBhbm9zIGRlIHNlY2Egc2V2ZXJhLg0KDQpgYGB7cn0NCmxpYnJhcnkobWdjdikNCmxpYnJhcnkoZHBseXIpDQoNCiMgLS0tIFByZXBhcmHDp8OjbyBkb3MgZGFkb3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpnZXJhX2VuZXJnX2RheSA8LSBnZXJhX2VuZXJnX2RheSAlPiUNCiAgbXV0YXRlKA0KICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhICsgZ2VyX2ZvdG92b2x0YWljYSArIGdlcl9oaWRyb2VsZXRyaWNhICsgZ2VyX3Rlcm1pY2EgKyBnZXJfbnVjbGVhciwNCiAgICBtb250aCA9IGFzLm51bWVyaWMoZm9ybWF0KGRhdGUsICIlbSIpKSwNCiAgICB0cmVuZCA9IGFzLm51bWVyaWMoZGF0ZSAtIG1pbihkYXRlKSkgLyAzMCAgIyB0ZW5kw6puY2lhIGxpbmVhciBlbSBtZXNlcw0KICApDQoNCiMgLS0tIE1vZGVsbyBHQU0gMzogR2VyYcOnw6NvIFTDqXJtaWNhIGNvbW8gZnVuw6fDo28gZGEgSGlkcm8gKyBvdXRyYXMgZm9udGVzIC0tLS0tDQptM19nYW1fdGVybWljYSA8LSBiYW0oDQogIGdlcl90ZXJtaWNhIH4gDQogICAgcyhnZXJfaGlkcm9lbGV0cmljYSwgayA9IDQpICsgICAgIyBwcmluY2lwYWwgZWZlaXRvIHN1YnN0aXR1dGl2bw0KICAgIHMoZ2VyX2VvbGllbGV0cmljYSwgayA9IDQpICsNCiAgICBzKGdlcl9mb3Rvdm9sdGFpY2EsIGsgPSA0KSArDQogICAgcyhnZXJfbnVjbGVhciwgayA9IDMpICsNCiAgICBzKHRyZW5kLCBrID0gMykgKw0KICAgIHMobW9udGgsIGJzID0gImNjIiwgayA9IDQpICsgICAgICMgcGFkcsOjbyBzYXpvbmFsDQogICAgcyhub21fc3Vic2lzdGVtYSwgYnMgPSAicmUiKSwgICMgZWZlaXRvIGFsZWF0w7NyaW8gcG9yIHN1YnNpc3RlbWENCiAgZGF0YSA9IGdlcmFfZW5lcmdfZGF5LA0KICBtZXRob2QgPSAiZlJFTUwiLA0KICBkaXNjcmV0ZSA9IFRSVUUsDQogIGZhbWlseSA9IGdhdXNzaWFuKCksDQogIG5hLmFjdGlvbiA9IG5hLmV4Y2x1ZGUNCikNCg0Kc3VtbWFyeShtM19nYW1fdGVybWljYSkNCg0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShtM19nYW1fdGVybWljYSkNCmd0c3VtbWFyeTo6dGJsX3JlZ3Jlc3Npb24obTNfZ2FtX3Rlcm1pY2EpDQpzdW1tYXJ5KG0zX2dhbV90ZXJtaWNhKQ0KZ2FtLmNoZWNrKG0zX2dhbV90ZXJtaWNhKSAgICAgICAgICAjIHJlc8OtZHVvcywgUVEsIGstaW5kZXgNCmNvbmN1cnZpdHkobTNfZ2FtX3Rlcm1pY2EsIGZ1bGw9VFJVRSkNCnBsb3QobTNfZ2FtX3Rlcm1pY2EsIHBhZ2VzPTQsIHNjaGVtZT0xLCBzaGFkZT1UUlVFLCBzZT1UUlVFKQ0KYGBgDQoNCg0KJPCdkZTwnZGS8J2RnyDwnZGh8J2RkvCdkZ/wnZGa8J2RlvCdkZDwnZGOX/CdkaE98J2Rk18xKPCdkZTwnZGSX2jwnZGW8J2RkfCdkZ/wnZGcX/CdkaEpK/CdkZNfMijwnZGU8J2RkvCdkZ9f8J2RkvCdkZzwnZGZ8J2RlvCdkZDwnZGOX/CdkaEpK/CdkZNfMyjwnZGU8J2RkvCdkZ9f8J2RoPCdkZzwnZGZ8J2RjvCdkZ9f8J2RoSkrX/CdkZNfNCjwnZGU8J2RkvCdkZ9f8J2Rm/CdkaLwnZGQ8J2RmfCdkZLwnZGO8J2Rn/CdkaEpK/CdkZNfNSjwnZGh8J2Rn/CdkZLwnZGb8J2RkV/wnZGhKSvwnZGTXzYo8J2RmvCdkZzwnZGb8J2RoeKEjl/wnZGhKSvwnZGi8J2RoPCdkaLwnZGP8J2RoPCdkZbwnZGg8J2RofCdkZLwnZGa8J2RjivwnZyAJA0KKlF1YWxpZGFkZSBkbyBhanVzdGUqDQoNCk8gbW9kZWxvIGFwcmVzZW50YSBSwrIgYWp1c3RhZG8gZGUgMCw2NCBlIGRldmlhbmNlIGV4cGxpY2FkYSBkZSA2NCwxJSwgaW5kaWNhbmRvIGJvYSBjYXBhY2lkYWRlIHByZWRpdGl2YSBkaWFudGUgZGEgYWx0YSB2YXJpYWJpbGlkYWRlIGludGVyZGnDoXJpYS4gVG9kb3Mgb3MgZWZlaXRvcyBzdWF2ZXMgc8OjbyBhbHRhbWVudGUgc2lnbmlmaWNhdGl2b3MgKHAgPCAwLjAwMSksIGNvbSBleGNlw6fDo28gZG8gaW50ZXJjZXB0by4gTyBoaXN0b2dyYW1hIGUgbyBRUS1wbG90IGRvcyByZXPDrWR1b3MgbW9zdHJhbSBkaXN0cmlidWnDp8OjbyBhcHJveGltYWRhbWVudGUgbm9ybWFsLCBjb20gbGV2ZSBhc3NpbWV0cmlhIG5hcyBjYXVkYXMg4oCUIHJlZmxleG8gZGUgcGljb3MgZGUgZGVzcGFjaG8gdMOpcm1pY28gZW0gcGVyw61vZG9zIGRlIHNlY2Egc2V2ZXJhLg0KDQpPIGdyw6FmaWNvIOKAnFJlc8OtZHVvcyB2cy4gVmFsb3JlcyBBanVzdGFkb3PigJ0gcmV2ZWxhIGRpc3BlcnPDo28gY3Jlc2NlbnRlIGNvbSBvIGF1bWVudG8gZGEgZ2VyYcOnw6NvIHByZXZpc3RhLCBzdWdlcmluZG8gaGV0ZXJvY2VkYXN0aWNpZGFkZSBtb2RlcmFkYSBhc3NvY2lhZGEgYSByZWdpbWVzIGRpc3RpbnRvcyBkZSBvcGVyYcOnw6NvIChiYXNlIMOXIHBpY28pLiBBaW5kYSBhc3NpbSwgb3MgcmVzw61kdW9zIHPDo28gY2VudHJhZG9zIGUgc2VtIHBhZHLDo28gc2lzdGVtw6F0aWNvLCBjb25maXJtYW5kbyBhIGFkZXF1YcOnw6NvIGdlcmFsIGRhIGVzcGVjaWZpY2HDp8Ojby4NCg0KKkVmZWl0b3MgcGFyY2lhaXMqDQoNCk9zIGVmZWl0b3MgbWFyZ2luYWlzIGVzdGltYWRvcyBleGliZW0gY29tcG9ydGFtZW50b3MgY29lcmVudGVzIGNvbSBhIGzDs2dpY2EgZsOtc2ljYSBkbyBzaXN0ZW1hOg0KDQotIHMoZ2VyX2hpZHJvZWxldHJpY2EpIOKGkiBmb3J0ZSByZWxhw6fDo28gaW52ZXJzYSBlIG7Do28gbGluZWFyOiByZWR1w6fDtWVzIG5hIGdlcmHDp8OjbyBow61kcmljYSBhdW1lbnRhbSBhIGdlcmHDp8OjbyB0w6lybWljYSwgZXNwZWNpYWxtZW50ZSBlbSBmYWl4YXMgaW50ZXJtZWRpw6FyaWFzIGRlIG9wZXJhw6fDo28gKHN1YnN0aXR1acOnw6NvIGVzdHJ1dHVyYWwpLiBFbSBuw612ZWlzIGV4dHJlbW9zLCBvIGVmZWl0byBzZSBlc3RhYmlsaXphLCBpbmRpY2FuZG8gbGltaXRlIGRlIGRlc3BhY2hvIHTDqXJtaWNvLg0KDQotcyhnZXJfZW9saWVsZXRyaWNhKSBlIHMoZ2VyX2ZvdG92b2x0YWljYSkg4oaSIGFtYmFzIGFwcmVzZW50YW0gZWZlaXRvcyBzdWJzdGl0dXRpdm9zIG5lZ2F0aXZvcywgZXZpZGVuY2lhbmRvIG8gcGFwZWwgZGFzIHJlbm92w6F2ZWlzIG5hIG1pdGlnYcOnw6NvIGRvIHVzbyB0w6lybWljby4NCg0KLSBzKGdlcl9udWNsZWFyKSDihpIgcmVsYcOnw6NvIGxldmVtZW50ZSBjw7RuY2F2YSwgZXN0w6F2ZWwsIHJlZmxldGluZG8gZGVzcGFjaG8gcHJhdGljYW1lbnRlIGZpeG8uDQoNCi0gcyh0cmVuZCkg4oaSIHRlbmTDqm5jaWEgYXNjZW5kZW50ZSwgaW5kaWNhbmRvIGF1bWVudG8gZ3JhZHVhbCBkYSBiYXNlIHTDqXJtaWNhIG5vIGxvbmdvIHByYXpvLCBjb2VyZW50ZSBjb20gYSBleHBhbnPDo28gZGUgdGVybWVsw6l0cmljYXMgZW50cmUgMjAwNeKAkzIwMTUuDQoNCi0gcyhtb250aCkg4oaSIHBhZHLDo28gcXVhc2UgcGxhbm8sIGNvbSBmcmFjYSBzYXpvbmFsaWRhZGUgcmVzaWR1YWwgYXDDs3MgbyBjb250cm9sZSBoaWRyb2zDs2dpY28uDQoNCi0gRWZlaXRvIGFsZWF0w7NyaW8gKG5vbV9zdWJzaXN0ZW1hKSDihpIgbyBhanVzdGUgY29uZmlybWEgZGlmZXJlbsOnYXMgZXN0cnV0dXJhaXMgcmVnaW9uYWlzOiBzdWJzaXN0ZW1hcyBkbyBTdWRlc3RlIGUgU3VsIGV4aWJlbSBtYWlvciBpbnRlbnNpZGFkZSB0w6lybWljYSByZWxhdGl2YSBxdWUgTm9ydGUgZSBOb3JkZXN0ZS4NCg0KKlPDrW50ZXNlKg0KTyBtb2RlbG8gY29uZmlybWEgbyBwYXBlbCBjb250cmFjw61jbGljbyBkYSBnZXJhw6fDo28gdMOpcm1pY2Egbm8gc2lzdGVtYSBlbMOpdHJpY28gYnJhc2lsZWlybzoNCnF1YW5kbyBvIGNsaW1hIHJlZHV6IGEgZ2VyYcOnw6NvIGjDrWRyaWNhLCBhIHJlc3Bvc3RhIHTDqXJtaWNhIGNvbXBlbnNhIHBhcnRlIGRvIGTDqWZpY2l0LCBjb20gc2Vuc2liaWxpZGFkZSBuw6NvIGxpbmVhciBlIGxpbWl0ZXMgb3BlcmFjaW9uYWlzIGRlZmluaWRvcy4NCg0KQSBlc3RydXR1cmEgc3Vhdml6YWRhIGRvcyBlZmVpdG9zIHBlcm1pdGUgcXVhbnRpZmljYXIgYSBlbGFzdGljaWRhZGUgbWFyZ2luYWwgZW50cmUgZm9udGVzLCBxdWUgc2Vyw6EgdXNhZGEgbmEgcHLDs3hpbWEgZXRhcGEgcGFyYSBlc3RpbWFyIGEgcGVuYWxpZGFkZSB0w6lybWljYSBwcm9wYWdhZGEgKM6UR190ZXJtKSByZXN1bHRhbnRlIGRhIHBlbmFsaWRhZGUgaMOtZHJpY2EgKM6UR19oaWRybykgb2J0aWRhIG5vIE1vZGVsbyANCg0KDQojIyBQcmVkacOnw7VlcyBmYWN0dWFsIHZzLiBjb250cmFmYWN0dWFsIChwcm9wYWdhw6fDo28gZGUgaW5jZXJ0ZXphKQ0KDQoNCmBgYHtyfQ0KIyAtLS0gUHJlZGnDp8O1ZXMgZmFjdHVhbCBlIGNvbnRyYWZhY3R1YWwgLS0tDQpzZXQuc2VlZCgyMDI1MTAxMykNCm5zaW0gPC0gNTAgICMgbsO6bWVybyBkZSBzaW11bGHDp8O1ZXMgY29uanVudGFzDQoNCiMgLS0tIDEuIE1hdHJpeiBkZSBjb3ZhcmnDom5jaWEgZGUgY2FkYSBtb2RlbG8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIC0tLSBDb3ZhcmnDom5jaWFzIGUgc29ydGVpb3MgZGUgY29lZmljaWVudGVzIC0tLQ0KVnAxIDwtIHZjb3YobTFfZ2FtKSAgICAgICAgICAgICAgICAgICMgTTE6IEVBUiB+IGNsaW1hDQpWcDIgPC0gdmNvdihtMl9oaWRybykgICAgICAgICAgICAgICAgIyBNMjogR19oaWRybyB+IEVBUg0KVnAzIDwtIHZjb3YobTNfZ2FtX3Rlcm1pY2EpICAgICAgICAgICMgTTM6IEdfdGVybSB+IEdfaGlkcm8gKyBjb250cm9sZXMNCg0KYjEgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0xX2dhbSksICAgICAgICAgVnAxKQ0KYjIgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0yX2hpZHJvKSwgICAgICAgVnAyKQ0KYjMgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0zX2dhbV90ZXJtaWNhKSwgVnAzKQ0KIyAtLS0gMi4gTWF0cml6ZXMgZGUgZGVzaWduIGRvIG1vZGVsbyAxIChjbGltYSDihpIgRUFSKSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KWDFfb2JzIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfb2JzLCB0eXBlID0gImxwbWF0cml4IikNClgxX2NmICA8LSBwcmVkaWN0KG0xX2dhbSwgbmV3ZGF0YSA9IG5kX2NmLCAgdHlwZSA9ICJscG1hdHJpeCIpDQpkZWx0YV9HdGVybV9tYXQgIDwtIG1hdHJpeChOQV9yZWFsXywgbnJvdyA9IG5yb3coZ2VyYV9lbmVyZ19kYXkpLCBuY29sID0gbnNpbSkNCg0KIyBQcmVwYXJhIGNoYXZlcyBwYXJhIGFncmVnYcOnw6NvIE0y4oaSTTMNCmtleXNfbTIgPC0gcmVzZXJ2ICU+JSBzZWxlY3QoZGF0ZSwgbm9tX3N1YnNpc3RlbWEueCkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0Ka2V5c19tMyA8LSBnZXJhX2VuZXJnX2RheSAlPiUgc2VsZWN0KGRhdGUsIG5vbV9zdWJzaXN0ZW1hKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQojIC0tLSA1LiBMb29wIHByaW5jaXBhbCBkZSBwcm9wYWdhw6fDo28gTW9udGUgQ2FybG8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmZvciAocyBpbiBzZXFfbGVuKG5zaW0pKSB7DQogICMgPT09PT0gKDEpIEVBUiBmYWN0dWFsIGUgY29udHJhZmFjdHVhbCAoTTEpIG5vIG7DrXZlbCBkZSByZXNlcnZhdMOzcmlvw5dkaWENCiAgZWFyX2YgPC0gYXMubnVtZXJpYyhYMV9vYnMgJSolIGIxW3MsIF0pDQogIGVhcl9jIDwtIGFzLm51bWVyaWMoWDFfY2YgICUqJSBiMVtzLCBdKQ0KDQogICMgPT09PT0gKDIpIFByZWRpw6fDo28gZGUgR19oaWRybyBmYWN0dWFsIGUgY2YgKE0yKSBubyBuw612ZWwgZGUgcmVzZXJ2YXTDs3Jpb8OXZGlhDQogIG5kMl9mIDwtIHJlc2VydiAlPiUgbXV0YXRlKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzID0gZWFyX2YpDQogIG5kMl9jIDwtIHJlc2VydiAlPiUgbXV0YXRlKGVhcl9yZXNlcnZhdG9yaW9fc3Vic2lzdGVtYV9wcm9wcmlvX213bWVzID0gZWFyX2MpDQoNCiAgWDJfZiA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gbmQyX2YsIHR5cGUgPSAibHBtYXRyaXgiKQ0KICBYMl9jIDwtIHByZWRpY3QobTJfaGlkcm8sIG5ld2RhdGEgPSBuZDJfYywgdHlwZSA9ICJscG1hdHJpeCIpDQoNCiAgZ19oX2ZfcmVzIDwtIGFzLm51bWVyaWMoWDJfZiAlKiUgYjJbcywgXSkgICMgcG9yIHJlc2VydmF0w7NyaW/Dl2RpYQ0KICBnX2hfY19yZXMgPC0gYXMubnVtZXJpYyhYMl9jICUqJSBiMltzLCBdKQ0KDQogICMgPT09PT0gKDMpIEFncmVnYXIgR19oaWRybyBwb3Igc3Vic2lzdGVtYcOXZGlhIChwYXJhIGFsaW1lbnRhciBNMykNCiAgZGZfaCA8LSBkYXRhLmZyYW1lKGRhdGUgPSBrZXlzX20yJGRhdGUsDQogICAgICAgICAgICAgICAgICAgICBzdWJzID0ga2V5c19tMiRub21fc3Vic2lzdGVtYS54LA0KICAgICAgICAgICAgICAgICAgICAgZ19oX2YgPSBnX2hfZl9yZXMsDQogICAgICAgICAgICAgICAgICAgICBnX2hfYyA9IGdfaF9jX3JlcykNCg0KICBnX2hfYWdnIDwtIGRmX2ggfD4NCiAgICBncm91cF9ieShkYXRlLCBzdWJzKSB8Pg0KICAgIHN1bW1hcmlzZShnX2hfZiA9IHN1bShnX2hfZiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgICAgZ19oX2MgPSBzdW0oZ19oX2MsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpDQoNCiAgIyDOlEdfaGlkcm9fY2xpbWEgKHN1YnNpc3RlbWHDl2RpYSkNCiAgZ19oX2FnZyA8LSBnX2hfYWdnIHw+DQogICAgbXV0YXRlKGRlbHRhX2dfaGlkcm9fY2xpbWEgPSBnX2hfZiAtIGdfaF9jKQ0KDQogICMgPT09PT0gKDQpIENvbnN0cnVpciBpbnB1dCBkbyBNMw0KICAjIGZhY3R1YWw6IHVzYSBhIGhpZHJlbMOpdHJpY2Egb2JzZXJ2YWRhIChnZXJhX2VuZXJnX2RheSRnZXJfaGlkcm9lbGV0cmljYSkNCiAgIyBjb250cmFmYWN0dWFsOiBvYnMg4oiSIM6UR19oaWRyb19jbGltYQ0KICBuZDMgPC0gZ2VyYV9lbmVyZ19kYXkgfD4NCiAgICBsZWZ0X2pvaW4oZ19oX2FnZywNCiAgICAgICAgICAgICAgYnkgPSBjKCJkYXRlIiA9ICJkYXRlIiwgIm5vbV9zdWJzaXN0ZW1hIiA9ICJzdWJzIikpDQoNCiAgIyBzZSBmYWx0YXIgc3Vic2lzdGVtYSBlbSBhbGd1bSBkaWEsIHRyYXRhIE5BIGNvbW8gMCBkZWx0YQ0KICBuZDMkZGVsdGFfZ19oaWRyb19jbGltYVtpcy5uYShuZDMkZGVsdGFfZ19oaWRyb19jbGltYSldIDwtIDANCg0KICBnX2hfb2JzIDwtIG5kMyRnZXJfaGlkcm9lbGV0cmljYQ0KICBnX2hfY2ZNMyA8LSBnX2hfb2JzIC0gbmQzJGRlbHRhX2dfaGlkcm9fY2xpbWEjIGNsaXBwaW5nIGVtIDANCg0KICBuZDNfZiA8LSBuZDMgJT4lIG11dGF0ZShnZXJfaGlkcm9lbGV0cmljYSA9IGdfaF9vYnMpICAgIyBmYWN0dWFsIChvYnNlcnZhZG8pDQogIG5kM19jIDwtIG5kMyAlPiUgbXV0YXRlKGdlcl9oaWRyb2VsZXRyaWNhID0gZ19oX2NmTTMpICAjIGNvbnRyYWZhY3R1YWwgKG9icyDiiJIgzpRjbGltYSkNCg0KICAjID09PT09ICg1KSBQcmVkacOnw6NvIHTDqXJtaWNhIGZhY3R1YWwgZSBjZiAoTTMpIG5vIG7DrXZlbCBzdWJzaXN0ZW1hw5dkaWENCiAgWDNfZiA8LSBwcmVkaWN0KG0zX2dhbV90ZXJtaWNhLCBuZXdkYXRhID0gbmQzX2YsIHR5cGUgPSAibHBtYXRyaXgiKQ0KICBYM19jIDwtIHByZWRpY3QobTNfZ2FtX3Rlcm1pY2EsIG5ld2RhdGEgPSBuZDNfYywgdHlwZSA9ICJscG1hdHJpeCIpDQoNCiAgZ190X2YgPC0gYXMubnVtZXJpYyhYM19mICUqJSBiM1tzLCBdKQ0KICBnX3RfYyA8LSBhcy5udW1lcmljKFgzX2MgJSolIGIzW3MsIF0pDQoNCiAgZGVsdGFfR3Rlcm1fbWF0Wywgc10gPC0gZ190X2YgLSBnX3RfYw0KICBwcmludChzKQ0KfQ0KDQpgYGANCmBgYHtyfQ0KZGVsdGFfR3Rlcm1fbWF0ICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIHNldE5hbWVzKHBhc3RlMCgic2ltXyIsIHNlcV9sZW4obnNpbSkpKSAlPiUNCiAgYmluZF9jb2xzKGdlcmFfZW5lcmdfZGF5WywgYygiZGF0ZSIsICJub21fc3Vic2lzdGVtYSIpXSkgJT4lIA0KICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInNpbV8iKSwgdmFsdWVzX3RvID0gImRlbHRhX0dfdGVybSIpICU+JQ0KICBtdXRhdGUoeWVhciA9IGx1YnJpZGF0ZTo6eWVhcihkYXRlKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyLA0KICAgICAgICAgICBub21fc3Vic2lzdGVtYSxuYW1lKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGRlbHRhX1Rfc3VtID0gc3VtKC1kZWx0YV9HX3Rlcm0sIG5hLnJtID0gVFJVRSksDQogICAgI2RlbHRhX1RfbHdyICA9IHF1YW50aWxlKGRlbHRhX0dfdGVybSwgMC4wNSwgbmEucm0gPSBUUlVFKSwNCiAgICAjZGVsdGFfVF91cHIgID0gcXVhbnRpbGUoZGVsdGFfR190ZXJtLCAwLjk1LCBuYS5ybSA9IFRSVUUpLA0KICAgICNkZWx0YV9UX3NkICAgPSBzZChkZWx0YV9HX3Rlcm0sIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApICU+JSBncm91cF9ieSh5ZWFyLA0KICAgIG5vbV9zdWJzaXN0ZW1hKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGRlbHRhX1RfbWVhbiA9IG1lYW4oZGVsdGFfVF9zdW0sIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfVF9sd3IgID0gcXVhbnRpbGUoZGVsdGFfVF9zdW0sIDAuMDUsIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfVF91cHIgID0gcXVhbnRpbGUoZGVsdGFfVF9zdW0sIDAuOTUsIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfVF9zZCAgID0gc2QoZGVsdGFfVF9zdW0sIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApICAtPiBtM190ZXJtX3N1bW1hcnlfbTNfYW5udWFsDQptM190ZXJtX3N1bW1hcnlfbTNfYW5udWFsDQptM190ZXJtX3N1bW1hcnlfbTNfYW5udWFsJGRlbHRhX1RfbWVhbiAlPiUgbWVhbiggbmEucm0gPSBUUlVFKQ0KbTNfdGVybV9zdW1tYXJ5X20zX2FubnVhbCRkZWx0YV9UX21lYW4gJT4lIHNkKCBuYS5ybSA9IFRSVUUpDQptM190ZXJtX3N1bW1hcnlfbTNfYW5udWFsJGRlbHRhX1Rfc2QgJT4lIHNkKCBuYS5ybSA9IFRSVUUpDQoNCmdncGxvdChtM190ZXJtX3N1bW1hcnlfbTNfYW5udWFsLCBhZXMoeCA9IHllYXIsIHkgPSBkZWx0YV9UX21lYW4pKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gZGVsdGFfVF9sd3IsIHltYXggPSBkZWx0YV9UX3VwciksZmlsbD0icmVkIiwgYWxwaGEgPSAwLjM1KSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gZGVsdGFfVF9tZWFuLCB5bWF4ID0gMCksIGFscGhhID0gMC4zNSkgKw0KICANCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH4gbm9tX3N1YnNpc3RlbWEsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUGVuYWxpZGFkZSBjbGltw6F0aWNhIHByb3BhZ2FkYSBuYSBnZXJhw6fDo28gdMOpcm1pY2EgKM6UR190ZXJtKSIsDQogICAgc3VidGl0bGUgPSBwYXN0ZSgiTcOpdG9kbzoiLCAiPyIsICJ8IG5zaW0gPSIsIG5zaW0pLA0KICAgIHggPSAiVHJpbWVzdHJlIiwgeSA9ICLOlEdfdGVybSAoTVfCt23DqnMpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQojIyMjDQoNCg0KDQpgYGB7cn0NCmRlbHRhX0d0ZXJtX21hdCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBzZXROYW1lcyhwYXN0ZTAoInNpbV8iLCBzZXFfbGVuKG5zaW0pKSkgJT4lDQogIGJpbmRfY29scyhnZXJhX2VuZXJnX2RheVssIGMoImRhdGUiLCAibm9tX3N1YnNpc3RlbWEiKV0pICU+JSANCiAgcGl2b3RfbG9uZ2VyKHN0YXJ0c193aXRoKCJzaW1fIiksIHZhbHVlc190byA9ICJkZWx0YV9HX3Rlcm0iKSAlPiUNCiAgbXV0YXRlKHllYXIgPSBsdWJyaWRhdGU6OnllYXIoZGF0ZSkpICU+JSANCiAgZ3JvdXBfYnkoDQogICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hLG5hbWUpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgZGVsdGFfVF9zdW0gPSBzdW0oLWRlbHRhX0dfdGVybSwgbmEucm0gPSBUUlVFKSwNCiAgICAjZGVsdGFfVF9sd3IgID0gcXVhbnRpbGUoZGVsdGFfR190ZXJtLCAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgICNkZWx0YV9UX3VwciAgPSBxdWFudGlsZShkZWx0YV9HX3Rlcm0sIDAuOTUsIG5hLnJtID0gVFJVRSksDQogICAgI2RlbHRhX1Rfc2QgICA9IHNkKGRlbHRhX0dfdGVybSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lIGdyb3VwX2J5KA0KICAgICAgICAgICAgICAgICBub21fc3Vic2lzdGVtYSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBkZWx0YV9UX21lYW4gPSBtZWFuKGRlbHRhX1Rfc3VtLCBuYS5ybSA9IFRSVUUpLA0KICAgIGRlbHRhX1RfbHdyICA9IHF1YW50aWxlKGRlbHRhX1Rfc3VtLCAwLjAyNSwgbmEucm0gPSBUUlVFKSwNCiAgICBkZWx0YV9UX3VwciAgPSBxdWFudGlsZShkZWx0YV9UX3N1bSwgMC45MjUsIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfVF9zZCAgID0gc2QoZGVsdGFfVF9zdW0sIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApICAtPiBtM190ZXJtX3N1bW1hcnlfbTNfcG9yc3Vic2lzdGVtYQ0KDQpsaWJyYXJ5KGd0KQ0KbTNfdGVybV9zdW1tYXJ5X20zX3BvcnN1YnNpc3RlbWFbLGMoIm5vbV9zdWJzaXN0ZW1hIiwiZGVsdGFfVF9tZWFuIiwiZGVsdGFfVF9sd3IiLCAiZGVsdGFfVF91cHIiKV0gJT4lIGphbml0b3I6OmFkb3JuX3RvdGFscygpICU+JSANCiAgZ3QoKSAlPiUNCiAgZm10X251bWJlcihjb2x1bW5zID0gMjo0LCBkZWNpbWFscyA9IDEpICU+JQ0KICBjb2xzX2xhYmVsKA0KICAgIG5vbV9zdWJzaXN0ZW1hID0gIlN1YnN5c3RlbSIsDQogICAgZGVsdGFfVF9tZWFuID0gIlN1bSDOlGdlciBUZXJtIChNV2gpIiwNCiAgICBkZWx0YV9UX2x3ciAgPSAiTG93ZXIgOTUlIiwNCiAgICBkZWx0YV9UX3VwciAgPSAiVXBwZXIgOTUlIiwNCiAgKSAlPiUNCiAgdGFiX2hlYWRlcigNCiAgICB0aXRsZSA9IG1kKCIqKkFnZ3JlZ2F0ZSBjbGltYXRlIHBlbmFsdHkgb24gc3RvcmVkIGVuZXJneSAoMjAwMeKAkzIwMTgpKioiKSwNCiAgICBzdWJ0aXRsZSA9ICJTaW11bGF0ZWQgbWVhbiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHBlciBzdWJzeXN0ZW0iDQogICkNCmBgYA0KDQoNCg0KDQoNCg0KIzMuNCBNb2RlbG8gMyBQTEQ6IEN1c3RvIHBhcmEgbyBzaXN0ZW1hDQpgYGB7cn0NCnBsZCAgICAgPC0gcmVhZC5jc3YoInByZWNvX3NlbWFuYWwuY3N2IikgICAgICAgICAgICMgUExEIHNlbWFuYWwNCnBsZCRkYXRlIDwtIGFzLkRhdGUocGxkJERBVEFfSU5JQ0lPKSAgICMgaWRlbSBwYXJhIGEgYmFzZSBkZSBQTEQNCnBsZCR3ZWVrICA8LSBsdWJyaWRhdGU6Omlzb3dlZWsocGxkJGRhdGUpDQpwbGQkeWVhciAgPC0gbHVicmlkYXRlOjp5ZWFyKHBsZCRkYXRlKQ0KYGBgDQoNCmBgYHtyfQ0KDQojcGxkJGRhdGU8LXBsZCREQVRBX0lOSUNJTyAlPiUgYXNfZGF0ZSgpIA0KcGxkICU+JSBzcHJlYWQoU3VibWVyY2FkbyxwcmVjbyktPnBsZA0KcGxkJGRhdGUgJT4lIG1pbigpLT5pbmljaW8NCnBsZCAlPiUgZmlsdGVyKERBVEFfSU5JQ0lPPT1pbmljaW8pDQpkYXRhczwtZ2VyYV9lbmVyZ19kYXkkZGF0ZSAlPiUgdW5pcXVlDQpkYXRhLmZyYW1lKGRhdGFzKSAlPiUgZmlsdGVyKGRhdGFzPmluaWNpby0xKSAlPiUgYXJyYW5nZShkYXRhcykgJT4lIGxlZnRfam9pbihwbGQsYnkgPSBjKCJkYXRhcyI9ImRhdGUiKSktPmRhYXNfY29tcGxldGFzDQpkYWFzX2NvbXBsZXRhcw0KaT0yDQpmb3IgKGkgaW4gMTpsZW5ndGgoZGFhc19jb21wbGV0YXMkQU5PKSkgeyNsZW5ndGgoZGFhc19jb21wbGV0YXMkQU5PKQ0KICBwcmludChpKQ0KICBpZiAoaXMubmEoZGFhc19jb21wbGV0YXMkQU5PW2ldKSkgew0KICAgIGRhYXNfY29tcGxldGFzJEFOT1tpXTwtZGFhc19jb21wbGV0YXMkQU5PW2ktMV0NCiAgICBkYWFzX2NvbXBsZXRhcyRNRVNbaV08LWRhYXNfY29tcGxldGFzJE1FU1tpLTFdDQogICAgZGFhc19jb21wbGV0YXMkU0VNQU5BW2ldPC1kYWFzX2NvbXBsZXRhcyRTRU1BTkFbaS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJERBVEFfRklNW2ldPC1kYWFzX2NvbXBsZXRhcyREQVRBX0ZJTVtpLTFdDQogICAgZGFhc19jb21wbGV0YXMkU1VERVNURVtpXTwtZGFhc19jb21wbGV0YXMkU1VERVNURVtpLTFdDQogICAgZGFhc19jb21wbGV0YXMkU1VMW2ldPC1kYWFzX2NvbXBsZXRhcyRTVUxbaS0xXQ0KICAgIGRhYXNfY29tcGxldGFzJE5PUkRFU1RFW2ldPC1kYWFzX2NvbXBsZXRhcyROT1JERVNURVtpLTFdDQogICAgZGFhc19jb21wbGV0YXMkTk9SVEVbaV08LWRhYXNfY29tcGxldGFzJE5PUlRFW2ktMV0NCg0KICAgIA0KICB9DQogIA0KfSAgDQpkYWFzX2NvbXBsZXRhcyAlPiUgZ2F0aGVyKGtleSA9ICJub21fc3Vic2l0ZW1hIix2YWx1ZSA9ICJwcmVjbyIsYygiTk9SREVTVEUiLCJTVURFU1RFIiwiU1VMIiwiTk9SVEUiKSktPnBsZA0Kd3JpdGVfY3N2KHBsZCwicGxkX2RpYXJpb19jb21wbGV0by5jc3YiLHJvdy5uYW1lcyA9IEYpDQpgYGANCg0KYGBge3J9DQpzZXJpZSA8LSBkYWFzX2NvbXBsZXRhcyAlPiUNCiAgcHVsbChOT1JERVNURSkgJT4lDQogIHRzKHN0YXJ0ID0gIGMoMjAwMSwgMTgxKSwgZnJlcXVlbmN5ID0gMzY1KQ0Kc3RsKHNlcmllLHMud2luZG93ID0gInBlcmlvZGljIikgJT4lIHBsb3QNCg0Kc2VyaWUgPC0gZGFhc19jb21wbGV0YXMgJT4lDQogIHB1bGwoU1VMKSAlPiUNCiAgdHMoc3RhcnQgPSAgYygyMDAxLCAxODEpLCBmcmVxdWVuY3kgPSAzNjUpDQpzdGwoc2VyaWUscy53aW5kb3cgPSAicGVyaW9kaWMiKSAlPiUgcGxvdA0KDQpzZXJpZSA8LSBkYWFzX2NvbXBsZXRhcyAlPiUNCiAgcHVsbChTVURFU1RFKSAlPiUNCiAgdHMoc3RhcnQgPSAgYygyMDAxLCAxODEpLCBmcmVxdWVuY3kgPSAzNjUpDQpzdGwoc2VyaWUscy53aW5kb3cgPSAicGVyaW9kaWMiKSAlPiUgcGxvdA0KDQpzZXJpZSA8LSBkYWFzX2NvbXBsZXRhcyAlPiUNCiAgcHVsbChOT1JURSkgJT4lDQogIHRzKHN0YXJ0ID0gIGMoMjAwMSwgMTgxKSwgZnJlcXVlbmN5ID0gMzY1KQ0Kc3RsKHNlcmllLHMud2luZG93ID0gInBlcmlvZGljIikgJT4lIHBsb3QNCg0KDQpgYGANCg0KYGBge3J9DQpwbGQkU3VibWVyY2FkbyAlPiUgdW5pcXVlKCkNCmdlcmFfZW5lcmdfZGF5JG5vbV9zdWJzaXN0ZW1hLnggJT4lIHVuaXF1ZQ0KDQojbmV3ZGF0YV9tMSAlPiUgd3JpdGUuY3N2KCJiYXNlIHZhbG9yZXMgcHJldmlzdG9zLmNzdiIpDQojZ2VyYV9lbmVyZ19kYXkgJT4lIHdyaXRlLmNzdigidmFsb3Jlc19wcmV2aXN0b3NfZGF5LmNzdiIpDQpgYGANCg0KYGBge3J9DQpnZXJhX2VuZXJnX2RheSAlPiUgaW5uZXJfam9pbihwbGQsYnk9YygiZGF0ZSI9ImRhdGFzIiwibm9tX3N1YnNpc3RlbWEiPSJub21fc3Vic2l0ZW1hIikpLT5wbGRfZnVsbA0Kd3JpdGUuY3N2KHBsZF9mdWxsLCJwbGRfZnVsbC5jc3YiKQ0KcGxkX2Z1bGwgJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCg0KIyMjIE1vZGVsbyBQTEQNCg0KYGBge3J9DQpwbGRfZnVsbCAlPiUNCiAgICAgICAgICAgICAgICAgbXV0YXRlKA0KICAgICAgICAgICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhID0gaWZlbHNlKGdlcl9oaWRyb2VsZXRyaWNhID09IDAsIDEsIGdlcl9oaWRyb2VsZXRyaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZm90b3ZvbHRhaWNhID0gaWZlbHNlKGdlcl9mb3Rvdm9sdGFpY2EgPT0gMCwgMSwgZ2VyX2ZvdG92b2x0YWljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX2VvbGllbGV0cmljYSA9IGlmZWxzZShnZXJfZW9saWVsZXRyaWNhID09IDAsIDEsIGdlcl9lb2xpZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl90ZXJtaWNhID0gaWZlbHNlKGdlcl90ZXJtaWNhID09IDAsIDEsIGdlcl90ZXJtaWNhKSwNCiAgICAgICAgICAgICAgICAgICAjRGVtYW5kYSA9IGlmZWxzZSh2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSA9PSAwLCAxLCB2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSkNCiAgICAgICAgICAgICAgICAgICBEZW1hbmRhID0gZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9oaWRyb2VsZXRyaWNhK2dlcl90ZXJtaWNhK2dlcl9udWNsZWFyLA0KICAgICAgICAgICAgICAgICApLT5wbGRfZnVsbDINCmdhbV80X3BsZCA8LSBnYW0ocHJlY28gfiAjdHJlbmQrDQogICAgICAgICAgICAgICAgIHMobG9nKGdlcl9oaWRyb2VsZXRyaWNhKSkgKyANCiAgICAgICAgICAgICAgICAgcyhsb2codHJlbmQpKSArICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBzKGxvZyhkb3kpKSsNCiAgICAgICAgICAgICAgICAgcyhsb2coZ2VyX2VvbGllbGV0cmljYSkpICsgDQogICAgICAgICAgICAgICAgIHMobG9nKGdlcl9mb3Rvdm9sdGFpY2EpKSArIA0KICAgICAgICAgICAgICAgICBzKGxvZyhEZW1hbmRhKSkgKyANCiAgICAgICAgICAgICAgICAgcyhsb2coZ2VyX3Rlcm1pY2EpKSsNCiAgICAgICAgICAgICAgICAgI3Mobm9tX3N1YnNpc3RlbWEueCwgYnMgPSAicmUiKSwjIGVmZWl0byBhbGVhdMOzcmlvIHBvciByZXNlcnZhdMOzcmlvDQogICAgICAgICAgICAgICAgIG5vbV9zdWJzaXN0ZW1hLA0KICAgICAgICAgICAgICAgZGF0YSA9IHBsZF9mdWxsMikNCg0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShnYW1fNF9wbGQpDQoNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoZ2FtXzRfcGxkKQ0KZ3RzdW1tYXJ5Ojp0YmxfcmVncmVzc2lvbihnYW1fNF9wbGQpDQpzdW1tYXJ5KGdhbV80X3BsZCkNCmdhbS5jaGVjayhnYW1fNF9wbGQpICAgICAgICAgICMgcmVzw61kdW9zLCBRUSwgay1pbmRleA0KY29uY3Vydml0eShnYW1fNF9wbGQsIGZ1bGw9VFJVRSkNCnBsb3QoZ2FtXzRfcGxkLCBwYWdlcz00LCBzY2hlbWU9MSwgc2hhZGU9VFJVRSwgc2U9VFJVRSkNCmBgYA0KDQoNCg0KDQoNCmBgYHtyfQ0KIyAtLS0gUHJlZGnDp8O1ZXMgZmFjdHVhbCBlIGNvbnRyYWZhY3R1YWwgLS0tDQpzZXQuc2VlZCgyMDI1MTAxMykNCm5zaW0gPC0gNTAgICMgbsO6bWVybyBkZSBzaW11bGHDp8O1ZXMgY29uanVudGFzDQoNCiMgLS0tIDEuIE1hdHJpeiBkZSBjb3ZhcmnDom5jaWEgZGUgY2FkYSBtb2RlbG8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIC0tLSBDb3ZhcmnDom5jaWFzIGUgc29ydGVpb3MgZGUgY29lZmljaWVudGVzIC0tLQ0KVnAxIDwtIHZjb3YobTFfZ2FtKSAgICAgICAgICAgICAgICAgICMgTTE6IEVBUiB+IGNsaW1hDQpWcDIgPC0gdmNvdihtMl9oaWRybykgICAgICAgICAgICAgICAgIyBNMjogR19oaWRybyB+IEVBUg0KVnAzIDwtIHZjb3YobTNfZ2FtX3Rlcm1pY2EpICAgICAgICAgICMgTTM6IEdfdGVybSB+IEdfaGlkcm8gKyBjb250cm9sZXMNClZwNCA8LSB2Y292KGdhbV80X3BsZCkgICAgICAgICAgICAgICMgTTM6IFByZcOnbyB+IEdfaGlkcm8gKyBHX3Rlcm0gKyBjb250cm9sZXMNCg0KYjEgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0xX2dhbSksICAgICAgICAgVnAxKQ0KYjIgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0yX2hpZHJvKSwgICAgICAgVnAyKQ0KYjMgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKG0zX2dhbV90ZXJtaWNhKSwgVnAzKQ0KYjQgPC0gTUFTUzo6bXZybm9ybShuc2ltLCBjb2VmKGdhbV80X3BsZCksIFZwNCkNCmBgYA0KDQoNCmBgYHtyfQ0KIyAtLS0gMi4gTWF0cml6ZXMgZGUgZGVzaWduIGRvIE0xIChjbGltYSDihpIgRUFSKSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpYMV9vYnMgPC0gcHJlZGljdChtMV9nYW0sIG5ld2RhdGEgPSBuZF9vYnMsIHR5cGUgPSAibHBtYXRyaXgiKQ0KWDFfY2YgIDwtIHByZWRpY3QobTFfZ2FtLCBuZXdkYXRhID0gbmRfY2YsICB0eXBlID0gImxwbWF0cml4IikNCmBgYA0KDQoNCmBgYHtyfQ0KIyAtLS0gMy4gUHJlcGFyYcOnw6NvIGRlIGJhc2VzIGUgbWF0cml6ZXMgZGUgc2HDrWRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KZGVsdGFfUExEX21hdCA8LSBtYXRyaXgoTkFfcmVhbF8sIG5yb3cgPSBucm93KHBsZF9mdWxsMiksIG5jb2wgPSBuc2ltKQ0KDQprZXlzX20yIDwtIHJlc2VydiAlPiUgc2VsZWN0KGRhdGUsIG5vbV9zdWJzaXN0ZW1hLngpICU+JSBhcy5kYXRhLmZyYW1lKCkNCmtleXNfbTMgPC0gZ2VyYV9lbmVyZ19kYXkgJT4lIHNlbGVjdChkYXRlLCBub21fc3Vic2lzdGVtYSkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0Ka2V5c19tNCA8LSBwbGRfZnVsbDIgJT4lIHNlbGVjdChkYXRlLCBub21fc3Vic2lzdGVtYSkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQpgYGANCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgLS0tIDQuIExvb3AgcHJpbmNpcGFsIGRlIHByb3BhZ2HDp8OjbyBNb250ZSBDYXJsbyAtLS0tLS0tLS0tDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCmZvciAocyBpbiBzZXFfbGVuKG5zaW0pKSB7DQoNCiAgIyA9PT09PSAoMSkgRUFSIGZhY3R1YWwgZSBjb250cmFmYWN0dWFsIChNMSkgcG9yIHJlc2VydmF0w7NyaW/Dl2RpYSA9PT09PT09PT09PQ0KICBlYXJfZiA8LSBhcy5udW1lcmljKFgxX29icyAlKiUgYjFbcywgXSkNCiAgZWFyX2MgPC0gYXMubnVtZXJpYyhYMV9jZiAgJSolIGIxW3MsIF0pDQoNCiAgIyA9PT09PSAoMikgUHJlZGnDp8OjbyBkZSBHX2hpZHJvIGZhY3R1YWwgZSBjZiAoTTIpID09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KICBuZDJfZiA8LSByZXNlcnYgJT4lIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9mKQ0KICBuZDJfYyA8LSByZXNlcnYgJT4lIG11dGF0ZShlYXJfcmVzZXJ2YXRvcmlvX3N1YnNpc3RlbWFfcHJvcHJpb19td21lcyA9IGVhcl9jKQ0KDQogIFgyX2YgPC0gcHJlZGljdChtMl9oaWRybywgbmV3ZGF0YSA9IG5kMl9mLCB0eXBlID0gImxwbWF0cml4IikNCiAgWDJfYyA8LSBwcmVkaWN0KG0yX2hpZHJvLCBuZXdkYXRhID0gbmQyX2MsIHR5cGUgPSAibHBtYXRyaXgiKQ0KDQogIGdfaF9mX3JlcyA8LSBhcy5udW1lcmljKFgyX2YgJSolIGIyW3MsIF0pICAjIGdlcmHDp8OjbyBow61kcmljYSBwb3IgcmVzZXJ2YXTDs3Jpb8OXZGlhDQogIGdfaF9jX3JlcyA8LSBhcy5udW1lcmljKFgyX2MgJSolIGIyW3MsIF0pDQoNCiAgIyA9PT09PSAoMykgQWdyZWdhciBHX2hpZHJvIHBhcmEgc3Vic2lzdGVtYcOXZGlhID09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQogIGRmX2ggPC0gZGF0YS5mcmFtZShkYXRlID0ga2V5c19tMiRkYXRlLA0KICAgICAgICAgICAgICAgICAgICAgc3VicyA9IGtleXNfbTIkbm9tX3N1YnNpc3RlbWEueCwNCiAgICAgICAgICAgICAgICAgICAgIGdfaF9mID0gZ19oX2ZfcmVzLA0KICAgICAgICAgICAgICAgICAgICAgZ19oX2MgPSBnX2hfY19yZXMpDQoNCiAgZ19oX2FnZyA8LSBkZl9oIHw+DQogICAgZ3JvdXBfYnkoZGF0ZSwgc3VicykgfD4NCiAgICBzdW1tYXJpc2UoZ19oX2YgPSBzdW0oZ19oX2YsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICAgIGdfaF9jID0gc3VtKGdfaF9jLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSB8Pg0KICAgIG11dGF0ZShkZWx0YV9nX2hpZHJvX2NsaW1hID0gZ19oX2YgLSBnX2hfYykNCg0KIyA9PT09PSAoNCkgQ29uc3RydWlyIGlucHV0IGRvIE0zIChzdWJzaXN0ZW1hw5dkaWEpID09PT09PT09PT09PT09PT09PT09PT09PT09DQogIG5kMyA8LSBnZXJhX2VuZXJnX2RheSB8Pg0KICAgIGxlZnRfam9pbihnX2hfYWdnLCBieSA9IGMoImRhdGUiID0gImRhdGUiLCAibm9tX3N1YnNpc3RlbWEiID0gInN1YnMiKSkNCg0KICBuZDMkZGVsdGFfZ19oaWRyb19jbGltYVtpcy5uYShuZDMkZGVsdGFfZ19oaWRyb19jbGltYSldIDwtIDANCg0KICBnX2hfb2JzIDwtIG5kMyRnZXJfaGlkcm9lbGV0cmljYQ0KICBnX2hfY2ZNMyA8LSBnX2hfb2JzIC0gbmQzJGRlbHRhX2dfaGlkcm9fY2xpbWEgICAjIHNlbSB0cnVuY2FnZW0NCg0KICBuZDNfZiA8LSBuZDMgJT4lIG11dGF0ZShnZXJfaGlkcm9lbGV0cmljYSA9IGdfaF9vYnMpJT4lDQogICAgICAgICAgICAgICAgIG11dGF0ZSgNCiAgICAgICAgICAgICAgICAgICBnZXJfaGlkcm9lbGV0cmljYSA9IGlmZWxzZShnZXJfaGlkcm9lbGV0cmljYSA9PSAwLCAxLCBnZXJfaGlkcm9lbGV0cmljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX2ZvdG92b2x0YWljYSA9IGlmZWxzZShnZXJfZm90b3ZvbHRhaWNhID09IDAsIDEsIGdlcl9mb3Rvdm9sdGFpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9lb2xpZWxldHJpY2EgPSBpZmVsc2UoZ2VyX2VvbGllbGV0cmljYSA9PSAwLCAxLCBnZXJfZW9saWVsZXRyaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfdGVybWljYSA9IGlmZWxzZShnZXJfdGVybWljYSA9PSAwLCAxLCBnZXJfdGVybWljYSksDQogICAgICAgICAgICAgICAgICAgI0RlbWFuZGEgPSBpZmVsc2UodmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEgPT0gMCwgMSwgdmFsX2dlcmFjYW9fZGF5X3N1YnNpc3RlbWEpDQogICAgICAgICAgICAgICAgICAgRGVtYW5kYSA9IGdlcl9lb2xpZWxldHJpY2ErZ2VyX2ZvdG92b2x0YWljYStnZXJfaGlkcm9lbGV0cmljYStnZXJfdGVybWljYStnZXJfbnVjbGVhciwNCiAgICAgICAgICAgICAgICAgKQ0KICBuZDNfYyA8LSBuZDMgJT4lIG11dGF0ZShnZXJfaGlkcm9lbGV0cmljYSA9IGdfaF9jZk0zKSU+JQ0KICAgICAgICAgICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICAgICAgZ2VyX2hpZHJvZWxldHJpY2EgPSBpZmVsc2UoZ2VyX2hpZHJvZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2hpZHJvZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9mb3Rvdm9sdGFpY2EgPSBpZmVsc2UoZ2VyX2ZvdG92b2x0YWljYSA9PSAwLCAxLCBnZXJfZm90b3ZvbHRhaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZW9saWVsZXRyaWNhID0gaWZlbHNlKGdlcl9lb2xpZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2VvbGllbGV0cmljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX3Rlcm1pY2EgPSBpZmVsc2UoZ2VyX3Rlcm1pY2EgPT0gMCwgMSwgZ2VyX3Rlcm1pY2EpLA0KICAgICAgICAgICAgICAgICAgICNEZW1hbmRhID0gaWZlbHNlKHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hID09IDAsIDEsIHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hKQ0KICAgICAgICAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIsDQogICAgICAgICAgICAgICAgICkNCg0KICAjID09PT09ICg1KSBQcmVkacOnw6NvIHTDqXJtaWNhIGZhY3R1YWwgZSBjZiAoTTMpID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KICBYM19mIDwtIHByZWRpY3QobTNfZ2FtX3Rlcm1pY2EsIG5ld2RhdGEgPSBuZDNfZiwgdHlwZSA9ICJscG1hdHJpeCIpDQogIFgzX2MgPC0gcHJlZGljdChtM19nYW1fdGVybWljYSwgbmV3ZGF0YSA9IG5kM19jLCB0eXBlID0gImxwbWF0cml4IikNCg0KICBnX3RfZiA8LSBhcy5udW1lcmljKFgzX2YgJSolIGIzW3MsIF0pDQogIGdfdF9jIDwtIGFzLm51bWVyaWMoWDNfYyAlKiUgYjNbcywgXSkNCg0KICBkZWx0YV9nX3Rlcm1fY2xpbWEgPC0gZ190X2YgLSBnX3RfYw0KDQojID09PT09ICg2KSBQcmVwYXJhciBpbnB1dCBwYXJhIE00IChwcmXDp28pID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiAgbmQ0IDwtIHBsZF9mdWxsMiB8Pg0KICAgIGxlZnRfam9pbigNCiAgICAgIG5kMyAlPiUgc2VsZWN0KGRhdGUsIG5vbV9zdWJzaXN0ZW1hLCBnZXJfaGlkcm9lbGV0cmljYSkgJT4lIA0KICAgICAgICBtdXRhdGUoZ190X2Y9Z190X2YsZ19oX2NmTTM9Z19oX2NmTTMsDQogICAgICAgICAgICAgICBnX3RfYz1nX3RfYyxnX2hfb2JzPWdfaF9vYnMsDQogICAgICAgICAgICAgICApLA0KICAgICAgYnkgPSBjKCJkYXRlIiwgIm5vbV9zdWJzaXN0ZW1hIikNCiAgICApIHw+DQogICAgbXV0YXRlKGdlcl90ZXJtaWNhX2YgPSBnX3RfZiwNCiAgICAgICAgICAgZ2VyX3Rlcm1pY2FfYyA9IGdfdF9jLA0KICAgICAgICAgICBnZXJfaGlkcm9lbGV0cmljYV9jID0gZ19oX2NmTTMsDQogICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhX2YgPSBnX2hfb2JzKQ0KDQogICMgZmFjdHVhbA0KICBuZDRfZiA8LSBuZDQgJT4lIG11dGF0ZSgNCiAgICBnZXJfdGVybWljYSA9IGdlcl90ZXJtaWNhX2YsDQogICAgZ2VyX2hpZHJvZWxldHJpY2EgPSBnZXJfaGlkcm9lbGV0cmljYV9mDQogICklPiUNCiAgICAgICAgICAgICAgICAgbXV0YXRlKA0KICAgICAgICAgICAgICAgICAgIGdlcl9oaWRyb2VsZXRyaWNhID0gaWZlbHNlKGdlcl9oaWRyb2VsZXRyaWNhID09IDAsIDEsIGdlcl9oaWRyb2VsZXRyaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZm90b3ZvbHRhaWNhID0gaWZlbHNlKGdlcl9mb3Rvdm9sdGFpY2EgPT0gMCwgMSwgZ2VyX2ZvdG92b2x0YWljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX2VvbGllbGV0cmljYSA9IGlmZWxzZShnZXJfZW9saWVsZXRyaWNhID09IDAsIDEsIGdlcl9lb2xpZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl90ZXJtaWNhID0gaWZlbHNlKGdlcl90ZXJtaWNhIDw9IDAsIDEsIGdlcl90ZXJtaWNhKSwNCiAgICAgICAgICAgICAgICAgICAjRGVtYW5kYSA9IGlmZWxzZSh2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSA9PSAwLCAxLCB2YWxfZ2VyYWNhb19kYXlfc3Vic2lzdGVtYSkNCiAgICAgICAgICAgICAgICAgICBEZW1hbmRhID0gZ2VyX2VvbGllbGV0cmljYStnZXJfZm90b3ZvbHRhaWNhK2dlcl9oaWRyb2VsZXRyaWNhK2dlcl90ZXJtaWNhK2dlcl9udWNsZWFyLA0KICAgICAgICAgICAgICAgICApDQogICMgY29udHJhZmFjdHVhbCAoY29tIHBlbmFsaWRhZGUgY2xpbcOhdGljYSBwcm9wYWdhZGEpDQogIG5kNF9jIDwtIG5kNCAlPiUgbXV0YXRlKA0KICAgIGdlcl90ZXJtaWNhID0gZ2VyX3Rlcm1pY2FfYywNCiAgICBnZXJfaGlkcm9lbGV0cmljYSA9IGdlcl9oaWRyb2VsZXRyaWNhX2MNCiAgKSU+JQ0KICAgICAgICAgICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICAgICAgZ2VyX2hpZHJvZWxldHJpY2EgPSBpZmVsc2UoZ2VyX2hpZHJvZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2hpZHJvZWxldHJpY2EpLA0KICAgICAgICAgICAgICAgICAgIGdlcl9mb3Rvdm9sdGFpY2EgPSBpZmVsc2UoZ2VyX2ZvdG92b2x0YWljYSA9PSAwLCAxLCBnZXJfZm90b3ZvbHRhaWNhKSwNCiAgICAgICAgICAgICAgICAgICBnZXJfZW9saWVsZXRyaWNhID0gaWZlbHNlKGdlcl9lb2xpZWxldHJpY2EgPT0gMCwgMSwgZ2VyX2VvbGllbGV0cmljYSksDQogICAgICAgICAgICAgICAgICAgZ2VyX3Rlcm1pY2EgPSBpZmVsc2UoZ2VyX3Rlcm1pY2EgPD0gMCwgMSwgZ2VyX3Rlcm1pY2EpLA0KICAgICAgICAgICAgICAgICAgICNEZW1hbmRhID0gaWZlbHNlKHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hID09IDAsIDEsIHZhbF9nZXJhY2FvX2RheV9zdWJzaXN0ZW1hKQ0KICAgICAgICAgICAgICAgICAgIERlbWFuZGEgPSBnZXJfZW9saWVsZXRyaWNhK2dlcl9mb3Rvdm9sdGFpY2ErZ2VyX2hpZHJvZWxldHJpY2ErZ2VyX3Rlcm1pY2ErZ2VyX251Y2xlYXIsDQogICAgICAgICAgICAgICAgICkNCiMgPT09PT0gKDcpIFByZWRpw6fDo28gZGUgcHJlw6dvIGZhY3R1YWwgZSBjZiAoTTQpID09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQogIFg0X2YgPC0gcHJlZGljdChnYW1fNF9wbGQsIG5ld2RhdGEgPSBuZDRfZiwgdHlwZSA9ICJscG1hdHJpeCIpDQogIFg0X2MgPC0gcHJlZGljdChnYW1fNF9wbGQsIG5ld2RhdGEgPSBuZDRfYywgdHlwZSA9ICJscG1hdHJpeCIpDQoNCiAgcGxkX2YgPC0gYXMubnVtZXJpYyhYNF9mICUqJSBiNFtzLCBdKQ0KICBwbGRfYyA8LSBhcy5udW1lcmljKFg0X2MgJSolIGI0W3MsIF0pDQoNCiAgZGVsdGFfUExEX21hdFssIHNdIDwtIHBsZF9mIC0gcGxkX2MgICAjIHBlbmFsaWRhZGUgY2xpbcOhdGljYSBlbSBwcmXDp28gKFIkL01XaCkNCiAgcHJpbnQocykNCn0NCmBgYA0KDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIC0tLSA1LiBBZ3JlZ2HDp8OjbyB0ZW1wb3JhbCBlIGVzdGF0w61zdGljYXMgZGUgaW5jZXJ0ZXphIC0tLS0tDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCm00X3BsZF9zdW1tYXJ5IDwtIGRlbHRhX1BMRF9tYXQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgc2V0TmFtZXMocGFzdGUwKCJzaW1fIiwgc2VxX2xlbihuc2ltKSkpICU+JQ0KICBiaW5kX2NvbHMocGxkX2Z1bGwyWywgYygiZGF0ZSIsICJub21fc3Vic2lzdGVtYSIpXSkgJT4lDQogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic2ltXyIpLCB2YWx1ZXNfdG8gPSAiZGVsdGFfUExEIikgJT4lDQogIG11dGF0ZShRdWFydGVyICA9IGx1YnJpZGF0ZTo6Zmxvb3JfZGF0ZShkYXRlLCAiMyBtb250aHMiKSkgJT4lDQogIGdyb3VwX2J5KFF1YXJ0ZXIgLCBub21fc3Vic2lzdGVtYSwgbmFtZSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBkZWx0YV9QTERfc3VtID0gbWVhbigtZGVsdGFfUExELCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKSAlPiUNCiAgZ3JvdXBfYnkoUXVhcnRlciwgbm9tX3N1YnNpc3RlbWEpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgZGVsdGFfUExEX21lYW4gPSBtZWFuKGRlbHRhX1BMRF9zdW0sIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfUExEX2x3ciAgPSBxdWFudGlsZShkZWx0YV9QTERfc3VtLCAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgIGRlbHRhX1BMRF91cHIgID0gcXVhbnRpbGUoZGVsdGFfUExEX3N1bSwgMC45NSwgbmEucm0gPSBUUlVFKSwNCiAgICBkZWx0YV9QTERfc2QgICA9IHNkKGRlbHRhX1BMRF9zdW0sIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApDQpgYGANCg0KIyAtLS0gNi4gVmlzdWFsaXphw6fDo286IEZhbiBDaGFydCBkbyBpbXBhY3RvIG5vIFBMRCAtLS0tLS0tLS0tDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIC0tLSA2LiBWaXN1YWxpemHDp8OjbzogRmFuIENoYXJ0IGRvIGltcGFjdG8gbm8gUExEIC0tLS0tLS0tLS0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KZ2dwbG90KG00X3BsZF9zdW1tYXJ5LCBhZXMoeCA9IFF1YXJ0ZXIsIHkgPSBkZWx0YV9QTERfbWVhbikpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSAwLCB5bWF4ID0gZGVsdGFfUExEX3VwciksIGZpbGwgPSAicmVkIiwgYWxwaGEgPSAwLjM1KSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gZGVsdGFfUExEX2x3ciwgeW1heCA9IGRlbHRhX1BMRF91cHIpLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGFscGhhID0gMC43NSkgKw0KDQogIGdlb21fbGluZShjb2xvciA9ICJibGFjayIpICsNCiAgZmFjZXRfd3JhcCh+IG5vbV9zdWJzaXN0ZW1hLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlbmFsaWRhZGUgY2xpbcOhdGljYSBwcm9wYWdhZGEgbm8gcHJlw6dvIGRlIGxpcXVpZGHDp8OjbyAozpRQTEQpIiwNCiAgICBzdWJ0aXRsZSA9IHBhc3RlKCJFbmNhZGVhbWVudG8gY29tcGxldG8gYXTDqSBvIG1vZGVsbyA0IHwgbnNpbSA9IiwgbnNpbSksDQogICAgeCA9ICJBbm8iLCB5ID0gIs6UUExEIChSJC9NV2gpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQoNCmRlbHRhX1BMRF9tYXQgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgc2V0TmFtZXMocGFzdGUwKCJzaW1fIiwgc2VxX2xlbihuc2ltKSkpICU+JQ0KICBiaW5kX2NvbHMocGxkX2Z1bGwyWywgYygiZGF0ZSIsICJub21fc3Vic2lzdGVtYSIpXSkgJT4lDQogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic2ltXyIpLCB2YWx1ZXNfdG8gPSAiZGVsdGFfUExEIikgJT4lDQogIG11dGF0ZShRdWFydGVyICA9IGx1YnJpZGF0ZTo6Zmxvb3JfZGF0ZShkYXRlLCAiMyBtb250aHMiKSkgJT4lDQogIGdyb3VwX2J5KG5vbV9zdWJzaXN0ZW1hLCBuYW1lKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGRlbHRhX1BMRF9zdW0gPSBtZWFuKC1kZWx0YV9QTEQsIG5hLnJtID0gVFJVRSksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApICU+JQ0KICBncm91cF9ieShub21fc3Vic2lzdGVtYSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBkZWx0YV9QTERfbWVhbiA9IG1lYW4oZGVsdGFfUExEX3N1bSwgbmEucm0gPSBUUlVFKSwNCiAgICBkZWx0YV9QTERfbHdyICA9IHF1YW50aWxlKGRlbHRhX1BMRF9zdW0sIDAuMDUsIG5hLnJtID0gVFJVRSksDQogICAgZGVsdGFfUExEX3VwciAgPSBxdWFudGlsZShkZWx0YV9QTERfc3VtLCAwLjk1LCBuYS5ybSA9IFRSVUUpLA0KICAgIGRlbHRhX1BMRF9zZCAgID0gc2QoZGVsdGFfUExEX3N1bSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgLT4gbTNfdGVybV9zdW1tYXJ5X200X3BvcnN1YnNpc3RlbWENCg0KbGlicmFyeShndCkNCm0zX3Rlcm1fc3VtbWFyeV9tNF9wb3JzdWJzaXN0ZW1hWyxjKCJub21fc3Vic2lzdGVtYSIsImRlbHRhX1BMRF9tZWFuIiwiZGVsdGFfUExEX2x3ciIsICJkZWx0YV9QTERfdXByIildICU+JSBqYW5pdG9yOjphZG9ybl90b3RhbHMoKSAlPiUgDQogIGd0KCkgJT4lDQogIGZtdF9udW1iZXIoY29sdW1ucyA9IDI6NCwgZGVjaW1hbHMgPSAxKSAlPiUNCiAgY29sc19sYWJlbCgNCiAgICBub21fc3Vic2lzdGVtYSA9ICJTdWJzeXN0ZW0iLA0KICAgIGRlbHRhX1BMRF9tZWFuID0gIm1lYW4gzpRwbGQgVGVybSAoTVdoKSIsDQogICAgZGVsdGFfUExEX2x3ciAgPSAiTG93ZXIgOTUlIiwNCiAgICBkZWx0YV9QTERfdXByICA9ICJVcHBlciA5NSUiLA0KICApICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gbWQoIioqQWdncmVnYXRlIGNsaW1hdGUgcGVuYWx0eSBvbiBzdG9yZWQgZW5lcmd5ICgyMDAx4oCTMjAxOCkqKiIpLA0KICAgIHN1YnRpdGxlID0gIlNpbXVsYXRlZCBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgcGVyIHN1YnN5c3RlbSINCiAgKQ0KYGBgDQoNCg==