Packages

Here we load all the packages we ae going to use in the analysis.

library(tidyverse)
library(gsheet)
library(cowplot)
library(ggthemes)
library(DescTools)
library(minpack.lm)
library(agricolae)
library(readxl)
library(patchwork)

Probability distributions

Fist step is to assemble the probability distributions for the for variable we are going to use for the simulations

SBR severity on untreated check.

Import data

Importing data of soybean rust severity (SBR) on the untreated check

sev_data = read.csv("data/sev_data.csv")
head(sev_data)

Filtering only values of severity in the check treatment

sev_check = sev_data %>% 
  filter(active_ingredient == "check")
head(sev_check)

Empirical distribution

sev_check %>% 
  ggplot(aes(severity/100))+
  geom_histogram(bins = 20, color = "black", fill = "gray")

Modeling

Since severity in proportional terms is between zero and one, we fit the empirical distribution into a beta probability distribution. For that we need to find the shape and scale parameters of the beta distribution function.

For that, obtain the empirical cumulative distribution and fit to the beta cumulative distribution.

sev = sev_check$severity
Fx= environment(ecdf(sev))$y
x = environment(ecdf(sev))$x/100

summary(nlsLM(Fx ~ pbeta(x, shape1, shape2, log = FALSE) ,
      start = c(shape1 = 1, shape2 = 1),
      control = nls.lm.control(maxiter = 100000)))
## Warning in nls.lm(par = start, fn = FCT, jac = jac, control = control, lower =
## lower, : resetting `maxiter' to 1024!
## 
## Formula: Fx ~ pbeta(x, shape1, shape2, log = FALSE)
## 
## Parameters:
##        Estimate Std. Error t value Pr(>|t|)    
## shape1  1.70736    0.02761   61.83   <2e-16 ***
## shape2  1.26581    0.01925   65.75   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.02053 on 186 degrees of freedom
## 
## Number of iterations to convergence: 6 
## Achieved convergence tolerance: 1.49e-08

Kolmogorov-Smirnov Test

ks.test(Fx,pbeta(x, 1.707, 1.266) )
## Warning in ks.test(Fx, pbeta(x, 1.707, 1.266)): p-value will be approximate in
## the presence of ties
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  Fx and pbeta(x, 1.707, 1.266)
## D = 0.053191, p-value = 0.953
## alternative hypothesis: two-sided
plot(x,Fx)
curve(pbeta(x, 1.707, 1.266),0,1, add = T)

plot(Fx,pbeta(x, 1.707, 1.266) )
abline(a=0,b=1)

Visualization

sev_dist_plot = sev_check %>% 
  ggplot(aes(severity/100))+
 geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "#AC08FF")+
   stat_function(fun=function(x) dbeta(x, 1.707, 1.266), color= "black", size = 1.2)+
  theme_bw()+
  labs(x="Severity (proportion)", y = "Density")
sev_dist_plot

# ggsave("figs/sev_dist.png", dpi=600, height = 3, width = 4)

Soybean price

Import data

soybean = gsheet2tbl("https://docs.google.com/spreadsheets/d/1-jQ9OgWdLQCb0iB0FqbrhuVi7LiNhqxvf9QU4-iuc3o/edit#gid=1085329359") 
head(soybean)

conversion to US dollar

sbr_price = soybean %>% 
  filter(year>=2018) %>% 
  mutate(price = (price/60)/4,
         national_price = (national_price/60)/4)
sbr_price
sbr_price %>% 
  ggplot(aes(year,price)) +
  geom_jitter(alpha =.2, size =2)+
  geom_boxplot(aes(group = year), fill = NA, size= 1)+
  scale_color_gradient()+
  theme_minimal_hgrid()

  # facet_wrap(~state)

Mean and Standad deviantion

mean(sbr_price$price)
## [1] 0.2932792
sd(sbr_price$price)
## [1] 0.02167031

Empirical distribution

sbr_price %>% 
  ggplot(aes(price))+
  geom_histogram(bins = 10, fill = "steelblue", color = "white")+
  theme_bw()+
  labs(x = "Soybean prince")+
  scale_x_continuous(breaks = seq(0,1,by=0.025))

hist((sbr_price$price), prob = T)
curve(dnorm(x, mean(sbr_price$price), sd(sbr_price$price)),0.15,0.35, add = T)

plot(ecdf(sbr_price$price))
curve(pnorm(x, mean(sbr_price$price), sd(sbr_price$price)),0.2,0.35, add = T)

Mean and median

mean(sbr_price$price)
## [1] 0.2932792
median(sbr_price$price)
## [1] 0.2935692

Shapiro

shapiro.test(sbr_price$price)
## 
##  Shapiro-Wilk normality test
## 
## data:  sbr_price$price
## W = 0.99021, p-value = 0.6164

Kolmogorov-Smirnov Test

Fx = environment(ecdf(sbr_price$price))$y
x= environment(ecdf(sbr_price$price))$x
ks.test(Fx, pnorm(x, mean(sbr_price$price), sd(sbr_price$price)))
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  Fx and pnorm(x, mean(sbr_price$price), sd(sbr_price$price))
## D = 0.054545, p-value = 0.9967
## alternative hypothesis: two-sided
plot(Fx, pnorm(x, mean(sbr_price$price), sd(sbr_price$price)))

Vizualization

price_plot = sbr_price %>% 
  ggplot(aes(price))+
 geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "#1C8C20")+
   stat_function(fun=function(x) dnorm(x, mean(sbr_price$price), sd(sbr_price$price)), color= "black", size = 1.2)+
  theme_bw()+
  labs(x="Soybean price (US$/kg)", y = "Density")+
  scale_x_continuous(breaks = seq(0,1,by=0.025))
price_plot

# ggsave("figs/sev_dist.png", dpi=600, height = 3, width = 4)

Regression coeficients

import data

Importing regression Slope and intercept data from the relationship between SBR severity and yield

damage_data = read_excel("data/dados histograma.xlsx") %>% 
  mutate(Slope = b1,
         Intercept = b0) %>% 
  dplyr::select(-b1,-b0)
head(damage_data)

Empirical distribution

Visualizando os hitogramas do slope e intercepto

damage_data %>% 
  gather(2:3, key = "par", value = "value") %>% 
  ggplot(aes(value))+
  geom_histogram(bins = 10, color = "gray40", fill = "gray90")+
  facet_wrap(~par, scales = "free_x")+
  theme_bw()

Regression lines

  ggplot() +
  geom_point(aes(x = 0:100, y = seq(0,5000,by = 50)), color = NA)+
  geom_abline(data =damage_data, aes(slope = Slope, intercept = Intercept),
              alpha = 0.5, color = "gray")+
  geom_abline(intercept = 2977,slope = -18, size = 1.2)+
  geom_abline(intercept = 2862,slope = -19.4 , size = .51, linetype = 2)+
  geom_abline(intercept = 3093,slope = -16.6, size = .51, linetype = 2)+
  
  labs(x = "SBR Severity (%)", y = "Yield (kg/ha) ")+
  theme_base()
## Warning: Removed 101 rows containing missing values (geom_point).

correlation

Correlation between slope and intercept

correlation(damage_data$Slope, damage_data$Intercept)
## 
## Pearson's product-moment correlation
## 
## data: damage_data$Slope and damage_data$Intercept 
## t = -3.144296 , df = 202 , p-value = 0.001915808 
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## cor
##  -0.2160089

plot

corr_emp_plot = damage_data %>% 
  ggplot(aes(Intercept, Slope))+
  geom_point(color = "black", size =2, alpha =0.5)+
  # geom_density2d_filled()+
  geom_smooth(method = "lm", se = F, color ="Red", size=1.2, fullrange=TRUE)+
  theme_light()+
  labs(title = "Empirical: r = -0.216")+
  coord_cartesian(
    xlim = c(0,6000),
    ylim = c(-75,0)
  )
corr_emp_plot
## `geom_smooth()` using formula 'y ~ x'

Cumulative density

Intercept

mean_intercept = mean(damage_data$Intercept)
sd_intercept = sd(damage_data$Intercept)

plot(ecdf(damage_data$Intercept))
curve(pnorm(x, mean_intercept,sd_intercept), 1000,5000, add = T, col = "red")

Kolmogorov-Smirnov Test

Fx = environment(ecdf(damage_data$Intercept))$y
x= environment(ecdf(damage_data$Intercept))$x
ks.test(Fx, pnorm(x, mean(damage_data$Intercept), sd(damage_data$Intercept)))
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  Fx and pnorm(x, mean(damage_data$Intercept), sd(damage_data$Intercept))
## D = 0.034314, p-value = 0.9997
## alternative hypothesis: two-sided
plot(Fx, pnorm(x, mean(damage_data$Intercept), sd(damage_data$Intercept)))

intercep_plot = damage_data %>% 
  ggplot(aes(Intercept))+
  geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "#FF4917")+
  stat_function(fun=function(x) dnorm(x, mean_intercept, sd_intercept), color ="black", size =1.2)+
  theme_bw()+
  labs(x="Intercept (kg/ha)", y = "Density")
intercep_plot

Slope

mean_slope = mean(damage_data$Slope)
sd_slope = sd(damage_data$Slope)

plot(ecdf(damage_data$Slope))
curve(pnorm(x, mean_slope, sd_slope), -60,5, add = T, col = "red")

Modeling

Fitting gamma distribution to the empirical cumulative density of the slope data

Fx =environment(ecdf(-damage_data$Slope))$y
x = environment(ecdf(-damage_data$Slope))$x

slope_reg = nlsLM(Fx ~ pgamma(x, shape, rate,log = FALSE) ,
      start = c(shape = 2.5, rate = 0.13),
      control = nls.lm.control(maxiter = 1024))
summary(slope_reg)
## 
## Formula: Fx ~ pgamma(x, shape, rate, log = FALSE)
## 
## Parameters:
##       Estimate Std. Error t value Pr(>|t|)    
## shape 3.044261   0.031275   97.34   <2e-16 ***
## rate  0.168269   0.001929   87.22   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.014 on 201 degrees of freedom
## 
## Number of iterations to convergence: 4 
## Achieved convergence tolerance: 1.49e-08

Kolmogorov-Smirnov Test

shape = summary(slope_reg)$coef[1]
rate = summary(slope_reg)$coef[2]

Fx =environment(ecdf(-damage_data$Slope))$y
x = environment(ecdf(-damage_data$Slope))$x
ks.test(Fx, pgamma(x, shape, rate))
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  Fx and pgamma(x, shape, rate)
## D = 0.034483, p-value = 0.9997
## alternative hypothesis: two-sided
shape = summary(slope_reg)$coef[1]
rate = summary(slope_reg)$coef[2]

slope_plot = damage_data %>% 
  ggplot(aes(Slope))+
 geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "#159EE6")+
   stat_function(fun=function(x) dgamma(-x, shape, rate), size = 1.2, color = "black")+
  theme_bw()+
  labs(x="Slope (kg/p.p.)", y = "Density")
slope_plot

Kolmogorov-Smirnov Test

ks.test(Fx,pgamma(x, shape, rate))
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  Fx and pgamma(x, shape, rate)
## D = 0.034483, p-value = 0.9997
## alternative hypothesis: two-sided

Multivariate Simulation using copula

Simulating two normal distributions correlated #### Function

######################################
gera.norm.bid.geral<-function(tamanho.amostra,correlacao,m1,m2,sigma1,sigma2)
{
  ro<-correlacao
  n<-tamanho.amostra
  x<-matrix(0,n,2)
  for (i in 1:n)
  {x[i,1]<-rnorm(1,m1,sigma1)
  x[i,2]<-rnorm(1,m2+ro*sigma1/sigma2*(x[i,1]-m1),sigma2*(sqrt(1-ro^2)))
  }
  return(x)
}

Test for correlation of 0.9

#testando
j<-gera.norm.bid.geral(1000,0.9,0,0,1,1)

plot(j[,1],j[,2])

For our data, we will use the positive correlation, becouse we want positive values of slope

#testando
j<-gera.norm.bid.geral(10000,0.2160089,0,0,1,1)

plot(j[,1],j[,2])

Intercept

Now we obtaing the probabilities from first distribution and insert in the quantiles function for the normal distribution of the intercept

b0 = pnorm(j[,2])
b0_t = qnorm(b0, 2977, 58.9*sqrt(210))
hist(b0_t, prob = T)
curve(dnorm(x, mean_intercept, sd_intercept), 0, 6000, add = T)

Slope

Now we obtaing the probabilities from first distribution and insert in the quantiles function for the gamma ditribution and multiply for -1 for obtain the negative outputs of the coeficient

b1 = pnorm(j[,1])
b1_t = qgamma(b1, shape, rate = rate)*-1
hist(b1_t, prob = T)
curve(dgamma(-x,shape=shape, rate = rate), -60,0, add = T)

Now we recalculate the correlation between the simulated coeficients. It matchs!

correlation(b1_t, b0_t)
## 
## Pearson's product-moment correlation
## 
## data: b1_t and b0_t 
## t = -21.87086 , df = 9998 , p-value = 0 
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## cor
##  -0.2136786

Viz. the correlation

corr_sim_plot = data.frame(b0_t,b1_t ) %>%
  mutate(alfa =(b1_t/b0_t)*100 ) %>% 
  filter(alfa > -3 & alfa < 0) %>% 
ggplot(aes(b0_t,b1_t ))+
  geom_point( size =2, color = "orange", alpha =0.3)+
  # geom_density_2d(color = "black")+
  geom_smooth(method = lm, color = "red", se = F, size = 1.2)+
  theme_light()+
  labs(y= "Slope",
       x = "Intercept",
       title = "Simulated: r = -0.204")+
  coord_cartesian(
    xlim = c(0,6000),
    ylim = c(-75,0)
  )
corr_sim_plot
## `geom_smooth()` using formula 'y ~ x'

Combo distributions

# plot_grid(sev_dist_plot,price_plot, intercep_plot, slope_plot, labels = "AUTO", nrow =2)

(sev_dist_plot+price_plot)/
  (intercep_plot+slope_plot)+
  # (corr_emp_plot+corr_sim_plot)+
  plot_annotation(tag_levels = 'A')&
  theme(plot.title = element_text(size =8))

ggsave("figs/coef_dist.png", dpi = 600, height = 5, width = 6)
ggsave("figs/coef_dist.pdf", dpi = 600, height = 5, width = 6)

Relative yield loss

Here we calculate the yield relative loss due to SBR severity using the original data set

empiric_ryl= damage_data %>% 
  mutate(cc = (Slope/Intercept)*100) %>% 
  filter( cc > -3 & cc <0 )
head(empiric_ryl)
stat_emp_ryl =empiric_ryl%>% 
  summarise(data = "empirical",
            mean =  mean(cc),
            median =  median(cc),
            variance = var(cc))
real_RYL= empiric_ryl %>% 
  ggplot(aes(cc))+
 geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "black")+
  scale_y_continuous(limits = c(0,1.4),breaks =  seq(0, 1.4,by = 0.4))+
  geom_vline(data = stat_emp_ryl, aes(xintercept = mean, color = "Mean"),size =1)+
  geom_vline(data = stat_emp_ryl, aes(xintercept = median, color = "Median"),size =1)+
  theme_bw()+
  scale_color_calc()+
  labs(x = "Relative yield loss (%/p.p.)",
       y = "Density",
       color = "",
       title = "Empirical")+
  xlim(-3,0.2)+
  theme(legend.position = "top")
real_RYL
## Warning: Removed 2 rows containing missing values (geom_bar).

And here we calculate the relative yield loss due to SBR severity using the simulated data set

simul_ryl = data.frame(b0_t, b1_t, cc = (b1_t/b0_t)*100) %>% 
  filter( cc > -3 & cc <0 )
head(simul_ryl)
stat_suml_ryl = simul_ryl%>% 
  summarise(data = "Simulated",
            mean =  mean(cc),
            median =  median(cc),
            variance = var(cc))
simul_RYL =simul_ryl %>% 
  ggplot(aes(cc))+
 geom_histogram(aes(y = ..density..),bins = 10, color = "white", fill = "orange")+
  scale_y_continuous(limits = c(0,1.4),breaks =  seq(0, 1.4,by = 0.4))+
  geom_vline(data = stat_suml_ryl, aes(xintercept = mean, color = "Mean"),size =1)+
  geom_vline(data = stat_suml_ryl, aes(xintercept = median, color = "Median"),size =1)+
  theme_bw()+
  scale_color_calc()+
  labs(x = "Relative yield loss (%/p.p.)",
       y = "Density",
       color ="",
       title = "Simulated")+
  xlim(-3,0.2)+
  theme(legend.position = "top")
simul_RYL
## Warning: Removed 2 rows containing missing values (geom_bar).

Comparision of mean, median and variance

damage_data %>% 
  mutate(cc = (Slope/Intercept)*100) %>% 
  filter( cc > -3 & cc <0 ) %>% 
  summarise(data = "empirical",
            mean =  mean(cc),
            median =  median(cc),
            variance = var(cc)) %>% 
  bind_rows(
    data.frame(b0_t, b1_t, cc = (b1_t/b0_t)*100) %>% 
  filter( cc > -3 & cc <0 ) %>% 
  summarise(data = "Simulated",
            mean =  mean(cc),
            median =  median(cc),
            variance = var(cc))
  )

Kolmogorov-Smirnov Test

actual_cc = damage_data %>% 
  mutate(cc = (Slope/Intercept)*100)

simulated_cc = data.frame(b0_t, b1_t, cc = (b1_t/b0_t)*100) %>% 
  filter( cc > -3 & cc <0 )

Distribution

ks.test(actual_cc$cc, simulated_cc$cc)
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  actual_cc$cc and simulated_cc$cc
## D = 0.050452, p-value = 0.6889
## alternative hypothesis: two-sided

cummulative distribution

fx_actual = environment(ecdf(actual_cc$cc))$y
fx_simu = environment(ecdf(simulated_cc$cc))$y
ks.test((fx_actual),(fx_simu))
## Warning in ks.test((fx_actual), (fx_simu)): p-value will be approximate in the
## presence of ties
## 
##  Two-sample Kolmogorov-Smirnov test
## 
## data:  (fx_actual) and (fx_simu)
## D = 0.004899, p-value = 1
## alternative hypothesis: two-sided
ecdf_damage = ggplot()+
  stat_ecdf(aes(simulated_cc$cc,color = "Simulated"), size=1.2,geom = "step")+
  stat_ecdf(aes(actual_cc$cc, color = "Empirical"), size=1.2,geom = "step")+
  theme_bw()+
  scale_color_manual(values = c("black","orange"))+
  labs(y = "Probability",
       x = "Relative percent yield loss",
       color ="",
       title = "Cumulative distribution function")+
  theme(legend.position = "top",
        legend.background = element_blank())
