Start set up
Install packages
#install.packages(c("tidyverse","lme4","emmeans","ggplot2","DescTools","gtable","cowplot","grid","MuMIn","data.table","here","optimx","DT"))
Load libraries
rm(list=ls())
library(tidyverse)
library(lme4)
library(emmeans)
library(ggplot2)
library(DescTools)
library(gtable)# grob plot for figure 2
library(cowplot)# grob plot for figure 2
library(grid)
library(MuMIn) #r.square
library(data.table) #list to dataframe
library(here)
library(optimx)
library(DHARMa)
library(DT)
Read functions
#relocate to empty area in the plot
shift_legend <- function(p){
# check if p is a valid object
if(!"gtable" %in% class(p)){
if("ggplot" %in% class(p)){
gp <- ggplotGrob(p) # convert to grob
} else {
message("This is neither a ggplot object nor a grob generated from ggplotGrob. Returning original plot.")
return(p)
}
} else {
gp <- p
}
# check for unfilled facet panels
facet.panels <- grep("^panel", gp[["layout"]][["name"]])
empty.facet.panels <- sapply(facet.panels, function(i) "zeroGrob" %in% class(gp[["grobs"]][[i]]))
empty.facet.panels <- facet.panels[empty.facet.panels]
if(length(empty.facet.panels) == 0){
message("There are no unfilled facet panels to shift legend into. Returning original plot.")
return(p)
}
# establish extent of unfilled facet panels (including any axis cells in between)
empty.facet.panels <- gp[["layout"]][empty.facet.panels, ]
empty.facet.panels <- list(min(empty.facet.panels[["t"]]), min(empty.facet.panels[["l"]]),
max(empty.facet.panels[["b"]]), max(empty.facet.panels[["r"]]))
names(empty.facet.panels) <- c("t", "l", "b", "r")
# extract legend & copy over to location of unfilled facet panels
guide.grob <- which(gp[["layout"]][["name"]] == "guide-box")
if(length(guide.grob) == 0){
message("There is no legend present. Returning original plot.")
return(p)
}
gp <- gtable_add_grob(x = gp,
grobs = gp[["grobs"]][[guide.grob]],
t = empty.facet.panels[["t"]],
l = empty.facet.panels[["l"]],
b = empty.facet.panels[["b"]],
r = empty.facet.panels[["r"]],
name = "new-guide-box")
# squash the original guide box's row / column (whichever applicable)
# & empty its cell
guide.grob <- gp[["layout"]][guide.grob, ]
if(guide.grob[["l"]] == guide.grob[["r"]]){
gp <- gtable_squash_cols(gp, cols = guide.grob[["l"]])
}
if(guide.grob[["t"]] == guide.grob[["b"]]){
gp <- gtable_squash_rows(gp, rows = guide.grob[["t"]])
}
gp <- gtable_remove_grobs(gp, "guide-box")
return(gp)
}
## plot with 95% CI using lmer objects
lmer.predict<-function(mod, newdat, se.mult, binom=NULL, poisson=NULL, glmmTMB=NULL){
if(glmmTMB==T){
pvar1 <- diag(as.matrix(newdat) %*% tcrossprod(vcov(mod)[[1]],as.matrix(newdat)))
newdat$y<- as.matrix(newdat) %*% fixef(mod)[[1]]}
else{
pvar1 <- diag(as.matrix(newdat) %*% tcrossprod(vcov(mod),as.matrix(newdat)))
newdat$y<- as.matrix(newdat) %*% fixef(mod)}
newdat <- data.frame(newdat, plo = newdat$y-(se.mult*sqrt(pvar1)), phi = newdat$y+(se.mult*sqrt(pvar1)))
if(binom==T) {
newdat$y<-plogis(newdat$y); newdat$plo<-plogis(newdat$plo); newdat$phi<-plogis(newdat$phi)
} else
if(poisson==T) {
newdat$y<-exp(newdat$y); newdat$plo<-exp(newdat$plo); newdat$phi<-exp(newdat$phi)
}
return(with(newdat, data.frame(y, phi, plo)))
}
plot.CI.func<- function(x.for.plot, pred, upper, lower, env.colour, env.trans=NA, line.colour, line.weight, line.type){
colour.rgb<-col2rgb(col=env.colour)
polygon.coords<-data.frame(rbind(cbind(x.for.plot[1], lower[1]),
cbind(x.for.plot, upper),
cbind(x.for.plot, lower)[rev(order(x.for.plot)),]))
names(polygon.coords)<-c("x", "y")
polygon(polygon.coords$x, polygon.coords$y, col=rgb(red=colour.rgb["red",],blue=colour.rgb["blue",], green=colour.rgb["green",] , alpha=env.trans, maxColorValue = 255), border=NA)
lines(x.for.plot, pred, col=line.colour, lwd=line.weight, lty=line.type)
}
seq.func2<-function(x)(seq(min(x, na.rm=T), max(x, na.rm=T), length.out=150))
seq.func<-function(x)(seq(min(x, na.rm=T), max(x, na.rm=T), length.out=100))
Germination of fresh seeds
Data showing mean germination percentages for fresh seed. Also in
Table S1-Germination of fresh seeds at 6 (41 days) and 8 (56 days)
weeks. Species in the Dark treatment received 2 weeks of light (56 days
germination) after the first 6 weeks of dark. Cabinet conditions were
night cycle 7 C° and daylight cycle 18 C°, 50% relative humidity
base<-read_csv(here("Data","baseline.csv"))%>%mutate(day_41.p=(day_41/25)*100,
day_56.p=(day_56/25)*100)%>%group_by(species,treatment)%>%summarise(mean_41_days=mean(day_41.p),
mean_56_days=mean(day_56.p))
DT::datatable(base,height=100,options=(list(scrollX=FALSE,scrollY=TRUE)))
Read data for cumulative germination curve for the main
experiment
plote<-read_csv(here("Data", "cumulative_curve.csv"))%>%rowid_to_column(var="plate")%>%pivot_longer(-(1:7),
names_to="time",values_to="germination_day",
values_transform = list(germination_day = as.numeric))%>%
mutate(total_nongerm=total_seeds_dish-germination_day)%>%mutate(time=as.numeric(time))%>%
separate_wider_delim(species, delim = ".",
names = c("genus", "species.1")
)%>%unite("species_names", genus,species.1, sep=" ", remove=T)%>%
group_by(species_names,total_seeds,temp, time)%>%
summarise(count_germ=sum(germination_day))%>%mutate(cumulative_count=cumsum(count_germ),
cumulative_percentage=(cumulative_count/total_seeds)*100)
Plot cumulative germination curves
pdf(here("Outputs","FigureS1.pdf"), width = 15, height = 11)
plote%>%ggplot(aes(x=time,y = cumulative_percentage, group=temp),show.legend = FALSE)+
geom_point(aes(color=temp,shape=temp))+
geom_line(aes(color=temp))+
scale_colour_manual(name="Treatment", values=c("blue","red"))+
scale_shape_manual(name="Treatment", values=c(19,22))+
facet_wrap(~species_names,ncol=4)+scale_y_continuous(breaks = seq(0,100, by = 15))+
ylab("Cumulative Germination (%)") + xlab("Days")+
theme(panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill=NA, linewidth=1))+
theme(strip.text.x= element_text(size=rel(1.8), face="italic"),
axis.title.x=element_text(size = rel(1.5),vjust=1),
axis.title.y=element_text(size = rel(1.5),vjust=1),
axis.text = element_text(size = rel(1.2)),
legend.title =element_text(size = rel(1.8)),
legend.text =element_text(size = rel(1.8)),
legend.key.size = unit(1.5, "cm"))
dev.off()
## png
## 2
Figure_S1 Cumulative germination for 19 winter
annual species from the understory of a York-gum jam Mediterranean
woodland in Western Australia under two temperature treatments: Cold
(7/18 °C, 12/12h light/dark, 50% relative humidity) and Warm (7/24 °C,
12/12h light/dark, 50% relative humidity).
Q1 Do species differ in their germination responses to different
temperature and light regimes?
Read data for Q1/Q2
cue_dat<-read_csv(here("Data","germ_cue.csv"))%>%
mutate(total_nongerm=total_seeds_dish-germination_total,
prop_germ =germination_total/total_seeds_dish)%>%rowid_to_column(var="plate")# plate is an unique id for random effects
Model containing all interactions and additive fixed effects
gres_mod<-glmer(cbind(germination_total,total_nongerm)~temp*light*species+(1|plate),family=binomial,data=cue_dat)
#model run with convergence warning
Eliminate convergence warning by removing random effects.
gres_mod2<-glm(cbind(germination_total,total_nongerm)~temp*light*species,family=binomial,data=cue_dat)
Check gres_mod assumptions
simulationOutput <- simulateResiduals(fittedModel = gres_mod2, plot = F)
plot(simulationOutput) #no major problems

