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)

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==