ecdf_damage

Combo Yield loss

((corr_emp_plot/corr_sim_plot)|(real_RYL/simul_RYL)+plot_layout(guides = 'collect')| ecdf_damage ) +
  # plot_layout(heights = c(1,1,0.5))+
  plot_annotation(tag_levels = 'A') & 
  
  theme(legend.position = 'bottom',
        plot.title = element_text(size=9),
        legend.key.size= unit(3, "mm"),
        legend.text =  element_text(size = 7))
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## Warning: Removed 2 rows containing missing values (geom_bar).

## Warning: Removed 2 rows containing missing values (geom_bar).

ggsave("figs/RYL.png", dpi = 600, height = 5, width = 10)
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## Warning: Removed 2 rows containing missing values (geom_bar).

## Warning: Removed 2 rows containing missing values (geom_bar).
ggsave("figs/RYL.pdf", dpi = 600, height = 5, width = 10)
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## Warning: Removed 2 rows containing missing values (geom_bar).

## Warning: Removed 2 rows containing missing values (geom_bar).

Simulations

set.seed(1)
n=40000
lambda = seq(0,1, by=0.05)
fun_price = seq(-10, 260, by=15)
n_aplication = 1
operational_cost = 10  

comb_matrix = as.matrix(data.table::CJ(lambda,fun_price))
colnames(comb_matrix) = c("lambda","fun_price")
comb_matrix = cbind(comb_matrix,operational_cost, n_aplication)
C = comb_matrix[,"n_aplication"]*(comb_matrix[,"operational_cost"]+comb_matrix[,"fun_price"] )
comb_matrix = cbind(comb_matrix,C)

N = length(comb_matrix[,1])*n
big_one = matrix(0, ncol = 12, nrow =N)
big_one[,1] = rep(comb_matrix[,1],n)
big_one[,2] = rep(comb_matrix[,2],n)
big_one[,3] = rep(comb_matrix[,3],n)
big_one[,4] = rep(comb_matrix[,4],n)
big_one[,5] = rep(comb_matrix[,5],n)

set.seed(1)
sn = rbeta(N, 1.707, 1.266)
sf = sn*(1-big_one[,1])
# simulating the coeficientes 
set.seed(1)
normal_correlated<-gera.norm.bid.geral(N,0.21,0,0,1,1)
b0_n = pnorm(normal_correlated[,2])
b1_n = pnorm(normal_correlated[,1])
b0 = qnorm(b0_n, mean_intercept,sd_intercept)
b1 = -qgamma(b1_n, shape, rate,)
rm(b0_n,b1_n,normal_correlated)
# b0[b0<0] = 0.0001
# Calculating the alha coeficient
alfa = (b1/b0)*100
# alfa[alfa > 0] = 0
# alfa[alfa < -3] = -3

# Calculating yield gain
# yn = b0*(1+sn*alfa) # Yield  non-treated
# yf = b0*(1+sf*alfa) # Yield  treated
yn  = b0 - (-alfa*b0*sn)
yf  = b0 - (-alfa*b0*sf)
# yn[yn<0] = 0
# yf[yf<0] = 0
# yield_gain = yf-yn # yield gain
# yield_gain_perc = (1-(yn/yf))*100


# Simulating soybean price
set.seed(1)
soy_price = rnorm(N, mean(sbr_price$price),sd(sbr_price$price))
# income = yield_gain*soy_price # calculating the income

big_one[,6] = yn
big_one[,7] = yf
big_one[,8] = soy_price
big_one[,9] = b1
big_one[,10] = alfa
big_one[,11] = b0
big_one[,12] = sn
colnames(big_one)  = c("lambda","fun_price","operational_cost","n_aplication","C","yn","yf","soy_price","b1","alfa","b0", "sn")
big_one_df = as.data.frame(big_one) %>% 
  filter(b0>=0) %>% 
  filter(yn>0) %>% 
  filter(alfa > -3 & alfa < 0) %>% 
  mutate(yield_gain = yf-yn,
         # yield_gain_perc = ((yf - yn)/yn)*100,
         yield_gain_perc = ((yf/yn)-1)*100,
         income = yield_gain*soy_price,
         CP = C/soy_price,
         # profit = (yield_gain>=CP)*1,
         profit = (income>=C)*1)

Breacking even

Tetris

big_one_df %>% 
  # mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 # sn <= median(sn) ~ "Low severity")) %>% 
  filter(lambda >=0.3) %>%
  group_by(lambda, C) %>% 
  summarise(n=n(),sumn = sum(profit), prob = sumn/n) %>%
  # filter(prob>0.5) %>%
  mutate(prob2 = case_when(prob < 0.50 ~ "Pr(I \u2265 C) \u2264 0.5 ",
                          prob >= 0.50 ~ "Pr(I \u2265 C) > 0.5")) %>% #,
  # #                         prob >= 0.75 ~ "75% \u2264 p < 100% "  )) %>% 
  ggplot(aes(as.factor(lambda*100),as.factor(C), fill = prob, 
             # color = prob2
             ))+
  geom_tile(size = 0.5, color ="white")+
  scale_fill_viridis_b(option ="B", direction = -1)+
  # scale_fill_manual(values = c("darkred",  "steelblue"))+
  # scale_fill_gradient2(low = "#E60E00",mid = "#00030F", high = "#55E344",midpoint = 0.5)+
  scale_color_manual(values = c("#E60E00","#55E344"))+
  # scale_fill_gradient2(low = "red",mid = "black", high = "steelblue",midpoint = 0.5)+
  # scale_color_manual(values = c("red","steelblue")) + 
  guides(color = guide_legend(override.aes = list(size=2)))+
  # scale_fill_viridis_d(option = "B")+
  labs(x = "Fungicide efficacy (%)",
       y = "Fungicide + Application cost ($)",
       fill  = "Pr(I \u2265 C)",
       color ="" )+
  # facet_wrap(~sev_class)+
  theme_light()
## `summarise()` regrouping output by 'lambda' (override with `.groups` argument)

# ggsave("figs/tetris.png", dpi = 600, height = 5, width = 7)

Tetris 2

median(big_one_df$b0)
## [1] 2995.191
tetris_plot = function(s_class, y_class, pal =1){
big_one_df %>% 
  mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 sn <= median(sn) ~ "Low severity"),
      yield_class =  case_when(b0 > median(b0) ~ "High yield",
                                 b0 <= median(b0) ~ "Low yield")) %>%
    filter(lambda >=0.3) %>% 
  group_by(lambda, C, sev_class,yield_class) %>% 
  summarise(n=n(),sumn = sum(profit), prob = sumn/n) %>%
  mutate(prob = case_when(prob >= .75 ~ "\u2265 0.75",
                          prob < .75 & prob >= 0.5 ~ "0.50-0.75",
                          prob < .50 & prob >= .25 ~ "0.25-0.50",
                          prob < .25 ~ "< 0.25"),
         prob =factor(prob,level = c("< 0.25","0.25-0.50","0.50-0.75", "\u2265 0.75"))) %>%
    filter(sev_class== s_class,
           yield_class == y_class) %>% 
  ggplot(aes(as.factor(lambda*100),as.factor(C), fill = prob))+
  geom_tile(size = 0.25, color ="gray70")+
  scale_fill_brewer(palette = pal)+
  labs(x = "Fungicide efficacy (%)",
       y = "Fungicide + Application cost ($)",
       fill  = "Probability",
       color ="" )+
  # facet_grid(~sev_class)+
  guides(color = guide_legend(override.aes = list(size=2)))+
  theme_light()+
  theme(text = element_text(size = 10),
        legend.position = "bottom",
        axis.text = element_text(size = 7),
        panel.spacing = unit(1.75, "lines"),
        strip.background =element_rect(fill="NA"),
        strip.text = element_text(color = "black", size =12))
}
tetris_Sh_Sh = tetris_plot(s_class = "High severity",
                          y_class = "High yield",pal =1)+
  labs(title = "High severity",
       subtitle = "High yield")
## `summarise()` regrouping output by 'lambda', 'C', 'sev_class' (override with `.groups` argument)
tetris_Sl_Yh = tetris_plot(s_class = "Low severity",
                          y_class = "High yield",pal =1
                         )+
  labs(title = "Low severity",
       subtitle = "High yield")
## `summarise()` regrouping output by 'lambda', 'C', 'sev_class' (override with `.groups` argument)
tetris_Sh_Yl = tetris_plot(s_class = "High severity",
                          y_class = "Low yield",pal =2
                         )+
  labs(title = "High severity",
       subtitle = "Low yield")
## `summarise()` regrouping output by 'lambda', 'C', 'sev_class' (override with `.groups` argument)
tetris_Sl_Sh = tetris_plot(s_class = "Low severity",
                          y_class = "Low yield",pal =2
                         )+
  labs(title = "Low severity",
       subtitle = "Low yield")
## `summarise()` regrouping output by 'lambda', 'C', 'sev_class' (override with `.groups` argument)

Combo tetris

((tetris_Sh_Sh+tetris_Sl_Yh)+plot_layout(guides = "collect"))/((tetris_Sh_Yl+tetris_Sl_Sh)+
   plot_layout(guides = "collect"))+
  plot_annotation(tag_levels = 'A')&
  theme(legend.position = "bottom",
        plot.title = element_text(size = 8),
        plot.subtitle = element_text(size = 8))

ggsave("figs/box_classes.png", dpi = 500, height = 8.5, width = 7.5)
ggsave("figs/box_classes.pdf", dpi = 500, height = 8.5, width = 7.5)

Yield gain

Absolute gain

overal_yg = big_one_df %>%
  mutate(sev_class = " Overall") %>% 
  group_by(lambda,sev_class) %>% 
  summarise(yield_gain_median = median(yield_gain),
            yield_gain_mean = mean(yield_gain),
            up_95 = quantile(yield_gain, 0.975),
            low_95 = quantile(yield_gain, 0.025),
            up_75 = quantile(yield_gain, 0.75),
            low_75 = quantile(yield_gain, 0.25))
## `summarise()` regrouping output by 'lambda' (override with `.groups` argument)
# m_absol = lm(yield_gain ~ lambda, big_one_df %>% mutate(lambda=lambda*100))
# summary(m_absol)
over_gg_kg = overal_yg %>% 
  ggplot(aes(lambda*100,yield_gain_mean))+
  geom_line(aes(lambda*100, low_95),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(aes(lambda*100, up_95),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(size = 1.2, aes(lambda*100,yield_gain_median))+
  # scale_linetype_manual(values=c(1,2))+
  theme_light()+
  # geom_abline(slope = 9.61, intercept = -0.1 )+
  # coord_equal()+
  labs(x = "Fungicide efficacy (%)",
       y = "Yield gain (kg/ha)",
       color = "Fungicide mixture", #(Dalla lana et al., 2018)
       linetype = "", fill = "")
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill
over_gg_kg

ygain_plot = function(s_class){
big_one_df %>% 
  mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 sn <= median(sn) ~ "Low severity"),
      yield_class =  case_when(b0 > median(b0) ~ "High yield",
                                 b0 <= median(b0) ~ "Low yield")) %>%
  group_by(lambda, sev_class,yield_class ) %>% 
  summarise(yield_gain_median = median(yield_gain),
            yield_gain_mean = mean(yield_gain),
            up_95 = quantile(yield_gain, 0.975),
            low_95 = quantile(yield_gain, 0.025),
            up_75 = quantile(yield_gain, 0.75),
            low_75 = quantile(yield_gain, 0.25)) %>% 
  mutate(sev_class = factor(sev_class, levels = c("Low severity","High severity"))) %>%
    filter(sev_class ==s_class ) %>% 
  ggplot(aes(lambda*100,yield_gain_mean))+
  geom_line(aes(lambda*100, low_95, color = yield_class),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(aes(lambda*100, up_95,color = yield_class),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(size = 1.2, aes(lambda*100,yield_gain_median,color = yield_class))+
  # scale_color_manual(values = c("#009628","#8A0004"))+
  scale_color_manual(values = c("steelblue","#009628"))+
  theme_light()+
    coord_cartesian(ylim=c(0,3000))+
  labs(x = "Fungicide efficacy (%)",
       y = "Yield gain (kg/ha)",
       color = "Attainable Yield", #(Dalla lana et al., 2018)
       linetype = "")
}
high_sev_yg = ygain_plot(s_class = "High severity")+
  labs(title = "High severity")
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill
low_sev_yg = ygain_plot(s_class = "Low severity")+
  labs(title = "Low severity")
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill
high_sev_yg+low_sev_yg

big_one_df %>%
  mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 sn <= median(sn) ~ "Low severity"),
      yield_class =  case_when(b0 > median(b0) ~ "High yield",
                                 b0 <= median(b0) ~ "Low yield")) %>%
  group_by(lambda, sev_class,yield_class ) %>% 
  summarise(yield_gain_mean = mean(yield_gain),
            yield_gain_median = median(yield_gain, na.rm = T),
            low_95 = quantile(yield_gain, 0.025),
            up_95 = quantile(yield_gain, 0.975),
            up_75 = quantile(yield_gain, 0.75),
            low_75 = quantile(yield_gain, 0.25)) %>% 
  bind_rows(overal_yg) %>% 
  filter(lambda==.75) %>% 
  arrange(yield_class)
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)

Percent gain

overal_percet = big_one_df %>%
  mutate(sev_class = " Overall") %>% 
  group_by(lambda,sev_class) %>% 
  mutate(yield_gain_perc = case_when(yield_gain_perc>quantile(yield_gain_perc,0.999)~quantile(yield_gain_perc,0.999),
                                     yield_gain_perc<=quantile(yield_gain_perc,0.999) ~yield_gain_perc)) %>%
  summarise(yield_gain_mean = mean(yield_gain_perc,na.rm = T),
            yield_gain_median = median(yield_gain_perc,na.rm = T),
            low_95 = quantile(yield_gain_perc, 0.025,na.rm = T),
            up_95 = quantile(yield_gain_perc, 0.975,na.rm = T),
            up_75 = quantile(yield_gain_perc, 0.75,na.rm = T),
            low_75 = quantile(yield_gain_perc, 0.25,na.rm = T))  
## `summarise()` regrouping output by 'lambda' (override with `.groups` argument)
over_gg = overal_percet %>% 
  ggplot(aes(lambda*100,yield_gain_mean))+
  geom_line(aes(lambda*100, low_95),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(aes(lambda*100, up_95),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(size = 1.2, aes(lambda*100,yield_gain_median))+
  # scale_linetype_manual(values=c(1,2))+
  theme_light()+
  # coord_equal()+
  labs(x = "Fungicide efficacy (%)",
       y = "Yield gain %",
       color = "Fungicide mixture", #(Dalla lana et al., 2018)
       linetype = "", fill = "")+
  coord_cartesian(ylim = c(0,100), xlim = c(-10,100))
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill
over_gg

ygain_perc_plot = function(s_class){
big_one_df %>% 
  mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 sn <= median(sn) ~ "Low severity"),
      yield_class =  case_when(b0 > median(b0) ~ "High yield",
                                 b0 <= median(b0) ~ "Low yield")) %>%
  group_by(lambda, sev_class,yield_class ) %>% 
  summarise(yield_gain_median = median(yield_gain_perc),
            yield_gain_mean = mean(yield_gain_perc),
            up_95 = quantile(yield_gain_perc, 0.975),
            low_95 = quantile(yield_gain_perc, 0.025),
            up_75 = quantile(yield_gain_perc, 0.75),
            low_75 = quantile(yield_gain_perc, 0.25)) %>% 
  mutate(sev_class = factor(sev_class, levels = c("Low severity","High severity"))) %>%
    filter(sev_class ==s_class ) %>% 
  ggplot(aes(lambda*100,yield_gain_mean))+
  geom_line(aes(lambda*100, low_95, color = yield_class),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(aes(lambda*100, up_95,color = yield_class),
              linetype = 2,
            size = 0.7,
            fill = NA)+
  geom_line(size = 1.2, aes(lambda*100,yield_gain_median,color = yield_class))+
  # scale_color_manual(values = c("#009628","#8A0004"))+
  scale_color_manual(values = c("steelblue","#009628"))+

  theme_light()+
  labs(x = "Fungicide efficacy (%)",
       y = "Yield gain (%)",
       color = "Attainable Yield", 
       linetype = "", fill = "")+
  coord_cartesian(ylim = c(0,100))
}
high_sev_yg_perc = ygain_perc_plot(s_class = "High severity")+
  labs(title = "High severity")
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill
low_sev_yg_perc = ygain_perc_plot(s_class = "Low severity")+
  labs(title = "Low severity")
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)
## Warning: Ignoring unknown parameters: fill

## Warning: Ignoring unknown parameters: fill

Combo yied gain

(high_sev_yg+low_sev_yg)/
(high_sev_yg_perc+low_sev_yg_perc)+
  plot_layout(guides = "collect",
               heights = c(1,1))+
  plot_annotation(tag_levels = 'A')& 
  theme(plot.title = element_text(size =8))

ggsave("figs/yield_gain_perc.png", dpi = 600, height = 6, width =8)
ggsave("figs/yield_gain_perc.pdf", dpi = 600, height = 6, width =8)
 big_one_df %>%
  mutate(sev_class = case_when(sn > median(sn) ~ "High severity",
                                 sn <= median(sn) ~ "Low severity"),
      yield_class =  case_when(b0 > median(b0) ~ "High yield",
                                 b0 <= median(b0) ~ "Low yield")) %>%
  group_by(lambda,sev_class,yield_class) %>%
  mutate(yield_gain_perc = case_when(yield_gain_perc>quantile(yield_gain_perc,0.999)~quantile(yield_gain_perc,0.999),
                                     yield_gain_perc<=quantile(yield_gain_perc,0.999) ~yield_gain_perc)) %>%
  summarise(yield_gain_mean = mean((yield_gain_perc),na.rm = T),
            yield_gain_median = median((yield_gain_perc),na.rm = T),
            low_95 = quantile((yield_gain_perc), 0.025,na.rm = T),
            up_95 = quantile((yield_gain_perc), 0.975,na.rm = T),
            up_75 = quantile((yield_gain_perc), 0.75,na.rm = T),
            low_75 = quantile((yield_gain_perc), 0.25,na.rm = T)) %>% 
  bind_rows(overal_percet)%>% 
  filter(lambda==0.75) %>% 
  arrange(yield_class)