TableS2-Estimated marginal probabilities for the winter annuals in
this study.
emmean_mod<-as.data.frame(emmeans(gres_mod2, ~temp*light|species, type="response"))
emmean_mod[,4:8]<-round(emmean_mod[,4:8],3)
print(emmean_mod)
## species = Calandrinia.eremaea:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.010 0.010 Inf 0.001 0.068
## Warm Dark 0.000 0.000 Inf 0.000 1.000
## Cold Light 0.020 0.014 Inf 0.005 0.076
## Warm Light 0.020 0.014 Inf 0.005 0.076
##
## species = Calotis.hispidula:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.040 0.020 Inf 0.015 0.102
## Warm Dark 0.010 0.010 Inf 0.001 0.068
## Cold Light 0.160 0.037 Inf 0.100 0.245
## Warm Light 0.120 0.032 Inf 0.069 0.200
##
## species = Chthonocephalus.pseudevax:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.200 0.040 Inf 0.133 0.290
## Warm Dark 0.020 0.014 Inf 0.005 0.076
## Cold Light 0.260 0.044 Inf 0.184 0.355
## Warm Light 0.220 0.041 Inf 0.149 0.312
##
## species = Crassula.colorata:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.000 0.000 Inf 0.000 1.000
## Warm Dark 0.000 0.000 Inf 0.000 1.000
## Cold Light 0.556 0.050 Inf 0.457 0.650
## Warm Light 0.360 0.048 Inf 0.272 0.458
##
## species = Goodenia.berardiana:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.060 0.024 Inf 0.027 0.127
## Warm Dark 0.080 0.027 Inf 0.041 0.152
## Cold Light 0.130 0.034 Inf 0.077 0.211
## Warm Light 0.050 0.022 Inf 0.021 0.115
##
## species = Goodenia.rosea:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.050 0.022 Inf 0.021 0.115
## Warm Dark 0.070 0.026 Inf 0.034 0.140
## Cold Light 0.270 0.044 Inf 0.192 0.365
## Warm Light 0.090 0.029 Inf 0.047 0.164
##
## species = Hyalosperma.glutinosum:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.000 0.000 Inf 0.000 1.000
## Warm Dark 0.000 0.000 Inf 0.000 1.000
## Cold Light 0.040 0.020 Inf 0.015 0.102
## Warm Light 0.000 0.000 Inf 0.000 1.000
##
## species = Medicago.minima:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.130 0.034 Inf 0.077 0.211
## Warm Dark 0.160 0.037 Inf 0.100 0.245
## Cold Light 0.150 0.036 Inf 0.092 0.234
## Warm Light 0.150 0.036 Inf 0.092 0.234
##
## species = Monoculus.monstrosus:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.000 0.000 Inf 0.000 1.000
## Warm Dark 0.000 0.000 Inf 0.000 1.000
## Cold Light 0.000 0.000 Inf 0.000 1.000
## Warm Light 0.000 0.000 Inf 0.000 1.000
##
## species = Pentameris.airoides:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.190 0.039 Inf 0.125 0.279
## Warm Dark 0.130 0.034 Inf 0.077 0.211
## Cold Light 0.460 0.050 Inf 0.365 0.558
## Warm Light 0.420 0.049 Inf 0.327 0.519
##
## species = Plantago.debilis:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.040 0.020 Inf 0.015 0.102
## Warm Dark 0.000 0.000 Inf 0.000 1.000
## Cold Light 0.340 0.047 Inf 0.254 0.438
## Warm Light 0.130 0.034 Inf 0.077 0.211
##
## species = Podolepis.aristata:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.380 0.049 Inf 0.290 0.479
## Warm Dark 0.250 0.043 Inf 0.175 0.344
## Cold Light 0.930 0.026 Inf 0.860 0.966
## Warm Light 0.890 0.031 Inf 0.812 0.938
##
## species = Pogonolepis.muelleriana:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.100 0.030 Inf 0.055 0.176
## Warm Dark 0.070 0.026 Inf 0.034 0.140
## Cold Light 0.320 0.047 Inf 0.236 0.417
## Warm Light 0.160 0.037 Inf 0.100 0.245
##
## species = Ptilotus.gaudichaudii:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.033 0.023 Inf 0.008 0.124
## Warm Dark 0.017 0.017 Inf 0.002 0.109
## Cold Light 0.150 0.036 Inf 0.092 0.234
## Warm Light 0.130 0.034 Inf 0.077 0.211
##
## species = Spergula.arvensis:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.110 0.031 Inf 0.062 0.188
## Warm Dark 0.060 0.024 Inf 0.027 0.127
## Cold Light 0.230 0.042 Inf 0.158 0.322
## Warm Light 0.400 0.049 Inf 0.309 0.499
##
## species = Stenopetalum.filifolium:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.140 0.035 Inf 0.085 0.223
## Warm Dark 0.080 0.027 Inf 0.041 0.152
## Cold Light 0.330 0.047 Inf 0.245 0.428
## Warm Light 0.260 0.044 Inf 0.184 0.355
##
## species = Trachymene.cyanopetala:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.150 0.036 Inf 0.092 0.234
## Warm Dark 0.110 0.031 Inf 0.062 0.188
## Cold Light 0.620 0.049 Inf 0.521 0.710
## Warm Light 0.420 0.049 Inf 0.327 0.519
##
## species = Trachymene.ornata:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.000 0.000 Inf 0.000 1.000
## Warm Dark 0.040 0.020 Inf 0.015 0.102
## Cold Light 0.020 0.014 Inf 0.005 0.076
## Warm Light 0.010 0.010 Inf 0.001 0.068
##
## species = Waitzia.acuminata:
## temp light prob SE df asymp.LCL asymp.UCL
## Cold Dark 0.200 0.040 Inf 0.133 0.290
## Warm Dark 0.130 0.034 Inf 0.077 0.211
## Cold Light 0.680 0.047 Inf 0.583 0.764
## Warm Light 0.690 0.046 Inf 0.593 0.773
##
## Confidence level used: 0.95
## Intervals are back-transformed from the logit scale
Table S3- Within-species differences in the probability of
germination under two temperature regimes (Cold: 7/18 °C and Warm: 7/24
°C) and two light regimes (12h/12h light/dark or continuous dark).
Significant differences (p ≤ 0.05) are in bold. For some species,
germination was insufficient to test any pairwise contrasts and for
others only those listed could be tested.
pa_mod<-as.data.frame(pairs(emmeans(gres_mod2, ~temp*light|species), type="response"))
DT::datatable(pa_mod,height=60,options=(list(scrollX=TRUE,scrollY=TRUE)))%>%formatRound(columns=c('odds.ratio', 'SE',"z.ratio","p.value"), digits=3)
Data for plotting
plot_box<-cue_dat%>%mutate(percent_germ=(germination_total/total_seeds_dish)*100)%>%
unite("Treatment", temp,light,sep= "+",remove=F)%>%unite("id",Treatment,species,remove=F)%>%
group_by(species, Treatment,dish)%>%
separate_wider_delim(species, delim = ".",
names = c("genus", "species.1")
)%>%unite("species_names", genus,species.1, sep=" ", remove=T)
prob<-emmean_mod%>%
unite("Treatment",temp,light, sep= "+", remove=F)%>%
unite("id",Treatment,species, remove=F)%>%select(id,prob,species)
plot_point<-merge(plot_box,prob,by.x="id",by.y="id")
legend_point<-read_csv(here("Data","legend_point.csv"))%>%separate_wider_delim(species, delim = ".",
names = c("genus", "species.1")
)%>%unite("species_names", genus,species.1, sep=" ", remove=T)
Plotting germination responses to experimental treatments
p1.2<-ggplot(plot_point,aes(x=Treatment,y=percent_germ,fill=Treatment))+geom_jitter(aes(color=Treatment),size=12,width=0.3,height=0.5)+
scale_fill_manual(values =c("Cold+Dark"="#1E88E5","Cold+Light"="#B8E0D9","Warm+Dark"= "#D81B60","Warm+Light"="#FFC107"))+
scale_color_manual(values =c("Cold+Dark"="#1E88E5","Cold+Light"="#B8E0D9","Warm+Dark"= "#D81B60","Warm+Light"="#FFC107"))+
scale_y_continuous(limits=c(0,110), breaks=c(0,20,40,60,80,100),
name="Probability of germination (%)")+
geom_point(mapping=aes(x=Treatment, y=prob*100, group=Treatment), size=14, shape=23, colour="black")+facet_wrap(.~species_names,ncol=5)+
theme(panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill=NA, linewidth=1))+
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank())+
theme(strip.text.x= element_text(size=rel(6), face="italic"),
plot.title = element_text(size = rel(5),color="black"),
axis.title.y=element_text(size = rel(6),vjust=1),
axis.text = element_text(size = rel(4)),
legend.title =element_text(size = rel(5)),
legend.text =element_text(size = rel(5)),
legend.key.size = unit(3, "cm"))+theme(plot.margin=unit(c(1,1.5,1,1.5), 'cm'))+
geom_text(data=legend_point, aes(x=x, y=y, label=label),colour="black",size=17)
pdf(here("Outputs","Figure_3.pdf"), width = 51, height = 29, useDingbats=F)
grid.draw(shift_legend(p1.2))
dev.off()
## png
## 2
Figure_3 Estimated marginal means (EMMs) from a
binomial generalized linear mixed model containing all interactions
between treatments and species. This plot shows the response to each
treatment combination. Diamonds are mean estimated probabilities for 19
winter annuals in the study (Table S2). Probabilities were multiplied by
100 to be given in percentages. Points are observed mean germination
percentages for each petri dish. Points were jittered to show
overlapping values more clearly.
Mean germination under the preferred conditions.
#filter out species that did not germinate and treatments that decreased germination
germ_t2<-plot_point%>%dplyr::filter(species!="Calandrinia.eremaea",species!="Hyalosperma.glutinosum",species!="Monoculus.monstrosus",species!="Trachymene.ornata")%>%
dplyr::filter(id!="Cold+Dark_Calotis.hispidula",id!= "Warm+Dark_Calotis.hispidula")%>%
dplyr::filter(id!="Warm+Dark_Chthonocephalus.pseudevax")%>%
dplyr::filter(id!="Cold+Dark_Crassula.colorata",id!="Warm+Dark_Crassula.colorata",id!="Warm+Light_Crassula.colorata")%>%
dplyr::filter(id!="Warm+Light_Goodenia.rosea",id!="Cold+Dark_Goodenia.rosea",id!="Warm+Dark_Goodenia.rosea")%>%
dplyr::filter(id!="Cold+Dark_Pentameris.airoides",id!="Warm+Dark_Pentameris.airoides")%>%
dplyr::filter(id!="Warm+Light_Plantago.debilis",id!="Cold+Dark_Plantago.debilis",id!="Warm+Dark_Plantago.debilis")%>%
dplyr::filter(id!="Cold+Dark_Podolepis.aristata",id!="Warm+Dark_Podolepis.aristata")%>%
dplyr::filter(id!="Warm+Light_Pogonolepis.muelleriana",id!="Cold+Dark_Pogonolepis.muelleriana",id!="Warm+Dark_Pogonolepis.muelleriana")%>%
dplyr::filter(id!="Cold+Light_Spergula.arvensis",id!="Cold+Dark_Spergula.arvensis",id!="Warm+Dark_Spergula.arvensis")%>%
dplyr::filter(id!="Cold+Dark_Stenopetalum.filifolium",id!="Warm+Dark_Stenopetalum.filifolium")%>%
dplyr::filter(id!="Warm+Light_Trachymene.cyanopetala",id!="Cold+Dark_Trachymene.cyanopetala",id!="Warm+Dark_Trachymene.cyanopetala")%>%
dplyr::filter(id!="Cold+Dark_Waitzia.acuminata",id!="Warm+Dark_Waitzia.acuminata")%>%
dplyr::filter(id!="Cold+Dark_Ptilotus.gaudichaudii", id!="Warm+Dark_Ptilotus.gaudichaudii")%>%mutate(species=as.character(species))%>%
as.data.frame()
Summarize germination percentages for species in the treatment
combination with the highest germination
mean_germination<-t(as.matrix(tapply(germ_t2$percent_germ, germ_t2$species, mean)))
Range
apply(mean_germination,1,range)
## [,1]
## [1,] 8
## [2,] 91
Table 2 Mean germination percentages for species
under treatment combinations with the highest germination identified on
Figure 3.
mean_germination2<-as.data.frame(mean_germination)
mean_germination2<-mean_germination2%>%pivot_longer(cols=1:15,names_to="species",values_to="mean")%>%mutate(mean=round(mean,1))
print(mean_germination2)
## # A tibble: 15 × 2
## species mean
## <chr> <dbl>
## 1 Calotis.hispidula 14
## 2 Chthonocephalus.pseudevax 22.7
## 3 Crassula.colorata 55.4
## 4 Goodenia.berardiana 8
## 5 Goodenia.rosea 27
## 6 Medicago.minima 14.8
## 7 Pentameris.airoides 44
## 8 Plantago.debilis 34
## 9 Podolepis.aristata 91
## 10 Pogonolepis.muelleriana 32
## 11 Ptilotus.gaudichaudii 14
## 12 Spergula.arvensis 40
## 13 Stenopetalum.filifolium 29.5
## 14 Trachymene.cyanopetala 62
## 15 Waitzia.acuminata 68.5
Q2 Question 2: Do species’ germination responses to experimental
temperature and light regimes correspond to their microhabitat
associations in the field?
Extract species’ experimental responses to light and temperature
species_data<-data.frame(species=unique(cue_dat$species))%>%
arrange(species)
temp<-emmean_mod[,4:8]
Calculate light and temperature germination responses
species_data$cold_light_effect<-temp[seq(3,76, 4),1] - temp[seq(1,76, 4),1]
species_data$warm_light_effect<-temp[seq(4,76, 4),1] - temp[seq(2,76, 4),1]
species_data$max_light_effect<- ifelse(species_data$cold_light_effect>species_data$warm_light_effect, species_data$cold_light_effect, species_data$warm_light_effect)
species_data$light_cool_effect<-temp[seq(3,76, 4),1] - temp[seq(4,76, 4),1]
species_data$dark_cool_effect<-temp[seq(1,76, 4),1] - temp[seq(2,76, 4),1]
species_data$max_cool_effect<- ifelse(species_data$light_cool_effect>species_data$dark_cool_effect, species_data$light_cool_effect, species_data$dark_cool_effect)
Read occurrence data
occ<-read_csv(here("Data","occurrence.csv"))%>%group_by(block)%>%mutate(mean_canopy=mean(canopy_cover))%>%ungroup()%>%mutate(std_mean_canopy= scale(mean_canopy)[,1],
std_sqrt_litter = scale(sqrt(litter_percent))[,1])%>%
left_join(species_data, by = "species")
Species with insufficient germination
insufficient_germ_species<-c("Calandrinia.eremaea","Hyalosperma.glutinosum","Monoculus.monstrosus","Trachymene.ornata")
Remove species with insufficient germination
occ_sufficient_germ<-occ%>%
filter(!species%in%insufficient_germ_species)
Do species’ experimental cool responses explain their occurrence
trends with shade?
cool_effect_mod<-glmer(occurrence~std_mean_canopy*max_cool_effect +(1|block)+(std_mean_canopy|species),data=occ_sufficient_germ, family="binomial")
summary(cool_effect_mod)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: occurrence ~ std_mean_canopy * max_cool_effect + (1 | block) +
## (std_mean_canopy | species)
## Data: occ_sufficient_germ
##
## AIC BIC logLik deviance df.resid
## 2174.3 2220.1 -1079.2 2158.3 2242
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.1491 -0.5162 -0.4108 -0.2838 3.8941
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## species (Intercept) 0.29148 0.5399
## std_mean_canopy 0.16519 0.4064 0.49
## block (Intercept) 0.07153 0.2675
## Number of obs: 2250, groups: species, 15; block, 10
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.6612 0.2936 -5.658 1.53e-08 ***
## std_mean_canopy 0.0690 0.2383 0.290 0.772
## max_cool_effect 1.3765 2.1511 0.640 0.522
## std_mean_canopy:max_cool_effect -1.3077 1.6959 -0.771 0.441
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) std_m_ mx_cl_
## std_mn_cnpy 0.362
## max_cl_ffct -0.807 -0.322
## std_mn_c:__ -0.331 -0.788 0.418
Check cool_effect_mod assumptions
simulationOutput3 <- simulateResiduals(fittedModel = cool_effect_mod, plot = F)
plot(simulationOutput3) #no major problems

Do species’ experimental light responses explain their occurrence
trends with litter?
light_effect_mod<-glmer(occurrence~std_sqrt_litter*max_light_effect +(1|block)+(std_sqrt_litter|species),data=occ_sufficient_germ, family="binomial")
summary(light_effect_mod)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: occurrence ~ std_sqrt_litter * max_light_effect + (1 | block) +
## (std_sqrt_litter | species)
## Data: occ_sufficient_germ
##
## AIC BIC logLik deviance df.resid
## 2180.7 2226.4 -1082.3 2164.7 2242
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.2065 -0.5115 -0.4132 -0.2971 3.9239
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## species (Intercept) 0.29559 0.5437
## std_sqrt_litter 0.14614 0.3823 0.31
## block (Intercept) 0.05885 0.2426
## Number of obs: 2250, groups: species, 15; block, 10
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.60405 0.29161 -5.501 3.78e-08 ***
## std_sqrt_litter 0.02155 0.21387 0.101 0.920
## max_light_effect 0.34604 0.81702 0.424 0.672
## std_sqrt_litter:max_light_effect -0.47689 0.61249 -0.779 0.436
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) std_s_ mx_lg_
## std_sqrt_lt 0.244
## mx_lght_ffc -0.811 -0.213
## std_sqr_:__ -0.207 -0.832 0.261
Check light_effect_mod assumptions
simulationOutput2 <- simulateResiduals(fittedModel = light_effect_mod, plot = F)
plot(simulationOutput2) #no major problems