## `summarise()` regrouping output by 'lambda', 'sev_class' (override with `.groups` argument)

Examples

Fungicide PICO+TEBU

n = 1000
# yield = rnorm(1000,682.11, 28.97)
efficacy = (1-exp(rnorm(1000,-1.204,0.0462)))

sev_n = rbeta(n, 1.707, 1.266)
sev_f = sev_n*(1-efficacy) 

normal_correlated<-gera.norm.bid.geral(n,0.21,0,0,1,1)
b0_n = pnorm(normal_correlated[,2])
b1_n = pnorm(normal_correlated[,1])
b0 = qnorm(b0_n, mean_intercept,sd_intercept)
b1 = -qgamma(b1_n, shape, rate,)
rm(b0_n,b1_n,normal_correlated)

# Calculating the alpha coeficient
alfa = (b1/b0)*100

# Calculating yield gain
yn  = b0 - (-alfa*b0*sev_n)
yf  = b0 - (-alfa*b0*sev_f)

cost = 125
soy_price = rnorm(n, mean(sbr_price$price),sd(sbr_price$price))

yield_gain = yf-yn
yield_gain_perc = ((yf - yn)/yn)*100
yield_gain_perc = ((yf/yn)-1)*100
income = yield_gain*soy_price
CP = cost/soy_price
profit = (yield_gain>=CP)*1
mean(profit)
## [1] 0.664
hist(income-cost)

hist(efficacy)

simulations overtime

Tebu

box_time = data.frame()
time = seq(0,10, 1)

b0_decline =-1.518
b0_se_decline =  0.065
b1_decline = 0.147
b1_se_decline = 0.012
n = 30000
for(i in 1:length(time)){
  
y =  rnorm(n, b0_decline,b0_se_decline) + time[i]* rnorm(n,b1_decline,b1_se_decline)  
efficacy = (1-exp(y))
a = data.frame(time = time[i],lambda=efficacy)
box_time = box_time %>% 
  bind_rows(a)
}

# box_time



# box_time %>% 
#   ggplot(aes(time, lambda*100))+
#   geom_point()+
#   labs(y = "Efficacy")+
#   ylim(0,100)
simul_decay = function(data_ef, cost){
# cost = 75
N = n*length(time)
sev_n = rbeta(N, 1.707, 1.266)
sev_f = sev_n*(1-data_ef$lambda) 
normal_correlated<-gera.norm.bid.geral(N,0.21,0,0,1,1)
b0_n = pnorm(normal_correlated[,2])
b1_n = pnorm(normal_correlated[,1])
b0 = qnorm(b0_n, mean_intercept,sd_intercept)
b1 = -qgamma(b1_n, shape, rate,)
rm(b0_n,b1_n,normal_correlated)

# Calculating the alpha coeficient
alfa = (b1/b0)*100

# Calculating yield gain
yn  = b0 - (-alfa*b0*sev_n)
yf  = b0 - (-alfa*b0*sev_f)

soy_price = rnorm(N, mean(sbr_price$price),sd(sbr_price$price))

yield_gain = yf-yn
yield_gain_perc = ((yf - yn)/yn)*100
yield_gain_perc = ((yf/yn)-1)*100
income = yield_gain*soy_price
CP = cost/soy_price
profit = (yield_gain>=CP)
profit_50 = (income>=cost+(cost*0.5))#*1

box_time2 = data_ef %>% 
  mutate(yield_gain) %>% 
  mutate(yield_gain_perc) %>% 
  mutate(income) %>% 
  mutate(CP, cost) %>% 
  mutate(profit,
         profit_50) %>% 
  group_by(time) %>% 
  mutate(P = mean(profit),
         P_50 = mean(profit_50))
return(box_time2)
}
tebu_75 = simul_decay(data_ef = box_time, cost = 75)
tebu_100 = simul_decay(data_ef = box_time, cost = 100)
tebu_125 = simul_decay(data_ef = box_time, cost = 125)
tebu = bind_rows(tebu_75,tebu_100, tebu_125)
tebu %>% 
  group_by(time,cost) %>% 
  slice(1L) %>% 
  pivot_longer(10:11, names_to = "Profits", values_to = "prob") %>% 
  mutate(Profits = case_when(Profits =="P" ~ " Break-even",
                             Profits =="P_50" ~ "50% profit")) %>% 
  ggplot()+
  geom_hline(yintercept = 0.5, color = "gray", size =1, linetype =2)+
  geom_line(aes((time+2004), prob, color = as.factor(cost) ),
            size = 1.2)+
  facet_wrap(~Profits)+
  scale_color_colorblind()+
  labs(y = "Probability of offseting costs",
       x = "Time",
       color = "Cost (US$)")+
  ylim(0,1)+
  theme_minimal_grid()

Cypr

box_time_mix = data.frame()
time = seq(0,10, 1)
#mix intercept
# b0_decline =-2.151
# b0_se_decline =  0.121

# tebu intercept
b0_decline =-1.518
b0_se_decline =  0.065

# b1_decline = 0.132
# b1_se_decline = 0.022

b1_decline =0.061
b1_se_decline = 0.015

n = 30000
for(i in 1:length(time)){
  
y =  rnorm(n, b0_decline,b0_se_decline) + time[i]* rnorm(n,b1_decline,b1_se_decline)  
efficacy = (1-exp(y))
a = data.frame(time = time[i],lambda=efficacy)
box_time_mix = box_time_mix %>% 
  bind_rows(a)
}
mix_75 = simul_decay(data_ef =  box_time_mix, cost = 75)
mix_100 = simul_decay(data_ef = box_time_mix, cost = 100)
mix_125 = simul_decay(data_ef = box_time_mix, cost = 125)
mix = bind_rows(mix_75,mix_100, mix_125)
mix %>% 
  group_by(time,cost) %>% 
  slice(1L) %>% 
  pivot_longer(10:11, names_to = "Profits", values_to = "prob") %>% 
  mutate(Profits = case_when(Profits =="P" ~ " Break-even",
                             Profits =="P_50" ~ "50% profit")) %>% 
  ggplot()+
  geom_hline(yintercept = 0.5, color = "gray", size =1, linetype =2)+
  geom_line(aes((time+2004), prob, color = as.factor(cost) ),
            size = 1.2)+
  facet_wrap(~Profits)+  
  scale_color_colorblind()+
  labs(y = "Probability of offseting costs",
       x = "Time",
       color = "Cost (US$)")+
  ylim(0,1)+
  theme_light()

Combo figura

prob_time =  function(data, prof_class){

data %>% 
  group_by(time,cost) %>% 
  slice(1L) %>% 
  pivot_longer(10:11, names_to = "Profits", values_to = "prob") %>% 
  mutate(Profits = case_when(Profits =="P" ~ "Break-even",
                             Profits =="P_50" ~ "50% profit")) %>% 
  filter(Profits == prof_class) %>% 
  ggplot(aes((time), prob))+
    
  annotate("rect",ymin = 0, ymax =0.25, 
            xmin = -5, xmax = 15,
            fill = "#eff3ff",colour="white",
            # alpha = 0.8,
           size = 0.3)+
  annotate("rect",ymin = 0.25, ymax =0.5, 
            xmin = -5, xmax = 15,
            fill = "#bdd7e7",colour="white",
            # alpha = 0.8,
           size = 0.3)+
    annotate("rect",ymin = 0.5, ymax =0.75, 
            xmin = -5, xmax = 15,
            fill = "#6baed6",colour="white",
            # alpha = 0.8,
            size = 0.3)+
    annotate("rect",ymin = 0.75, ymax =1, 
            xmin = -5, xmax = 15,
            fill = "#2171b5", colour="white",
            # alpha = 0.8,
            size = 0.3)+
    
    
  # geom_hline(yintercept = 0.75, color = "gray", size =0.8, linetype =2)+
  geom_step(direction = "hv",size = 1.2,
            aes( color = as.factor(cost) ))+
  scale_x_continuous(breaks = seq(0,10,1))+
  # scale_color_manual(values = c("red" , "#DC143C","darkred"))+
  scale_color_manual(values = c("#fecc5c" , "#fd8d3c","#e31a1c"))+
  # scale_color_manual(values = c("#000000" , "#252525","#525252"))+
  labs(y = "Probability",
       x = "Time (years)",
       color = "Cost (US$/ha)")+
 coord_cartesian(xlim=c(0,10), ylim = c(0,1))+
  theme_light()+
    theme(#panel.grid.major = element_blank()+
          panel.grid =  element_blank())
  
  }
tebu_g1 = prob_time(tebu, prof_class ="Break-even")+
    labs(title = "High annual rate of decline"
         # subtitle = "Offset costs"
         )
tebu_g2 = prob_time(tebu, prof_class ="50% profit")+
    labs(title = "High annual rate of decline",
         subtitle = "50% profit"
         )
mix_g1 = prob_time(mix, prof_class ="Break-even")+
    labs(title = "Low annual rate of decline"
         # subtitle = "Offset costs"
         )
mix_g2 = prob_time(mix, prof_class ="50% profit")+
    labs(title = "Low annual rate of decline",
         subtitle = "50% profit"
         )
tebu_g1+mix_g1+
  plot_layout(guides = "collect")+
  plot_annotation(tag_levels = 'A')&
  theme(legend.position = "bottom",
        plot.title = element_text(size = 10))