Occurrences explained by either canopy cover or litter for each of
the 19 species
Probability of occurrence explained by litter cover
Models in a loop. One model for each species
species_names1<-sort(unique(occ$species))
litter_dat<-data.frame(species=species_names1,
intercept=vector(mode="numeric",length=length(species_names1)),
std_intercept=vector(mode="numeric",length=length(species_names1)),
z_intercept=vector(mode="numeric",length=length(species_names1)),
pvalue_intercept=vector(mode="numeric",length=length(species_names1)),
coef_litter=vector(mode="numeric",length=length(species_names1)),
std_litter=vector(mode="numeric",length=length(species_names1)),
z_litter=vector(mode="numeric",length=length(species_names1)),
pvalue_litter=vector(mode="numeric",length=length(species_names1)),
CI_2.5=vector(mode="numeric",length=length(species_names1)),
CI_97.5=vector(mode="numeric",length=length(species_names1)),
block_intercept=vector(mode="numeric",length=length(species_names1)),
r2_marginal=vector(mode="numeric",length=length(species_names1)),
r2_conditional=vector(mode="numeric",length=length(species_names1)))
spec_mod.2<-list()
loop_pred_litter<-list()
spec_datlitter_list<-list()
x_litter_list<-list()
for (i in 1:length(species_names1)){
spec_data<-subset(occ, species==species_names1[i])
spec_datlitter_list[[i]]<-subset(occ, species==species_names1[i])
spec_mod.2[[i]]<-glmer(occurrence ~ std_sqrt_litter+ (1|block), family=binomial(link="logit"), data = spec_data,control=glmerControl(optimizer ='optimx', optCtrl=list(method='L-BFGS-B')))
mood<-glmer(occurrence ~ std_sqrt_litter+ (1|block), family=binomial(link="logit"), data = spec_data,control=glmerControl(optimizer ='optimx', optCtrl=list(method='L-BFGS-B')))
summar<-summary(mood)
litter_dat$intercept[i]<-round(summar$coefficients[1,1],digits=4)#intercept
litter_dat$std_intercept[i]<-round(summar$coefficients[1,2], digits=4)#std_intercept
litter_dat$pvalue_intercept[i]<-round(summar$coefficients[1,4],digits=4)#p-value_intercept
litter_dat$coef_litter[i]<-round(summar$coefficients[2,1],digits=4)#coef_canopy
litter_dat$std_litter[i]<-round(summar$coefficients[2,2],digits=4)#std_canopy
litter_dat$pvalue_litter[i]<-round(summar$coefficients[2,4],digits=4)#pvalue_canopy
litter_dat$z_intercept[i]<-round(summar$coefficients[1,3],digits=4)#z_intercept
litter_dat$z_litter[i]<-round(summar$coefficients[2,3],digits=4)#z_canopy
litter_dat$block_intercept[i]<-summar$varcor$block[1,1]
confin<-confint(mood,method="Wald")
r2<-r.squaredGLMM(mood)
litter_dat$CI_2.5[i]<-confin[3]#lower confidence interval
litter_dat$CI_97.5[i]<-confin[6]#upper confidence interval
litter_dat$r2_marginal[i]<-r2[1]#theoretical R2
litter_dat$r2_conditional[i]<-r2[3]#theoretical R2
#data for plotting
loop_newdata<-data.frame(1, seq.func2(spec_data$std_sqrt_litter))
loop_pred_litter[[i]]<-lmer.predict(mod =mood,newdat = loop_newdata, se.mult = 1.96, binom=T, poisson = F, glmmTMB=F)
x_litter_list[[i]]<-data.frame(x_for_plot=seq.func2(spec_data$std_sqrt_litter))
}
Table s4 Probability of occurrence for the 19 winter annual species
along a gradient of litter cover in a York gum and jam woodland in
Western Australia. CI = confidence interval. Significant litter effects
(p<0.05) are in bold.
litter_table<-litter_dat%>%dplyr::select(species,intercept,pvalue_intercept,coef_litter,pvalue_litter,CI_2.5,CI_97.5,block_intercept, r2_marginal,r2_conditional)%>%mutate(intercept=round(intercept,3),
pvalue_intercept=round(pvalue_intercept,3),
coef_litter=round(coef_litter,3),
pvalue_litter=round(pvalue_litter,3),
CI_2.5=round(CI_2.5,2),
CI_97.5=round(CI_97.5,2), block_intercept=round(block_intercept,2),
r2_marginal=round(r2_marginal,2),
r2_conditional=round(r2_conditional,2))
DT::datatable(litter_table,height=100,options=(list(scrollX=TRUE,scrollY=TRUE)))
Plotting models for litter cover
####data from loop for litter plot
litter_list <- Map(as.data.frame,spec_datlitter_list)
spec_litterdat_plot<-rbindlist(litter_list)
list_litter_loop<-Map(as.data.frame,loop_pred_litter)
predict_litter_dat<-rbindlist(list_litter_loop)
list_litter_x<-Map(as.data.frame, x_litter_list)
x_litter_dat<-rbindlist(list_litter_x)
dat_litter_plot<-cbind(spec_litterdat_plot,predict_litter_dat,x_litter_dat)%>%
separate_wider_delim(species, delim = ".",
names = c("genus", "species.1")
)%>%unite("species_names", genus,species.1, sep=" ", remove=T)%>%
mutate(line_color=if_else(species_names=="Chthonocephalus pseudevax","grey6","grey49"),
line_color=if_else(species_names=="Hyalosperma glutinosum","grey6",line_color),
line_color=if_else(species_names=="Podolepis aristata","grey6",line_color),
line_color=if_else(species_names=="Pogonolepis muelleriana","grey6",line_color),
line_color=if_else(species_names=="Medicago minima","grey6",line_color),
line_color=if_else(species_names=="Trachymene ornata","grey6",line_color),
ci_color=if_else(species_names=="Chthonocephalus pseudevax","grey26","grey74"),
ci_color=if_else(species_names=="Hyalosperma glutinosum","grey26",ci_color),
ci_color=if_else(species_names=="Podolepis aristata","grey26",ci_color),
ci_color=if_else(species_names=="Pogonolepis muelleriana","grey26",ci_color),
ci_color=if_else(species_names=="Medicago minima","grey26",ci_color),
ci_color=if_else(species_names=="Trachymene ornata","grey26",ci_color))
#Sup. litter plot#
litter_plot<-ggplot(dat_litter_plot, aes(x =std_sqrt_litter , y = occurrence)) +facet_wrap(.~species_names,ncol=4)+
geom_jitter(width=0.2, height=0.05, size=4, color=dat_litter_plot$line_color)+
geom_line(aes(x=x_for_plot, y=y, size=2), color=dat_litter_plot$line_color)+
labs(x="Litter cover (square root transformed and standardized)", y="Probability of occurrence")+
geom_ribbon(aes(x=x_for_plot, ymin =plo, ymax =phi, alpha = 0.05), fill=dat_litter_plot$ci_color, color=dat_litter_plot$ci_color)+
theme(panel.background = element_blank())+
theme(strip.text.x= element_text(size=rel(6), face="italic"),
plot.title = element_text(size = rel(5),color="black"),
axis.title.y=element_text(size = rel(5),vjust=1),
axis.title.x=element_text(size = rel(5)),
axis.text = element_text(size = rel(4)),
axis.line = element_line(size = 1, colour = "grey74", linetype=1),
axis.ticks = element_line(size = 1.5, colour = "grey74"),
axis.ticks.length = unit(.3, "cm"),
legend.position = "none")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
pdf(here("Outputs","FigureS2.pdf"), width = 45, height = 35, useDingbats=F)
litter_plot
dev.off()
## png
## 2
FigureS2 Bivariate plots from GLMMs for
probability of occurrence in response to litter cover. Shaded areas
represent ± 95% confidence intervals. Points were jittered to show
overlapping values more clearly. Significant results are shown in dark
grey.
Probability of occurrence explained by canopy cover
Models in a loop. One model per species.
species_names<-sort(unique(occ$species))
canopy_dat<-data.frame(species=species_names,
intercept=vector(mode="numeric",length=length(species_names)),
std_intercept=vector(mode="numeric",length=length(species_names)),
z_intercept=vector(mode="numeric",length=length(species_names)),
pvalue_intercept=vector(mode="numeric",length=length(species_names)),
coef_canopy=vector(mode="numeric",length=length(species_names)),
std_canopy=vector(mode="numeric",length=length(species_names)),
z_canopy=vector(mode="numeric",length=length(species_names)),
pvalue_canopy=vector(mode="numeric",length=length(species_names)),
CI_2.5=vector(mode="numeric",length=length(species_names)),
CI_97.5=vector(mode="numeric",length=length(species_names)),
block_intercept=vector(mode="numeric",length=length(species_names)),
r2_marginal=vector(mode="numeric",length=length(species_names)),
r2_conditional=vector(mode="numeric",length=length(species_names)))
loop_pred_canopy<-list()
spec_mod.1<-list()
spec_datcanopy_list<-list()
x_canopy_list<-list()
for (i in 1:length(species_names)){
spec_data<-subset(occ, species==species_names[i])
spec_datcanopy_list[[i]]<-subset(occ, species==species_names[i])
spec_mod.1[[i]]<-glmer(occurrence ~ std_mean_canopy+ (1|block), family=binomial(link="logit"), data = spec_data,control=glmerControl(optimizer ='optimx', optCtrl=list(method='L-BFGS-B')))
mood<-glmer(occurrence ~ std_mean_canopy+ (1|block), family=binomial(link="logit"), data = spec_data,control=glmerControl(optimizer ='optimx', optCtrl=list(method='L-BFGS-B')))
summar<-summary(mood)
canopy_dat$intercept[i]<-round(summar$coefficients[1,1],digits=4)#intercept
canopy_dat$std_intercept[i]<-round(summar$coefficients[1,2], digits=4)#std_intercept
canopy_dat$pvalue_intercept[i]<-round(summar$coefficients[1,4],digits=4)#p-value_intercept
canopy_dat$coef_canopy[i]<-round(summar$coefficients[2,1],digits=4)#coef_canopy
canopy_dat$std_canopy[i]<-round(summar$coefficients[2,2],digits=4)#std_canopy
canopy_dat$pvalue_canopy[i]<-round(summar$coefficients[2,4],digits=4)#pvalue_canopy
canopy_dat$z_intercept[i]<-round(summar$coefficients[1,3],digits=4)#z_intercept
canopy_dat$z_canopy[i]<-round(summar$coefficients[2,3],digits=4)#z_canopy
canopy_dat$block_intercept[i]<-summar$varcor$block[1,1]
confin<-confint(mood,method="Wald")
r2<-r.squaredGLMM(mood)
canopy_dat$CI_2.5[i]<-confin[3]#lower confidence interval
canopy_dat$CI_97.5[i]<-confin[6]#upper confidence interval
canopy_dat$r2_marginal[i]<-r2[1]#theoretical R2
canopy_dat$r2_conditional[i]<-r2[3]#theoretical R2
#predict dat
loop_newdata<-data.frame(1, seq.func2(spec_data$std_mean_canopy))
loop_pred_canopy[[i]]<-lmer.predict(mod =mood,newdat = loop_newdata, se.mult = 1.96, binom=T, poisson = F, glmmTMB=F)
x_canopy_list[[i]]<-data.frame(x_for_plot=seq.func2(spec_data$std_mean_canopy))
}
Table S5 Probability of occurrence for the 19 winter annual species
along a gradient of canopy cover in a York gum and jam woodland in
Western Australia. CI = confidence interval.
canopy_table<-canopy_dat%>%dplyr::select(species,intercept,pvalue_intercept,coef_canopy,pvalue_canopy,CI_2.5,CI_97.5,block_intercept, r2_marginal,r2_conditional)%>%mutate(intercept=round(intercept,3),
pvalue_intercept=round(pvalue_intercept,3),
coef_canopy=round(coef_canopy,3),
pvalue_canopy=round(pvalue_canopy,3),
CI_2.5=round(CI_2.5,2),
CI_97.5=round(CI_97.5,2), block_intercept=round(block_intercept,2),
r2_marginal=round(r2_marginal,2),
r2_conditional=round(r2_conditional,2))
DT::datatable(canopy_table,height=100,options=(list(scrollX=TRUE,scrollY=TRUE)))
Plot models for canopy
cover
####data from loop for canopy plot
canopy_list <- Map(as.data.frame,spec_datcanopy_list)
spec_canopydat_plot<-rbindlist(canopy_list)
list_canopy_loop<-Map(as.data.frame,loop_pred_canopy)
predict_canopy_dat<-rbindlist(list_canopy_loop)
list_canopy_x<-Map(as.data.frame, x_canopy_list)
x_canopy_dat<-rbindlist(list_canopy_x)
dat_canopy_plot<-cbind(spec_canopydat_plot,predict_canopy_dat,x_canopy_dat)%>%
separate_wider_delim(species, delim = ".",
names = c("genus", "species.1")
)%>%unite("species_names", genus,species.1, sep=" ", remove=T)
canopy_plot<-ggplot(dat_canopy_plot, aes(x =std_mean_canopy , y = occurrence)) +facet_wrap(.~species_names,ncol=4)+
geom_jitter(width=0.2, height=0.05, size=4, color="grey49")+
geom_line(aes(x=x_for_plot, y=y, size=2), color="grey49")+
labs(x="Mean canopy cover (standardized)", y="Probability of occurrence")+
geom_ribbon(aes(x=x_for_plot, ymin =plo, ymax =phi, alpha = 0.05), fill="grey74", color="grey74")+
theme(panel.background = element_blank())+
theme(strip.text.x= element_text(size=rel(6), face="italic"),
plot.title = element_text(size = rel(5),color="black"),
axis.title.y=element_text(size = rel(5),vjust=1),
axis.title.x=element_text(size = rel(5)),
axis.text = element_text(size = rel(4)),
axis.line = element_line(size = 1, colour = "grey74", linetype=1),
axis.ticks = element_line(size = 1.5, colour = "grey74"),
axis.ticks.length = unit(.3, "cm"),
legend.position = "none")
pdf(here("Outputs","FigureS3.pdf"), width = 45, height = 35, useDingbats=F)
canopy_plot
dev.off()
## png
## 2
FigureS3 Bivariate plots from GLMMs for
probability of occurrence in response to mean canopy cover. Shaded areas
represent ± 95% confidence intervals. Points were jittered to show
overlapping values more clearly. There were no significant
effects.
Seed mass supplementary analyses
Read seed mass data
seed_mass<-read_csv(here("data","seed_mass.csv"))%>%mutate(std_log_mean_sm=scale(log(mean_SM))[,1])
## Rows: 19 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): species
## dbl (1): mean_SM
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Can seed mass explain species’ germination in response to light?
cue_dat2<-occ_sufficient_germ%>%left_join(seed_mass, by="species")
lightsm_dat<-cue_dat2%>%select(species,max_light_effect,std_log_mean_sm)%>%distinct()
lightsm_mod<-lm(max_light_effect~std_log_mean_sm,data=lightsm_dat)
summary(lightsm_mod)
##
## Call:
## lm(formula = max_light_effect ~ std_log_mean_sm, data = lightsm_dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.20321 -0.11696 -0.06376 0.07806 0.31585
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.27559 0.04583 6.014 4.35e-05 ***
## std_log_mean_sm -0.08864 0.04750 -1.866 0.0848 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1757 on 13 degrees of freedom
## Multiple R-squared: 0.2113, Adjusted R-squared: 0.1506
## F-statistic: 3.482 on 1 and 13 DF, p-value: 0.08475
Model Assumptions
simulationOutput5 <- simulateResiduals(fittedModel = lightsm_mod, plot = F)
plot(simulationOutput5)

pdf(here("Outputs","Figure_S4.pdf"), width = 12, height = 8, useDingbats=F)
par(mar = c(8, 7, 5, 2),
bty="l")
Mgp(title= 4,
labels = 2)
with(lightsm_dat, plot(max_light_effect ~ std_log_mean_sm, cex=2,
ylab = "Relative germination response to light", xlab = "log Seed mass (Standardised)",
cex.axis=2.5, cex.lab=2.5, pch=16),ylim=c(-2,1))
new.dat<-data.frame(intercept=1,std_log_mean_sm=seq.func(lightsm_dat$std_log_mean_sm))
pvar1<-diag(as.matrix(new.dat) %*% tcrossprod(vcov(lightsm_mod), as.matrix(new.dat)))
y<- as.matrix(new.dat) %*% coef(lightsm_mod)
predicted.data<-data.frame(new.dat, plo = y-(1.96*sqrt(pvar1)), phi = y+(1.96*sqrt(pvar1)))
plot.CI.func(x.for.plot=seq.func(lightsm_dat$std_log_mean_sm),
y, predicted.data$phi,predicted.data$plo, env.colour="gray30", env.trans=40, line.colour="gray30", line.type=1, line.weight=3)
dev.off()
## png
## 2
FigureS4 Species’ germination responses to light
versus ln(seed mass) for 15 annual species with sufficient germination
to calculate germination responses. The line is from a simple linear
regression and the shaded envelope represents 95% confidence intervals.
Refer to Table S7 for the model summary table.
LS0tDQp0aXRsZTogIkNPREUtQW5udWFsIHNwZWNpZXPigJkgZXhwZXJpbWVudGFsIGdlcm1pbmF0aW9uIHJlc3BvbnNlcyB0byBsaWdodCBhbmQgdGVtcGVyYXR1cmUgZG8gbm90IGNvcnJlc3BvbmQgd2l0aCB0aGVpciBtaWNyb2hhYml0YXQgYXNzb2NpYXRpb25zIGluIHRoZSBmaWVsZC4gSm91cm5hbCBvZiBWZWdldGF0aW9uIFNjaWVuY2UiDQphdXRob3I6ICJJc2lzIEEuIGRhIFNpbHZhLCBEYXZpZCBKLiBNZXJyaXR0LCBUb2RkIEUuIEVyaWNrc29uLCBNYXJnYXJldCBNLiBNYXlmaWVsZCwgYW5kIEpvaG4gTS4gRHd5ZXIiDQpkYXRlOiAgImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIg0Kb3V0cHV0Og0KICAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9IA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KZGV2dG9vbHM6OnNvdXJjZV9naXN0KCJjODNlMDc4YmY4YzgxYjAzNWUzMmMzZmMwY2YwNGVlOCIsDQogICAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWUgPSAncmVuZGVyX3RvYy5SJykNCmBgYA0KDQoNCmBgYHtyIHRvYywgZWNobz1GQUxTRX0gDQpyZW5kZXJfdG9jKCJHZXJtaW5hdGlvbl9PY2N1cnJlbmNlLlJtZCIsIHRvY19kZXB0aD0yKQ0KYGBgDQoNCg0KIyAgU3RhcnQgc2V0IHVwDQpJbnN0YWxsIHBhY2thZ2VzDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKGMoInRpZHl2ZXJzZSIsImxtZTQiLCJlbW1lYW5zIiwiZ2dwbG90MiIsIkRlc2NUb29scyIsImd0YWJsZSIsImNvd3Bsb3QiLCJncmlkIiwiTXVNSW4iLCJkYXRhLnRhYmxlIiwiaGVyZSIsIm9wdGlteCIsIkRUIikpDQpgYGANCg0KDQoNCg0KTG9hZCBsaWJyYXJpZXMNCmBgYHtyLHJlc3VsdHM9ImhpZGUiLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnJtKGxpc3Q9bHMoKSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsbWU0KQ0KbGlicmFyeShlbW1lYW5zKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShEZXNjVG9vbHMpDQpsaWJyYXJ5KGd0YWJsZSkjIGdyb2IgcGxvdCBmb3IgZmlndXJlIDINCmxpYnJhcnkoY293cGxvdCkjIGdyb2IgcGxvdCBmb3IgZmlndXJlIDINCmxpYnJhcnkoZ3JpZCkNCmxpYnJhcnkoTXVNSW4pICNyLnNxdWFyZQ0KbGlicmFyeShkYXRhLnRhYmxlKSAjbGlzdCB0byBkYXRhZnJhbWUNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkob3B0aW14KQ0KbGlicmFyeShESEFSTWEpDQpsaWJyYXJ5KERUKQ0KYGBgDQoNClJlYWQgZnVuY3Rpb25zDQoNCmBgYHtyLHJlc3VsdHM9ImhpZGUiLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCiNyZWxvY2F0ZSB0byBlbXB0eSBhcmVhIGluIHRoZSBwbG90DQpzaGlmdF9sZWdlbmQgPC0gZnVuY3Rpb24ocCl7DQogIA0KICAjIGNoZWNrIGlmIHAgaXMgYSB2YWxpZCBvYmplY3QNCiAgaWYoISJndGFibGUiICVpbiUgY2xhc3MocCkpew0KICAgIGlmKCJnZ3Bsb3QiICVpbiUgY2xhc3MocCkpew0KICAgICAgZ3AgPC0gZ2dwbG90R3JvYihwKSAjIGNvbnZlcnQgdG8gZ3JvYg0KICAgIH0gZWxzZSB7DQogICAgICBtZXNzYWdlKCJUaGlzIGlzIG5laXRoZXIgYSBnZ3Bsb3Qgb2JqZWN0IG5vciBhIGdyb2IgZ2VuZXJhdGVkIGZyb20gZ2dwbG90R3JvYi4gUmV0dXJuaW5nIG9yaWdpbmFsIHBsb3QuIikNCiAgICAgIHJldHVybihwKQ0KICAgIH0NCiAgfSBlbHNlIHsNCiAgICBncCA8LSBwDQogIH0NCiAgDQogICMgY2hlY2sgZm9yIHVuZmlsbGVkIGZhY2V0IHBhbmVscw0KICBmYWNldC5wYW5lbHMgPC0gZ3JlcCgiXnBhbmVsIiwgZ3BbWyJsYXlvdXQiXV1bWyJuYW1lIl1dKQ0KICBlbXB0eS5mYWNldC5wYW5lbHMgPC0gc2FwcGx5KGZhY2V0LnBhbmVscywgZnVuY3Rpb24oaSkgInplcm9Hcm9iIiAlaW4lIGNsYXNzKGdwW1siZ3JvYnMiXV1bW2ldXSkpDQogIGVtcHR5LmZhY2V0LnBhbmVscyA8LSBmYWNldC5wYW5lbHNbZW1wdHkuZmFjZXQucGFuZWxzXQ0KICBpZihsZW5ndGgoZW1wdHkuZmFjZXQucGFuZWxzKSA9PSAwKXsNCiAgICBtZXNzYWdlKCJUaGVyZSBhcmUgbm8gdW5maWxsZWQgZmFjZXQgcGFuZWxzIHRvIHNoaWZ0IGxlZ2VuZCBpbnRvLiBSZXR1cm5pbmcgb3JpZ2luYWwgcGxvdC4iKQ0KICAgIHJldHVybihwKQ0KICB9DQogIA0KICAjIGVzdGFibGlzaCBleHRlbnQgb2YgdW5maWxsZWQgZmFjZXQgcGFuZWxzIChpbmNsdWRpbmcgYW55IGF4aXMgY2VsbHMgaW4gYmV0d2VlbikNCiAgZW1wdHkuZmFjZXQucGFuZWxzIDwtIGdwW1sibGF5b3V0Il1dW2VtcHR5LmZhY2V0LnBhbmVscywgXQ0KICBlbXB0eS5mYWNldC5wYW5lbHMgPC0gbGlzdChtaW4oZW1wdHkuZmFjZXQucGFuZWxzW1sidCJdXSksIG1pbihlbXB0eS5mYWNldC5wYW5lbHNbWyJsIl1dKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KGVtcHR5LmZhY2V0LnBhbmVsc1tbImIiXV0pLCBtYXgoZW1wdHkuZmFjZXQucGFuZWxzW1siciJdXSkpDQogIG5hbWVzKGVtcHR5LmZhY2V0LnBhbmVscykgPC0gYygidCIsICJsIiwgImIiLCAiciIpDQogIA0KICAjIGV4dHJhY3QgbGVnZW5kICYgY29weSBvdmVyIHRvIGxvY2F0aW9uIG9mIHVuZmlsbGVkIGZhY2V0IHBhbmVscw0KICBndWlkZS5ncm9iIDwtIHdoaWNoKGdwW1sibGF5b3V0Il1dW1sibmFtZSJdXSA9PSAiZ3VpZGUtYm94IikNCiAgaWYobGVuZ3RoKGd1aWRlLmdyb2IpID09IDApew0KICAgIG1lc3NhZ2UoIlRoZXJlIGlzIG5vIGxlZ2VuZCBwcmVzZW50LiBSZXR1cm5pbmcgb3JpZ2luYWwgcGxvdC4iKQ0KICAgIHJldHVybihwKQ0KICB9DQogIGdwIDwtIGd0YWJsZV9hZGRfZ3JvYih4ID0gZ3AsDQogICAgICAgICAgICAgICAgICAgICAgICBncm9icyA9IGdwW1siZ3JvYnMiXV1bW2d1aWRlLmdyb2JdXSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHQgPSBlbXB0eS5mYWNldC5wYW5lbHNbWyJ0Il1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgbCA9IGVtcHR5LmZhY2V0LnBhbmVsc1tbImwiXV0sDQogICAgICAgICAgICAgICAgICAgICAgICBiID0gZW1wdHkuZmFjZXQucGFuZWxzW1siYiJdXSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHIgPSBlbXB0eS5mYWNldC5wYW5lbHNbWyJyIl1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJuZXctZ3VpZGUtYm94IikNCiAgDQogICMgc3F1YXNoIHRoZSBvcmlnaW5hbCBndWlkZSBib3gncyByb3cgLyBjb2x1bW4gKHdoaWNoZXZlciBhcHBsaWNhYmxlKQ0KICAjICYgZW1wdHkgaXRzIGNlbGwNCiAgZ3VpZGUuZ3JvYiA8LSBncFtbImxheW91dCJdXVtndWlkZS5ncm9iLCBdDQogIGlmKGd1aWRlLmdyb2JbWyJsIl1dID09IGd1aWRlLmdyb2JbWyJyIl1dKXsNCiAgICBncCA8LSBndGFibGVfc3F1YXNoX2NvbHMoZ3AsIGNvbHMgPSBndWlkZS5ncm9iW1sibCJdXSkNCiAgfQ0KICBpZihndWlkZS5ncm9iW1sidCJdXSA9PSBndWlkZS5ncm9iW1siYiJdXSl7DQogICAgZ3AgPC0gZ3RhYmxlX3NxdWFzaF9yb3dzKGdwLCByb3dzID0gZ3VpZGUuZ3JvYltbInQiXV0pDQogIH0NCiAgZ3AgPC0gZ3RhYmxlX3JlbW92ZV9ncm9icyhncCwgImd1aWRlLWJveCIpDQogIA0KICByZXR1cm4oZ3ApDQp9DQoNCg0KIyMgcGxvdCB3aXRoIDk1JSBDSSB1c2luZyBsbWVyIG9iamVjdHMNCmxtZXIucHJlZGljdDwtZnVuY3Rpb24obW9kLCBuZXdkYXQsIHNlLm11bHQsIGJpbm9tPU5VTEwsIHBvaXNzb249TlVMTCwgZ2xtbVRNQj1OVUxMKXsNCiAgaWYoZ2xtbVRNQj09VCl7DQogICAgcHZhcjEgPC0gZGlhZyhhcy5tYXRyaXgobmV3ZGF0KSAlKiUgdGNyb3NzcHJvZCh2Y292KG1vZClbWzFdXSxhcy5tYXRyaXgobmV3ZGF0KSkpDQogICAgbmV3ZGF0JHk8LSBhcy5tYXRyaXgobmV3ZGF0KSAlKiUgZml4ZWYobW9kKVtbMV1dfQ0KICBlbHNlew0KICAgIHB2YXIxIDwtIGRpYWcoYXMubWF0cml4KG5ld2RhdCkgJSolIHRjcm9zc3Byb2QodmNvdihtb2QpLGFzLm1hdHJpeChuZXdkYXQpKSkNCiAgICBuZXdkYXQkeTwtIGFzLm1hdHJpeChuZXdkYXQpICUqJSBmaXhlZihtb2QpfQ0KICANCiAgbmV3ZGF0IDwtIGRhdGEuZnJhbWUobmV3ZGF0LCBwbG8gPSBuZXdkYXQkeS0oc2UubXVsdCpzcXJ0KHB2YXIxKSksIHBoaSA9IG5ld2RhdCR5KyhzZS5tdWx0KnNxcnQocHZhcjEpKSkNCiAgDQogIA0KICBpZihiaW5vbT09VCkgew0KICAgIG5ld2RhdCR5PC1wbG9naXMobmV3ZGF0JHkpOyBuZXdkYXQkcGxvPC1wbG9naXMobmV3ZGF0JHBsbyk7IG5ld2RhdCRwaGk8LXBsb2dpcyhuZXdkYXQkcGhpKQ0KICB9IGVsc2UgDQogICAgDQogICAgDQogICAgaWYocG9pc3Nvbj09VCkgew0KICAgICAgbmV3ZGF0JHk8LWV4cChuZXdkYXQkeSk7IG5ld2RhdCRwbG88LWV4cChuZXdkYXQkcGxvKTsgbmV3ZGF0JHBoaTwtZXhwKG5ld2RhdCRwaGkpDQogICAgfSANCiAgcmV0dXJuKHdpdGgobmV3ZGF0LCBkYXRhLmZyYW1lKHksIHBoaSwgcGxvKSkpDQp9DQoNCg0KDQoNCnBsb3QuQ0kuZnVuYzwtIGZ1bmN0aW9uKHguZm9yLnBsb3QsIHByZWQsIHVwcGVyLCBsb3dlciwgZW52LmNvbG91ciwgZW52LnRyYW5zPU5BLCBsaW5lLmNvbG91ciwgbGluZS53ZWlnaHQsIGxpbmUudHlwZSl7DQogIGNvbG91ci5yZ2I8LWNvbDJyZ2IoY29sPWVudi5jb2xvdXIpICANCiAgcG9seWdvbi5jb29yZHM8LWRhdGEuZnJhbWUocmJpbmQoY2JpbmQoeC5mb3IucGxvdFsxXSwgbG93ZXJbMV0pLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2JpbmQoeC5mb3IucGxvdCwgdXBwZXIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2JpbmQoeC5mb3IucGxvdCwgbG93ZXIpW3JldihvcmRlcih4LmZvci5wbG90KSksXSkpDQogIG5hbWVzKHBvbHlnb24uY29vcmRzKTwtYygieCIsICJ5IikJCQkJCQkJDQogIHBvbHlnb24ocG9seWdvbi5jb29yZHMkeCwgcG9seWdvbi5jb29yZHMkeSwgY29sPXJnYihyZWQ9Y29sb3VyLnJnYlsicmVkIixdLGJsdWU9Y29sb3VyLnJnYlsiYmx1ZSIsXSwgZ3JlZW49Y29sb3VyLnJnYlsiZ3JlZW4iLF0gLCBhbHBoYT1lbnYudHJhbnMsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBib3JkZXI9TkEpDQogIGxpbmVzKHguZm9yLnBsb3QsIHByZWQsIGNvbD1saW5lLmNvbG91ciwgbHdkPWxpbmUud2VpZ2h0LCBsdHk9bGluZS50eXBlKSAgICAgICAgIA0KfSANCg0KDQpzZXEuZnVuYzI8LWZ1bmN0aW9uKHgpKHNlcShtaW4oeCwgbmEucm09VCksIG1heCh4LCBuYS5ybT1UKSwgbGVuZ3RoLm91dD0xNTApKQ0Kc2VxLmZ1bmM8LWZ1bmN0aW9uKHgpKHNlcShtaW4oeCwgbmEucm09VCksIG1heCh4LCBuYS5ybT1UKSwgbGVuZ3RoLm91dD0xMDApKQ0KYGBgDQoNCg0KDQoNCg0KIyBHZXJtaW5hdGlvbiBvZiBmcmVzaCBzZWVkcw0KDQpEYXRhIHNob3dpbmcgbWVhbiBnZXJtaW5hdGlvbiBwZXJjZW50YWdlcyBmb3IgZnJlc2ggc2VlZC4gQWxzbyBpbiBUYWJsZSBTMS1HZXJtaW5hdGlvbiBvZiBmcmVzaCBzZWVkcyBhdCA2ICg0MSBkYXlzKSBhbmQgOCAoNTYgZGF5cykgd2Vla3MuIFNwZWNpZXMgaW4gdGhlIERhcmsgdHJlYXRtZW50IHJlY2VpdmVkIDIgd2Vla3Mgb2YgbGlnaHQgKDU2IGRheXMgZ2VybWluYXRpb24pIGFmdGVyIHRoZSBmaXJzdCA2IHdlZWtzIG9mIGRhcmsuIENhYmluZXQgY29uZGl0aW9ucyB3ZXJlIG5pZ2h0IGN5Y2xlIDcgQ8KwIGFuZCBkYXlsaWdodCBjeWNsZSAxOCBDwrAsIDUwJSByZWxhdGl2ZSBodW1pZGl0eQ0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KYmFzZTwtcmVhZF9jc3YoaGVyZSgiRGF0YSIsImJhc2VsaW5lLmNzdiIpKSU+JW11dGF0ZShkYXlfNDEucD0oZGF5XzQxLzI1KSoxMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlfNTYucD0oZGF5XzU2LzI1KSoxMDApJT4lZ3JvdXBfYnkoc3BlY2llcyx0cmVhdG1lbnQpJT4lc3VtbWFyaXNlKG1lYW5fNDFfZGF5cz1tZWFuKGRheV80MS5wKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuXzU2X2RheXM9bWVhbihkYXlfNTYucCkpDQpEVDo6ZGF0YXRhYmxlKGJhc2UsaGVpZ2h0PTEwMCxvcHRpb25zPShsaXN0KHNjcm9sbFg9RkFMU0Usc2Nyb2xsWT1UUlVFKSkpDQpgYGANCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCg0KDQpSZWFkIGRhdGEgZm9yIGN1bXVsYXRpdmUgZ2VybWluYXRpb24gY3VydmUgZm9yIHRoZSBtYWluIGV4cGVyaW1lbnQNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KcGxvdGU8LXJlYWRfY3N2KGhlcmUoIkRhdGEiLCAiY3VtdWxhdGl2ZV9jdXJ2ZS5jc3YiKSklPiVyb3dpZF90b19jb2x1bW4odmFyPSJwbGF0ZSIpJT4lcGl2b3RfbG9uZ2VyKC0oMTo3KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190bz0idGltZSIsdmFsdWVzX3RvPSJnZXJtaW5hdGlvbl9kYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190cmFuc2Zvcm0gPSBsaXN0KGdlcm1pbmF0aW9uX2RheSA9IGFzLm51bWVyaWMpKSU+JQ0KICBtdXRhdGUodG90YWxfbm9uZ2VybT10b3RhbF9zZWVkc19kaXNoLWdlcm1pbmF0aW9uX2RheSklPiVtdXRhdGUodGltZT1hcy5udW1lcmljKHRpbWUpKSU+JQ0KICBzZXBhcmF0ZV93aWRlcl9kZWxpbShzcGVjaWVzLCBkZWxpbSA9ICIuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMgPSBjKCJnZW51cyIsICJzcGVjaWVzLjEiKQ0KICApJT4ldW5pdGUoInNwZWNpZXNfbmFtZXMiLCBnZW51cyxzcGVjaWVzLjEsIHNlcD0iICIsIHJlbW92ZT1UKSU+JQ0KZ3JvdXBfYnkoc3BlY2llc19uYW1lcyx0b3RhbF9zZWVkcyx0ZW1wLCB0aW1lKSU+JQ0KICBzdW1tYXJpc2UoY291bnRfZ2VybT1zdW0oZ2VybWluYXRpb25fZGF5KSklPiVtdXRhdGUoY3VtdWxhdGl2ZV9jb3VudD1jdW1zdW0oY291bnRfZ2VybSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdW11bGF0aXZlX3BlcmNlbnRhZ2U9KGN1bXVsYXRpdmVfY291bnQvdG90YWxfc2VlZHMpKjEwMCkNCg0KYGBgDQoNCg0KUGxvdCBjdW11bGF0aXZlIGdlcm1pbmF0aW9uIGN1cnZlcw0KDQpgYGB7cn0NCnBkZihoZXJlKCJPdXRwdXRzIiwiRmlndXJlUzEucGRmIiksIHdpZHRoID0gMTUsIGhlaWdodCA9IDExKQ0KDQpwbG90ZSU+JWdncGxvdChhZXMoeD10aW1lLHkgPSBjdW11bGF0aXZlX3BlcmNlbnRhZ2UsIGdyb3VwPXRlbXApLHNob3cubGVnZW5kID0gRkFMU0UpKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvcj10ZW1wLHNoYXBlPXRlbXApKSsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj10ZW1wKSkrDQogIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0iVHJlYXRtZW50IiwgdmFsdWVzPWMoImJsdWUiLCJyZWQiKSkrDQogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lPSJUcmVhdG1lbnQiLCB2YWx1ZXM9YygxOSwyMikpKw0KICBmYWNldF93cmFwKH5zcGVjaWVzX25hbWVzLG5jb2w9NCkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEwMCwgYnkgPSAxNSkpKw0KICB5bGFiKCJDdW11bGF0aXZlIEdlcm1pbmF0aW9uICglKSIpICsgeGxhYigiRGF5cyIpKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBsaW5ld2lkdGg9MSkpKw0KICB0aGVtZShzdHJpcC50ZXh0Lng9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgxLjgpLCBmYWNlPSJpdGFsaWMiKSwNCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksdmp1c3Q9MSksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjUpLHZqdXN0PTEpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID1lbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjgpKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuOCkpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEuNSwgImNtIikpDQoNCmRldi5vZmYoKQ0KYGBgDQohW0ZpZ3VyZV9TMSBDdW11bGF0aXZlIGdlcm1pbmF0aW9uIGZvciAxOSB3aW50ZXIgYW5udWFsIHNwZWNpZXMgZnJvbSB0aGUgdW5kZXJzdG9yeSBvZiBhIFlvcmstZ3VtIGphbSBNZWRpdGVycmFuZWFuIHdvb2RsYW5kIGluIFdlc3Rlcm4gQXVzdHJhbGlhIHVuZGVyIHR3byB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzOiBDb2xkICg3LzE4IMKwQywgMTIvMTJoIGxpZ2h0L2RhcmssIDUwJSByZWxhdGl2ZSBodW1pZGl0eSkgYW5kIFdhcm0gKDcvMjQgwrBDLCAxMi8xMmggbGlnaHQvZGFyaywgNTAlIHJlbGF0aXZlIGh1bWlkaXR5KS5dKE91dHB1dHMvRmlndXJlUzEucGRmKXt3aWR0aD04MCUgaGVpZ2h0PTQwMH0NCg0KDQoNCg0KDQoNCiMgUTEgRG8gc3BlY2llcyBkaWZmZXIgaW4gdGhlaXIgZ2VybWluYXRpb24gcmVzcG9uc2VzIHRvIGRpZmZlcmVudCB0ZW1wZXJhdHVyZSBhbmQgbGlnaHQgcmVnaW1lcz8NCg0KUmVhZCBkYXRhIGZvciBRMS9RMg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KY3VlX2RhdDwtcmVhZF9jc3YoaGVyZSgiRGF0YSIsImdlcm1fY3VlLmNzdiIpKSU+JQ0KICBtdXRhdGUodG90YWxfbm9uZ2VybT10b3RhbF9zZWVkc19kaXNoLWdlcm1pbmF0aW9uX3RvdGFsLA0KICAgICAgICBwcm9wX2dlcm0gPWdlcm1pbmF0aW9uX3RvdGFsL3RvdGFsX3NlZWRzX2Rpc2gpJT4lcm93aWRfdG9fY29sdW1uKHZhcj0icGxhdGUiKSMgcGxhdGUgaXMgYW4gdW5pcXVlIGlkIGZvciByYW5kb20gZWZmZWN0cw0KYGBgDQoNCk1vZGVsIGNvbnRhaW5pbmcgYWxsIGludGVyYWN0aW9ucyBhbmQgYWRkaXRpdmUgZml4ZWQgZWZmZWN0cw0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsdWF0ZT1GQUxTRX0NCmdyZXNfbW9kPC1nbG1lcihjYmluZChnZXJtaW5hdGlvbl90b3RhbCx0b3RhbF9ub25nZXJtKX50ZW1wKmxpZ2h0KnNwZWNpZXMrKDF8cGxhdGUpLGZhbWlseT1iaW5vbWlhbCxkYXRhPWN1ZV9kYXQpDQojbW9kZWwgcnVuIHdpdGggY29udmVyZ2VuY2Ugd2FybmluZw0KYGBgDQoNCkVsaW1pbmF0ZSBjb252ZXJnZW5jZSB3YXJuaW5nIGJ5IHJlbW92aW5nIHJhbmRvbSBlZmZlY3RzLg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ3Jlc19tb2QyPC1nbG0oY2JpbmQoZ2VybWluYXRpb25fdG90YWwsdG90YWxfbm9uZ2VybSl+dGVtcCpsaWdodCpzcGVjaWVzLGZhbWlseT1iaW5vbWlhbCxkYXRhPWN1ZV9kYXQpDQpgYGANCg0KQ2hlY2sgZ3Jlc19tb2QgYXNzdW1wdGlvbnMNCg0KYGBge3J9DQpzaW11bGF0aW9uT3V0cHV0IDwtIHNpbXVsYXRlUmVzaWR1YWxzKGZpdHRlZE1vZGVsID0gZ3Jlc19tb2QyLCBwbG90ID0gRikNCg0KcGxvdChzaW11bGF0aW9uT3V0cHV0KSAjbm8gbWFqb3IgcHJvYmxlbXMNCg0KYGBgDQoNClRhYmxlUzItRXN0aW1hdGVkIG1hcmdpbmFsIHByb2JhYmlsaXRpZXMgZm9yIHRoZSB3aW50ZXIgYW5udWFscyBpbiB0aGlzIHN0dWR5Lg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KZW1tZWFuX21vZDwtYXMuZGF0YS5mcmFtZShlbW1lYW5zKGdyZXNfbW9kMiwgfnRlbXAqbGlnaHR8c3BlY2llcywgdHlwZT0icmVzcG9uc2UiKSkNCg0KZW1tZWFuX21vZFssNDo4XTwtcm91bmQoZW1tZWFuX21vZFssNDo4XSwzKQ0KcHJpbnQoZW1tZWFuX21vZCkNCmBgYA0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KDQoNClRhYmxlIFMzLSBXaXRoaW4tc3BlY2llcyBkaWZmZXJlbmNlcyBpbiB0aGUgcHJvYmFiaWxpdHkgb2YgZ2VybWluYXRpb24gdW5kZXIgdHdvIHRlbXBlcmF0dXJlIHJlZ2ltZXMgKENvbGQ6IDcvMTggwrBDIGFuZCBXYXJtOiA3LzI0IMKwQykgYW5kIHR3byBsaWdodCByZWdpbWVzICgxMmgvMTJoIGxpZ2h0L2Rhcmsgb3IgY29udGludW91cyBkYXJrKS4gU2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgKHAg4omkIDAuMDUpIGFyZSBpbiBib2xkLiBGb3Igc29tZSBzcGVjaWVzLCBnZXJtaW5hdGlvbiB3YXMgaW5zdWZmaWNpZW50IHRvIHRlc3QgYW55IHBhaXJ3aXNlIGNvbnRyYXN0cyBhbmQgZm9yIG90aGVycyBvbmx5IHRob3NlIGxpc3RlZCBjb3VsZCBiZSB0ZXN0ZWQuDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpwYV9tb2Q8LWFzLmRhdGEuZnJhbWUocGFpcnMoZW1tZWFucyhncmVzX21vZDIsIH50ZW1wKmxpZ2h0fHNwZWNpZXMpLCB0eXBlPSJyZXNwb25zZSIpKQ0KDQoNCkRUOjpkYXRhdGFibGUocGFfbW9kLGhlaWdodD02MCxvcHRpb25zPShsaXN0KHNjcm9sbFg9VFJVRSxzY3JvbGxZPVRSVUUpKSklPiVmb3JtYXRSb3VuZChjb2x1bW5zPWMoJ29kZHMucmF0aW8nLCAnU0UnLCJ6LnJhdGlvIiwicC52YWx1ZSIpLCBkaWdpdHM9MykNCmBgYA0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KRGF0YSBmb3IgcGxvdHRpbmcNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBsb3RfYm94PC1jdWVfZGF0JT4lbXV0YXRlKHBlcmNlbnRfZ2VybT0oZ2VybWluYXRpb25fdG90YWwvdG90YWxfc2VlZHNfZGlzaCkqMTAwKSU+JQ0KICB1bml0ZSgiVHJlYXRtZW50IiwgdGVtcCxsaWdodCxzZXA9ICIrIixyZW1vdmU9RiklPiV1bml0ZSgiaWQiLFRyZWF0bWVudCxzcGVjaWVzLHJlbW92ZT1GKSU+JQ0KICBncm91cF9ieShzcGVjaWVzLCBUcmVhdG1lbnQsZGlzaCklPiUNCiAgc2VwYXJhdGVfd2lkZXJfZGVsaW0oc3BlY2llcywgZGVsaW0gPSAiLiIsDQogICAgbmFtZXMgPSBjKCJnZW51cyIsICJzcGVjaWVzLjEiKQ0KICApJT4ldW5pdGUoInNwZWNpZXNfbmFtZXMiLCBnZW51cyxzcGVjaWVzLjEsIHNlcD0iICIsIHJlbW92ZT1UKQ0KDQpwcm9iPC1lbW1lYW5fbW9kJT4lDQogIHVuaXRlKCJUcmVhdG1lbnQiLHRlbXAsbGlnaHQsIHNlcD0gIisiLCByZW1vdmU9RiklPiUNCiAgdW5pdGUoImlkIixUcmVhdG1lbnQsc3BlY2llcywgcmVtb3ZlPUYpJT4lc2VsZWN0KGlkLHByb2Isc3BlY2llcykNCg0KcGxvdF9wb2ludDwtbWVyZ2UocGxvdF9ib3gscHJvYixieS54PSJpZCIsYnkueT0iaWQiKQ0KbGVnZW5kX3BvaW50PC1yZWFkX2NzdihoZXJlKCJEYXRhIiwibGVnZW5kX3BvaW50LmNzdiIpKSU+JXNlcGFyYXRlX3dpZGVyX2RlbGltKHNwZWNpZXMsIGRlbGltID0gIi4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMgPSBjKCJnZW51cyIsICJzcGVjaWVzLjEiKQ0KKSU+JXVuaXRlKCJzcGVjaWVzX25hbWVzIiwgZ2VudXMsc3BlY2llcy4xLCBzZXA9IiAiLCByZW1vdmU9VCkNCmBgYA0KDQoNClBsb3R0aW5nIGdlcm1pbmF0aW9uIHJlc3BvbnNlcyB0byBleHBlcmltZW50YWwgdHJlYXRtZW50cw0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KcDEuMjwtZ2dwbG90KHBsb3RfcG9pbnQsYWVzKHg9VHJlYXRtZW50LHk9cGVyY2VudF9nZXJtLGZpbGw9VHJlYXRtZW50KSkrZ2VvbV9qaXR0ZXIoYWVzKGNvbG9yPVRyZWF0bWVudCksc2l6ZT0xMix3aWR0aD0wLjMsaGVpZ2h0PTAuNSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9YygiQ29sZCtEYXJrIj0iIzFFODhFNSIsIkNvbGQrTGlnaHQiPSIjQjhFMEQ5IiwiV2FybStEYXJrIj0gIiNEODFCNjAiLCJXYXJtK0xpZ2h0Ij0iI0ZGQzEwNyIpKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9YygiQ29sZCtEYXJrIj0iIzFFODhFNSIsIkNvbGQrTGlnaHQiPSIjQjhFMEQ5IiwiV2FybStEYXJrIj0gIiNEODFCNjAiLCJXYXJtK0xpZ2h0Ij0iI0ZGQzEwNyIpKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsMTEwKSwgYnJlYWtzPWMoMCwyMCw0MCw2MCw4MCwxMDApLA0KICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUHJvYmFiaWxpdHkgb2YgZ2VybWluYXRpb24gKCUpIikrDQogIGdlb21fcG9pbnQobWFwcGluZz1hZXMoeD1UcmVhdG1lbnQsIHk9cHJvYioxMDAsIGdyb3VwPVRyZWF0bWVudCksIHNpemU9MTQsIHNoYXBlPTIzLCBjb2xvdXI9ImJsYWNrIikrZmFjZXRfd3JhcCgufnNwZWNpZXNfbmFtZXMsbmNvbD01KSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbD1OQSwgbGluZXdpZHRoPTEpKSsNCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWUoc3RyaXAudGV4dC54PSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoNiksIGZhY2U9Iml0YWxpYyIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoNSksY29sb3I9ImJsYWNrIiksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZSA9IHJlbCg2KSx2anVzdD0xKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoNCkpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPWVsZW1lbnRfdGV4dChzaXplID0gcmVsKDUpKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplID0gcmVsKDUpKSwNCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgzLCAiY20iKSkrdGhlbWUocGxvdC5tYXJnaW49dW5pdChjKDEsMS41LDEsMS41KSwgJ2NtJykpKw0KDQogIGdlb21fdGV4dChkYXRhPWxlZ2VuZF9wb2ludCwgYWVzKHg9eCwgeT15LCBsYWJlbD1sYWJlbCksY29sb3VyPSJibGFjayIsc2l6ZT0xNykNCg0KcGRmKGhlcmUoIk91dHB1dHMiLCJGaWd1cmVfMy5wZGYiKSwgd2lkdGggPSA1MSwgaGVpZ2h0ID0gMjksIHVzZURpbmdiYXRzPUYpDQpncmlkLmRyYXcoc2hpZnRfbGVnZW5kKHAxLjIpKQ0KZGV2Lm9mZigpDQpgYGANCg0KDQohW0ZpZ3VyZV8zIEVzdGltYXRlZCBtYXJnaW5hbCBtZWFucyAoRU1NcykgZnJvbSBhIGJpbm9taWFsIGdlbmVyYWxpemVkIGxpbmVhciBtaXhlZCBtb2RlbCBjb250YWluaW5nIGFsbCBpbnRlcmFjdGlvbnMgYmV0d2VlbiB0cmVhdG1lbnRzIGFuZCBzcGVjaWVzLiBUaGlzIHBsb3Qgc2hvd3MgdGhlIHJlc3BvbnNlIHRvIGVhY2ggdHJlYXRtZW50IGNvbWJpbmF0aW9uLiBEaWFtb25kcyBhcmUgbWVhbiBlc3RpbWF0ZWQgcHJvYmFiaWxpdGllcyBmb3IgMTkgd2ludGVyIGFubnVhbHMgaW4gdGhlIHN0dWR5IChUYWJsZSBTMikuIFByb2JhYmlsaXRpZXMgd2VyZSBtdWx0aXBsaWVkIGJ5IDEwMCB0byBiZSBnaXZlbiBpbiBwZXJjZW50YWdlcy4gUG9pbnRzIGFyZSBvYnNlcnZlZCBtZWFuIGdlcm1pbmF0aW9uIHBlcmNlbnRhZ2VzIGZvciBlYWNoIHBldHJpIGRpc2guIFBvaW50cyB3ZXJlIGppdHRlcmVkIHRvIHNob3cgb3ZlcmxhcHBpbmcgdmFsdWVzIG1vcmUgY2xlYXJseS5dKE91dHB1dHMvRmlndXJlXzMucGRmKXt3aWR0aD0xMDAlIGhlaWdodD02MDB9DQoNCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCg0KTWVhbiBnZXJtaW5hdGlvbiB1bmRlciB0aGUgcHJlZmVycmVkIGNvbmRpdGlvbnMuIA0KDQpgYGB7cn0NCiNmaWx0ZXIgb3V0IHNwZWNpZXMgdGhhdCBkaWQgbm90IGdlcm1pbmF0ZSBhbmQgdHJlYXRtZW50cyB0aGF0IGRlY3JlYXNlZCBnZXJtaW5hdGlvbg0KZ2VybV90MjwtcGxvdF9wb2ludCU+JWRwbHlyOjpmaWx0ZXIoc3BlY2llcyE9IkNhbGFuZHJpbmlhLmVyZW1hZWEiLHNwZWNpZXMhPSJIeWFsb3NwZXJtYS5nbHV0aW5vc3VtIixzcGVjaWVzIT0iTW9ub2N1bHVzLm1vbnN0cm9zdXMiLHNwZWNpZXMhPSJUcmFjaHltZW5lLm9ybmF0YSIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJDb2xkK0RhcmtfQ2Fsb3Rpcy5oaXNwaWR1bGEiLGlkIT0gIldhcm0rRGFya19DYWxvdGlzLmhpc3BpZHVsYSIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJXYXJtK0RhcmtfQ2h0aG9ub2NlcGhhbHVzLnBzZXVkZXZheCIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJDb2xkK0RhcmtfQ3Jhc3N1bGEuY29sb3JhdGEiLGlkIT0iV2FybStEYXJrX0NyYXNzdWxhLmNvbG9yYXRhIixpZCE9Ildhcm0rTGlnaHRfQ3Jhc3N1bGEuY29sb3JhdGEiKSU+JQ0KICBkcGx5cjo6ZmlsdGVyKGlkIT0iV2FybStMaWdodF9Hb29kZW5pYS5yb3NlYSIsaWQhPSJDb2xkK0RhcmtfR29vZGVuaWEucm9zZWEiLGlkIT0iV2FybStEYXJrX0dvb2RlbmlhLnJvc2VhIiklPiUNCiAgZHBseXI6OmZpbHRlcihpZCE9IkNvbGQrRGFya19QZW50YW1lcmlzLmFpcm9pZGVzIixpZCE9Ildhcm0rRGFya19QZW50YW1lcmlzLmFpcm9pZGVzIiklPiUNCiAgZHBseXI6OmZpbHRlcihpZCE9Ildhcm0rTGlnaHRfUGxhbnRhZ28uZGViaWxpcyIsaWQhPSJDb2xkK0RhcmtfUGxhbnRhZ28uZGViaWxpcyIsaWQhPSJXYXJtK0RhcmtfUGxhbnRhZ28uZGViaWxpcyIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJDb2xkK0RhcmtfUG9kb2xlcGlzLmFyaXN0YXRhIixpZCE9Ildhcm0rRGFya19Qb2RvbGVwaXMuYXJpc3RhdGEiKSU+JQ0KICBkcGx5cjo6ZmlsdGVyKGlkIT0iV2FybStMaWdodF9Qb2dvbm9sZXBpcy5tdWVsbGVyaWFuYSIsaWQhPSJDb2xkK0RhcmtfUG9nb25vbGVwaXMubXVlbGxlcmlhbmEiLGlkIT0iV2FybStEYXJrX1BvZ29ub2xlcGlzLm11ZWxsZXJpYW5hIiklPiUNCiAgZHBseXI6OmZpbHRlcihpZCE9IkNvbGQrTGlnaHRfU3Blcmd1bGEuYXJ2ZW5zaXMiLGlkIT0iQ29sZCtEYXJrX1NwZXJndWxhLmFydmVuc2lzIixpZCE9Ildhcm0rRGFya19TcGVyZ3VsYS5hcnZlbnNpcyIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJDb2xkK0RhcmtfU3Rlbm9wZXRhbHVtLmZpbGlmb2xpdW0iLGlkIT0iV2FybStEYXJrX1N0ZW5vcGV0YWx1bS5maWxpZm9saXVtIiklPiUNCiAgZHBseXI6OmZpbHRlcihpZCE9Ildhcm0rTGlnaHRfVHJhY2h5bWVuZS5jeWFub3BldGFsYSIsaWQhPSJDb2xkK0RhcmtfVHJhY2h5bWVuZS5jeWFub3BldGFsYSIsaWQhPSJXYXJtK0RhcmtfVHJhY2h5bWVuZS5jeWFub3BldGFsYSIpJT4lDQogIGRwbHlyOjpmaWx0ZXIoaWQhPSJDb2xkK0RhcmtfV2FpdHppYS5hY3VtaW5hdGEiLGlkIT0iV2FybStEYXJrX1dhaXR6aWEuYWN1bWluYXRhIiklPiUNCiAgZHBseXI6OmZpbHRlcihpZCE9IkNvbGQrRGFya19QdGlsb3R1cy5nYXVkaWNoYXVkaWkiLCBpZCE9Ildhcm0rRGFya19QdGlsb3R1cy5nYXVkaWNoYXVkaWkiKSU+JW11dGF0ZShzcGVjaWVzPWFzLmNoYXJhY3RlcihzcGVjaWVzKSklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNClN1bW1hcml6ZSBnZXJtaW5hdGlvbiBwZXJjZW50YWdlcyBmb3Igc3BlY2llcyBpbiB0aGUgdHJlYXRtZW50IGNvbWJpbmF0aW9uIHdpdGggdGhlIGhpZ2hlc3QgZ2VybWluYXRpb24NCmBgYHtyfQ0KbWVhbl9nZXJtaW5hdGlvbjwtdChhcy5tYXRyaXgodGFwcGx5KGdlcm1fdDIkcGVyY2VudF9nZXJtLCBnZXJtX3QyJHNwZWNpZXMsIG1lYW4pKSkNCmBgYA0KUmFuZ2UNCmBgYHtyfQ0KYXBwbHkobWVhbl9nZXJtaW5hdGlvbiwxLHJhbmdlKQ0KYGBgDQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQpUYWJsZSAyIE1lYW4gZ2VybWluYXRpb24gcGVyY2VudGFnZXMgZm9yIHNwZWNpZXMgdW5kZXIgdHJlYXRtZW50IGNvbWJpbmF0aW9ucyB3aXRoIHRoZSBoaWdoZXN0IGdlcm1pbmF0aW9uIGlkZW50aWZpZWQgb24gRmlndXJlIDMuDQpgYGB7cn0NCm1lYW5fZ2VybWluYXRpb24yPC1hcy5kYXRhLmZyYW1lKG1lYW5fZ2VybWluYXRpb24pIA0KbWVhbl9nZXJtaW5hdGlvbjI8LW1lYW5fZ2VybWluYXRpb24yJT4lcGl2b3RfbG9uZ2VyKGNvbHM9MToxNSxuYW1lc190bz0ic3BlY2llcyIsdmFsdWVzX3RvPSJtZWFuIiklPiVtdXRhdGUobWVhbj1yb3VuZChtZWFuLDEpKQ0KcHJpbnQobWVhbl9nZXJtaW5hdGlvbjIpDQpgYGANCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCg0KDQojIFEyIFF1ZXN0aW9uIDI6IERvIHNwZWNpZXPigJkgZ2VybWluYXRpb24gcmVzcG9uc2VzIHRvIGV4cGVyaW1lbnRhbCB0ZW1wZXJhdHVyZSBhbmQgbGlnaHQgcmVnaW1lcyBjb3JyZXNwb25kIHRvIHRoZWlyIG1pY3JvaGFiaXRhdCBhc3NvY2lhdGlvbnMgaW4gdGhlIGZpZWxkPw0KDQoNCkV4dHJhY3Qgc3BlY2llcycgZXhwZXJpbWVudGFsIHJlc3BvbnNlcyB0byBsaWdodCBhbmQgdGVtcGVyYXR1cmUNCg0KYGBge3J9DQpzcGVjaWVzX2RhdGE8LWRhdGEuZnJhbWUoc3BlY2llcz11bmlxdWUoY3VlX2RhdCRzcGVjaWVzKSklPiUNCiAgYXJyYW5nZShzcGVjaWVzKQ0KDQp0ZW1wPC1lbW1lYW5fbW9kWyw0OjhdDQoNCmBgYA0KDQoNCkNhbGN1bGF0ZSBsaWdodCBhbmQgdGVtcGVyYXR1cmUgZ2VybWluYXRpb24gcmVzcG9uc2VzDQoNCmBgYHtyfQ0KDQpzcGVjaWVzX2RhdGEkY29sZF9saWdodF9lZmZlY3Q8LXRlbXBbc2VxKDMsNzYsIDQpLDFdIC0gdGVtcFtzZXEoMSw3NiwgNCksMV0NCg0Kc3BlY2llc19kYXRhJHdhcm1fbGlnaHRfZWZmZWN0PC10ZW1wW3NlcSg0LDc2LCA0KSwxXSAtIHRlbXBbc2VxKDIsNzYsIDQpLDFdDQpzcGVjaWVzX2RhdGEkbWF4X2xpZ2h0X2VmZmVjdDwtIGlmZWxzZShzcGVjaWVzX2RhdGEkY29sZF9saWdodF9lZmZlY3Q+c3BlY2llc19kYXRhJHdhcm1fbGlnaHRfZWZmZWN0LCBzcGVjaWVzX2RhdGEkY29sZF9saWdodF9lZmZlY3QsIHNwZWNpZXNfZGF0YSR3YXJtX2xpZ2h0X2VmZmVjdCkNCg0Kc3BlY2llc19kYXRhJGxpZ2h0X2Nvb2xfZWZmZWN0PC10ZW1wW3NlcSgzLDc2LCA0KSwxXSAtIHRlbXBbc2VxKDQsNzYsIDQpLDFdDQpzcGVjaWVzX2RhdGEkZGFya19jb29sX2VmZmVjdDwtdGVtcFtzZXEoMSw3NiwgNCksMV0gLSB0ZW1wW3NlcSgyLDc2LCA0KSwxXQ0Kc3BlY2llc19kYXRhJG1heF9jb29sX2VmZmVjdDwtIGlmZWxzZShzcGVjaWVzX2RhdGEkbGlnaHRfY29vbF9lZmZlY3Q+c3BlY2llc19kYXRhJGRhcmtfY29vbF9lZmZlY3QsIHNwZWNpZXNfZGF0YSRsaWdodF9jb29sX2VmZmVjdCwgc3BlY2llc19kYXRhJGRhcmtfY29vbF9lZmZlY3QpDQpgYGANCg0KDQoNClJlYWQgb2NjdXJyZW5jZSBkYXRhDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpvY2M8LXJlYWRfY3N2KGhlcmUoIkRhdGEiLCJvY2N1cnJlbmNlLmNzdiIpKSU+JWdyb3VwX2J5KGJsb2NrKSU+JW11dGF0ZShtZWFuX2Nhbm9weT1tZWFuKGNhbm9weV9jb3ZlcikpJT4ldW5ncm91cCgpJT4lbXV0YXRlKHN0ZF9tZWFuX2Nhbm9weT0gc2NhbGUobWVhbl9jYW5vcHkpWywxXSwNCiAgICAgICAgIHN0ZF9zcXJ0X2xpdHRlciA9IHNjYWxlKHNxcnQobGl0dGVyX3BlcmNlbnQpKVssMV0pJT4lDQogIGxlZnRfam9pbihzcGVjaWVzX2RhdGEsIGJ5ID0gInNwZWNpZXMiKQ0KDQpgYGANCg0KU3BlY2llcyB3aXRoIGluc3VmZmljaWVudCBnZXJtaW5hdGlvbg0KDQpgYGB7cn0NCmluc3VmZmljaWVudF9nZXJtX3NwZWNpZXM8LWMoIkNhbGFuZHJpbmlhLmVyZW1hZWEiLCJIeWFsb3NwZXJtYS5nbHV0aW5vc3VtIiwiTW9ub2N1bHVzLm1vbnN0cm9zdXMiLCJUcmFjaHltZW5lLm9ybmF0YSIpDQoNCmBgYA0KDQpSZW1vdmUgc3BlY2llcyB3aXRoIGluc3VmZmljaWVudCBnZXJtaW5hdGlvbg0KYGBge3J9DQpvY2Nfc3VmZmljaWVudF9nZXJtPC1vY2MlPiUNCiAgZmlsdGVyKCFzcGVjaWVzJWluJWluc3VmZmljaWVudF9nZXJtX3NwZWNpZXMpDQoNCmBgYA0KDQoNCg0KIyMgRG8gc3BlY2llcycgZXhwZXJpbWVudGFsIGNvb2wgcmVzcG9uc2VzIGV4cGxhaW4gdGhlaXIgb2NjdXJyZW5jZSB0cmVuZHMgd2l0aCBzaGFkZT8NCg0KDQpgYGB7cn0NCmNvb2xfZWZmZWN0X21vZDwtZ2xtZXIob2NjdXJyZW5jZX5zdGRfbWVhbl9jYW5vcHkqbWF4X2Nvb2xfZWZmZWN0ICsoMXxibG9jaykrKHN0ZF9tZWFuX2Nhbm9weXxzcGVjaWVzKSxkYXRhPW9jY19zdWZmaWNpZW50X2dlcm0sIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShjb29sX2VmZmVjdF9tb2QpDQpgYGANCg0KQ2hlY2sgY29vbF9lZmZlY3RfbW9kIGFzc3VtcHRpb25zDQpgYGB7cn0NCnNpbXVsYXRpb25PdXRwdXQzIDwtIHNpbXVsYXRlUmVzaWR1YWxzKGZpdHRlZE1vZGVsID0gY29vbF9lZmZlY3RfbW9kLCBwbG90ID0gRikNCg0KcGxvdChzaW11bGF0aW9uT3V0cHV0MykgI25vIG1ham9yIHByb2JsZW1zDQoNCmBgYA0KDQoNCg0KDQoNCiMjIERvIHNwZWNpZXMnIGV4cGVyaW1lbnRhbCBsaWdodCByZXNwb25zZXMgZXhwbGFpbiB0aGVpciBvY2N1cnJlbmNlIHRyZW5kcyB3aXRoIGxpdHRlcj8NCg0KYGBge3J9DQpsaWdodF9lZmZlY3RfbW9kPC1nbG1lcihvY2N1cnJlbmNlfnN0ZF9zcXJ0X2xpdHRlciptYXhfbGlnaHRfZWZmZWN0ICsoMXxibG9jaykrKHN0ZF9zcXJ0X2xpdHRlcnxzcGVjaWVzKSxkYXRhPW9jY19zdWZmaWNpZW50X2dlcm0sIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShsaWdodF9lZmZlY3RfbW9kKQ0KDQpgYGANCg0KDQpDaGVjayBsaWdodF9lZmZlY3RfbW9kIGFzc3VtcHRpb25zDQpgYGB7cn0NCnNpbXVsYXRpb25PdXRwdXQyIDwtIHNpbXVsYXRlUmVzaWR1YWxzKGZpdHRlZE1vZGVsID0gbGlnaHRfZWZmZWN0X21vZCwgcGxvdCA9IEYpDQoNCnBsb3Qoc2ltdWxhdGlvbk91dHB1dDIpICNubyBtYWpvciBwcm9ibGVtcw0KDQpgYGANCg0KDQojIyBPY2N1cnJlbmNlcyBleHBsYWluZWQgYnkgZWl0aGVyIGNhbm9weSBjb3ZlciBvciBsaXR0ZXIgZm9yIGVhY2ggb2YgdGhlIDE5IHNwZWNpZXMNCg0KDQoNCg0KIyMjIFByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UgZXhwbGFpbmVkIGJ5IGxpdHRlciBjb3Zlcg0KDQpNb2RlbHMgaW4gYSBsb29wLiBPbmUgbW9kZWwgZm9yIGVhY2ggc3BlY2llcw0KYGBge3IsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxlcnJvcj1GQUxTRX0NCg0Kc3BlY2llc19uYW1lczE8LXNvcnQodW5pcXVlKG9jYyRzcGVjaWVzKSkNCg0KbGl0dGVyX2RhdDwtZGF0YS5mcmFtZShzcGVjaWVzPXNwZWNpZXNfbmFtZXMxLA0KICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmNlcHQ9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc3RkX2ludGVyY2VwdD12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICB6X2ludGVyY2VwdD12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVfaW50ZXJjZXB0PXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMxKSksDQogICAgICAgICAgICAgICAgICAgICAgIGNvZWZfbGl0dGVyPXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMxKSksDQogICAgICAgICAgICAgICAgICAgICAgIHN0ZF9saXR0ZXI9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgel9saXR0ZXI9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlX2xpdHRlcj12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICBDSV8yLjU9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgQ0lfOTcuNT12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICBibG9ja19pbnRlcmNlcHQ9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcjJfbWFyZ2luYWw9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcjJfY29uZGl0aW9uYWw9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lczEpKSkNCg0KDQoNCg0Kc3BlY19tb2QuMjwtbGlzdCgpDQpsb29wX3ByZWRfbGl0dGVyPC1saXN0KCkNCnNwZWNfZGF0bGl0dGVyX2xpc3Q8LWxpc3QoKQ0KeF9saXR0ZXJfbGlzdDwtbGlzdCgpDQoNCmZvciAoaSBpbiAxOmxlbmd0aChzcGVjaWVzX25hbWVzMSkpew0KICBzcGVjX2RhdGE8LXN1YnNldChvY2MsIHNwZWNpZXM9PXNwZWNpZXNfbmFtZXMxW2ldKQ0KICBzcGVjX2RhdGxpdHRlcl9saXN0W1tpXV08LXN1YnNldChvY2MsIHNwZWNpZXM9PXNwZWNpZXNfbmFtZXMxW2ldKQ0KICBzcGVjX21vZC4yW1tpXV08LWdsbWVyKG9jY3VycmVuY2UgfiBzdGRfc3FydF9saXR0ZXIrICgxfGJsb2NrKSwgZmFtaWx5PWJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSBzcGVjX2RhdGEsY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0nb3B0aW14Jywgb3B0Q3RybD1saXN0KG1ldGhvZD0nTC1CRkdTLUInKSkpDQogIG1vb2Q8LWdsbWVyKG9jY3VycmVuY2UgfiBzdGRfc3FydF9saXR0ZXIrICgxfGJsb2NrKSwgZmFtaWx5PWJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSBzcGVjX2RhdGEsY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0nb3B0aW14Jywgb3B0Q3RybD1saXN0KG1ldGhvZD0nTC1CRkdTLUInKSkpDQogIHN1bW1hcjwtc3VtbWFyeShtb29kKQ0KICANCiAgbGl0dGVyX2RhdCRpbnRlcmNlcHRbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMSwxXSxkaWdpdHM9NCkjaW50ZXJjZXB0DQogIGxpdHRlcl9kYXQkc3RkX2ludGVyY2VwdFtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1sxLDJdLCBkaWdpdHM9NCkjc3RkX2ludGVyY2VwdA0KICBsaXR0ZXJfZGF0JHB2YWx1ZV9pbnRlcmNlcHRbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMSw0XSxkaWdpdHM9NCkjcC12YWx1ZV9pbnRlcmNlcHQNCiAgbGl0dGVyX2RhdCRjb2VmX2xpdHRlcltpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1syLDFdLGRpZ2l0cz00KSNjb2VmX2Nhbm9weQ0KICBsaXR0ZXJfZGF0JHN0ZF9saXR0ZXJbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMiwyXSxkaWdpdHM9NCkjc3RkX2Nhbm9weQ0KICBsaXR0ZXJfZGF0JHB2YWx1ZV9saXR0ZXJbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMiw0XSxkaWdpdHM9NCkjcHZhbHVlX2Nhbm9weQ0KICBsaXR0ZXJfZGF0JHpfaW50ZXJjZXB0W2ldPC1yb3VuZChzdW1tYXIkY29lZmZpY2llbnRzWzEsM10sZGlnaXRzPTQpI3pfaW50ZXJjZXB0DQogIGxpdHRlcl9kYXQkel9saXR0ZXJbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMiwzXSxkaWdpdHM9NCkjel9jYW5vcHkNCiAgbGl0dGVyX2RhdCRibG9ja19pbnRlcmNlcHRbaV08LXN1bW1hciR2YXJjb3IkYmxvY2tbMSwxXQ0KICANCiAgY29uZmluPC1jb25maW50KG1vb2QsbWV0aG9kPSJXYWxkIikNCiAgcjI8LXIuc3F1YXJlZEdMTU0obW9vZCkNCiAgDQogIGxpdHRlcl9kYXQkQ0lfMi41W2ldPC1jb25maW5bM10jbG93ZXIgY29uZmlkZW5jZSBpbnRlcnZhbA0KICBsaXR0ZXJfZGF0JENJXzk3LjVbaV08LWNvbmZpbls2XSN1cHBlciBjb25maWRlbmNlIGludGVydmFsDQogIGxpdHRlcl9kYXQkcjJfbWFyZ2luYWxbaV08LXIyWzFdI3RoZW9yZXRpY2FsIFIyDQogIGxpdHRlcl9kYXQkcjJfY29uZGl0aW9uYWxbaV08LXIyWzNdI3RoZW9yZXRpY2FsIFIyDQogIA0KICANCiAgDQogICNkYXRhIGZvciBwbG90dGluZw0KICANCiAgbG9vcF9uZXdkYXRhPC1kYXRhLmZyYW1lKDEsIHNlcS5mdW5jMihzcGVjX2RhdGEkc3RkX3NxcnRfbGl0dGVyKSkNCiAgDQogIGxvb3BfcHJlZF9saXR0ZXJbW2ldXTwtbG1lci5wcmVkaWN0KG1vZCA9bW9vZCxuZXdkYXQgPSBsb29wX25ld2RhdGEsIHNlLm11bHQgPSAxLjk2LCBiaW5vbT1ULCBwb2lzc29uID0gRiwgZ2xtbVRNQj1GKQ0KICANCiAgeF9saXR0ZXJfbGlzdFtbaV1dPC1kYXRhLmZyYW1lKHhfZm9yX3Bsb3Q9c2VxLmZ1bmMyKHNwZWNfZGF0YSRzdGRfc3FydF9saXR0ZXIpKQ0KICANCn0NCmBgYA0KDQoNClRhYmxlIHM0IFByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UgZm9yIHRoZSAxOSB3aW50ZXIgYW5udWFsIHNwZWNpZXMgYWxvbmcgYSBncmFkaWVudCBvZiBsaXR0ZXIgY292ZXIgaW4gYSBZb3JrIGd1bSBhbmQgamFtIHdvb2RsYW5kIGluIFdlc3Rlcm4gQXVzdHJhbGlhLiBDSSA9IGNvbmZpZGVuY2UgaW50ZXJ2YWwuIFNpZ25pZmljYW50IGxpdHRlciBlZmZlY3RzIChwPDAuMDUpIGFyZSBpbiBib2xkLg0KYGBge3J9DQpsaXR0ZXJfdGFibGU8LWxpdHRlcl9kYXQlPiVkcGx5cjo6c2VsZWN0KHNwZWNpZXMsaW50ZXJjZXB0LHB2YWx1ZV9pbnRlcmNlcHQsY29lZl9saXR0ZXIscHZhbHVlX2xpdHRlcixDSV8yLjUsQ0lfOTcuNSxibG9ja19pbnRlcmNlcHQsIHIyX21hcmdpbmFsLHIyX2NvbmRpdGlvbmFsKSU+JW11dGF0ZShpbnRlcmNlcHQ9cm91bmQoaW50ZXJjZXB0LDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZV9pbnRlcmNlcHQ9cm91bmQocHZhbHVlX2ludGVyY2VwdCwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmX2xpdHRlcj1yb3VuZChjb2VmX2xpdHRlciwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVfbGl0dGVyPXJvdW5kKHB2YWx1ZV9saXR0ZXIsMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0lfMi41PXJvdW5kKENJXzIuNSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDSV85Ny41PXJvdW5kKENJXzk3LjUsMiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsb2NrX2ludGVyY2VwdD1yb3VuZChibG9ja19pbnRlcmNlcHQsMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcjJfbWFyZ2luYWw9cm91bmQocjJfbWFyZ2luYWwsMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcjJfY29uZGl0aW9uYWw9cm91bmQocjJfY29uZGl0aW9uYWwsMikpDQpEVDo6ZGF0YXRhYmxlKGxpdHRlcl90YWJsZSxoZWlnaHQ9MTAwLG9wdGlvbnM9KGxpc3Qoc2Nyb2xsWD1UUlVFLHNjcm9sbFk9VFJVRSkpKQ0KYGBgDQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQoNClBsb3R0aW5nIG1vZGVscyBmb3IgbGl0dGVyIGNvdmVyDQpgYGB7cn0NCiMjIyNkYXRhIGZyb20gbG9vcCBmb3IgbGl0dGVyIHBsb3QNCg0KbGl0dGVyX2xpc3QgPC0gTWFwKGFzLmRhdGEuZnJhbWUsc3BlY19kYXRsaXR0ZXJfbGlzdCkNCnNwZWNfbGl0dGVyZGF0X3Bsb3Q8LXJiaW5kbGlzdChsaXR0ZXJfbGlzdCkNCg0KbGlzdF9saXR0ZXJfbG9vcDwtTWFwKGFzLmRhdGEuZnJhbWUsbG9vcF9wcmVkX2xpdHRlcikNCnByZWRpY3RfbGl0dGVyX2RhdDwtcmJpbmRsaXN0KGxpc3RfbGl0dGVyX2xvb3ApDQoNCmxpc3RfbGl0dGVyX3g8LU1hcChhcy5kYXRhLmZyYW1lLCB4X2xpdHRlcl9saXN0KQ0KeF9saXR0ZXJfZGF0PC1yYmluZGxpc3QobGlzdF9saXR0ZXJfeCkNCg0KZGF0X2xpdHRlcl9wbG90PC1jYmluZChzcGVjX2xpdHRlcmRhdF9wbG90LHByZWRpY3RfbGl0dGVyX2RhdCx4X2xpdHRlcl9kYXQpJT4lDQogIHNlcGFyYXRlX3dpZGVyX2RlbGltKHNwZWNpZXMsIGRlbGltID0gIi4iLA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyA9IGMoImdlbnVzIiwgInNwZWNpZXMuMSIpDQogICklPiV1bml0ZSgic3BlY2llc19uYW1lcyIsIGdlbnVzLHNwZWNpZXMuMSwgc2VwPSIgIiwgcmVtb3ZlPVQpJT4lDQogIG11dGF0ZShsaW5lX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09IkNodGhvbm9jZXBoYWx1cyBwc2V1ZGV2YXgiLCJncmV5NiIsImdyZXk0OSIpLA0KICAgICAgICAgbGluZV9jb2xvcj1pZl9lbHNlKHNwZWNpZXNfbmFtZXM9PSJIeWFsb3NwZXJtYSBnbHV0aW5vc3VtIiwiZ3JleTYiLGxpbmVfY29sb3IpLA0KICAgICAgICAgbGluZV9jb2xvcj1pZl9lbHNlKHNwZWNpZXNfbmFtZXM9PSJQb2RvbGVwaXMgYXJpc3RhdGEiLCJncmV5NiIsbGluZV9jb2xvciksDQogICAgICAgICBsaW5lX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09IlBvZ29ub2xlcGlzIG11ZWxsZXJpYW5hIiwiZ3JleTYiLGxpbmVfY29sb3IpLA0KICAgICAgICAgbGluZV9jb2xvcj1pZl9lbHNlKHNwZWNpZXNfbmFtZXM9PSJNZWRpY2FnbyBtaW5pbWEiLCJncmV5NiIsbGluZV9jb2xvciksDQogICAgICAgICBsaW5lX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09IlRyYWNoeW1lbmUgb3JuYXRhIiwiZ3JleTYiLGxpbmVfY29sb3IpLA0KICAgICAgICAgDQogICAgICAgICANCiAgICAgICAgIGNpX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09IkNodGhvbm9jZXBoYWx1cyBwc2V1ZGV2YXgiLCJncmV5MjYiLCJncmV5NzQiKSwNCiAgICAgICAgIGNpX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09Ikh5YWxvc3Blcm1hIGdsdXRpbm9zdW0iLCJncmV5MjYiLGNpX2NvbG9yKSwNCiAgICAgICAgIGNpX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09IlBvZG9sZXBpcyBhcmlzdGF0YSIsImdyZXkyNiIsY2lfY29sb3IpLA0KICAgICAgICAgY2lfY29sb3I9aWZfZWxzZShzcGVjaWVzX25hbWVzPT0iUG9nb25vbGVwaXMgbXVlbGxlcmlhbmEiLCJncmV5MjYiLGNpX2NvbG9yKSwNCiAgICAgICAgIGNpX2NvbG9yPWlmX2Vsc2Uoc3BlY2llc19uYW1lcz09Ik1lZGljYWdvIG1pbmltYSIsImdyZXkyNiIsY2lfY29sb3IpLA0KICAgICAgICAgY2lfY29sb3I9aWZfZWxzZShzcGVjaWVzX25hbWVzPT0iVHJhY2h5bWVuZSBvcm5hdGEiLCJncmV5MjYiLGNpX2NvbG9yKSkNCg0KDQojU3VwLiBsaXR0ZXIgcGxvdCMNCg0KDQpsaXR0ZXJfcGxvdDwtZ2dwbG90KGRhdF9saXR0ZXJfcGxvdCwgYWVzKHggPXN0ZF9zcXJ0X2xpdHRlciAsIHkgPSBvY2N1cnJlbmNlKSkgK2ZhY2V0X3dyYXAoLn5zcGVjaWVzX25hbWVzLG5jb2w9NCkrDQogIGdlb21faml0dGVyKHdpZHRoPTAuMiwgaGVpZ2h0PTAuMDUsIHNpemU9NCwgY29sb3I9ZGF0X2xpdHRlcl9wbG90JGxpbmVfY29sb3IpKw0KICBnZW9tX2xpbmUoYWVzKHg9eF9mb3JfcGxvdCwgeT15LCBzaXplPTIpLCBjb2xvcj1kYXRfbGl0dGVyX3Bsb3QkbGluZV9jb2xvcikrDQogIGxhYnMoeD0iTGl0dGVyIGNvdmVyIChzcXVhcmUgcm9vdCB0cmFuc2Zvcm1lZCBhbmQgc3RhbmRhcmRpemVkKSIsIHk9IlByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UiKSsNCiAgDQogIGdlb21fcmliYm9uKGFlcyh4PXhfZm9yX3Bsb3QsIHltaW4gPXBsbywgeW1heCA9cGhpLCBhbHBoYSA9IDAuMDUpLCBmaWxsPWRhdF9saXR0ZXJfcGxvdCRjaV9jb2xvciwgY29sb3I9ZGF0X2xpdHRlcl9wbG90JGNpX2NvbG9yKSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHRoZW1lKHN0cmlwLnRleHQueD0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDYpLCBmYWNlPSJpdGFsaWMiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDUpLGNvbG9yPSJibGFjayIpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemUgPSByZWwoNSksdmp1c3Q9MSksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZSA9IHJlbCg1KSksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDQpKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAxLCBjb2xvdXIgPSAiZ3JleTc0IiwgbGluZXR5cGU9MSksDQogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEuNSwgY29sb3VyID0gImdyZXk3NCIpLA0KICAgICAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoLjMsICJjbSIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCg0KcGRmKGhlcmUoIk91dHB1dHMiLCJGaWd1cmVTMi5wZGYiKSwgd2lkdGggPSA0NSwgaGVpZ2h0ID0gMzUsIHVzZURpbmdiYXRzPUYpDQpsaXR0ZXJfcGxvdA0KZGV2Lm9mZigpDQpgYGANCiFbRmlndXJlUzIgQml2YXJpYXRlIHBsb3RzIGZyb20gR0xNTXMgZm9yIHByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UgaW4gcmVzcG9uc2UgdG8gbGl0dGVyIGNvdmVyLiBTaGFkZWQgYXJlYXMgcmVwcmVzZW50IMKxIDk1JSBjb25maWRlbmNlIGludGVydmFscy4gUG9pbnRzIHdlcmUgaml0dGVyZWQgdG8gc2hvdyBvdmVybGFwcGluZyB2YWx1ZXMgbW9yZSBjbGVhcmx5LiBTaWduaWZpY2FudCByZXN1bHRzIGFyZSBzaG93biBpbiBkYXJrIGdyZXkuXShPdXRwdXRzL0ZpZ3VyZVMyLnBkZil7d2lkdGg9MTAwJSBoZWlnaHQ9NjAwfQ0KDQoNCg0KDQojIyMgUHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSBleHBsYWluZWQgYnkgY2Fub3B5IGNvdmVyDQoNCk1vZGVscyBpbiBhIGxvb3AuIE9uZSBtb2RlbCBwZXIgc3BlY2llcy4NCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGVycm9yPUZBTFNFfQ0Kc3BlY2llc19uYW1lczwtc29ydCh1bmlxdWUob2NjJHNwZWNpZXMpKQ0KDQpjYW5vcHlfZGF0PC1kYXRhLmZyYW1lKHNwZWNpZXM9c3BlY2llc19uYW1lcywNCiAgICAgICAgICAgICAgICAgaW50ZXJjZXB0PXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMpKSwNCiAgICAgICAgICAgICAgICAgc3RkX2ludGVyY2VwdD12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIHpfaW50ZXJjZXB0PXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMpKSwNCiAgICAgICAgICAgICAgICAgcHZhbHVlX2ludGVyY2VwdD12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIGNvZWZfY2Fub3B5PXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMpKSwNCiAgICAgICAgICAgICAgICAgc3RkX2Nhbm9weT12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIHpfY2Fub3B5PXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMpKSwNCiAgICAgICAgICAgICAgICAgcHZhbHVlX2Nhbm9weT12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIENJXzIuNT12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIENJXzk3LjU9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lcykpLA0KICAgICAgICAgICAgICAgICBibG9ja19pbnRlcmNlcHQ9dmVjdG9yKG1vZGU9Im51bWVyaWMiLGxlbmd0aD1sZW5ndGgoc3BlY2llc19uYW1lcykpLA0KICAgICAgICAgICAgICAgICByMl9tYXJnaW5hbD12ZWN0b3IobW9kZT0ibnVtZXJpYyIsbGVuZ3RoPWxlbmd0aChzcGVjaWVzX25hbWVzKSksDQogICAgICAgICAgICAgICAgIHIyX2NvbmRpdGlvbmFsPXZlY3Rvcihtb2RlPSJudW1lcmljIixsZW5ndGg9bGVuZ3RoKHNwZWNpZXNfbmFtZXMpKSkNCg0KDQoNCmxvb3BfcHJlZF9jYW5vcHk8LWxpc3QoKQ0Kc3BlY19tb2QuMTwtbGlzdCgpDQpzcGVjX2RhdGNhbm9weV9saXN0PC1saXN0KCkNCnhfY2Fub3B5X2xpc3Q8LWxpc3QoKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgoc3BlY2llc19uYW1lcykpew0KICBzcGVjX2RhdGE8LXN1YnNldChvY2MsIHNwZWNpZXM9PXNwZWNpZXNfbmFtZXNbaV0pDQogIHNwZWNfZGF0Y2Fub3B5X2xpc3RbW2ldXTwtc3Vic2V0KG9jYywgc3BlY2llcz09c3BlY2llc19uYW1lc1tpXSkNCiAgc3BlY19tb2QuMVtbaV1dPC1nbG1lcihvY2N1cnJlbmNlIH4gc3RkX21lYW5fY2Fub3B5KyAoMXxibG9jayksIGZhbWlseT1iaW5vbWlhbChsaW5rPSJsb2dpdCIpLCBkYXRhID0gc3BlY19kYXRhLGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9J29wdGlteCcsIG9wdEN0cmw9bGlzdChtZXRob2Q9J0wtQkZHUy1CJykpKQ0KICBtb29kPC1nbG1lcihvY2N1cnJlbmNlIH4gc3RkX21lYW5fY2Fub3B5KyAoMXxibG9jayksIGZhbWlseT1iaW5vbWlhbChsaW5rPSJsb2dpdCIpLCBkYXRhID0gc3BlY19kYXRhLGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9J29wdGlteCcsIG9wdEN0cmw9bGlzdChtZXRob2Q9J0wtQkZHUy1CJykpKQ0KICBzdW1tYXI8LXN1bW1hcnkobW9vZCkNCg0KICBjYW5vcHlfZGF0JGludGVyY2VwdFtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1sxLDFdLGRpZ2l0cz00KSNpbnRlcmNlcHQNCiAgY2Fub3B5X2RhdCRzdGRfaW50ZXJjZXB0W2ldPC1yb3VuZChzdW1tYXIkY29lZmZpY2llbnRzWzEsMl0sIGRpZ2l0cz00KSNzdGRfaW50ZXJjZXB0DQogIGNhbm9weV9kYXQkcHZhbHVlX2ludGVyY2VwdFtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1sxLDRdLGRpZ2l0cz00KSNwLXZhbHVlX2ludGVyY2VwdA0KICBjYW5vcHlfZGF0JGNvZWZfY2Fub3B5W2ldPC1yb3VuZChzdW1tYXIkY29lZmZpY2llbnRzWzIsMV0sZGlnaXRzPTQpI2NvZWZfY2Fub3B5DQogIGNhbm9weV9kYXQkc3RkX2Nhbm9weVtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1syLDJdLGRpZ2l0cz00KSNzdGRfY2Fub3B5DQogIGNhbm9weV9kYXQkcHZhbHVlX2Nhbm9weVtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1syLDRdLGRpZ2l0cz00KSNwdmFsdWVfY2Fub3B5DQogIGNhbm9weV9kYXQkel9pbnRlcmNlcHRbaV08LXJvdW5kKHN1bW1hciRjb2VmZmljaWVudHNbMSwzXSxkaWdpdHM9NCkjel9pbnRlcmNlcHQNCiAgY2Fub3B5X2RhdCR6X2Nhbm9weVtpXTwtcm91bmQoc3VtbWFyJGNvZWZmaWNpZW50c1syLDNdLGRpZ2l0cz00KSN6X2Nhbm9weQ0KICBjYW5vcHlfZGF0JGJsb2NrX2ludGVyY2VwdFtpXTwtc3VtbWFyJHZhcmNvciRibG9ja1sxLDFdDQogIA0KICBjb25maW48LWNvbmZpbnQobW9vZCxtZXRob2Q9IldhbGQiKQ0KICByMjwtci5zcXVhcmVkR0xNTShtb29kKQ0KICANCiAgY2Fub3B5X2RhdCRDSV8yLjVbaV08LWNvbmZpblszXSNsb3dlciBjb25maWRlbmNlIGludGVydmFsDQogIGNhbm9weV9kYXQkQ0lfOTcuNVtpXTwtY29uZmluWzZdI3VwcGVyIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgY2Fub3B5X2RhdCRyMl9tYXJnaW5hbFtpXTwtcjJbMV0jdGhlb3JldGljYWwgUjINCiAgY2Fub3B5X2RhdCRyMl9jb25kaXRpb25hbFtpXTwtcjJbM10jdGhlb3JldGljYWwgUjINCiAgDQojcHJlZGljdCBkYXQNCiAgDQogIGxvb3BfbmV3ZGF0YTwtZGF0YS5mcmFtZSgxLCBzZXEuZnVuYzIoc3BlY19kYXRhJHN0ZF9tZWFuX2Nhbm9weSkpDQogIA0KICBsb29wX3ByZWRfY2Fub3B5W1tpXV08LWxtZXIucHJlZGljdChtb2QgPW1vb2QsbmV3ZGF0ID0gbG9vcF9uZXdkYXRhLCBzZS5tdWx0ID0gMS45NiwgYmlub209VCwgcG9pc3NvbiA9IEYsIGdsbW1UTUI9RikNCiAgDQogIHhfY2Fub3B5X2xpc3RbW2ldXTwtZGF0YS5mcmFtZSh4X2Zvcl9wbG90PXNlcS5mdW5jMihzcGVjX2RhdGEkc3RkX21lYW5fY2Fub3B5KSkNCiAgDQogIH0NCg0KYGBgDQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQo8YnI+DQoNCg0KVGFibGUgUzUgUHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSBmb3IgdGhlIDE5IHdpbnRlciBhbm51YWwgc3BlY2llcyBhbG9uZyBhIGdyYWRpZW50IG9mIGNhbm9weSBjb3ZlciBpbiBhIFlvcmsgZ3VtIGFuZCBqYW0gd29vZGxhbmQgaW4gV2VzdGVybiBBdXN0cmFsaWEuIENJID0gY29uZmlkZW5jZSBpbnRlcnZhbC4gIA0KDQpgYGB7cn0NCmNhbm9weV90YWJsZTwtY2Fub3B5X2RhdCU+JWRwbHlyOjpzZWxlY3Qoc3BlY2llcyxpbnRlcmNlcHQscHZhbHVlX2ludGVyY2VwdCxjb2VmX2Nhbm9weSxwdmFsdWVfY2Fub3B5LENJXzIuNSxDSV85Ny41LGJsb2NrX2ludGVyY2VwdCwgcjJfbWFyZ2luYWwscjJfY29uZGl0aW9uYWwpJT4lbXV0YXRlKGludGVyY2VwdD1yb3VuZChpbnRlcmNlcHQsMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlX2ludGVyY2VwdD1yb3VuZChwdmFsdWVfaW50ZXJjZXB0LDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZfY2Fub3B5PXJvdW5kKGNvZWZfY2Fub3B5LDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZV9jYW5vcHk9cm91bmQocHZhbHVlX2Nhbm9weSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDSV8yLjU9cm91bmQoQ0lfMi41LDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENJXzk3LjU9cm91bmQoQ0lfOTcuNSwyKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmxvY2tfaW50ZXJjZXB0PXJvdW5kKGJsb2NrX2ludGVyY2VwdCwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByMl9tYXJnaW5hbD1yb3VuZChyMl9tYXJnaW5hbCwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByMl9jb25kaXRpb25hbD1yb3VuZChyMl9jb25kaXRpb25hbCwyKSkNCkRUOjpkYXRhdGFibGUoY2Fub3B5X3RhYmxlLGhlaWdodD0xMDAsb3B0aW9ucz0obGlzdChzY3JvbGxYPVRSVUUsc2Nyb2xsWT1UUlVFKSkpDQpgYGANCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NCjxicj4NClBsb3QgbW9kZWxzIGZvciBjYW5vcHkgY292ZXIgDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjZGF0YSBmcm9tIGxvb3AgZm9yIGNhbm9weSBwbG90DQpjYW5vcHlfbGlzdCA8LSBNYXAoYXMuZGF0YS5mcmFtZSxzcGVjX2RhdGNhbm9weV9saXN0KQ0Kc3BlY19jYW5vcHlkYXRfcGxvdDwtcmJpbmRsaXN0KGNhbm9weV9saXN0KQ0KDQpsaXN0X2Nhbm9weV9sb29wPC1NYXAoYXMuZGF0YS5mcmFtZSxsb29wX3ByZWRfY2Fub3B5KQ0KcHJlZGljdF9jYW5vcHlfZGF0PC1yYmluZGxpc3QobGlzdF9jYW5vcHlfbG9vcCkNCg0KbGlzdF9jYW5vcHlfeDwtTWFwKGFzLmRhdGEuZnJhbWUsIHhfY2Fub3B5X2xpc3QpDQp4X2Nhbm9weV9kYXQ8LXJiaW5kbGlzdChsaXN0X2Nhbm9weV94KQ0KDQpkYXRfY2Fub3B5X3Bsb3Q8LWNiaW5kKHNwZWNfY2Fub3B5ZGF0X3Bsb3QscHJlZGljdF9jYW5vcHlfZGF0LHhfY2Fub3B5X2RhdCklPiUNCiAgc2VwYXJhdGVfd2lkZXJfZGVsaW0oc3BlY2llcywgZGVsaW0gPSAiLiIsDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWVzID0gYygiZ2VudXMiLCAic3BlY2llcy4xIikNCiAgKSU+JXVuaXRlKCJzcGVjaWVzX25hbWVzIiwgZ2VudXMsc3BlY2llcy4xLCBzZXA9IiAiLCByZW1vdmU9VCkNCg0KDQpjYW5vcHlfcGxvdDwtZ2dwbG90KGRhdF9jYW5vcHlfcGxvdCwgYWVzKHggPXN0ZF9tZWFuX2Nhbm9weSAsIHkgPSBvY2N1cnJlbmNlKSkgK2ZhY2V0X3dyYXAoLn5zcGVjaWVzX25hbWVzLG5jb2w9NCkrDQogIGdlb21faml0dGVyKHdpZHRoPTAuMiwgaGVpZ2h0PTAuMDUsIHNpemU9NCwgY29sb3I9ImdyZXk0OSIpKw0KICBnZW9tX2xpbmUoYWVzKHg9eF9mb3JfcGxvdCwgeT15LCBzaXplPTIpLCBjb2xvcj0iZ3JleTQ5IikrDQogICBsYWJzKHg9Ik1lYW4gY2Fub3B5IGNvdmVyIChzdGFuZGFyZGl6ZWQpIiwgeT0iUHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSIpKw0KICANCiAgZ2VvbV9yaWJib24oYWVzKHg9eF9mb3JfcGxvdCwgeW1pbiA9cGxvLCB5bWF4ID1waGksIGFscGhhID0gMC4wNSksIGZpbGw9ImdyZXk3NCIsIGNvbG9yPSJncmV5NzQiKSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHRoZW1lKHN0cmlwLnRleHQueD0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDYpLCBmYWNlPSJpdGFsaWMiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDUpLGNvbG9yPSJibGFjayIpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemUgPSByZWwoNSksdmp1c3Q9MSksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZSA9IHJlbCg1KSksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDQpKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAxLCBjb2xvdXIgPSAiZ3JleTc0IiwgbGluZXR5cGU9MSksDQogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEuNSwgY29sb3VyID0gImdyZXk3NCIpLA0KICAgICAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoLjMsICJjbSIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCg0KcGRmKGhlcmUoIk91dHB1dHMiLCJGaWd1cmVTMy5wZGYiKSwgd2lkdGggPSA0NSwgaGVpZ2h0ID0gMzUsIHVzZURpbmdiYXRzPUYpDQpjYW5vcHlfcGxvdA0KZGV2Lm9mZigpDQpgYGANCiFbRmlndXJlUzMgQml2YXJpYXRlIHBsb3RzIGZyb20gR0xNTXMgZm9yIHByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UgaW4gcmVzcG9uc2UgdG8gbWVhbiBjYW5vcHkgY292ZXIuIFNoYWRlZCBhcmVhcyByZXByZXNlbnQgwrEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBQb2ludHMgd2VyZSBqaXR0ZXJlZCB0byBzaG93IG92ZXJsYXBwaW5nIHZhbHVlcyBtb3JlIGNsZWFybHkuIFRoZXJlIHdlcmUgbm8gc2lnbmlmaWNhbnQgZWZmZWN0cy5dKE91dHB1dHMvRmlndXJlUzMucGRmKXt3aWR0aD0xMDAlIGhlaWdodD02MDB9DQoNCg0KDQojIFNlZWQgbWFzcyBzdXBwbGVtZW50YXJ5IGFuYWx5c2VzDQoNClJlYWQgc2VlZCBtYXNzIGRhdGENCg0KYGBge3J9DQpzZWVkX21hc3M8LXJlYWRfY3N2KGhlcmUoImRhdGEiLCJzZWVkX21hc3MuY3N2IikpJT4lbXV0YXRlKHN0ZF9sb2dfbWVhbl9zbT1zY2FsZShsb2cobWVhbl9TTSkpWywxXSkNCmBgYA0KDQpDYW4gc2VlZCBtYXNzIGV4cGxhaW4gc3BlY2llcycgZ2VybWluYXRpb24gaW4gcmVzcG9uc2UgdG8gbGlnaHQ/DQoNCg0KYGBge3J9DQpjdWVfZGF0Mjwtb2NjX3N1ZmZpY2llbnRfZ2VybSU+JWxlZnRfam9pbihzZWVkX21hc3MsIGJ5PSJzcGVjaWVzIikNCg0KbGlnaHRzbV9kYXQ8LWN1ZV9kYXQyJT4lc2VsZWN0KHNwZWNpZXMsbWF4X2xpZ2h0X2VmZmVjdCxzdGRfbG9nX21lYW5fc20pJT4lZGlzdGluY3QoKQ0KDQpsaWdodHNtX21vZDwtbG0obWF4X2xpZ2h0X2VmZmVjdH5zdGRfbG9nX21lYW5fc20sZGF0YT1saWdodHNtX2RhdCkNCg0Kc3VtbWFyeShsaWdodHNtX21vZCkNCmBgYA0KDQoNCk1vZGVsIEFzc3VtcHRpb25zDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0Kc2ltdWxhdGlvbk91dHB1dDUgPC0gc2ltdWxhdGVSZXNpZHVhbHMoZml0dGVkTW9kZWwgPSBsaWdodHNtX21vZCwgcGxvdCA9IEYpDQoNCnBsb3Qoc2ltdWxhdGlvbk91dHB1dDUpIA0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KcGRmKGhlcmUoIk91dHB1dHMiLCJGaWd1cmVfUzQucGRmIiksIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsIHVzZURpbmdiYXRzPUYpDQoNCnBhcihtYXIgPSBjKDgsIDcsIDUsIDIpLA0KICAgIGJ0eT0ibCIpDQpNZ3AodGl0bGU9IDQsDQogICAgICBsYWJlbHMgPSAyKQ0Kd2l0aChsaWdodHNtX2RhdCwgcGxvdChtYXhfbGlnaHRfZWZmZWN0IH4gc3RkX2xvZ19tZWFuX3NtLCBjZXg9MiwNCiAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJSZWxhdGl2ZSBnZXJtaW5hdGlvbiByZXNwb25zZSB0byBsaWdodCIsIHhsYWIgPSAibG9nIFNlZWQgbWFzcyAoU3RhbmRhcmRpc2VkKSIsDQogICAgICAgICAgICAgICAgICAgIGNleC5heGlzPTIuNSwgY2V4LmxhYj0yLjUsIHBjaD0xNikseWxpbT1jKC0yLDEpKQ0KDQpuZXcuZGF0PC1kYXRhLmZyYW1lKGludGVyY2VwdD0xLHN0ZF9sb2dfbWVhbl9zbT1zZXEuZnVuYyhsaWdodHNtX2RhdCRzdGRfbG9nX21lYW5fc20pKQ0KDQpwdmFyMTwtZGlhZyhhcy5tYXRyaXgobmV3LmRhdCkgJSolIHRjcm9zc3Byb2QodmNvdihsaWdodHNtX21vZCksIGFzLm1hdHJpeChuZXcuZGF0KSkpDQoNCnk8LSBhcy5tYXRyaXgobmV3LmRhdCkgJSolIGNvZWYobGlnaHRzbV9tb2QpDQoNCnByZWRpY3RlZC5kYXRhPC1kYXRhLmZyYW1lKG5ldy5kYXQsIHBsbyA9IHktKDEuOTYqc3FydChwdmFyMSkpLCBwaGkgPSB5KygxLjk2KnNxcnQocHZhcjEpKSkNCg0KcGxvdC5DSS5mdW5jKHguZm9yLnBsb3Q9c2VxLmZ1bmMobGlnaHRzbV9kYXQkc3RkX2xvZ19tZWFuX3NtKSwNCiAgICAgICAgICAgICB5LCBwcmVkaWN0ZWQuZGF0YSRwaGkscHJlZGljdGVkLmRhdGEkcGxvLCBlbnYuY29sb3VyPSJncmF5MzAiLCBlbnYudHJhbnM9NDAsIGxpbmUuY29sb3VyPSJncmF5MzAiLCBsaW5lLnR5cGU9MSwgbGluZS53ZWlnaHQ9MykNCg0KDQpkZXYub2ZmKCkNCg0KYGBgDQoNCiFbRmlndXJlUzQgU3BlY2llc+KAmSBnZXJtaW5hdGlvbiByZXNwb25zZXMgdG8gbGlnaHQgdmVyc3VzIGxuKHNlZWQgbWFzcykgZm9yIDE1IGFubnVhbCBzcGVjaWVzIHdpdGggc3VmZmljaWVudCBnZXJtaW5hdGlvbiB0byBjYWxjdWxhdGUgZ2VybWluYXRpb24gcmVzcG9uc2VzLiBUaGUgbGluZSBpcyBmcm9tIGEgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIGFuZCB0aGUgc2hhZGVkIGVudmVsb3BlIHJlcHJlc2VudHMgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBSZWZlciB0byBUYWJsZSBTNyBmb3IgdGhlIG1vZGVsIHN1bW1hcnkgdGFibGUuXShPdXRwdXRzL0ZpZ3VyZV9TNC5wZGYpe3dpZHRoPTEwMCUgaGVpZ2h0PTYwMH0NCg0KDQoNCg==