ggsave("figs/prob_time.png", dpi = 600, height = 4, width = 7)
ggsave("figs/prob_time.pdf", dpi = 600, height = 4, width = 7)
JSBEYXRhIGFuYWx5c2lzDQoNCg0KIyBQYWNrYWdlcw0KSGVyZSB3ZSBsb2FkIGFsbCB0aGUgcGFja2FnZXMgd2UgYWUgZ29pbmcgdG8gdXNlIGluIHRoZSBhbmFseXNpcy4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnc2hlZXQpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShEZXNjVG9vbHMpDQpsaWJyYXJ5KG1pbnBhY2subG0pDQpsaWJyYXJ5KGFncmljb2xhZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShwYXRjaHdvcmspDQpgYGANCg0KDQojIFByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMNCg0KRmlzdCBzdGVwIGlzIHRvIGFzc2VtYmxlIHRoZSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zIGZvciB0aGUgZm9yIHZhcmlhYmxlIHdlIGFyZSBnb2luZyB0byB1c2UgZm9yIHRoZSBzaW11bGF0aW9ucw0KDQojIyBTQlIgc2V2ZXJpdHkgb24gdW50cmVhdGVkIGNoZWNrLg0KDQojIyMgSW1wb3J0IGRhdGENCg0KSW1wb3J0aW5nIGRhdGEgb2Ygc295YmVhbiBydXN0IHNldmVyaXR5IChTQlIpIG9uIHRoZSB1bnRyZWF0ZWQgY2hlY2sNCg0KYGBge3J9DQpzZXZfZGF0YSA9IHJlYWQuY3N2KCJkYXRhL3Nldl9kYXRhLmNzdiIpDQpoZWFkKHNldl9kYXRhKQ0KYGBgDQoNCkZpbHRlcmluZyBvbmx5IHZhbHVlcyBvZiBzZXZlcml0eSBpbiB0aGUgY2hlY2sgdHJlYXRtZW50DQpgYGB7cn0NCnNldl9jaGVjayA9IHNldl9kYXRhICU+JSANCiAgZmlsdGVyKGFjdGl2ZV9pbmdyZWRpZW50ID09ICJjaGVjayIpDQpoZWFkKHNldl9jaGVjaykNCmBgYA0KDQojIyMgRW1waXJpY2FsIGRpc3RyaWJ1dGlvbg0KDQpgYGB7cn0NCnNldl9jaGVjayAlPiUgDQogIGdncGxvdChhZXMoc2V2ZXJpdHkvMTAwKSkrDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCwgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyYXkiKQ0KYGBgDQoNCg0KIyMjIE1vZGVsaW5nDQoNClNpbmNlIHNldmVyaXR5IGluIHByb3BvcnRpb25hbCB0ZXJtcyBpcyBiZXR3ZWVuIHplcm8gYW5kIG9uZSwgd2UgZml0IHRoZSBlbXBpcmljYWwgZGlzdHJpYnV0aW9uIGludG8gYSBiZXRhIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbi4gRm9yIHRoYXQgd2UgbmVlZCB0byBmaW5kIHRoZSBzaGFwZSBhbmQgc2NhbGUgcGFyYW1ldGVycyBvZiB0aGUgYmV0YSBkaXN0cmlidXRpb24gZnVuY3Rpb24uDQoNCkZvciB0aGF0LCBvYnRhaW4gdGhlIGVtcGlyaWNhbCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBhbmQgZml0IHRvIHRoZSBiZXRhIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uLg0KDQpgYGB7cn0NCnNldiA9IHNldl9jaGVjayRzZXZlcml0eQ0KRng9IGVudmlyb25tZW50KGVjZGYoc2V2KSkkeQ0KeCA9IGVudmlyb25tZW50KGVjZGYoc2V2KSkkeC8xMDANCg0Kc3VtbWFyeShubHNMTShGeCB+IHBiZXRhKHgsIHNoYXBlMSwgc2hhcGUyLCBsb2cgPSBGQUxTRSkgLA0KICAgICAgc3RhcnQgPSBjKHNoYXBlMSA9IDEsIHNoYXBlMiA9IDEpLA0KICAgICAgY29udHJvbCA9IG5scy5sbS5jb250cm9sKG1heGl0ZXIgPSAxMDAwMDApKSkNCmBgYA0KDQojIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCmBgYHtyfQ0Ka3MudGVzdChGeCxwYmV0YSh4LCAxLjcwNywgMS4yNjYpICkNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdCh4LEZ4KQ0KY3VydmUocGJldGEoeCwgMS43MDcsIDEuMjY2KSwwLDEsIGFkZCA9IFQpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QoRngscGJldGEoeCwgMS43MDcsIDEuMjY2KSApDQphYmxpbmUoYT0wLGI9MSkNCmBgYA0KDQoNCiMjIyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCnNldl9kaXN0X3Bsb3QgPSBzZXZfY2hlY2sgJT4lIA0KICBnZ3Bsb3QoYWVzKHNldmVyaXR5LzEwMCkpKw0KIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLGJpbnMgPSAxMCwgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIiNBQzA4RkYiKSsNCiAgIHN0YXRfZnVuY3Rpb24oZnVuPWZ1bmN0aW9uKHgpIGRiZXRhKHgsIDEuNzA3LCAxLjI2NiksIGNvbG9yPSAiYmxhY2siLCBzaXplID0gMS4yKSsNCiAgdGhlbWVfYncoKSsNCiAgbGFicyh4PSJTZXZlcml0eSAocHJvcG9ydGlvbikiLCB5ID0gIkRlbnNpdHkiKQ0Kc2V2X2Rpc3RfcGxvdA0KIyBnZ3NhdmUoImZpZ3Mvc2V2X2Rpc3QucG5nIiwgZHBpPTYwMCwgaGVpZ2h0ID0gMywgd2lkdGggPSA0KQ0KYGBgDQoNCg0KDQojIyBTb3liZWFuIHByaWNlIA0KDQojIyMgSW1wb3J0IGRhdGENCg0KYGBge3J9DQpzb3liZWFuID0gZ3NoZWV0MnRibCgiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMS1qUTlPZ1dkTFFDYjBpQjBGcWJyaHVWaTdMaU5ocXh2ZjlRVTQtaXVjM28vZWRpdCNnaWQ9MTA4NTMyOTM1OSIpIA0KaGVhZChzb3liZWFuKQ0KYGBgDQoNCg0KY29udmVyc2lvbiB0byBVUyBkb2xsYXINCmBgYHtyfQ0Kc2JyX3ByaWNlID0gc295YmVhbiAlPiUgDQogIGZpbHRlcih5ZWFyPj0yMDE4KSAlPiUgDQogIG11dGF0ZShwcmljZSA9IChwcmljZS82MCkvNCwNCiAgICAgICAgIG5hdGlvbmFsX3ByaWNlID0gKG5hdGlvbmFsX3ByaWNlLzYwKS80KQ0Kc2JyX3ByaWNlDQpgYGANCg0KYGBge3J9DQpzYnJfcHJpY2UgJT4lIA0KICBnZ3Bsb3QoYWVzKHllYXIscHJpY2UpKSArDQogIGdlb21faml0dGVyKGFscGhhID0uMiwgc2l6ZSA9MikrDQogIGdlb21fYm94cGxvdChhZXMoZ3JvdXAgPSB5ZWFyKSwgZmlsbCA9IE5BLCBzaXplPSAxKSsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQoKSsNCiAgdGhlbWVfbWluaW1hbF9oZ3JpZCgpDQogICMgZmFjZXRfd3JhcCh+c3RhdGUpDQpgYGANCg0KDQpNZWFuIGFuZCBTdGFuZGFkIGRldmlhbnRpb24NCg0KYGBge3J9DQptZWFuKHNicl9wcmljZSRwcmljZSkNCnNkKHNicl9wcmljZSRwcmljZSkNCmBgYA0KDQojIyMgRW1waXJpY2FsIGRpc3RyaWJ1dGlvbg0KDQpgYGB7cn0NCnNicl9wcmljZSAlPiUgDQogIGdncGxvdChhZXMocHJpY2UpKSsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGNvbG9yID0gIndoaXRlIikrDQogIHRoZW1lX2J3KCkrDQogIGxhYnMoeCA9ICJTb3liZWFuIHByaW5jZSIpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMSxieT0wLjAyNSkpDQpgYGANCg0KDQogDQpgYGB7cn0NCmhpc3QoKHNicl9wcmljZSRwcmljZSksIHByb2IgPSBUKQ0KY3VydmUoZG5vcm0oeCwgbWVhbihzYnJfcHJpY2UkcHJpY2UpLCBzZChzYnJfcHJpY2UkcHJpY2UpKSwwLjE1LDAuMzUsIGFkZCA9IFQpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QoZWNkZihzYnJfcHJpY2UkcHJpY2UpKQ0KY3VydmUocG5vcm0oeCwgbWVhbihzYnJfcHJpY2UkcHJpY2UpLCBzZChzYnJfcHJpY2UkcHJpY2UpKSwwLjIsMC4zNSwgYWRkID0gVCkNCmBgYA0KDQpNZWFuIGFuZCBtZWRpYW4NCmBgYHtyfQ0KbWVhbihzYnJfcHJpY2UkcHJpY2UpDQptZWRpYW4oc2JyX3ByaWNlJHByaWNlKQ0KYGBgDQoNCiMjIyBTaGFwaXJvDQpgYGB7cn0NCnNoYXBpcm8udGVzdChzYnJfcHJpY2UkcHJpY2UpDQpgYGANCg0KIyMjIEtvbG1vZ29yb3YtU21pcm5vdiBUZXN0DQpgYGB7cn0NCkZ4ID0gZW52aXJvbm1lbnQoZWNkZihzYnJfcHJpY2UkcHJpY2UpKSR5DQp4PSBlbnZpcm9ubWVudChlY2RmKHNicl9wcmljZSRwcmljZSkpJHgNCmtzLnRlc3QoRngsIHBub3JtKHgsIG1lYW4oc2JyX3ByaWNlJHByaWNlKSwgc2Qoc2JyX3ByaWNlJHByaWNlKSkpDQpgYGANCg0KYGBge3J9DQpwbG90KEZ4LCBwbm9ybSh4LCBtZWFuKHNicl9wcmljZSRwcmljZSksIHNkKHNicl9wcmljZSRwcmljZSkpKQ0KYGBgDQoNCg0KIyMjIFZpenVhbGl6YXRpb24NCg0KYGBge3J9DQpwcmljZV9wbG90ID0gc2JyX3ByaWNlICU+JSANCiAgZ2dwbG90KGFlcyhwcmljZSkpKw0KIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLGJpbnMgPSAxMCwgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIiMxQzhDMjAiKSsNCiAgIHN0YXRfZnVuY3Rpb24oZnVuPWZ1bmN0aW9uKHgpIGRub3JtKHgsIG1lYW4oc2JyX3ByaWNlJHByaWNlKSwgc2Qoc2JyX3ByaWNlJHByaWNlKSksIGNvbG9yPSAiYmxhY2siLCBzaXplID0gMS4yKSsNCiAgdGhlbWVfYncoKSsNCiAgbGFicyh4PSJTb3liZWFuIHByaWNlIChVUyQva2cpIiwgeSA9ICJEZW5zaXR5IikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxLGJ5PTAuMDI1KSkNCnByaWNlX3Bsb3QNCiMgZ2dzYXZlKCJmaWdzL3Nldl9kaXN0LnBuZyIsIGRwaT02MDAsIGhlaWdodCA9IDMsIHdpZHRoID0gNCkNCmBgYA0KDQoNCg0KDQojIyBSZWdyZXNzaW9uIGNvZWZpY2llbnRzIA0KDQojIyMgaW1wb3J0IGRhdGENCkltcG9ydGluZyByZWdyZXNzaW9uIFNsb3BlIGFuZCBpbnRlcmNlcHQgZGF0YSBmcm9tIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBTQlIgc2V2ZXJpdHkgYW5kIHlpZWxkDQoNCmBgYHtyfQ0KZGFtYWdlX2RhdGEgPSByZWFkX2V4Y2VsKCJkYXRhL2RhZG9zIGhpc3RvZ3JhbWEueGxzeCIpICU+JSANCiAgbXV0YXRlKFNsb3BlID0gYjEsDQogICAgICAgICBJbnRlcmNlcHQgPSBiMCkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1iMSwtYjApDQpoZWFkKGRhbWFnZV9kYXRhKQ0KYGBgDQoNCiMjIyBFbXBpcmljYWwgZGlzdHJpYnV0aW9uDQpWaXN1YWxpemFuZG8gb3MgaGl0b2dyYW1hcyBkbyBzbG9wZSBlIGludGVyY2VwdG8NCg0KYGBge3J9DQpkYW1hZ2VfZGF0YSAlPiUgDQogIGdhdGhlcigyOjMsIGtleSA9ICJwYXIiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgZ2dwbG90KGFlcyh2YWx1ZSkpKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAsIGNvbG9yID0gImdyYXk0MCIsIGZpbGwgPSAiZ3JheTkwIikrDQogIGZhY2V0X3dyYXAofnBhciwgc2NhbGVzID0gImZyZWVfeCIpKw0KICB0aGVtZV9idygpDQpgYGANCg0KDQojIyMgUmVncmVzc2lvbiBsaW5lcw0KYGBge3J9DQogIGdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IDA6MTAwLCB5ID0gc2VxKDAsNTAwMCxieSA9IDUwKSksIGNvbG9yID0gTkEpKw0KICBnZW9tX2FibGluZShkYXRhID1kYW1hZ2VfZGF0YSwgYWVzKHNsb3BlID0gU2xvcGUsIGludGVyY2VwdCA9IEludGVyY2VwdCksDQogICAgICAgICAgICAgIGFscGhhID0gMC41LCBjb2xvciA9ICJncmF5IikrDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDI5Nzcsc2xvcGUgPSAtMTgsIHNpemUgPSAxLjIpKw0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAyODYyLHNsb3BlID0gLTE5LjQgLCBzaXplID0gLjUxLCBsaW5ldHlwZSA9IDIpKw0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzMDkzLHNsb3BlID0gLTE2LjYsIHNpemUgPSAuNTEsIGxpbmV0eXBlID0gMikrDQogIA0KICBsYWJzKHggPSAiU0JSIFNldmVyaXR5ICglKSIsIHkgPSAiWWllbGQgKGtnL2hhKSAiKSsNCiAgdGhlbWVfYmFzZSgpDQogIA0KYGBgDQoNCiMjIyBjb3JyZWxhdGlvbg0KQ29ycmVsYXRpb24gYmV0d2VlbiBzbG9wZSBhbmQgaW50ZXJjZXB0DQoNCmBgYHtyfQ0KY29ycmVsYXRpb24oZGFtYWdlX2RhdGEkU2xvcGUsIGRhbWFnZV9kYXRhJEludGVyY2VwdCkNCmBgYA0KDQojIyMjIHBsb3QgDQpgYGB7cn0NCmNvcnJfZW1wX3Bsb3QgPSBkYW1hZ2VfZGF0YSAlPiUgDQogIGdncGxvdChhZXMoSW50ZXJjZXB0LCBTbG9wZSkpKw0KICBnZW9tX3BvaW50KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9MiwgYWxwaGEgPTAuNSkrDQogICMgZ2VvbV9kZW5zaXR5MmRfZmlsbGVkKCkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRiwgY29sb3IgPSJSZWQiLCBzaXplPTEuMiwgZnVsbHJhbmdlPVRSVUUpKw0KICB0aGVtZV9saWdodCgpKw0KICBsYWJzKHRpdGxlID0gIkVtcGlyaWNhbDogciA9IC0wLjIxNiIpKw0KICBjb29yZF9jYXJ0ZXNpYW4oDQogICAgeGxpbSA9IGMoMCw2MDAwKSwNCiAgICB5bGltID0gYygtNzUsMCkNCiAgKQ0KY29ycl9lbXBfcGxvdA0KYGBgDQoNCg0KIyMjIEN1bXVsYXRpdmUgZGVuc2l0eQ0KDQojIyMgSW50ZXJjZXB0DQpgYGB7cn0NCm1lYW5faW50ZXJjZXB0ID0gbWVhbihkYW1hZ2VfZGF0YSRJbnRlcmNlcHQpDQpzZF9pbnRlcmNlcHQgPSBzZChkYW1hZ2VfZGF0YSRJbnRlcmNlcHQpDQoNCnBsb3QoZWNkZihkYW1hZ2VfZGF0YSRJbnRlcmNlcHQpKQ0KY3VydmUocG5vcm0oeCwgbWVhbl9pbnRlcmNlcHQsc2RfaW50ZXJjZXB0KSwgMTAwMCw1MDAwLCBhZGQgPSBULCBjb2wgPSAicmVkIikNCmBgYA0KDQojIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCmBgYHtyfQ0KRnggPSBlbnZpcm9ubWVudChlY2RmKGRhbWFnZV9kYXRhJEludGVyY2VwdCkpJHkNCng9IGVudmlyb25tZW50KGVjZGYoZGFtYWdlX2RhdGEkSW50ZXJjZXB0KSkkeA0Ka3MudGVzdChGeCwgcG5vcm0oeCwgbWVhbihkYW1hZ2VfZGF0YSRJbnRlcmNlcHQpLCBzZChkYW1hZ2VfZGF0YSRJbnRlcmNlcHQpKSkNCmBgYA0KYGBge3J9DQpwbG90KEZ4LCBwbm9ybSh4LCBtZWFuKGRhbWFnZV9kYXRhJEludGVyY2VwdCksIHNkKGRhbWFnZV9kYXRhJEludGVyY2VwdCkpKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmludGVyY2VwX3Bsb3QgPSBkYW1hZ2VfZGF0YSAlPiUgDQogIGdncGxvdChhZXMoSW50ZXJjZXB0KSkrDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLGJpbnMgPSAxMCwgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gIiNGRjQ5MTciKSsNCiAgc3RhdF9mdW5jdGlvbihmdW49ZnVuY3Rpb24oeCkgZG5vcm0oeCwgbWVhbl9pbnRlcmNlcHQsIHNkX2ludGVyY2VwdCksIGNvbG9yID0iYmxhY2siLCBzaXplID0xLjIpKw0KICB0aGVtZV9idygpKw0KICBsYWJzKHg9IkludGVyY2VwdCAoa2cvaGEpIiwgeSA9ICJEZW5zaXR5IikNCmludGVyY2VwX3Bsb3QNCmBgYA0KDQoNCg0KDQoNCiMjIyBTbG9wZQ0KDQpgYGB7cn0NCm1lYW5fc2xvcGUgPSBtZWFuKGRhbWFnZV9kYXRhJFNsb3BlKQ0Kc2Rfc2xvcGUgPSBzZChkYW1hZ2VfZGF0YSRTbG9wZSkNCg0KcGxvdChlY2RmKGRhbWFnZV9kYXRhJFNsb3BlKSkNCmN1cnZlKHBub3JtKHgsIG1lYW5fc2xvcGUsIHNkX3Nsb3BlKSwgLTYwLDUsIGFkZCA9IFQsIGNvbCA9ICJyZWQiKQ0KDQpgYGANCg0KDQojIyMjIE1vZGVsaW5nDQpGaXR0aW5nIGdhbW1hIGRpc3RyaWJ1dGlvbiB0byB0aGUgZW1waXJpY2FsIGN1bXVsYXRpdmUgZGVuc2l0eSBvZiB0aGUgc2xvcGUgZGF0YQ0KYGBge3J9DQpGeCA9ZW52aXJvbm1lbnQoZWNkZigtZGFtYWdlX2RhdGEkU2xvcGUpKSR5DQp4ID0gZW52aXJvbm1lbnQoZWNkZigtZGFtYWdlX2RhdGEkU2xvcGUpKSR4DQoNCnNsb3BlX3JlZyA9IG5sc0xNKEZ4IH4gcGdhbW1hKHgsIHNoYXBlLCByYXRlLGxvZyA9IEZBTFNFKSAsDQogICAgICBzdGFydCA9IGMoc2hhcGUgPSAyLjUsIHJhdGUgPSAwLjEzKSwNCiAgICAgIGNvbnRyb2wgPSBubHMubG0uY29udHJvbChtYXhpdGVyID0gMTAyNCkpDQpzdW1tYXJ5KHNsb3BlX3JlZykNCg0KYGBgDQoNCiMjIyBLb2xtb2dvcm92LVNtaXJub3YgVGVzdA0KYGBge3J9DQpzaGFwZSA9IHN1bW1hcnkoc2xvcGVfcmVnKSRjb2VmWzFdDQpyYXRlID0gc3VtbWFyeShzbG9wZV9yZWcpJGNvZWZbMl0NCg0KRnggPWVudmlyb25tZW50KGVjZGYoLWRhbWFnZV9kYXRhJFNsb3BlKSkkeQ0KeCA9IGVudmlyb25tZW50KGVjZGYoLWRhbWFnZV9kYXRhJFNsb3BlKSkkeA0Ka3MudGVzdChGeCwgcGdhbW1hKHgsIHNoYXBlLCByYXRlKSkNCmBgYA0KDQoNCmBgYHtyfQ0Kc2hhcGUgPSBzdW1tYXJ5KHNsb3BlX3JlZykkY29lZlsxXQ0KcmF0ZSA9IHN1bW1hcnkoc2xvcGVfcmVnKSRjb2VmWzJdDQoNCnNsb3BlX3Bsb3QgPSBkYW1hZ2VfZGF0YSAlPiUgDQogIGdncGxvdChhZXMoU2xvcGUpKSsNCiBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSxiaW5zID0gMTAsIGNvbG9yID0gIndoaXRlIiwgZmlsbCA9ICIjMTU5RUU2IikrDQogICBzdGF0X2Z1bmN0aW9uKGZ1bj1mdW5jdGlvbih4KSBkZ2FtbWEoLXgsIHNoYXBlLCByYXRlKSwgc2l6ZSA9IDEuMiwgY29sb3IgPSAiYmxhY2siKSsNCiAgdGhlbWVfYncoKSsNCiAgbGFicyh4PSJTbG9wZSAoa2cvcC5wLikiLCB5ID0gIkRlbnNpdHkiKQ0Kc2xvcGVfcGxvdA0KYGBgDQoNCiMjIyBLb2xtb2dvcm92LVNtaXJub3YgVGVzdA0KYGBge3J9DQoNCmtzLnRlc3QoRngscGdhbW1hKHgsIHNoYXBlLCByYXRlKSkNCg0KYGBgDQoNCg0KDQoNCiMjIyBNdWx0aXZhcmlhdGUgU2ltdWxhdGlvbiB1c2luZyBjb3B1bGEgDQoNClNpbXVsYXRpbmcgdHdvIG5vcm1hbCBkaXN0cmlidXRpb25zIGNvcnJlbGF0ZWQgDQojIyMjIEZ1bmN0aW9uDQoNCg0KYGBge3J9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KZ2VyYS5ub3JtLmJpZC5nZXJhbDwtZnVuY3Rpb24odGFtYW5oby5hbW9zdHJhLGNvcnJlbGFjYW8sbTEsbTIsc2lnbWExLHNpZ21hMikNCnsNCiAgcm88LWNvcnJlbGFjYW8NCiAgbjwtdGFtYW5oby5hbW9zdHJhDQogIHg8LW1hdHJpeCgwLG4sMikNCiAgZm9yIChpIGluIDE6bikNCiAge3hbaSwxXTwtcm5vcm0oMSxtMSxzaWdtYTEpDQogIHhbaSwyXTwtcm5vcm0oMSxtMitybypzaWdtYTEvc2lnbWEyKih4W2ksMV0tbTEpLHNpZ21hMiooc3FydCgxLXJvXjIpKSkNCiAgfQ0KICByZXR1cm4oeCkNCn0NCg0KYGBgDQoNClRlc3QgZm9yIGNvcnJlbGF0aW9uIG9mIDAuOQ0KYGBge3J9DQojdGVzdGFuZG8NCmo8LWdlcmEubm9ybS5iaWQuZ2VyYWwoMTAwMCwwLjksMCwwLDEsMSkNCg0KcGxvdChqWywxXSxqWywyXSkNCmBgYA0KDQpGb3Igb3VyIGRhdGEsIHdlIHdpbGwgdXNlIHRoZSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiwgYmVjb3VzZSB3ZSB3YW50IHBvc2l0aXZlIHZhbHVlcyBvZiBzbG9wZSANCmBgYHtyfQ0KI3Rlc3RhbmRvDQpqPC1nZXJhLm5vcm0uYmlkLmdlcmFsKDEwMDAwLDAuMjE2MDA4OSwwLDAsMSwxKQ0KDQpwbG90KGpbLDFdLGpbLDJdKQ0KYGBgDQoNCg0KDQojIyMgSW50ZXJjZXB0DQpOb3cgd2Ugb2J0YWluZyB0aGUgcHJvYmFiaWxpdGllcyBmcm9tIGZpcnN0IGRpc3RyaWJ1dGlvbiBhbmQgaW5zZXJ0IGluIHRoZSBxdWFudGlsZXMgZnVuY3Rpb24gZm9yIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBpbnRlcmNlcHQNCg0KYGBge3J9DQpiMCA9IHBub3JtKGpbLDJdKQ0KYjBfdCA9IHFub3JtKGIwLCAyOTc3LCA1OC45KnNxcnQoMjEwKSkNCmhpc3QoYjBfdCwgcHJvYiA9IFQpDQpjdXJ2ZShkbm9ybSh4LCBtZWFuX2ludGVyY2VwdCwgc2RfaW50ZXJjZXB0KSwgMCwgNjAwMCwgYWRkID0gVCkNCmBgYA0KDQoNCiMjIyBTbG9wZQ0KTm93IHdlIG9idGFpbmcgdGhlIHByb2JhYmlsaXRpZXMgZnJvbSBmaXJzdCBkaXN0cmlidXRpb24gYW5kIGluc2VydCBpbiB0aGUgcXVhbnRpbGVzIGZ1bmN0aW9uIGZvciB0aGUgZ2FtbWEgZGl0cmlidXRpb24gYW5kIG11bHRpcGx5IGZvciAtMSBmb3Igb2J0YWluIHRoZSBuZWdhdGl2ZSBvdXRwdXRzIG9mIHRoZSBjb2VmaWNpZW50IA0KYGBge3J9DQpiMSA9IHBub3JtKGpbLDFdKQ0KYjFfdCA9IHFnYW1tYShiMSwgc2hhcGUsIHJhdGUgPSByYXRlKSotMQ0KaGlzdChiMV90LCBwcm9iID0gVCkNCmN1cnZlKGRnYW1tYSgteCxzaGFwZT1zaGFwZSwgcmF0ZSA9IHJhdGUpLCAtNjAsMCwgYWRkID0gVCkNCmBgYA0KDQoNCk5vdyB3ZSByZWNhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2ltdWxhdGVkIGNvZWZpY2llbnRzLiBJdCBtYXRjaHMhDQoNCmBgYHtyfQ0KY29ycmVsYXRpb24oYjFfdCwgYjBfdCkNCmBgYA0KDQoNCiMjIyMgVml6LiB0aGUgY29ycmVsYXRpb24NCmBgYHtyfQ0KY29ycl9zaW1fcGxvdCA9IGRhdGEuZnJhbWUoYjBfdCxiMV90ICkgJT4lDQogIG11dGF0ZShhbGZhID0oYjFfdC9iMF90KSoxMDAgKSAlPiUgDQogIGZpbHRlcihhbGZhID4gLTMgJiBhbGZhIDwgMCkgJT4lIA0KZ2dwbG90KGFlcyhiMF90LGIxX3QgKSkrDQogIGdlb21fcG9pbnQoIHNpemUgPTIsIGNvbG9yID0gIm9yYW5nZSIsIGFscGhhID0wLjMpKw0KICAjIGdlb21fZGVuc2l0eV8yZChjb2xvciA9ICJibGFjayIpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgY29sb3IgPSAicmVkIiwgc2UgPSBGLCBzaXplID0gMS4yKSsNCiAgdGhlbWVfbGlnaHQoKSsNCiAgbGFicyh5PSAiU2xvcGUiLA0KICAgICAgIHggPSAiSW50ZXJjZXB0IiwNCiAgICAgICB0aXRsZSA9ICJTaW11bGF0ZWQ6IHIgPSAtMC4yMDQiKSsNCiAgY29vcmRfY2FydGVzaWFuKA0KICAgIHhsaW0gPSBjKDAsNjAwMCksDQogICAgeWxpbSA9IGMoLTc1LDApDQogICkNCmNvcnJfc2ltX3Bsb3QNCmBgYA0KDQoNCiMjIyMgQ29tYm8gZGlzdHJpYnV0aW9ucw0KDQpgYGB7cn0NCg0KIyBwbG90X2dyaWQoc2V2X2Rpc3RfcGxvdCxwcmljZV9wbG90LCBpbnRlcmNlcF9wbG90LCBzbG9wZV9wbG90LCBsYWJlbHMgPSAiQVVUTyIsIG5yb3cgPTIpDQoNCihzZXZfZGlzdF9wbG90K3ByaWNlX3Bsb3QpLw0KICAoaW50ZXJjZXBfcGxvdCtzbG9wZV9wbG90KSsNCiAgIyAoY29ycl9lbXBfcGxvdCtjb3JyX3NpbV9wbG90KSsNCiAgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpJg0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPTgpKQ0KICANCmdnc2F2ZSgiZmlncy9jb2VmX2Rpc3QucG5nIiwgZHBpID0gNjAwLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYpDQpnZ3NhdmUoImZpZ3MvY29lZl9kaXN0LnBkZiIsIGRwaSA9IDYwMCwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2KQ0KYGBgDQoNCg0KDQojIyMgUmVsYXRpdmUgeWllbGQgbG9zcw0KDQpIZXJlIHdlIGNhbGN1bGF0ZSB0aGUgeWllbGQgcmVsYXRpdmUgbG9zcyBkdWUgdG8gU0JSIHNldmVyaXR5IHVzaW5nIHRoZSBvcmlnaW5hbCBkYXRhIHNldA0KDQpgYGB7cn0NCmVtcGlyaWNfcnlsPSBkYW1hZ2VfZGF0YSAlPiUgDQogIG11dGF0ZShjYyA9IChTbG9wZS9JbnRlcmNlcHQpKjEwMCkgJT4lIA0KICBmaWx0ZXIoIGNjID4gLTMgJiBjYyA8MCApDQpoZWFkKGVtcGlyaWNfcnlsKQ0KYGBgDQoNCmBgYHtyfQ0Kc3RhdF9lbXBfcnlsID1lbXBpcmljX3J5bCU+JSANCiAgc3VtbWFyaXNlKGRhdGEgPSAiZW1waXJpY2FsIiwNCiAgICAgICAgICAgIG1lYW4gPSAgbWVhbihjYyksDQogICAgICAgICAgICBtZWRpYW4gPSAgbWVkaWFuKGNjKSwNCiAgICAgICAgICAgIHZhcmlhbmNlID0gdmFyKGNjKSkNCmBgYA0KDQoNCmBgYHtyfQ0KDQpyZWFsX1JZTD0gZW1waXJpY19yeWwgJT4lIA0KICBnZ3Bsb3QoYWVzKGNjKSkrDQogZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksYmlucyA9IDEwLCBjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAiYmxhY2siKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxLjQpLGJyZWFrcyA9ICBzZXEoMCwgMS40LGJ5ID0gMC40KSkrDQogIGdlb21fdmxpbmUoZGF0YSA9IHN0YXRfZW1wX3J5bCwgYWVzKHhpbnRlcmNlcHQgPSBtZWFuLCBjb2xvciA9ICJNZWFuIiksc2l6ZSA9MSkrDQogIGdlb21fdmxpbmUoZGF0YSA9IHN0YXRfZW1wX3J5bCwgYWVzKHhpbnRlcmNlcHQgPSBtZWRpYW4sIGNvbG9yID0gIk1lZGlhbiIpLHNpemUgPTEpKw0KICB0aGVtZV9idygpKw0KICBzY2FsZV9jb2xvcl9jYWxjKCkrDQogIGxhYnMoeCA9ICJSZWxhdGl2ZSB5aWVsZCBsb3NzICglL3AucC4pIiwNCiAgICAgICB5ID0gIkRlbnNpdHkiLA0KICAgICAgIGNvbG9yID0gIiIsDQogICAgICAgdGl0bGUgPSAiRW1waXJpY2FsIikrDQogIHhsaW0oLTMsMC4yKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpyZWFsX1JZTA0KYGBgDQoNCkFuZCBoZXJlIHdlIGNhbGN1bGF0ZSB0aGUgcmVsYXRpdmUgeWllbGQgbG9zcyBkdWUgdG8gU0JSIHNldmVyaXR5IHVzaW5nIHRoZSBzaW11bGF0ZWQgZGF0YSBzZXQNCg0KDQpgYGB7cn0NCnNpbXVsX3J5bCA9IGRhdGEuZnJhbWUoYjBfdCwgYjFfdCwgY2MgPSAoYjFfdC9iMF90KSoxMDApICU+JSANCiAgZmlsdGVyKCBjYyA+IC0zICYgY2MgPDAgKQ0KaGVhZChzaW11bF9yeWwpDQpgYGANCg0KYGBge3J9DQpzdGF0X3N1bWxfcnlsID0gc2ltdWxfcnlsJT4lIA0KICBzdW1tYXJpc2UoZGF0YSA9ICJTaW11bGF0ZWQiLA0KICAgICAgICAgICAgbWVhbiA9ICBtZWFuKGNjKSwNCiAgICAgICAgICAgIG1lZGlhbiA9ICBtZWRpYW4oY2MpLA0KICAgICAgICAgICAgdmFyaWFuY2UgPSB2YXIoY2MpKQ0KYGBgDQoNCg0KYGBge3J9DQpzaW11bF9SWUwgPXNpbXVsX3J5bCAlPiUgDQogIGdncGxvdChhZXMoY2MpKSsNCiBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSxiaW5zID0gMTAsIGNvbG9yID0gIndoaXRlIiwgZmlsbCA9ICJvcmFuZ2UiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxLjQpLGJyZWFrcyA9ICBzZXEoMCwgMS40LGJ5ID0gMC40KSkrDQogIGdlb21fdmxpbmUoZGF0YSA9IHN0YXRfc3VtbF9yeWwsIGFlcyh4aW50ZXJjZXB0ID0gbWVhbiwgY29sb3IgPSAiTWVhbiIpLHNpemUgPTEpKw0KICBnZW9tX3ZsaW5lKGRhdGEgPSBzdGF0X3N1bWxfcnlsLCBhZXMoeGludGVyY2VwdCA9IG1lZGlhbiwgY29sb3IgPSAiTWVkaWFuIiksc2l6ZSA9MSkrDQogIHRoZW1lX2J3KCkrDQogIHNjYWxlX2NvbG9yX2NhbGMoKSsNCiAgbGFicyh4ID0gIlJlbGF0aXZlIHlpZWxkIGxvc3MgKCUvcC5wLikiLA0KICAgICAgIHkgPSAiRGVuc2l0eSIsDQogICAgICAgY29sb3IgPSIiLA0KICAgICAgIHRpdGxlID0gIlNpbXVsYXRlZCIpKw0KICB4bGltKC0zLDAuMikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0Kc2ltdWxfUllMDQoNCmBgYA0KDQojIyMgQ29tcGFyaXNpb24gb2YgbWVhbiwgbWVkaWFuIGFuZCB2YXJpYW5jZSANCg0KYGBge3J9DQpkYW1hZ2VfZGF0YSAlPiUgDQogIG11dGF0ZShjYyA9IChTbG9wZS9JbnRlcmNlcHQpKjEwMCkgJT4lIA0KICBmaWx0ZXIoIGNjID4gLTMgJiBjYyA8MCApICU+JSANCiAgc3VtbWFyaXNlKGRhdGEgPSAiZW1waXJpY2FsIiwNCiAgICAgICAgICAgIG1lYW4gPSAgbWVhbihjYyksDQogICAgICAgICAgICBtZWRpYW4gPSAgbWVkaWFuKGNjKSwNCiAgICAgICAgICAgIHZhcmlhbmNlID0gdmFyKGNjKSkgJT4lIA0KICBiaW5kX3Jvd3MoDQogICAgZGF0YS5mcmFtZShiMF90LCBiMV90LCBjYyA9IChiMV90L2IwX3QpKjEwMCkgJT4lIA0KICBmaWx0ZXIoIGNjID4gLTMgJiBjYyA8MCApICU+JSANCiAgc3VtbWFyaXNlKGRhdGEgPSAiU2ltdWxhdGVkIiwNCiAgICAgICAgICAgIG1lYW4gPSAgbWVhbihjYyksDQogICAgICAgICAgICBtZWRpYW4gPSAgbWVkaWFuKGNjKSwNCiAgICAgICAgICAgIHZhcmlhbmNlID0gdmFyKGNjKSkNCiAgKQ0KDQpgYGANCg0KDQojIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCmBgYHtyfQ0KYWN0dWFsX2NjID0gZGFtYWdlX2RhdGEgJT4lIA0KICBtdXRhdGUoY2MgPSAoU2xvcGUvSW50ZXJjZXB0KSoxMDApDQoNCnNpbXVsYXRlZF9jYyA9IGRhdGEuZnJhbWUoYjBfdCwgYjFfdCwgY2MgPSAoYjFfdC9iMF90KSoxMDApICU+JSANCiAgZmlsdGVyKCBjYyA+IC0zICYgY2MgPDAgKQ0KYGBgDQoNCkRpc3RyaWJ1dGlvbg0KYGBge3J9DQprcy50ZXN0KGFjdHVhbF9jYyRjYywgc2ltdWxhdGVkX2NjJGNjKQ0KYGBgDQoNCmN1bW11bGF0aXZlIGRpc3RyaWJ1dGlvbg0KYGBge3J9DQpmeF9hY3R1YWwgPSBlbnZpcm9ubWVudChlY2RmKGFjdHVhbF9jYyRjYykpJHkNCmZ4X3NpbXUgPSBlbnZpcm9ubWVudChlY2RmKHNpbXVsYXRlZF9jYyRjYykpJHkNCmtzLnRlc3QoKGZ4X2FjdHVhbCksKGZ4X3NpbXUpKQ0KYGBgDQoNCmBgYHtyfQ0KZWNkZl9kYW1hZ2UgPSBnZ3Bsb3QoKSsNCiAgc3RhdF9lY2RmKGFlcyhzaW11bGF0ZWRfY2MkY2MsY29sb3IgPSAiU2ltdWxhdGVkIiksIHNpemU9MS4yLGdlb20gPSAic3RlcCIpKw0KICBzdGF0X2VjZGYoYWVzKGFjdHVhbF9jYyRjYywgY29sb3IgPSAiRW1waXJpY2FsIiksIHNpemU9MS4yLGdlb20gPSAic3RlcCIpKw0KICB0aGVtZV9idygpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCJvcmFuZ2UiKSkrDQogIGxhYnMoeSA9ICJQcm9iYWJpbGl0eSIsDQogICAgICAgeCA9ICJSZWxhdGl2ZSBwZXJjZW50IHlpZWxkIGxvc3MiLA0KICAgICAgIGNvbG9yID0iIiwNCiAgICAgICB0aXRsZSA9ICJDdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpDQplY2RmX2RhbWFnZQ0KYGBgDQoNCg0KIyMjIENvbWJvIFlpZWxkIGxvc3MNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9OH0NCigoY29ycl9lbXBfcGxvdC9jb3JyX3NpbV9wbG90KXwocmVhbF9SWUwvc2ltdWxfUllMKStwbG90X2xheW91dChndWlkZXMgPSAnY29sbGVjdCcpfCBlY2RmX2RhbWFnZSApICsNCiAgIyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDEsMC41KSkrDQogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKSAmIA0KICANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05KSwNCiAgICAgICAgbGVnZW5kLmtleS5zaXplPSB1bml0KDMsICJtbSIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9ICBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQ0KDQpnZ3NhdmUoImZpZ3MvUllMLnBuZyIsIGRwaSA9IDYwMCwgaGVpZ2h0ID0gNSwgd2lkdGggPSAxMCkNCmdnc2F2ZSgiZmlncy9SWUwucGRmIiwgZHBpID0gNjAwLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDEwKQ0KYGBgDQoNCg0KIyBTaW11bGF0aW9ucyANCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCm49NDAwMDANCmxhbWJkYSA9IHNlcSgwLDEsIGJ5PTAuMDUpDQpmdW5fcHJpY2UgPSBzZXEoLTEwLCAyNjAsIGJ5PTE1KQ0Kbl9hcGxpY2F0aW9uID0gMQ0Kb3BlcmF0aW9uYWxfY29zdCA9IDEwICANCg0KY29tYl9tYXRyaXggPSBhcy5tYXRyaXgoZGF0YS50YWJsZTo6Q0oobGFtYmRhLGZ1bl9wcmljZSkpDQpjb2xuYW1lcyhjb21iX21hdHJpeCkgPSBjKCJsYW1iZGEiLCJmdW5fcHJpY2UiKQ0KY29tYl9tYXRyaXggPSBjYmluZChjb21iX21hdHJpeCxvcGVyYXRpb25hbF9jb3N0LCBuX2FwbGljYXRpb24pDQpDID0gY29tYl9tYXRyaXhbLCJuX2FwbGljYXRpb24iXSooY29tYl9tYXRyaXhbLCJvcGVyYXRpb25hbF9jb3N0Il0rY29tYl9tYXRyaXhbLCJmdW5fcHJpY2UiXSApDQpjb21iX21hdHJpeCA9IGNiaW5kKGNvbWJfbWF0cml4LEMpDQoNCk4gPSBsZW5ndGgoY29tYl9tYXRyaXhbLDFdKSpuDQpiaWdfb25lID0gbWF0cml4KDAsIG5jb2wgPSAxMiwgbnJvdyA9TikNCmJpZ19vbmVbLDFdID0gcmVwKGNvbWJfbWF0cml4WywxXSxuKQ0KYmlnX29uZVssMl0gPSByZXAoY29tYl9tYXRyaXhbLDJdLG4pDQpiaWdfb25lWywzXSA9IHJlcChjb21iX21hdHJpeFssM10sbikNCmJpZ19vbmVbLDRdID0gcmVwKGNvbWJfbWF0cml4Wyw0XSxuKQ0KYmlnX29uZVssNV0gPSByZXAoY29tYl9tYXRyaXhbLDVdLG4pDQoNCnNldC5zZWVkKDEpDQpzbiA9IHJiZXRhKE4sIDEuNzA3LCAxLjI2NikNCnNmID0gc24qKDEtYmlnX29uZVssMV0pDQojIHNpbXVsYXRpbmcgdGhlIGNvZWZpY2llbnRlcyANCnNldC5zZWVkKDEpDQpub3JtYWxfY29ycmVsYXRlZDwtZ2VyYS5ub3JtLmJpZC5nZXJhbChOLDAuMjEsMCwwLDEsMSkNCmIwX24gPSBwbm9ybShub3JtYWxfY29ycmVsYXRlZFssMl0pDQpiMV9uID0gcG5vcm0obm9ybWFsX2NvcnJlbGF0ZWRbLDFdKQ0KYjAgPSBxbm9ybShiMF9uLCBtZWFuX2ludGVyY2VwdCxzZF9pbnRlcmNlcHQpDQpiMSA9IC1xZ2FtbWEoYjFfbiwgc2hhcGUsIHJhdGUsKQ0Kcm0oYjBfbixiMV9uLG5vcm1hbF9jb3JyZWxhdGVkKQ0KIyBiMFtiMDwwXSA9IDAuMDAwMQ0KIyBDYWxjdWxhdGluZyB0aGUgYWxoYSBjb2VmaWNpZW50DQphbGZhID0gKGIxL2IwKSoxMDANCiMgYWxmYVthbGZhID4gMF0gPSAwDQojIGFsZmFbYWxmYSA8IC0zXSA9IC0zDQoNCiMgQ2FsY3VsYXRpbmcgeWllbGQgZ2Fpbg0KIyB5biA9IGIwKigxK3NuKmFsZmEpICMgWWllbGQgIG5vbi10cmVhdGVkDQojIHlmID0gYjAqKDErc2YqYWxmYSkgIyBZaWVsZCAgdHJlYXRlZA0KeW4gID0gYjAgLSAoLWFsZmEqYjAqc24pDQp5ZiAgPSBiMCAtICgtYWxmYSpiMCpzZikNCiMgeW5beW48MF0gPSAwDQojIHlmW3lmPDBdID0gMA0KIyB5aWVsZF9nYWluID0geWYteW4gIyB5aWVsZCBnYWluDQojIHlpZWxkX2dhaW5fcGVyYyA9ICgxLSh5bi95ZikpKjEwMA0KDQoNCiMgU2ltdWxhdGluZyBzb3liZWFuIHByaWNlDQpzZXQuc2VlZCgxKQ0Kc295X3ByaWNlID0gcm5vcm0oTiwgbWVhbihzYnJfcHJpY2UkcHJpY2UpLHNkKHNicl9wcmljZSRwcmljZSkpDQojIGluY29tZSA9IHlpZWxkX2dhaW4qc295X3ByaWNlICMgY2FsY3VsYXRpbmcgdGhlIGluY29tZQ0KDQpiaWdfb25lWyw2XSA9IHluDQpiaWdfb25lWyw3XSA9IHlmDQpiaWdfb25lWyw4XSA9IHNveV9wcmljZQ0KYmlnX29uZVssOV0gPSBiMQ0KYmlnX29uZVssMTBdID0gYWxmYQ0KYmlnX29uZVssMTFdID0gYjANCmJpZ19vbmVbLDEyXSA9IHNuDQpjb2xuYW1lcyhiaWdfb25lKSAgPSBjKCJsYW1iZGEiLCJmdW5fcHJpY2UiLCJvcGVyYXRpb25hbF9jb3N0Iiwibl9hcGxpY2F0aW9uIiwiQyIsInluIiwieWYiLCJzb3lfcHJpY2UiLCJiMSIsImFsZmEiLCJiMCIsICJzbiIpDQpgYGANCg0KDQpgYGB7cn0NCmJpZ19vbmVfZGYgPSBhcy5kYXRhLmZyYW1lKGJpZ19vbmUpICU+JSANCiAgZmlsdGVyKGIwPj0wKSAlPiUgDQogIGZpbHRlcih5bj4wKSAlPiUgDQogIGZpbHRlcihhbGZhID4gLTMgJiBhbGZhIDwgMCkgJT4lIA0KICBtdXRhdGUoeWllbGRfZ2FpbiA9IHlmLXluLA0KICAgICAgICAgIyB5aWVsZF9nYWluX3BlcmMgPSAoKHlmIC0geW4pL3luKSoxMDAsDQogICAgICAgICB5aWVsZF9nYWluX3BlcmMgPSAoKHlmL3luKS0xKSoxMDAsDQogICAgICAgICBpbmNvbWUgPSB5aWVsZF9nYWluKnNveV9wcmljZSwNCiAgICAgICAgIENQID0gQy9zb3lfcHJpY2UsDQogICAgICAgICAjIHByb2ZpdCA9ICh5aWVsZF9nYWluPj1DUCkqMSwNCiAgICAgICAgIHByb2ZpdCA9IChpbmNvbWU+PUMpKjEpDQogIA0KDQpgYGANCg0KDQojIyMgQnJlYWNraW5nIGV2ZW4NCg0KIyMjIyBUZXRyaXMNCg0KYGBge3J9DQpiaWdfb25lX2RmICU+JSANCiAgIyBtdXRhdGUoc2V2X2NsYXNzID0gY2FzZV93aGVuKHNuID4gbWVkaWFuKHNuKSB+ICJIaWdoIHNldmVyaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc24gPD0gbWVkaWFuKHNuKSB+ICJMb3cgc2V2ZXJpdHkiKSkgJT4lIA0KICBmaWx0ZXIobGFtYmRhID49MC4zKSAlPiUNCiAgZ3JvdXBfYnkobGFtYmRhLCBDKSAlPiUgDQogIHN1bW1hcmlzZShuPW4oKSxzdW1uID0gc3VtKHByb2ZpdCksIHByb2IgPSBzdW1uL24pICU+JQ0KICAjIGZpbHRlcihwcm9iPjAuNSkgJT4lDQogIG11dGF0ZShwcm9iMiA9IGNhc2Vfd2hlbihwcm9iIDwgMC41MCB+ICJQcihJIFx1MjI2NSBDKSBcdTIyNjQgMC41ICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHByb2IgPj0gMC41MCB+ICJQcihJIFx1MjI2NSBDKSA+IDAuNSIpKSAlPiUgIywNCiAgIyAjICAgICAgICAgICAgICAgICAgICAgICAgIHByb2IgPj0gMC43NSB+ICI3NSUgXHUyMjY0IHAgPCAxMDAlICIgICkpICU+JSANCiAgZ2dwbG90KGFlcyhhcy5mYWN0b3IobGFtYmRhKjEwMCksYXMuZmFjdG9yKEMpLCBmaWxsID0gcHJvYiwgDQogICAgICAgICAgICAgIyBjb2xvciA9IHByb2IyDQogICAgICAgICAgICAgKSkrDQogIGdlb21fdGlsZShzaXplID0gMC41LCBjb2xvciA9IndoaXRlIikrDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19iKG9wdGlvbiA9IkIiLCBkaXJlY3Rpb24gPSAtMSkrDQogICMgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGFya3JlZCIsICAic3RlZWxibHVlIikpKw0KICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICIjRTYwRTAwIixtaWQgPSAiIzAwMDMwRiIsIGhpZ2ggPSAiIzU1RTM0NCIsbWlkcG9pbnQgPSAwLjUpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0U2MEUwMCIsIiM1NUUzNDQiKSkrDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gInJlZCIsbWlkID0gImJsYWNrIiwgaGlnaCA9ICJzdGVlbGJsdWUiLG1pZHBvaW50ID0gMC41KSsNCiAgIyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwic3RlZWxibHVlIikpICsgDQogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MikpKSsNCiAgIyBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAiQiIpKw0KICBsYWJzKHggPSAiRnVuZ2ljaWRlIGVmZmljYWN5ICglKSIsDQogICAgICAgeSA9ICJGdW5naWNpZGUgKyBBcHBsaWNhdGlvbiBjb3N0ICgkKSIsDQogICAgICAgZmlsbCAgPSAiUHIoSSBcdTIyNjUgQykiLA0KICAgICAgIGNvbG9yID0iIiApKw0KICAjIGZhY2V0X3dyYXAofnNldl9jbGFzcykrDQogIHRoZW1lX2xpZ2h0KCkNCiMgZ2dzYXZlKCJmaWdzL3RldHJpcy5wbmciLCBkcGkgPSA2MDAsIGhlaWdodCA9IDUsIHdpZHRoID0gNykNCmBgYA0KDQojIyMjIFRldHJpcyAyDQoNCmBgYHtyfQ0KbWVkaWFuKGJpZ19vbmVfZGYkYjApDQpgYGANCg0KYGBge3J9DQp0ZXRyaXNfcGxvdCA9IGZ1bmN0aW9uKHNfY2xhc3MsIHlfY2xhc3MsIHBhbCA9MSl7DQpiaWdfb25lX2RmICU+JSANCiAgbXV0YXRlKHNldl9jbGFzcyA9IGNhc2Vfd2hlbihzbiA+IG1lZGlhbihzbikgfiAiSGlnaCBzZXZlcml0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbiA8PSBtZWRpYW4oc24pIH4gIkxvdyBzZXZlcml0eSIpLA0KICAgICAgeWllbGRfY2xhc3MgPSAgY2FzZV93aGVuKGIwID4gbWVkaWFuKGIwKSB+ICJIaWdoIHlpZWxkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIwIDw9IG1lZGlhbihiMCkgfiAiTG93IHlpZWxkIikpICU+JQ0KICAgIGZpbHRlcihsYW1iZGEgPj0wLjMpICU+JSANCiAgZ3JvdXBfYnkobGFtYmRhLCBDLCBzZXZfY2xhc3MseWllbGRfY2xhc3MpICU+JSANCiAgc3VtbWFyaXNlKG49bigpLHN1bW4gPSBzdW0ocHJvZml0KSwgcHJvYiA9IHN1bW4vbikgJT4lDQogIG11dGF0ZShwcm9iID0gY2FzZV93aGVuKHByb2IgPj0gLjc1IH4gIlx1MjI2NSAwLjc1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYiA8IC43NSAmIHByb2IgPj0gMC41IH4gIjAuNTAtMC43NSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHByb2IgPCAuNTAgJiBwcm9iID49IC4yNSB+ICIwLjI1LTAuNTAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iIDwgLjI1IH4gIjwgMC4yNSIpLA0KICAgICAgICAgcHJvYiA9ZmFjdG9yKHByb2IsbGV2ZWwgPSBjKCI8IDAuMjUiLCIwLjI1LTAuNTAiLCIwLjUwLTAuNzUiLCAiXHUyMjY1IDAuNzUiKSkpICU+JQ0KICAgIGZpbHRlcihzZXZfY2xhc3M9PSBzX2NsYXNzLA0KICAgICAgICAgICB5aWVsZF9jbGFzcyA9PSB5X2NsYXNzKSAlPiUgDQogIGdncGxvdChhZXMoYXMuZmFjdG9yKGxhbWJkYSoxMDApLGFzLmZhY3RvcihDKSwgZmlsbCA9IHByb2IpKSsNCiAgZ2VvbV90aWxlKHNpemUgPSAwLjI1LCBjb2xvciA9ImdyYXk3MCIpKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gcGFsKSsNCiAgbGFicyh4ID0gIkZ1bmdpY2lkZSBlZmZpY2FjeSAoJSkiLA0KICAgICAgIHkgPSAiRnVuZ2ljaWRlICsgQXBwbGljYXRpb24gY29zdCAoJCkiLA0KICAgICAgIGZpbGwgID0gIlByb2JhYmlsaXR5IiwNCiAgICAgICBjb2xvciA9IiIgKSsNCiAgIyBmYWNldF9ncmlkKH5zZXZfY2xhc3MpKw0KICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkrDQogIHRoZW1lX2xpZ2h0KCkrDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksDQogICAgICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDEuNzUsICJsaW5lcyIpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID1lbGVtZW50X3JlY3QoZmlsbD0iTkEiKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsIHNpemUgPTEyKSkNCn0NCg0KYGBgDQoNCmBgYHtyfQ0KdGV0cmlzX1NoX1NoID0gdGV0cmlzX3Bsb3Qoc19jbGFzcyA9ICJIaWdoIHNldmVyaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeV9jbGFzcyA9ICJIaWdoIHlpZWxkIixwYWwgPTEpKw0KICBsYWJzKHRpdGxlID0gIkhpZ2ggc2V2ZXJpdHkiLA0KICAgICAgIHN1YnRpdGxlID0gIkhpZ2ggeWllbGQiKQ0KDQp0ZXRyaXNfU2xfWWggPSB0ZXRyaXNfcGxvdChzX2NsYXNzID0gIkxvdyBzZXZlcml0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHlfY2xhc3MgPSAiSGlnaCB5aWVsZCIscGFsID0xDQogICAgICAgICAgICAgICAgICAgICAgICAgKSsNCiAgbGFicyh0aXRsZSA9ICJMb3cgc2V2ZXJpdHkiLA0KICAgICAgIHN1YnRpdGxlID0gIkhpZ2ggeWllbGQiKQ0KDQp0ZXRyaXNfU2hfWWwgPSB0ZXRyaXNfcGxvdChzX2NsYXNzID0gIkhpZ2ggc2V2ZXJpdHkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5X2NsYXNzID0gIkxvdyB5aWVsZCIscGFsID0yDQogICAgICAgICAgICAgICAgICAgICAgICAgKSsNCiAgbGFicyh0aXRsZSA9ICJIaWdoIHNldmVyaXR5IiwNCiAgICAgICBzdWJ0aXRsZSA9ICJMb3cgeWllbGQiKQ0KDQp0ZXRyaXNfU2xfU2ggPSB0ZXRyaXNfcGxvdChzX2NsYXNzID0gIkxvdyBzZXZlcml0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHlfY2xhc3MgPSAiTG93IHlpZWxkIixwYWwgPTINCiAgICAgICAgICAgICAgICAgICAgICAgICApKw0KICBsYWJzKHRpdGxlID0gIkxvdyBzZXZlcml0eSIsDQogICAgICAgc3VidGl0bGUgPSAiTG93IHlpZWxkIikNCg0KDQpgYGANCg0KDQoNCiMjIyMgQ29tYm8gdGV0cmlzDQpgYGB7cn0NCigodGV0cmlzX1NoX1NoK3RldHJpc19TbF9ZaCkrcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSkvKCh0ZXRyaXNfU2hfWWwrdGV0cmlzX1NsX1NoKSsNCiAgIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikpKw0KICBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdBJykmDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpDQogIA0KDQpnZ3NhdmUoImZpZ3MvYm94X2NsYXNzZXMucG5nIiwgZHBpID0gNTAwLCBoZWlnaHQgPSA4LjUsIHdpZHRoID0gNy41KQ0KZ2dzYXZlKCJmaWdzL2JveF9jbGFzc2VzLnBkZiIsIGRwaSA9IDUwMCwgaGVpZ2h0ID0gOC41LCB3aWR0aCA9IDcuNSkNCmBgYA0KDQoNCg0KIyMgWWllbGQgZ2Fpbg0KIyMjIEFic29sdXRlIGdhaW4NCg0KYGBge3J9DQpvdmVyYWxfeWcgPSBiaWdfb25lX2RmICU+JQ0KICBtdXRhdGUoc2V2X2NsYXNzID0gIiBPdmVyYWxsIikgJT4lIA0KICBncm91cF9ieShsYW1iZGEsc2V2X2NsYXNzKSAlPiUgDQogIHN1bW1hcmlzZSh5aWVsZF9nYWluX21lZGlhbiA9IG1lZGlhbih5aWVsZF9nYWluKSwNCiAgICAgICAgICAgIHlpZWxkX2dhaW5fbWVhbiA9IG1lYW4oeWllbGRfZ2FpbiksDQogICAgICAgICAgICB1cF85NSA9IHF1YW50aWxlKHlpZWxkX2dhaW4sIDAuOTc1KSwNCiAgICAgICAgICAgIGxvd185NSA9IHF1YW50aWxlKHlpZWxkX2dhaW4sIDAuMDI1KSwNCiAgICAgICAgICAgIHVwXzc1ID0gcXVhbnRpbGUoeWllbGRfZ2FpbiwgMC43NSksDQogICAgICAgICAgICBsb3dfNzUgPSBxdWFudGlsZSh5aWVsZF9nYWluLCAwLjI1KSkNCmBgYA0KDQpgYGB7cn0NCiMgbV9hYnNvbCA9IGxtKHlpZWxkX2dhaW4gfiBsYW1iZGEsIGJpZ19vbmVfZGYgJT4lIG11dGF0ZShsYW1iZGE9bGFtYmRhKjEwMCkpDQojIHN1bW1hcnkobV9hYnNvbCkNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCm92ZXJfZ2dfa2cgPSBvdmVyYWxfeWcgJT4lIA0KICBnZ3Bsb3QoYWVzKGxhbWJkYSoxMDAseWllbGRfZ2Fpbl9tZWFuKSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgbG93Xzk1KSwNCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgc2l6ZSA9IDAuNywNCiAgICAgICAgICAgIGZpbGwgPSBOQSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgdXBfOTUpLA0KICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICBzaXplID0gMC43LA0KICAgICAgICAgICAgZmlsbCA9IE5BKSsNCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIsIGFlcyhsYW1iZGEqMTAwLHlpZWxkX2dhaW5fbWVkaWFuKSkrDQogICMgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcz1jKDEsMikpKw0KICB0aGVtZV9saWdodCgpKw0KICAjIGdlb21fYWJsaW5lKHNsb3BlID0gOS42MSwgaW50ZXJjZXB0ID0gLTAuMSApKw0KICAjIGNvb3JkX2VxdWFsKCkrDQogIGxhYnMoeCA9ICJGdW5naWNpZGUgZWZmaWNhY3kgKCUpIiwNCiAgICAgICB5ID0gIllpZWxkIGdhaW4gKGtnL2hhKSIsDQogICAgICAgY29sb3IgPSAiRnVuZ2ljaWRlIG1peHR1cmUiLCAjKERhbGxhIGxhbmEgZXQgYWwuLCAyMDE4KQ0KICAgICAgIGxpbmV0eXBlID0gIiIsIGZpbGwgPSAiIikNCm92ZXJfZ2dfa2cNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCnlnYWluX3Bsb3QgPSBmdW5jdGlvbihzX2NsYXNzKXsNCmJpZ19vbmVfZGYgJT4lIA0KICBtdXRhdGUoc2V2X2NsYXNzID0gY2FzZV93aGVuKHNuID4gbWVkaWFuKHNuKSB+ICJIaWdoIHNldmVyaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNuIDw9IG1lZGlhbihzbikgfiAiTG93IHNldmVyaXR5IiksDQogICAgICB5aWVsZF9jbGFzcyA9ICBjYXNlX3doZW4oYjAgPiBtZWRpYW4oYjApIH4gIkhpZ2ggeWllbGQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjAgPD0gbWVkaWFuKGIwKSB+ICJMb3cgeWllbGQiKSkgJT4lDQogIGdyb3VwX2J5KGxhbWJkYSwgc2V2X2NsYXNzLHlpZWxkX2NsYXNzICkgJT4lIA0KICBzdW1tYXJpc2UoeWllbGRfZ2Fpbl9tZWRpYW4gPSBtZWRpYW4oeWllbGRfZ2FpbiksDQogICAgICAgICAgICB5aWVsZF9nYWluX21lYW4gPSBtZWFuKHlpZWxkX2dhaW4pLA0KICAgICAgICAgICAgdXBfOTUgPSBxdWFudGlsZSh5aWVsZF9nYWluLCAwLjk3NSksDQogICAgICAgICAgICBsb3dfOTUgPSBxdWFudGlsZSh5aWVsZF9nYWluLCAwLjAyNSksDQogICAgICAgICAgICB1cF83NSA9IHF1YW50aWxlKHlpZWxkX2dhaW4sIDAuNzUpLA0KICAgICAgICAgICAgbG93Xzc1ID0gcXVhbnRpbGUoeWllbGRfZ2FpbiwgMC4yNSkpICU+JSANCiAgbXV0YXRlKHNldl9jbGFzcyA9IGZhY3RvcihzZXZfY2xhc3MsIGxldmVscyA9IGMoIkxvdyBzZXZlcml0eSIsIkhpZ2ggc2V2ZXJpdHkiKSkpICU+JQ0KICAgIGZpbHRlcihzZXZfY2xhc3MgPT1zX2NsYXNzICkgJT4lIA0KICBnZ3Bsb3QoYWVzKGxhbWJkYSoxMDAseWllbGRfZ2Fpbl9tZWFuKSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgbG93Xzk1LCBjb2xvciA9IHlpZWxkX2NsYXNzKSwNCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgc2l6ZSA9IDAuNywNCiAgICAgICAgICAgIGZpbGwgPSBOQSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgdXBfOTUsY29sb3IgPSB5aWVsZF9jbGFzcyksDQogICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgIHNpemUgPSAwLjcsDQogICAgICAgICAgICBmaWxsID0gTkEpKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEuMiwgYWVzKGxhbWJkYSoxMDAseWllbGRfZ2Fpbl9tZWRpYW4sY29sb3IgPSB5aWVsZF9jbGFzcykpKw0KICAjIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA5NjI4IiwiIzhBMDAwNCIpKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInN0ZWVsYmx1ZSIsIiMwMDk2MjgiKSkrDQogIHRoZW1lX2xpZ2h0KCkrDQogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDMwMDApKSsNCiAgbGFicyh4ID0gIkZ1bmdpY2lkZSBlZmZpY2FjeSAoJSkiLA0KICAgICAgIHkgPSAiWWllbGQgZ2FpbiAoa2cvaGEpIiwNCiAgICAgICBjb2xvciA9ICJBdHRhaW5hYmxlIFlpZWxkIiwgIyhEYWxsYSBsYW5hIGV0IGFsLiwgMjAxOCkNCiAgICAgICBsaW5ldHlwZSA9ICIiKQ0KfQ0KaGlnaF9zZXZfeWcgPSB5Z2Fpbl9wbG90KHNfY2xhc3MgPSAiSGlnaCBzZXZlcml0eSIpKw0KICBsYWJzKHRpdGxlID0gIkhpZ2ggc2V2ZXJpdHkiKQ0KbG93X3Nldl95ZyA9IHlnYWluX3Bsb3Qoc19jbGFzcyA9ICJMb3cgc2V2ZXJpdHkiKSsNCiAgbGFicyh0aXRsZSA9ICJMb3cgc2V2ZXJpdHkiKQ0KYGBgDQoNCg0KYGBge3J9DQpoaWdoX3Nldl95Zytsb3dfc2V2X3lnDQpgYGANCg0KYGBge3J9DQpiaWdfb25lX2RmICU+JQ0KICBtdXRhdGUoc2V2X2NsYXNzID0gY2FzZV93aGVuKHNuID4gbWVkaWFuKHNuKSB+ICJIaWdoIHNldmVyaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNuIDw9IG1lZGlhbihzbikgfiAiTG93IHNldmVyaXR5IiksDQogICAgICB5aWVsZF9jbGFzcyA9ICBjYXNlX3doZW4oYjAgPiBtZWRpYW4oYjApIH4gIkhpZ2ggeWllbGQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjAgPD0gbWVkaWFuKGIwKSB+ICJMb3cgeWllbGQiKSkgJT4lDQogIGdyb3VwX2J5KGxhbWJkYSwgc2V2X2NsYXNzLHlpZWxkX2NsYXNzICkgJT4lIA0KICBzdW1tYXJpc2UoeWllbGRfZ2Fpbl9tZWFuID0gbWVhbih5aWVsZF9nYWluKSwNCiAgICAgICAgICAgIHlpZWxkX2dhaW5fbWVkaWFuID0gbWVkaWFuKHlpZWxkX2dhaW4sIG5hLnJtID0gVCksDQogICAgICAgICAgICBsb3dfOTUgPSBxdWFudGlsZSh5aWVsZF9nYWluLCAwLjAyNSksDQogICAgICAgICAgICB1cF85NSA9IHF1YW50aWxlKHlpZWxkX2dhaW4sIDAuOTc1KSwNCiAgICAgICAgICAgIHVwXzc1ID0gcXVhbnRpbGUoeWllbGRfZ2FpbiwgMC43NSksDQogICAgICAgICAgICBsb3dfNzUgPSBxdWFudGlsZSh5aWVsZF9nYWluLCAwLjI1KSkgJT4lIA0KICBiaW5kX3Jvd3Mob3ZlcmFsX3lnKSAlPiUgDQogIGZpbHRlcihsYW1iZGE9PS43NSkgJT4lIA0KICBhcnJhbmdlKHlpZWxkX2NsYXNzKQ0KDQoNCmBgYA0KDQoNCiMjIyBQZXJjZW50ICBnYWluIA0KDQpgYGB7cn0NCm92ZXJhbF9wZXJjZXQgPSBiaWdfb25lX2RmICU+JQ0KICBtdXRhdGUoc2V2X2NsYXNzID0gIiBPdmVyYWxsIikgJT4lIA0KICBncm91cF9ieShsYW1iZGEsc2V2X2NsYXNzKSAlPiUgDQogIG11dGF0ZSh5aWVsZF9nYWluX3BlcmMgPSBjYXNlX3doZW4oeWllbGRfZ2Fpbl9wZXJjPnF1YW50aWxlKHlpZWxkX2dhaW5fcGVyYywwLjk5OSl+cXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLDAuOTk5KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5aWVsZF9nYWluX3BlcmM8PXF1YW50aWxlKHlpZWxkX2dhaW5fcGVyYywwLjk5OSkgfnlpZWxkX2dhaW5fcGVyYykpICU+JQ0KICBzdW1tYXJpc2UoeWllbGRfZ2Fpbl9tZWFuID0gbWVhbih5aWVsZF9nYWluX3BlcmMsbmEucm0gPSBUKSwNCiAgICAgICAgICAgIHlpZWxkX2dhaW5fbWVkaWFuID0gbWVkaWFuKHlpZWxkX2dhaW5fcGVyYyxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgbG93Xzk1ID0gcXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLCAwLjAyNSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgdXBfOTUgPSBxdWFudGlsZSh5aWVsZF9nYWluX3BlcmMsIDAuOTc1LG5hLnJtID0gVCksDQogICAgICAgICAgICB1cF83NSA9IHF1YW50aWxlKHlpZWxkX2dhaW5fcGVyYywgMC43NSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgbG93Xzc1ID0gcXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLCAwLjI1LG5hLnJtID0gVCkpICANCg0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0Kb3Zlcl9nZyA9IG92ZXJhbF9wZXJjZXQgJT4lIA0KICBnZ3Bsb3QoYWVzKGxhbWJkYSoxMDAseWllbGRfZ2Fpbl9tZWFuKSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgbG93Xzk1KSwNCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgc2l6ZSA9IDAuNywNCiAgICAgICAgICAgIGZpbGwgPSBOQSkrDQogIGdlb21fbGluZShhZXMobGFtYmRhKjEwMCwgdXBfOTUpLA0KICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICBzaXplID0gMC43LA0KICAgICAgICAgICAgZmlsbCA9IE5BKSsNCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIsIGFlcyhsYW1iZGEqMTAwLHlpZWxkX2dhaW5fbWVkaWFuKSkrDQogICMgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcz1jKDEsMikpKw0KICB0aGVtZV9saWdodCgpKw0KICAjIGNvb3JkX2VxdWFsKCkrDQogIGxhYnMoeCA9ICJGdW5naWNpZGUgZWZmaWNhY3kgKCUpIiwNCiAgICAgICB5ID0gIllpZWxkIGdhaW4gJSIsDQogICAgICAgY29sb3IgPSAiRnVuZ2ljaWRlIG1peHR1cmUiLCAjKERhbGxhIGxhbmEgZXQgYWwuLCAyMDE4KQ0KICAgICAgIGxpbmV0eXBlID0gIiIsIGZpbGwgPSAiIikrDQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCksIHhsaW0gPSBjKC0xMCwxMDApKQ0Kb3Zlcl9nZw0KYGBgDQoNCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMn0NCnlnYWluX3BlcmNfcGxvdCA9IGZ1bmN0aW9uKHNfY2xhc3Mpew0KYmlnX29uZV9kZiAlPiUgDQogIG11dGF0ZShzZXZfY2xhc3MgPSBjYXNlX3doZW4oc24gPiBtZWRpYW4oc24pIH4gIkhpZ2ggc2V2ZXJpdHkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc24gPD0gbWVkaWFuKHNuKSB+ICJMb3cgc2V2ZXJpdHkiKSwNCiAgICAgIHlpZWxkX2NsYXNzID0gIGNhc2Vfd2hlbihiMCA+IG1lZGlhbihiMCkgfiAiSGlnaCB5aWVsZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiMCA8PSBtZWRpYW4oYjApIH4gIkxvdyB5aWVsZCIpKSAlPiUNCiAgZ3JvdXBfYnkobGFtYmRhLCBzZXZfY2xhc3MseWllbGRfY2xhc3MgKSAlPiUgDQogIHN1bW1hcmlzZSh5aWVsZF9nYWluX21lZGlhbiA9IG1lZGlhbih5aWVsZF9nYWluX3BlcmMpLA0KICAgICAgICAgICAgeWllbGRfZ2Fpbl9tZWFuID0gbWVhbih5aWVsZF9nYWluX3BlcmMpLA0KICAgICAgICAgICAgdXBfOTUgPSBxdWFudGlsZSh5aWVsZF9nYWluX3BlcmMsIDAuOTc1KSwNCiAgICAgICAgICAgIGxvd185NSA9IHF1YW50aWxlKHlpZWxkX2dhaW5fcGVyYywgMC4wMjUpLA0KICAgICAgICAgICAgdXBfNzUgPSBxdWFudGlsZSh5aWVsZF9nYWluX3BlcmMsIDAuNzUpLA0KICAgICAgICAgICAgbG93Xzc1ID0gcXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLCAwLjI1KSkgJT4lIA0KICBtdXRhdGUoc2V2X2NsYXNzID0gZmFjdG9yKHNldl9jbGFzcywgbGV2ZWxzID0gYygiTG93IHNldmVyaXR5IiwiSGlnaCBzZXZlcml0eSIpKSkgJT4lDQogICAgZmlsdGVyKHNldl9jbGFzcyA9PXNfY2xhc3MgKSAlPiUgDQogIGdncGxvdChhZXMobGFtYmRhKjEwMCx5aWVsZF9nYWluX21lYW4pKSsNCiAgZ2VvbV9saW5lKGFlcyhsYW1iZGEqMTAwLCBsb3dfOTUsIGNvbG9yID0geWllbGRfY2xhc3MpLA0KICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICBzaXplID0gMC43LA0KICAgICAgICAgICAgZmlsbCA9IE5BKSsNCiAgZ2VvbV9saW5lKGFlcyhsYW1iZGEqMTAwLCB1cF85NSxjb2xvciA9IHlpZWxkX2NsYXNzKSwNCiAgICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgc2l6ZSA9IDAuNywNCiAgICAgICAgICAgIGZpbGwgPSBOQSkrDQogIGdlb21fbGluZShzaXplID0gMS4yLCBhZXMobGFtYmRhKjEwMCx5aWVsZF9nYWluX21lZGlhbixjb2xvciA9IHlpZWxkX2NsYXNzKSkrDQogICMgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDk2MjgiLCIjOEEwMDA0IikpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygic3RlZWxibHVlIiwiIzAwOTYyOCIpKSsNCg0KICB0aGVtZV9saWdodCgpKw0KICBsYWJzKHggPSAiRnVuZ2ljaWRlIGVmZmljYWN5ICglKSIsDQogICAgICAgeSA9ICJZaWVsZCBnYWluICglKSIsDQogICAgICAgY29sb3IgPSAiQXR0YWluYWJsZSBZaWVsZCIsIA0KICAgICAgIGxpbmV0eXBlID0gIiIsIGZpbGwgPSAiIikrDQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpDQp9DQpoaWdoX3Nldl95Z19wZXJjID0geWdhaW5fcGVyY19wbG90KHNfY2xhc3MgPSAiSGlnaCBzZXZlcml0eSIpKw0KICBsYWJzKHRpdGxlID0gIkhpZ2ggc2V2ZXJpdHkiKQ0KbG93X3Nldl95Z19wZXJjID0geWdhaW5fcGVyY19wbG90KHNfY2xhc3MgPSAiTG93IHNldmVyaXR5IikrDQogIGxhYnModGl0bGUgPSAiTG93IHNldmVyaXR5IikNCg0KYGBgDQoNCiMjIyBDb21ibyB5aWVkIGdhaW4NCmBgYHtyfQ0KKGhpZ2hfc2V2X3lnK2xvd19zZXZfeWcpLw0KKGhpZ2hfc2V2X3lnX3BlcmMrbG93X3Nldl95Z19wZXJjKSsNCiAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiLA0KICAgICAgICAgICAgICAgaGVpZ2h0cyA9IGMoMSwxKSkrDQogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKSYgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9OCkpDQogIA0KICANCmdnc2F2ZSgiZmlncy95aWVsZF9nYWluX3BlcmMucG5nIiwgZHBpID0gNjAwLCBoZWlnaHQgPSA2LCB3aWR0aCA9OCkNCmdnc2F2ZSgiZmlncy95aWVsZF9nYWluX3BlcmMucGRmIiwgZHBpID0gNjAwLCBoZWlnaHQgPSA2LCB3aWR0aCA9OCkNCmBgYA0KDQoNCg0KYGBge3J9DQogYmlnX29uZV9kZiAlPiUNCiAgbXV0YXRlKHNldl9jbGFzcyA9IGNhc2Vfd2hlbihzbiA+IG1lZGlhbihzbikgfiAiSGlnaCBzZXZlcml0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbiA8PSBtZWRpYW4oc24pIH4gIkxvdyBzZXZlcml0eSIpLA0KICAgICAgeWllbGRfY2xhc3MgPSAgY2FzZV93aGVuKGIwID4gbWVkaWFuKGIwKSB+ICJIaWdoIHlpZWxkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIwIDw9IG1lZGlhbihiMCkgfiAiTG93IHlpZWxkIikpICU+JQ0KICBncm91cF9ieShsYW1iZGEsc2V2X2NsYXNzLHlpZWxkX2NsYXNzKSAlPiUNCiAgbXV0YXRlKHlpZWxkX2dhaW5fcGVyYyA9IGNhc2Vfd2hlbih5aWVsZF9nYWluX3BlcmM+cXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLDAuOTk5KX5xdWFudGlsZSh5aWVsZF9nYWluX3BlcmMsMC45OTkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlpZWxkX2dhaW5fcGVyYzw9cXVhbnRpbGUoeWllbGRfZ2Fpbl9wZXJjLDAuOTk5KSB+eWllbGRfZ2Fpbl9wZXJjKSkgJT4lDQogIHN1bW1hcmlzZSh5aWVsZF9nYWluX21lYW4gPSBtZWFuKCh5aWVsZF9nYWluX3BlcmMpLG5hLnJtID0gVCksDQogICAgICAgICAgICB5aWVsZF9nYWluX21lZGlhbiA9IG1lZGlhbigoeWllbGRfZ2Fpbl9wZXJjKSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgbG93Xzk1ID0gcXVhbnRpbGUoKHlpZWxkX2dhaW5fcGVyYyksIDAuMDI1LG5hLnJtID0gVCksDQogICAgICAgICAgICB1cF85NSA9IHF1YW50aWxlKCh5aWVsZF9nYWluX3BlcmMpLCAwLjk3NSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgdXBfNzUgPSBxdWFudGlsZSgoeWllbGRfZ2Fpbl9wZXJjKSwgMC43NSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgbG93Xzc1ID0gcXVhbnRpbGUoKHlpZWxkX2dhaW5fcGVyYyksIDAuMjUsbmEucm0gPSBUKSkgJT4lIA0KICBiaW5kX3Jvd3Mob3ZlcmFsX3BlcmNldCklPiUgDQogIGZpbHRlcihsYW1iZGE9PTAuNzUpICU+JSANCiAgYXJyYW5nZSh5aWVsZF9jbGFzcykNCg0KYGBgDQoNCg0KIyBFeGFtcGxlcw0KDQpGdW5naWNpZGUgUElDTytURUJVDQoNCmBgYHtyfQ0KbiA9IDEwMDANCiMgeWllbGQgPSBybm9ybSgxMDAwLDY4Mi4xMSwgMjguOTcpDQplZmZpY2FjeSA9ICgxLWV4cChybm9ybSgxMDAwLC0xLjIwNCwwLjA0NjIpKSkNCg0Kc2V2X24gPSByYmV0YShuLCAxLjcwNywgMS4yNjYpDQpzZXZfZiA9IHNldl9uKigxLWVmZmljYWN5KSANCg0Kbm9ybWFsX2NvcnJlbGF0ZWQ8LWdlcmEubm9ybS5iaWQuZ2VyYWwobiwwLjIxLDAsMCwxLDEpDQpiMF9uID0gcG5vcm0obm9ybWFsX2NvcnJlbGF0ZWRbLDJdKQ0KYjFfbiA9IHBub3JtKG5vcm1hbF9jb3JyZWxhdGVkWywxXSkNCmIwID0gcW5vcm0oYjBfbiwgbWVhbl9pbnRlcmNlcHQsc2RfaW50ZXJjZXB0KQ0KYjEgPSAtcWdhbW1hKGIxX24sIHNoYXBlLCByYXRlLCkNCnJtKGIwX24sYjFfbixub3JtYWxfY29ycmVsYXRlZCkNCg0KIyBDYWxjdWxhdGluZyB0aGUgYWxwaGEgY29lZmljaWVudA0KYWxmYSA9IChiMS9iMCkqMTAwDQoNCiMgQ2FsY3VsYXRpbmcgeWllbGQgZ2Fpbg0KeW4gID0gYjAgLSAoLWFsZmEqYjAqc2V2X24pDQp5ZiAgPSBiMCAtICgtYWxmYSpiMCpzZXZfZikNCg0KY29zdCA9IDEyNQ0Kc295X3ByaWNlID0gcm5vcm0obiwgbWVhbihzYnJfcHJpY2UkcHJpY2UpLHNkKHNicl9wcmljZSRwcmljZSkpDQoNCnlpZWxkX2dhaW4gPSB5Zi15bg0KeWllbGRfZ2Fpbl9wZXJjID0gKCh5ZiAtIHluKS95bikqMTAwDQp5aWVsZF9nYWluX3BlcmMgPSAoKHlmL3luKS0xKSoxMDANCmluY29tZSA9IHlpZWxkX2dhaW4qc295X3ByaWNlDQpDUCA9IGNvc3Qvc295X3ByaWNlDQpwcm9maXQgPSAoeWllbGRfZ2Fpbj49Q1ApKjENCm1lYW4ocHJvZml0KQ0KDQpoaXN0KGluY29tZS1jb3N0KQ0KaGlzdChlZmZpY2FjeSkNCmBgYA0KDQoNCiMjIHNpbXVsYXRpb25zIG92ZXJ0aW1lDQojIyMgVGVidQ0KYGBge3J9DQpib3hfdGltZSA9IGRhdGEuZnJhbWUoKQ0KdGltZSA9IHNlcSgwLDEwLCAxKQ0KDQpiMF9kZWNsaW5lID0tMS41MTgNCmIwX3NlX2RlY2xpbmUgPSAgMC4wNjUNCmIxX2RlY2xpbmUgPSAwLjE0Nw0KYjFfc2VfZGVjbGluZSA9IDAuMDEyDQpuID0gMzAwMDANCmZvcihpIGluIDE6bGVuZ3RoKHRpbWUpKXsNCiAgDQp5ID0gIHJub3JtKG4sIGIwX2RlY2xpbmUsYjBfc2VfZGVjbGluZSkgKyB0aW1lW2ldKiBybm9ybShuLGIxX2RlY2xpbmUsYjFfc2VfZGVjbGluZSkgIA0KZWZmaWNhY3kgPSAoMS1leHAoeSkpDQphID0gZGF0YS5mcmFtZSh0aW1lID0gdGltZVtpXSxsYW1iZGE9ZWZmaWNhY3kpDQpib3hfdGltZSA9IGJveF90aW1lICU+JSANCiAgYmluZF9yb3dzKGEpDQp9DQoNCiMgYm94X3RpbWUNCg0KDQoNCiMgYm94X3RpbWUgJT4lIA0KIyAgIGdncGxvdChhZXModGltZSwgbGFtYmRhKjEwMCkpKw0KIyAgIGdlb21fcG9pbnQoKSsNCiMgICBsYWJzKHkgPSAiRWZmaWNhY3kiKSsNCiMgICB5bGltKDAsMTAwKQ0KDQpgYGANCg0KYGBge3J9DQpzaW11bF9kZWNheSA9IGZ1bmN0aW9uKGRhdGFfZWYsIGNvc3Qpew0KIyBjb3N0ID0gNzUNCk4gPSBuKmxlbmd0aCh0aW1lKQ0Kc2V2X24gPSByYmV0YShOLCAxLjcwNywgMS4yNjYpDQpzZXZfZiA9IHNldl9uKigxLWRhdGFfZWYkbGFtYmRhKSANCm5vcm1hbF9jb3JyZWxhdGVkPC1nZXJhLm5vcm0uYmlkLmdlcmFsKE4sMC4yMSwwLDAsMSwxKQ0KYjBfbiA9IHBub3JtKG5vcm1hbF9jb3JyZWxhdGVkWywyXSkNCmIxX24gPSBwbm9ybShub3JtYWxfY29ycmVsYXRlZFssMV0pDQpiMCA9IHFub3JtKGIwX24sIG1lYW5faW50ZXJjZXB0LHNkX2ludGVyY2VwdCkNCmIxID0gLXFnYW1tYShiMV9uLCBzaGFwZSwgcmF0ZSwpDQpybShiMF9uLGIxX24sbm9ybWFsX2NvcnJlbGF0ZWQpDQoNCiMgQ2FsY3VsYXRpbmcgdGhlIGFscGhhIGNvZWZpY2llbnQNCmFsZmEgPSAoYjEvYjApKjEwMA0KDQojIENhbGN1bGF0aW5nIHlpZWxkIGdhaW4NCnluICA9IGIwIC0gKC1hbGZhKmIwKnNldl9uKQ0KeWYgID0gYjAgLSAoLWFsZmEqYjAqc2V2X2YpDQoNCnNveV9wcmljZSA9IHJub3JtKE4sIG1lYW4oc2JyX3ByaWNlJHByaWNlKSxzZChzYnJfcHJpY2UkcHJpY2UpKQ0KDQp5aWVsZF9nYWluID0geWYteW4NCnlpZWxkX2dhaW5fcGVyYyA9ICgoeWYgLSB5bikveW4pKjEwMA0KeWllbGRfZ2Fpbl9wZXJjID0gKCh5Zi95biktMSkqMTAwDQppbmNvbWUgPSB5aWVsZF9nYWluKnNveV9wcmljZQ0KQ1AgPSBjb3N0L3NveV9wcmljZQ0KcHJvZml0ID0gKHlpZWxkX2dhaW4+PUNQKQ0KcHJvZml0XzUwID0gKGluY29tZT49Y29zdCsoY29zdCowLjUpKSMqMQ0KDQpib3hfdGltZTIgPSBkYXRhX2VmICU+JSANCiAgbXV0YXRlKHlpZWxkX2dhaW4pICU+JSANCiAgbXV0YXRlKHlpZWxkX2dhaW5fcGVyYykgJT4lIA0KICBtdXRhdGUoaW5jb21lKSAlPiUgDQogIG11dGF0ZShDUCwgY29zdCkgJT4lIA0KICBtdXRhdGUocHJvZml0LA0KICAgICAgICAgcHJvZml0XzUwKSAlPiUgDQogIGdyb3VwX2J5KHRpbWUpICU+JSANCiAgbXV0YXRlKFAgPSBtZWFuKHByb2ZpdCksDQogICAgICAgICBQXzUwID0gbWVhbihwcm9maXRfNTApKQ0KcmV0dXJuKGJveF90aW1lMikNCn0NCg0KYGBgDQoNCmBgYHtyfQ0KdGVidV83NSA9IHNpbXVsX2RlY2F5KGRhdGFfZWYgPSBib3hfdGltZSwgY29zdCA9IDc1KQ0KdGVidV8xMDAgPSBzaW11bF9kZWNheShkYXRhX2VmID0gYm94X3RpbWUsIGNvc3QgPSAxMDApDQp0ZWJ1XzEyNSA9IHNpbXVsX2RlY2F5KGRhdGFfZWYgPSBib3hfdGltZSwgY29zdCA9IDEyNSkNCnRlYnUgPSBiaW5kX3Jvd3ModGVidV83NSx0ZWJ1XzEwMCwgdGVidV8xMjUpDQpgYGANCg0KDQpgYGB7cn0NCnRlYnUgJT4lIA0KICBncm91cF9ieSh0aW1lLGNvc3QpICU+JSANCiAgc2xpY2UoMUwpICU+JSANCiAgcGl2b3RfbG9uZ2VyKDEwOjExLCBuYW1lc190byA9ICJQcm9maXRzIiwgdmFsdWVzX3RvID0gInByb2IiKSAlPiUgDQogIG11dGF0ZShQcm9maXRzID0gY2FzZV93aGVuKFByb2ZpdHMgPT0iUCIgfiAiIEJyZWFrLWV2ZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcm9maXRzID09IlBfNTAiIH4gIjUwJSBwcm9maXQiKSkgJT4lIA0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC41LCBjb2xvciA9ICJncmF5Iiwgc2l6ZSA9MSwgbGluZXR5cGUgPTIpKw0KICBnZW9tX2xpbmUoYWVzKCh0aW1lKzIwMDQpLCBwcm9iLCBjb2xvciA9IGFzLmZhY3Rvcihjb3N0KSApLA0KICAgICAgICAgICAgc2l6ZSA9IDEuMikrDQogIGZhY2V0X3dyYXAoflByb2ZpdHMpKw0KICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkrDQogIGxhYnMoeSA9ICJQcm9iYWJpbGl0eSBvZiBvZmZzZXRpbmcgY29zdHMiLA0KICAgICAgIHggPSAiVGltZSIsDQogICAgICAgY29sb3IgPSAiQ29zdCAoVVMkKSIpKw0KICB5bGltKDAsMSkrDQogIHRoZW1lX21pbmltYWxfZ3JpZCgpDQpgYGANCg0KDQojIyMgQ3lwcg0KDQpgYGB7cn0NCmJveF90aW1lX21peCA9IGRhdGEuZnJhbWUoKQ0KdGltZSA9IHNlcSgwLDEwLCAxKQ0KI21peCBpbnRlcmNlcHQNCiMgYjBfZGVjbGluZSA9LTIuMTUxDQojIGIwX3NlX2RlY2xpbmUgPSAgMC4xMjENCg0KIyB0ZWJ1IGludGVyY2VwdA0KYjBfZGVjbGluZSA9LTEuNTE4DQpiMF9zZV9kZWNsaW5lID0gIDAuMDY1DQoNCiMgYjFfZGVjbGluZSA9IDAuMTMyDQojIGIxX3NlX2RlY2xpbmUgPSAwLjAyMg0KDQpiMV9kZWNsaW5lID0wLjA2MQ0KYjFfc2VfZGVjbGluZSA9IDAuMDE1DQoNCm4gPSAzMDAwMA0KZm9yKGkgaW4gMTpsZW5ndGgodGltZSkpew0KICANCnkgPSAgcm5vcm0obiwgYjBfZGVjbGluZSxiMF9zZV9kZWNsaW5lKSArIHRpbWVbaV0qIHJub3JtKG4sYjFfZGVjbGluZSxiMV9zZV9kZWNsaW5lKSAgDQplZmZpY2FjeSA9ICgxLWV4cCh5KSkNCmEgPSBkYXRhLmZyYW1lKHRpbWUgPSB0aW1lW2ldLGxhbWJkYT1lZmZpY2FjeSkNCmJveF90aW1lX21peCA9IGJveF90aW1lX21peCAlPiUgDQogIGJpbmRfcm93cyhhKQ0KfQ0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KbWl4Xzc1ID0gc2ltdWxfZGVjYXkoZGF0YV9lZiA9ICBib3hfdGltZV9taXgsIGNvc3QgPSA3NSkNCm1peF8xMDAgPSBzaW11bF9kZWNheShkYXRhX2VmID0gYm94X3RpbWVfbWl4LCBjb3N0ID0gMTAwKQ0KbWl4XzEyNSA9IHNpbXVsX2RlY2F5KGRhdGFfZWYgPSBib3hfdGltZV9taXgsIGNvc3QgPSAxMjUpDQptaXggPSBiaW5kX3Jvd3MobWl4Xzc1LG1peF8xMDAsIG1peF8xMjUpDQpgYGANCg0KDQpgYGB7cn0NCm1peCAlPiUgDQogIGdyb3VwX2J5KHRpbWUsY29zdCkgJT4lIA0KICBzbGljZSgxTCkgJT4lIA0KICBwaXZvdF9sb25nZXIoMTA6MTEsIG5hbWVzX3RvID0gIlByb2ZpdHMiLCB2YWx1ZXNfdG8gPSAicHJvYiIpICU+JSANCiAgbXV0YXRlKFByb2ZpdHMgPSBjYXNlX3doZW4oUHJvZml0cyA9PSJQIiB+ICIgQnJlYWstZXZlbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb2ZpdHMgPT0iUF81MCIgfiAiNTAlIHByb2ZpdCIpKSAlPiUgDQogIGdncGxvdCgpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGNvbG9yID0gImdyYXkiLCBzaXplID0xLCBsaW5ldHlwZSA9MikrDQogIGdlb21fbGluZShhZXMoKHRpbWUrMjAwNCksIHByb2IsIGNvbG9yID0gYXMuZmFjdG9yKGNvc3QpICksDQogICAgICAgICAgICBzaXplID0gMS4yKSsNCiAgZmFjZXRfd3JhcCh+UHJvZml0cykrICANCiAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpKw0KICBsYWJzKHkgPSAiUHJvYmFiaWxpdHkgb2Ygb2Zmc2V0aW5nIGNvc3RzIiwNCiAgICAgICB4ID0gIlRpbWUiLA0KICAgICAgIGNvbG9yID0gIkNvc3QgKFVTJCkiKSsNCiAgeWxpbSgwLDEpKw0KICB0aGVtZV9saWdodCgpDQpgYGANCg0KIyMjIyBDb21ibyBmaWd1cmENCmBgYHtyfQ0KcHJvYl90aW1lID0gIGZ1bmN0aW9uKGRhdGEsIHByb2ZfY2xhc3Mpew0KDQpkYXRhICU+JSANCiAgZ3JvdXBfYnkodGltZSxjb3N0KSAlPiUgDQogIHNsaWNlKDFMKSAlPiUgDQogIHBpdm90X2xvbmdlcigxMDoxMSwgbmFtZXNfdG8gPSAiUHJvZml0cyIsIHZhbHVlc190byA9ICJwcm9iIikgJT4lIA0KICBtdXRhdGUoUHJvZml0cyA9IGNhc2Vfd2hlbihQcm9maXRzID09IlAiIH4gIkJyZWFrLWV2ZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcm9maXRzID09IlBfNTAiIH4gIjUwJSBwcm9maXQiKSkgJT4lIA0KICBmaWx0ZXIoUHJvZml0cyA9PSBwcm9mX2NsYXNzKSAlPiUgDQogIGdncGxvdChhZXMoKHRpbWUpLCBwcm9iKSkrDQogICAgDQogIGFubm90YXRlKCJyZWN0Iix5bWluID0gMCwgeW1heCA9MC4yNSwgDQogICAgICAgICAgICB4bWluID0gLTUsIHhtYXggPSAxNSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2VmZjNmZiIsY29sb3VyPSJ3aGl0ZSIsDQogICAgICAgICAgICAjIGFscGhhID0gMC44LA0KICAgICAgICAgICBzaXplID0gMC4zKSsNCiAgYW5ub3RhdGUoInJlY3QiLHltaW4gPSAwLjI1LCB5bWF4ID0wLjUsIA0KICAgICAgICAgICAgeG1pbiA9IC01LCB4bWF4ID0gMTUsDQogICAgICAgICAgICBmaWxsID0gIiNiZGQ3ZTciLGNvbG91cj0id2hpdGUiLA0KICAgICAgICAgICAgIyBhbHBoYSA9IDAuOCwNCiAgICAgICAgICAgc2l6ZSA9IDAuMykrDQogICAgYW5ub3RhdGUoInJlY3QiLHltaW4gPSAwLjUsIHltYXggPTAuNzUsIA0KICAgICAgICAgICAgeG1pbiA9IC01LCB4bWF4ID0gMTUsDQogICAgICAgICAgICBmaWxsID0gIiM2YmFlZDYiLGNvbG91cj0id2hpdGUiLA0KICAgICAgICAgICAgIyBhbHBoYSA9IDAuOCwNCiAgICAgICAgICAgIHNpemUgPSAwLjMpKw0KICAgIGFubm90YXRlKCJyZWN0Iix5bWluID0gMC43NSwgeW1heCA9MSwgDQogICAgICAgICAgICB4bWluID0gLTUsIHhtYXggPSAxNSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzIxNzFiNSIsIGNvbG91cj0id2hpdGUiLA0KICAgICAgICAgICAgIyBhbHBoYSA9IDAuOCwNCiAgICAgICAgICAgIHNpemUgPSAwLjMpKw0KICAgIA0KICAgIA0KICAjIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNzUsIGNvbG9yID0gImdyYXkiLCBzaXplID0wLjgsIGxpbmV0eXBlID0yKSsNCiAgZ2VvbV9zdGVwKGRpcmVjdGlvbiA9ICJodiIsc2l6ZSA9IDEuMiwNCiAgICAgICAgICAgIGFlcyggY29sb3IgPSBhcy5mYWN0b3IoY29zdCkgKSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMCwxKSkrDQogICMgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIgLCAiI0RDMTQzQyIsImRhcmtyZWQiKSkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmVjYzVjIiAsICIjZmQ4ZDNjIiwiI2UzMWExYyIpKSsNCiAgIyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzAwMDAwMCIgLCAiIzI1MjUyNSIsIiM1MjUyNTIiKSkrDQogIGxhYnMoeSA9ICJQcm9iYWJpbGl0eSIsDQogICAgICAgeCA9ICJUaW1lICh5ZWFycykiLA0KICAgICAgIGNvbG9yID0gIkNvc3QgKFVTJC9oYSkiKSsNCiBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsMTApLCB5bGltID0gYygwLDEpKSsNCiAgdGhlbWVfbGlnaHQoKSsNCiAgICB0aGVtZSgjcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSsNCiAgICAgICAgICBwYW5lbC5ncmlkID0gIGVsZW1lbnRfYmxhbmsoKSkNCiAgDQogIH0NCmBgYA0KPCEtLSBFZmZpY2FjeSBkZWNheSAwLjE0NyAveWVhciAtLT4NCmBgYHtyfQ0KdGVidV9nMSA9IHByb2JfdGltZSh0ZWJ1LCBwcm9mX2NsYXNzID0iQnJlYWstZXZlbiIpKw0KICAgIGxhYnModGl0bGUgPSAiSGlnaCBhbm51YWwgcmF0ZSBvZiBkZWNsaW5lIg0KICAgICAgICAgIyBzdWJ0aXRsZSA9ICJPZmZzZXQgY29zdHMiDQogICAgICAgICApDQp0ZWJ1X2cyID0gcHJvYl90aW1lKHRlYnUsIHByb2ZfY2xhc3MgPSI1MCUgcHJvZml0IikrDQogICAgbGFicyh0aXRsZSA9ICJIaWdoIGFubnVhbCByYXRlIG9mIGRlY2xpbmUiLA0KICAgICAgICAgc3VidGl0bGUgPSAiNTAlIHByb2ZpdCINCiAgICAgICAgICkNCm1peF9nMSA9IHByb2JfdGltZShtaXgsIHByb2ZfY2xhc3MgPSJCcmVhay1ldmVuIikrDQogICAgbGFicyh0aXRsZSA9ICJMb3cgYW5udWFsIHJhdGUgb2YgZGVjbGluZSINCiAgICAgICAgICMgc3VidGl0bGUgPSAiT2Zmc2V0IGNvc3RzIg0KICAgICAgICAgKQ0KbWl4X2cyID0gcHJvYl90aW1lKG1peCwgcHJvZl9jbGFzcyA9IjUwJSBwcm9maXQiKSsNCiAgICBsYWJzKHRpdGxlID0gIkxvdyBhbm51YWwgcmF0ZSBvZiBkZWNsaW5lIiwNCiAgICAgICAgIHN1YnRpdGxlID0gIjUwJSBwcm9maXQiDQogICAgICAgICApDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0NCnRlYnVfZzErbWl4X2cxKw0KICBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpKw0KICBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdBJykmDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpDQpnZ3NhdmUoImZpZ3MvcHJvYl90aW1lLnBuZyIsIGRwaSA9IDYwMCwgaGVpZ2h0ID0gNCwgd2lkdGggPSA3KQ0KZ2dzYXZlKCJmaWdzL3Byb2JfdGltZS5wZGYiLCBkcGkgPSA2MDAsIGhlaWdodCA9IDQsIHdpZHRoID0gNykNCmBgYA0KDQoNCg0KDQoNCg0K
Copyright 2017 Emerson Del Ponte