#Library loading

#library loading---------------------------------------------------
library(lme4)
library(ggplot2)
library(xlsx)
library(parallel)
library(sjmisc)
library(sjlabelled)
library(dplyr)
library(doParallel)
library(sjPlot)
#library(MuMIn)
library(boot)
library(table1)
library(partR2)
library(buildmer)
library(rptR)
library(furrr)
library(future)
library(glmmTMB)

#Options

CapNoLowFlow = FALSE
ExcludeDrWithFewOHCA = FALSE
ExcludeSex = FALSE

CategorizeVar = TRUE
quadratic = FALSE

computeRptR = FALSE
bootstrapSigma = FALSE

numberOfResidualSimulations = 10 #dharma
nBootPartR2 = 10 #nboot rptr and partR2
nBootPartR2Compare = 10
nbBootPrimary = 10

#Data importation & cleaning

Correction of doctor names and anonymisation has been done before the importation process

data <- read.xlsx("C:/Users/thoma/Desktop/reaclast.xlsx", 1)
nb <- nrow(data)

Delete corrupted/incomplete data

data <- filter(data, rythm >= 0)
print("Removing corrupt or unknown data about rythm")
print(nrow(data))
print(nb - nrow(data))
nb <- nrow(data)

data <- filter(data, sexe < 3)
print("Removing corrupt or unknown data about sex")
print(nrow(data))
print(nb - nrow(data))
nb <- nrow(data)

data <- filter(data, lowflow >= 0)
print("Removing corrupt or unknown data about low-flow")
print(nrow(data))
print(nb - nrow(data))
nb <- nrow(data)

data <- filter(data, noflow >= 0)
print("Removing corrupt or unknown data about no-flow")
print(nrow(data))
print(nb - nrow(data))
nb <- nrow(data)

Remove traumatic arrests

data <- filter(data, medical > 0)
print("Removing traumatic arrests")
print(nrow(data))
print(nb - nrow(data))
nb <- nrow(data)

Options : Remove arrest linked to Dr with to few arrest (not in primary analysis but used in appendix)

if(ExcludeDrWithFewOHCA) {
  data <- data %>% group_by(dr) %>% filter(n() >= 40)
  
  data <- data %>% ungroup
  
  print("Removing arrests linked with Dr with less than 3 arrests")
  print(nrow(data))
  print(nb - nrow(data))
  nb <- nrow(data)
}

#Data preprocessing

Creation of binary score for the presence or absence for each observed medical history

data <- data %>% mutate("ATCD.Cardiovasculaire" = replace(ATCD.Cardiovasculaire, ATCD.Cardiovasculaire == -1, 0))
data <- data %>% mutate("ATCD.Respiratoire" = replace(ATCD.Respiratoire, ATCD.Respiratoire == -1, 0))
data <- data %>% mutate("ATCD.Diabete" = replace(ATCD.Diabete, ATCD.Diabete == -1, 0))
data <- data %>% mutate("ATCD.EOL" = replace(ATCD.EOL, ATCD.EOL == -1, 0))
data <- data %>% mutate("ATCD.Other" = replace(ATCD.Other, ATCD.Other == -1, 0))

Adjust sex to binary value

#Transforming men = 1 et women = 2 in men = 0 et women = 1
data <- data %>% mutate("sexe" = data$sexe-1)

Regroup asystole and pulseless electrical activity (two group remaining Asystole/PEA and other rythms)

data <- data %>% mutate("Asystolie/RSP" = replace(chocable, chocable == 3, 1))
data <- data %>% mutate("Asystolie/RSP" = data$`Asystolie/RSP`-1)

Calculate low-flow BEFORE SAMU-MICU arrival

#Creation of smurdelay useful for calculation just below
data <- data %>% mutate(delaysmur = difftime(data$smurHour, data$acHour, units ="mins"))
data <- data %>% mutate(delaysmur = ifelse(data$delaysmur > 720, difftime((as.Date(data$acHour)+1), data$smurHour, units ="mins"), data$delaysmur))
data <- data %>% mutate(delaysmur = ifelse(data$delaysmur < -720, difftime((as.Date(data$smurHour)+1), data$acHour, units ="mins"), data$delaysmur))

#Creation of lowflow before SMUR arrival
data <- data %>% mutate(low.flow = ifelse(pmin(data$delaysmur-data$noflow, data$lowflow) > 0, pmin(data$delaysmur-data$noflow, data$lowflow), data$lowflow))

Calculate the existence of a ROSC before SAMU-MICU arrival

data <- data %>% mutate(racs = ifelse((data$racsdelay < data$delaysmur) & (data$racsdelay != -1), 1, 0))

Creation of TOR column (termination of resuscitation)

data <- data %>% mutate(TOR = ifelse(!(data$reasmur == 1 | data$transport == 1), 1, 0))

Creation of data labels

label(data$age)   <- "Age"
label(data$sexe)   <- "Sex"
label(data$noflow)   <- "No-flow"
label(data$witness)   <- "Witness"
label(data$dr)   <- "Doctor"
label(data$low.flow)   <- "Low-flow"
label(data$racs)   <- "ROSC before SMUR"
label(data$TOR)   <- "Termination of ressusitation"
label(data$`ATCD.Cardiovasculaire`)   <- "Cardiac history"
label(data$`ATCD.Respiratoire`)   <- "Respiratory history"
label(data$`ATCD.EOL`)   <- "End of life / dependency"
label(data$`ATCD.Diabete`)   <- "Diabetes"
label(data$`ATCD.Other`)   <- "Other medical issue including oncologic"
label(data$`Asystolie/RSP`)   <- "Rythm"

print(paste0("Included cardiac arrests : ", nrow(data)))

Graph of continuous variables

hist(data$age, breaks = 50)
dataCapped <- data
dataCapped <- dataCapped %>% mutate("noflow" = replace(noflow, noflow >= 100, 100))
dataCapped <- dataCapped %>% mutate("low.flow" = replace(low.flow, low.flow >= 100, 100))
hist(dataCapped$noflow, breaks = 100)
hist(dataCapped$low.flow, breaks = 100)

Option : Capping low flow and no-flow

if(CapNoLowFlow) {
  dataCapped <- data
  dataCapped <- dataCapped %>% mutate("noflow" = replace(noflow, noflow >= 100, 100))
  dataCapped <- dataCapped %>% mutate("low.flow" = replace(low.flow, low.flow >= 100, 100))
  data <- dataCapped
}

Option : Categorize variables

dataSv <- data
if(CategorizeVar) {
  datacat <- data
  datacat$age <- cut(data$age, 
                   breaks=c(-Inf, 65, 75, 85, Inf), 
                   labels=c("< 65 years","65-75 years","75-85 years", "85 years and beyond"))
  datacat$noflow <- cut(data$noflow, 
                   breaks=c(-Inf, 1, 5, 10, 20, Inf), 
                   labels=c("< 1 minute", "1 to 5 minutes", "5 to 10 minutes","10 to 20 minutes", "20 minutes and beyond"))
  datacat$low.flow <- cut(data$low.flow, 
                   breaks=c(-Inf, 10, 20, 40, Inf), 
                   labels=c("< 10 minutes","10 to 20 minutes","20 to 40 minutes", "40 minutes and beyond"))
  data <- datacat
}

#Table1 : charasteristics of population Creation of table1 : Characteristics of population

if(CategorizeVar) {
  datacat <- dataSv
  datacat$age <- cut(dataSv$age, 
                   breaks=c(-Inf, 65, 75, 85, Inf), 
                   labels=c("Age ≤ 65","Age in [66, 75]","Age in [76, 85]", "Age > 85"))
  datacat$noflow <- cut(dataSv$noflow, 
                   breaks=c(-Inf, 1, 5, 10, 20, Inf), 
                   labels=c("No-flow ≤ 1", "No-flow in [2, 5]", "No-flow in [6, 10]","No-flow in [11, 20]", "No-flow > 20"))
  datacat$low.flow <- cut(dataSv$low.flow, 
                   breaks=c(-Inf, 10, 20, 40, Inf), 
                   labels=c("Low-flow ≤ 10","Low-flow in [11, 20]","Low-flow in [21, 40]", "Low-flow > 40"))
  dataT <- datacat
} else {
  dataT <- data
}

library(table1)
#dataT is a copy of data used for table display


render <- function(x, name, missing) {
  if (!is.numeric(x)) return(render.cat(x))
  else if (name == "age") {
    what <- switch(name,
        age = "Mean (SD)")
    parse.abbrev.render.code(c("", what))(x)
    
    # what <- switch(name,
    #     age = "Mean (SD)",
    #     low.flow  = "Median (IQR)",
    #     noflow  = "Median (IQR)")
    # parse.abbrev.render.code(c("", what))(x)
  } else {
    with(stats.apply.rounding(stats.default(x), digits=2), c("",
          "Median (IQR)"=sprintf("%s [%s-%s]", MEDIAN, Q1, Q3)))
  }
}


render.cat <- function(x) {
    c("", sapply(stats.default(x), function(y) with(y,
        sprintf("%d (%0.0f %%)", FREQ, PCT))))
}
  
dataT$TOR <- 
  factor(dataT$TOR, 
         levels=c(0,1),
         labels=c("Advanced life support", # Reference
                  "Termination of resuscitation"))



dataT$sexe <- 
  factor(dataT$sexe, levels=c(1,0),
         labels=c("Men", 
                  "Women"))

units(dataT$age) <- "Years"
units(dataT$noflow) <- "Minutes"
units(dataT$low.flow) <- "Minutes"

dataT$`Asystolie/RSP` <- 
  factor(dataT$`Asystolie/RSP`, levels=c(1,0),
         labels=c("Asystole/PEA", 
                  "VF/VT/SA"))

dataT$witness <- 
  factor(dataT$witness, levels=c(1),
         labels=c("Present"))

dataT$racs <- 
  factor(dataT$racs, levels=c(1),
         labels=c("Present"))

dataT$`ATCD.Cardiovasculaire` <- 
  factor(dataT$`ATCD.Cardiovasculaire`, levels=c(1),
         labels=c("Present"))

dataT$`ATCD.EOL` <- 
  factor(dataT$`ATCD.EOL`, levels=c(1),
         labels=c("Present"))

dataT$`ATCD.Respiratoire` <- 
  factor(dataT$`ATCD.Respiratoire`, levels=c(1),
         labels=c("Present"))

dataT$`ATCD.Diabete` <- 
  factor(dataT$`ATCD.Diabete`, levels=c(1),
         labels=c("Present"))

dataT$`ATCD.Other` <- 
  factor(dataT$`ATCD.Other`, levels=c(1),
         labels=c("Present"))

label(dataT$age)   <- "Age"
label(dataT$sexe)   <- "Sex"
label(dataT$noflow)   <- "No-flow"
label(dataT$`witness`)   <- "Witness"
label(dataT$dr)   <- "Doctor"
label(dataT$low.flow)   <- "Low-flow"
label(dataT$racs)   <- "ROSC before SAMU-MICU arrival"
label(dataT$TOR)   <- "Termination of resuscitation"
label(dataT$`ATCD.Cardiovasculaire`)   <- "Cardiac history"
label(dataT$`ATCD.Respiratoire`)   <- "Respiratory history"
label(dataT$`ATCD.EOL`)   <- "End of life / dependancy"
label(dataT$`ATCD.Diabete`)   <- "Diabetes history"
label(dataT$`ATCD.Other`)   <- "Other medical issue including oncologic history"
label(dataT$`Asystolie/RSP`)   <- "Rhythm"

table <- table1( ~ age + sexe + noflow + low.flow + `Asystolie/RSP` + witness + racs + `ATCD.Cardiovasculaire` + `ATCD.Respiratoire` + `ATCD.EOL` + `ATCD.Diabete` + `ATCD.Other` | TOR, data=dataT,  topclass="Rtable1-zebra", overall="Total", render=render)

#Mean and median of OHCA by doctor

median(aggregate(data$age, by=list(data$dr), FUN=length)$x)
mean(aggregate(data$age, by=list(data$dr), FUN=length)$x)

t.test(aggregate(data$age, by=list(data$dr), FUN=length)$x)
quantile(aggregate(data$age, by=list(data$dr), FUN=length)$x)

#Creating formulae

formula = `TOR` ~ `racs` + `noflow` + `Asystolie/RSP` + `low.flow` + `sexe` + `witness` + `age` + `ATCD.Cardiovasculaire` + `ATCD.Diabete`+ `ATCD.EOL` + `ATCD.Respiratoire` + `ATCD.Other` + (1|`dr`)

if(quadratic) {
  formulaNonLinear = `TOR` ~ `racs` + `noflow` + I(`noflow`^2) + `Asystolie/RSP` + `low.flow` + I(`low.flow`^2) + `sexe` + `witness` + `age` + I(`age`^2) + `ATCD.Cardiovasculaire` + `ATCD.Diabete`+ `ATCD.EOL` + `ATCD.Respiratoire` + `ATCD.Other` + (1|`dr`)
}

formulaGLM = `TOR` ~ `racs` + `noflow` + `Asystolie/RSP` + `low.flow` + `sexe` + `witness` + `age` + `ATCD.Cardiovasculaire` + `ATCD.Diabete`+ `ATCD.EOL` + `ATCD.Respiratoire` + `ATCD.Other`

if(ExcludeSex) {
  formula = remove.terms(formula, "sexe")
  formulaGLM = remove.terms(formulaGLM, "sexe")
  if(quadratic) {
    formulaNonLinear = remove.terms(formulaNonLinear, "sexe")
  }
}

#Implementation of GLMM and GLM models (FitGLMM and ReducedGLM)

FitGLMM : - Binomial family since outcome is binary - Dr effect (random effect) implemented without random slope, only intersect.

library(lme4)
label(data$TOR)   <- "TOR"
FitGLMM <- glmer(formula, family=binomial, data=data)

if(quadratic)
  FitGLMMnonLinear <- glmer(formulaNonLinear, family=binomial, data=data)

ReducedGLM - Same as fit GLMM without Dr effect (no random effect)

label(data$TOR)   <- "TOR (without random effect)"
ReducedGLM <- glm(formulaGLM, family=binomial, data=data)
label(data$TOR)   <- "TOR"

#Fitting concurrent models

We fit concurrent GLMM models with some predictors missing to assess the impact.

label(data$TOR)   <- "TOR (without medical history / end of life)"
formulaWithoutHistoryEOL = remove.terms(formula, "`ATCD.Cardiovasculaire` + `ATCD.Diabete`+ `ATCD.EOL`+ `ATCD.Respiratoire` + `ATCD.Other`")
glmmWithoutHistoryEOL <- glmer(formulaWithoutHistoryEOL, family=binomial, data=data)
label(data$TOR)   <- "TOR (without medical history)"
formulaWithoutHistory = remove.terms(formula, "ATCD.EOL")
glmmWithoutHistory <- glmer(formulaWithoutHistory, family=binomial, data=data)
label(data$TOR)   <- "TOR (without no-flow)"
formulaWithoutNF = remove.terms(formula, "noflow")
glmmWithoutNF <- glmer(formulaWithoutNF, family=binomial, data=data)
label(data$TOR)   <- "TOR (without low-flow)"
formulaWithoutLF = remove.terms(formula, "low.flow")
glmmWithoutLF <- glmer(formulaWithoutLF, family=binomial, data=data)
label(data$TOR)   <- "TOR (without rythm and ROSC)"
formulaWithoutRythm = remove.terms(formula, "`racs` + `Asystolie/RSP`")
glmmWithoutRythm <- glmer(formulaWithoutRythm, family=binomial, data=data)
label(data$TOR)   <- "TOR (without sex)"
formulaWithoutSex = remove.terms(formula, "sexe")
glmmWithoutSex <- glmer(formulaWithoutSex, family=binomial, data=data)
label(data$TOR)   <- "TOR (without age)"
formulaWithoutAge = remove.terms(formula, "age")
glmmWithoutAge <- glmer(formulaWithoutAge, family=binomial, data=data)
label(data$TOR)   <- "TOR (without witness)"
formulaWithoutWitness = remove.terms(formula, "witness")
glmmWithoutWitness <- glmer(formulaWithoutWitness, family=binomial, data=data)

#Checking GLMM model asumptions

s <- summary(FitGLMM, correlation = TRUE)
s
summary(ReducedGLM, correlation = TRUE)
confint(FitGLMM, method = "Wald")

Using Dharma which create visualy interpretable residuals by simulating many response and and using the cumulative density for the observed data point to create residuals (more information in package vignette). (Refit = T pour un bootstrap paramétrique)

From this graph, we check : normality of residus, hemegeneity of residus for the whole package and also for each individual predictors

library(DHARMa)
#simFit <- simulateResiduals(fittedModel = FitGLMM, n = numberOfResidualSimulations, refit = T)
simFit <- simulateResiduals(fittedModel = FitGLMM, n = numberOfResidualSimulations)
plot(simFit)

simReduced <- simulateResiduals(fittedModel = ReducedGLM, n = numberOfResidualSimulations)
plot(simReduced)

plotResiduals(simulationOutput = FitGLMM, form=data$low.flow)
plotResiduals(simulationOutput = FitGLMM, form=data$noflow)
plotResiduals(simulationOutput = FitGLMM, form=data$racs)
plotResiduals(simulationOutput = FitGLMM, form=data$`Asystolie/RSP`)
plotResiduals(simulationOutput = FitGLMM, form=data$`sexe`)
plotResiduals(simulationOutput = FitGLMM, form=data$`witness`)
plotResiduals(simulationOutput = FitGLMM, form=data$`age`)
plotResiduals(simulationOutput = FitGLMM, form=data$`ATCD.Cardiovasculaire`)
plotResiduals(simulationOutput = FitGLMM, form=data$`ATCD.Diabete`)
plotResiduals(simulationOutput = FitGLMM, form=data$`ATCD.EOL`)
plotResiduals(simulationOutput = FitGLMM, form=data$`ATCD.Respiratoire`)
plotResiduals(simulationOutput = FitGLMM)
plotResiduals(simulationOutput = ReducedGLM)
#Quantile normalization of scaled residuals to visualize them in a 
residualsNorm <- residuals(simFit, quantileFunction = qnorm, outlierValues = c(0,1))

h <- hist(residualsNorm, breaks = 40, density = 10,
          col = "black", xlab = "Scaled residues (after quantile normalisation)", ylab = "Number of observation", main = "Distribution of residues") 
xfit <- seq(min(residualsNorm), max(residualsNorm), length = 40) 
yfit <- dnorm(xfit, mean = mean(residualsNorm), sd = sd(residualsNorm)) 
yfit <- yfit * diff(h$mids[1:2]) * length(residualsNorm) 

lines(xfit, yfit, col = "red", lwd = 2)
plot(h)
plot_model(FitGLMM, type="diag", sort.est=TRUE,
           vline.color="#A9A9A9", dot.size=1.5,
           show.values=T, value.offset=.2)
save_plot("qqplot.jpg", dpi = 500, width = 20, height = 15)

Here we look at the variance-covariance table which informs us on linear correlations

print(s, correlation = TRUE)
summary(ReducedGLM, correlation = TRUE)
if(computeRptR) {
  rptRadjust100 <- rptR::rpt(formula, "dr", data = data, datatype = "Binary", nboot = nBootPartR2, npermut = nBootPartR2, parallel = TRUE, ncores = 6, adjusted = FALSE)
  rptRadjust100
  
  sprintf("Part of explained variance of Dr effect for full model : %s %%", trunc(rptRadjust100[["R"]][["dr"]][2]*10^4)/10^2)
}
if(computeRptR) {
  rptRadjustWithoutLF <- rptR::rpt(formulaWithoutLF, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without low flow) : %s %%", trunc(rptRadjustWithoutLF[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutNF <- rptR::rpt(formulaWithoutNF, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without no flow) : %s %%", trunc(rptRadjustWithoutNF[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutHistoryEOL <- rptR::rpt(formulaWithoutHistoryEOL, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without history) : %s %%", trunc(rptRadjustWithoutHistoryEOL[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutEOL <- rptR::rpt(formulaWithoutHistory, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without end of life) : %s %%", trunc(rptRadjustWithoutEOL[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutRythm <- rptR::rpt(formulaWithoutRythm, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without rythm) : %s %%", trunc(rptRadjustWithoutRythm[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutSex <- rptR::rpt(formulaWithoutSex, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without sex) : %s %%", trunc(rptRadjustWithoutSex[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutAge <- rptR::rpt(formulaWithoutAge, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without age) : %s %%", trunc(rptRadjustWithoutAge[["R"]][["dr"]][2]*10^4)/10^2)
  
  rptRadjustWithoutWitness <- rptR::rpt(formulaWithoutWitness, "dr", data = data, datatype = "Binary", nboot = nBootPartR2Compare, npermut = nBootPartR2Compare, parallel = TRUE, ncores = 6, adjusted = FALSE)
  sprintf("Part of explained variance of Dr effect (without witness) : %s %%", trunc(rptRadjustWithoutWitness[["R"]][["dr"]][2]*10^4)/10^2)
}

#Checking FitGLMM model performance

Comparing all models via AIC, pseudo-R2 to check for : - random effect independance to fixed effects choice - Pertinence of chosen fixed variables

anova(FitGLMM, glmmWithoutHistoryEOL, glmmWithoutHistory, glmmWithoutNF, glmmWithoutLF, glmmWithoutRythm, glmmWithoutSex, glmmWithoutAge, glmmWithoutWitness, ReducedGLM)

if(computeRptR) {
  R2cFull <- partR2(FitGLMM, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (full) : %s %%", trunc(R2cFull[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutLF <- partR2(glmmWithoutLF, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without low flow) : %s %%", trunc(R2cWithoutLF[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutNF <- partR2(glmmWithoutNF, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without no flow) : %s %%", trunc(R2cWithoutNF[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutEOL <- partR2(glmmWithoutHistory, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without end of life) : %s %%", trunc(R2cWithoutEOL[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutHistoryEOL <- partR2(glmmWithoutHistoryEOL, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without history and end of life) : %s %%", trunc(R2cWithoutHistoryEOL[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutRythm <- partR2(glmmWithoutRythm, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without rythm) : %s %%", trunc(R2cWithoutRythm[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutSex <- partR2(glmmWithoutSex, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without sex) : %s %%", trunc(R2cWithoutSex[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutAge <- partR2(glmmWithoutAge, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without age) : %s %%", trunc(R2cWithoutAge[["R2"]][["estimate"]][1]*10^4)/10^2)
  
  R2cWithoutWitness <- partR2(glmmWithoutWitness, R2_type = "conditional", max_level = 1, nboot = NULL, CI = 0.95, parallel = TRUE, data=data)
  sprintf("Part of explained variance of model (without witness) : %s %%", trunc(R2cWithoutWitness[["R2"]][["estimate"]][1]*10^4)/10^2)
}

compareTab = tab_model(FitGLMM, glmmWithoutHistoryEOL, glmmWithoutHistory, glmmWithoutNF, glmmWithoutLF, glmmWithoutRythm, glmmWithoutSex, glmmWithoutAge, glmmWithoutWitness, ReducedGLM, p.style = "stars", pred.labels = c("Intercept","ROSC","No-flow", "Asystole/PEA", "Low-flow", "Sex", "Witness", "Age", "Cardiac history", "Diabetes", "End of life / dependancy", "Respiratory history", "Other medical issue including oncologic history"))

#RESULTS #Primary endpoint

#Evaluating the significance of doctor effect through comparison of ReducedGLM and FitGLMM through wilk’s test (Maximum likelihood ratio test)

anova(FitGLMM,ReducedGLM, test="LRT")

#Computing sd of random effect and it’s p-value with parametric bootstrap

Computing primary objective and it’s confidence interval. Parametric bootstrap between FitGLMM et ReducedGLM.

if(bootstrapSigma){
  library(doParallel)
  # Bootstrap iterations
  nsamples <- nbBootPrimary
  
  # Multithreading
  ncores=6
  cl = makeCluster(ncores)
  registerDoParallel(cl)
  
  # Vector of random effect variance of FitGLMM on data simulated through ReducedGLM
  estimated_var<- c() 
  
  # Bootstrap loop
  estimated_var = foreach(i=1:nsamples) %dopar% { 
    library(lme4)
    
    # Creation of simulated data from experimental data by replacing
    sim_data <- data[sample(1:nrow(data), nrow(data), replace=TRUE), ]
    
    # Simulation of response (TOR) for simulated data using ReducedGLM and adding a noise similar to the one found in experimental data
    sim_reasmur <- simulate(ReducedGLM, nsim = nrow(data), newdata=sim_data)
    
    # Integration of the responses to simulated data frame 
    sim_data["TOR"] <- sim_reasmur
    # We apply a model similar in every way to FitGLMM called BootGlmm and we fit it on simdata
    BootGlmm <- glmer(formula, family=binomial, data=sim_data)
  
    # We add sd of random effect to estimated_var
    var <- as.data.frame(VarCorr(BootGlmm))["sdcor"][1]
    var
  }
  
  # Threads closing
  stopCluster(cl)
  
  estimated_var_list <- estimated_var
  estimated_var <- as.numeric(unlist(estimated_var))
  
  # Statistic test between sd of random effect of experimental data and simulated data
  testEffectDr <- VarCorr(FitGLMM) > quantile(estimated_var,.95) 
  testEffectDr["dr"]
  
  # Extraction of quantile of sd
  quantile(estimated_var, probs = c(0.05, 0.95))
  
  # Calculation of p-value of sd of random effect
  pvalueSdDevDrEffect<- mean(VarCorr(FitGLMM) < estimated_var) 
  pvalueSdDevDrEffect[1]
  
  qplot(estimated_var, geom="histogram")
}

#Secondary endpoint

#OR of fixed effects (standardized for 1 increase of SD value)

#OR_LF = exp(coef(summary(FitGLMM))["low.flow", "Estimate"]*sqrt(var(data$low.flow)))
#exp(confint(FitGLMM))
plot_model(FitGLMM, sort.est = TRUE, show.values = TRUE, value.offset = .3, type = "std")

#OR of random effect #point estimate for the odds ratio can be obtained for a doctor one SD above the mean, relative to a doctor at the mean, by exponentiating the value of sigma

#exp(sd(ranef(FitGLMM)$dr[1, ]))

#OR sans interval de confiance

racsOR <- exp(coef(summary(FitGLMM))["racs", "Estimate"])#*sqrt(var(dataB$racs)))
sprintf("OR Racs : %s", racsOR)
  
AsystolieOR <- exp(coef(summary(FitGLMM))["`Asystolie/RSP`", "Estimate"])
sprintf("OR asystolie : %s", AsystolieOR)

witnessOR <- exp(coef(summary(FitGLMM))["witness", "Estimate"])
sprintf("OR witness : %s", witnessOR)

ATCDcardioOR <- exp(coef(summary(FitGLMM))["ATCD.Cardiovasculaire", "Estimate"])
sprintf("OR atcd cardio : %s", ATCDcardioOR)

ATCDdiaOR <- exp(coef(summary(FitGLMM))["ATCD.Diabete", "Estimate"])
sprintf("OR atcd dia : %s", ATCDdiaOR)

ATCD_EOL_OR <- exp(coef(summary(FitGLMM))["ATCD.EOL", "Estimate"])
sprintf("OR EOL : %s", ATCD_EOL_OR)

ATCDrespOR <- exp(coef(summary(FitGLMM))["ATCD.Respiratoire", "Estimate"])
sprintf("OR atcd resp : %s", ATCDrespOR)

ATCDotherOR <- exp(coef(summary(FitGLMM))["ATCD.Other", "Estimate"])
sprintf("OR atcd other : %s", ATCDotherOR)

sexeOR <- 0
  if(ExcludeSex == FALSE)
    sexeOR <- exp(coef(summary(FitGLMM))["sexe", "Estimate"])

sprintf("OR sex : %s", sexeOR)

if(CategorizeVar) {
  LF_OR10 <- exp(coef(summary(FitGLMM))["low.flow10 to 20 minutes", "Estimate"])
  LF_OR20 <- exp(coef(summary(FitGLMM))["low.flow20 to 40 minutes", "Estimate"])
  LF_OR40 <- exp(coef(summary(FitGLMM))["low.flow40 minutes and beyond", "Estimate"])
  print(sprintf("OR lf < 20 : %s", LF_OR10))
  print(sprintf("OR lf < 40 : %s", LF_OR20))
  print(sprintf("OR lf > 40 : %s", LF_OR40))
  
  noflowOR1 <- exp(coef(summary(FitGLMM))["noflow1 to 5 minutes", "Estimate"])
  noflowOR5 <- exp(coef(summary(FitGLMM))["noflow5 to 10 minutes", "Estimate"])
  noflowOR10 <- exp(coef(summary(FitGLMM))["noflow10 to 20 minutes", "Estimate"])
  noflowOR20 <- exp(coef(summary(FitGLMM))["noflow20 minutes and beyond", "Estimate"])
  print(sprintf("OR nf > 1 : %s", noflowOR1))
  print(sprintf("OR nf > 5 : %s", noflowOR5))
  print(sprintf("OR nf > 10 : %s", noflowOR10))
  print(sprintf("OR nf > 20 : %s", noflowOR20))
  
  ageOR65 <- exp(coef(summary(FitGLMM))["age65-75 years", "Estimate"])
  ageOR75 <- exp(coef(summary(FitGLMM))["age75-85 years", "Estimate"])
  ageOR85 <- exp(coef(summary(FitGLMM))["age85 years and beyond", "Estimate"])
  print(sprintf("OR age > 65 : %s", ageOR65))
  print(sprintf("OR age > 75 : %s", ageOR75))
  print(sprintf("OR age > 85 : %s", ageOR85))
} else {
  LF_OR <- exp(coef(summary(FitGLMM))["low.flow", "Estimate"]*sqrt(var(dataB$low.flow)))
  ageOR <- exp(coef(summary(FitGLMM))["age", "Estimate"]*sqrt(var(dataB$age)))
  noflowOR <- exp(coef(summary(FitGLMM))["noflow", "Estimate"]*sqrt(var(dataB$noflow)))
  print(sprintf("OR lf : %s", LF_OR))
  print(sprintf("OR nf : %s", noflowOR))
  print(sprintf("OR age : %s", ageOR))
}

#bootstrapped confidence interval

nbBootPrimary = 1000

library(doParallel)
# Bootstrap iterations
nsamples <- nbBootPrimary

# Multithreading
ncores=6
cl = makeCluster(ncores)
registerDoParallel(cl)

# Define the bootstrapping function
estimated_var <- function(dataB, index) {
  sim_data <- dataB[sample(1:nrow(dataB), nrow(dataB), replace=TRUE), ]
  if(quadratic)
    BootGLMM <- glmer(formulaNonLinear, family=binomial, data=sim_data)
  else
    BootGLMM <- glmer(formula, family=binomial, data=sim_data)
  
  #OR of mixed effect (dr)
  Mixed <- exp(sd(ranef(BootGLMM)$dr[,]))
  
  #OR of fixed effects
  racsOR <- exp(coef(summary(BootGLMM))["racs", "Estimate"])#*sqrt(var(dataB$racs)))
  AsystolieOR <- exp(coef(summary(BootGLMM))["`Asystolie/RSP`", "Estimate"])#*sqrt(var(dataB$`Asystolie/RSP`)))
  witnessOR <- exp(coef(summary(BootGLMM))["witness", "Estimate"])#*sqrt(var(dataB$witness)))
  ATCDcardioOR <- exp(coef(summary(BootGLMM))["ATCD.Cardiovasculaire", "Estimate"])#*sqrt(var(dataB$ATCD.Cardiovasculaire)))
  ATCDdiaOR <- exp(coef(summary(BootGLMM))["ATCD.Diabete", "Estimate"])#*sqrt(var(dataB$ATCD.Diabete)))
  ATCD_EOL_OR <- exp(coef(summary(BootGLMM))["ATCD.EOL", "Estimate"])#*sqrt(var(dataB$ATCD.EOL)))
  ATCDrespOR <- exp(coef(summary(BootGLMM))["ATCD.Respiratoire", "Estimate"])#*sqrt(var(dataB$ATCD.Respiratoire)))
  ATCDotherOR <- exp(coef(summary(BootGLMM))["ATCD.Other", "Estimate"])#*sqrt(var(dataB$ATCD.Other)))
  
  
  
  sexeOR <- 0
  if(ExcludeSex == FALSE)
    sexeOR <- exp(coef(summary(BootGLMM))["sexe", "Estimate"])#*sqrt(var(dataB$sexe)))
  
  if(CategorizeVar) {
    LF_OR10 <- exp(coef(summary(BootGLMM))["low.flow10 to 20 minutes", "Estimate"])
    LF_OR20 <- exp(coef(summary(BootGLMM))["low.flow20 to 40 minutes", "Estimate"])
    LF_OR40 <- exp(coef(summary(BootGLMM))["low.flow40 minutes and beyond", "Estimate"])
    
    noflowOR1 <- exp(coef(summary(BootGLMM))["noflow1 to 5 minutes", "Estimate"])
    noflowOR5 <- exp(coef(summary(BootGLMM))["noflow5 to 10 minutes", "Estimate"])
    noflowOR10 <- exp(coef(summary(BootGLMM))["noflow10 to 20 minutes", "Estimate"])
    noflowOR20 <- exp(coef(summary(BootGLMM))["noflow20 minutes and beyond", "Estimate"])
    
    ageOR65 <- exp(coef(summary(BootGLMM))["age65-75 years", "Estimate"])
    ageOR75 <- exp(coef(summary(BootGLMM))["age75-85 years", "Estimate"])
    ageOR85 <- exp(coef(summary(BootGLMM))["age85 years and beyond", "Estimate"])
  } else {
    
    LF_OR <- exp(coef(summary(BootGLMM))["low.flow", "Estimate"]*sqrt(var(dataB$low.flow)))
    ageOR <- exp(coef(summary(BootGLMM))["age", "Estimate"]*sqrt(var(dataB$age)))
    noflowOR <- exp(coef(summary(BootGLMM))["noflow", "Estimate"]*sqrt(var(dataB$noflow)))
    
    noflowORnoSD <- exp(coef(summary(BootGLMM))["noflow", "Estimate"])
    LF_ORnoSD <- exp(coef(summary(BootGLMM))["low.flow", "Estimate"])
    ageORnoSD <- exp(coef(summary(BootGLMM))["age", "Estimate"])
  }
  
if(CategorizeVar) {
      Fixed <- data.frame("racs" = racsOR, "noflow1 to 5 minutes" = noflowOR1, "noflow5 to 10 minutes" = noflowOR5, "noflow10 to 20 minutes" = noflowOR10, "noflow20 minutes and beyond" = noflowOR20, "Asystolie/RSP" = AsystolieOR, "low.flow10 to 20 minutes" = LF_OR10, "low.flow20 to 40 minutes" = LF_OR20, "low.flow40 minutes and beyond" = LF_OR40, "sexe"= sexeOR, "witness" = witnessOR, "age65-75 years"= ageOR65, "age75-85 years"= ageOR75, "age85 years and beyond"= ageOR85, "ATCD.Cardiovasculaire"= ATCDcardioOR, "ATCD.Diabete" = ATCDdiaOR, "ATCD.EOL" = ATCD_EOL_OR, "ATCD.Respiratoire" = ATCDrespOR, "ATCD.Other"= ATCDotherOR)
      
      NoSD <- Fixed
      
} else {
  #named vector of fixed effects OR
    Fixed <- data.frame("racs" = racsOR, "noflow" = noflowOR, "Asystolie/RSP" = AsystolieOR, "low.flow" = LF_OR, "sexe"= sexeOR, "witness" = witnessOR, "age"= ageOR, "ATCD.Cardiovasculaire"= ATCDcardioOR, "ATCD.Diabete" = ATCDdiaOR, "ATCD.EOL" = ATCD_EOL_OR, "ATCD.Respiratoire" = ATCDrespOR, "ATCD.Other"= ATCDotherOR)
    
    NoSD <- data.frame("racs" = racsOR, "noflow" = noflowORnoSD, "Asystolie/RSP" = AsystolieOR, "low.flow" = LF_ORnoSD, "sexe"= sexeOR, "witness" = witnessOR, "age"= ageORnoSD, "ATCD.Cardiovasculaire"= ATCDcardioOR, "ATCD.Diabete" = ATCDdiaOR, "ATCD.EOL" = ATCD_EOL_OR, "ATCD.Respiratoire" = ATCDrespOR, "ATCD.Other"= ATCDotherOR)
}

  
  
  
  #Fixed <- exp(coef(summary(BootGLMM))[, "Estimate"]*sqrt(var(dataB$low.flow)))
  output<-list(Mixed,Fixed, NoSD)
  return(output)
}

# Bootstrapped estimates
#results <- boot(data=sim_data, statistic=estimated_var, R=nbBootPrimary, progress="text") #nbBootPrimary

# Initialize a vector to store the bootstrapped estimates
resultsMixed <- numeric(nbBootPrimary)

if(CategorizeVar) {
  resultsFixed <- data.frame("racs" = numeric(), "noflow1 to 5 minutes" = numeric(), "noflow5 to 10 minutes" = numeric(), "noflow10 to 20 minutes" = numeric(), "noflow20 minutes and beyond" = numeric(), "Asystolie/RSP" = numeric(), "low.flow10 to 20 minutes" = numeric(), "low.flow20 to 40 minutes" = numeric(), "low.flow40 minutes and beyond" = numeric(), "sexe"= numeric(), "witness" = numeric(), "age65-75 years"= numeric(), "age75-85 years"= numeric(), "age85 years and beyond"= numeric(), "ATCD.Cardiovasculaire"= numeric(), "ATCD.Diabete" = numeric(), "ATCD.EOL" = numeric(), "ATCD.Respiratoire" = numeric(), "ATCD.Other"= numeric())
  
  resultsNoSD <- resultsFixed
} else {
  resultsFixed <- data.frame("racs"= numeric(), "noflow"= numeric(), "Asystolie/RSP"= numeric(), "low.flow"= numeric(), "sexe"= numeric(), "witness"= numeric(), "age"= numeric(), "ATCD.Cardiovasculaire"= numeric(), "ATCD.Diabete"= numeric(), "ATCD.EOL"= numeric(), "ATCD.Respiratoire"= numeric(), "ATCD.Other"= numeric())
  resultsNoSD <- resultsFixed
}
#colnames(resultsFixed) = c("Intercept", "racs", "noflow", "Asystolie/RSP", "low.flow", "sexe", "witness", "age", "ATCD.Cardiovasculaire", "ATCD.Diabete", "ATCD.EOL", "ATCD.Respiratoire", "ATCD.Other")

  if(ExcludeSex) {
    resultsFixed <- select(resultsFixed, -sexe)
    resultsNoSD <- select(resultsNoSD, -sexe)
  }

resultsB<- c() 

# Bootstrapped estimates with progress counter
resultsB = foreach(i=1:nbBootPrimary) %dopar% { 
#for (i in 1:nbBootPrimary) {
  library(lme4)
  index <- sample(1:nrow(data), replace=TRUE)
  results <- estimated_var(data, index)
  
  
  # Display the progress counter
  # if (i %% 25 == 0) {
  #   cat("Iteration", i, "of ", nbBootPrimary, "\n time : ", Sys.time())
  # }
  
  return(results)
}

# resultsMixed[i] <- results[1]
# resultsFixed <- rbind(resultsFixed, data.frame(as.list(results[2][[1]])))
# resultsNoSD <- rbind(resultsNoSD, data.frame(as.list(results[3][[1]])))

# Threads closing
  stopCluster(cl)

resultsMixed <- c()
for (i in 1:length(resultsB)) {
  resultsMixed[i] = resultsB[[i]][1]
  resultsFixed <- rbind(resultsFixed, data.frame(as.list(resultsB[[i]][2][[1]])))
  resultsNoSD <- rbind(resultsNoSD, data.frame(as.list(resultsB[[i]][3][[1]])))
}


  if(ExcludeSex) {
    resultsFixed <- select(resultsFixed, -sexe)
    resultsNoSD <- select(resultsNoSD, -sexe)
  }
resultsMixed <- as.numeric(unlist(resultsMixed))

mean(resultsMixed)
median(resultsMixed)
quantile(resultsMixed, probs = c(0.025, 0.975))
hist(resultsMixed, main = "Frequency Plot of Bootstrapped Means", xlab = "Bootstrapped Means", ylab = "Frequency", breaks = 100)
statsBootstrap <- data.frame(Predictor = "Dr Effect", OR = mean(resultsMixed), Lower = quantile(resultsMixed, probs = c(0.025, 0.975))["2.5%"][[1]], Upper = quantile(resultsMixed, probs = c(0.025, 0.975))["97.5%"][[1]])

for (i in colnames(resultsFixed)){
  #print(resultsFixed[[i]])
  #as.numeric(unlist(resultsMixed))
  print(i)
  cat("\n")

  print(mean(resultsFixed[[i]]))
  print(median(resultsFixed[[i]]))
  print(quantile(resultsFixed[[i]], probs = c(0.025, 0.975)))
  cat("\n\n")
  
  statsBootstrap <- statsBootstrap %>% 
   add_row(Predictor = i, OR = mean(resultsFixed[[i]]), Lower = quantile(resultsFixed[[i]], probs = c(0.025, 0.975))["2.5%"][[1]], Upper = quantile(resultsFixed[[i]], probs = c(0.025, 0.975))["97.5%"][[1]])
}

print("NON NORMALIZED")

for (i in colnames(resultsNoSD)){
  #print(resultsNoSD[[i]])
  #as.numeric(unlist(resultsMixed))
  print(i)
  cat("\n")

  print(mean(resultsNoSD[[i]]))
  print(median(resultsNoSD[[i]]))
  print(quantile(resultsNoSD[[i]], probs = c(0.025, 0.975)))
  cat("\n\n")
  
}

#Prepare data for plot

library(ggplot2)

stats <- statsBootstrap[order(statsBootstrap$OR, decreasing=TRUE),]
stats <- stats %>% mutate(names=NA) %>% add_row(Predictor = "Dr Effect beneath", OR = 1/stats$OR[stats$Predictor == "Dr Effect"], Lower =1/stats$Lower[stats$Predictor == "Dr Effect"], Upper = 1/stats$Upper[stats$Predictor == "Dr Effect"])

if(CategorizeVar) {
  stats$names[stats$Predictor == "age65.75.years"] <- "Age in [66, 75] years" 
  stats$names[stats$Predictor == "age75.85.years"] <- "Age in [76, 85] years" 
  stats$names[stats$Predictor == "age85.years.and.beyond"] <- "Age > 85 years"
  
  stats$names[stats$Predictor == "noflow1.to.5.minutes"] <- "No-flow in [2, 5] min" 
  stats$names[stats$Predictor == "noflow5.to.10.minutes"] <- "No-flow in [6, 10] min" 
  stats$names[stats$Predictor == "noflow10.to.20.minutes"] <- "No-flow in [11, 20] min" 
  stats$names[stats$Predictor == "noflow20.minutes.and.beyond"] <- "No-flow > 20 min" 
  
  stats$names[stats$Predictor == "low.flow10.to.20.minutes"] <- "Low-flow in [11, 20] min" 
  stats$names[stats$Predictor == "low.flow20.to.40.minutes"] <- "Low-flow in [21, 40] min" 
  stats$names[stats$Predictor == "low.flow40.minutes.and.beyond"] <- "Low-flow > 40 min" 
} else {
  stats$names[stats$Predictor == "age"] <- "Age" 
  stats$names[stats$Predictor == "low.flow"] <- "Low-Flow" 
  stats$names[stats$Predictor == "noflow"] <- "No-Flow" 
}

stats$names[stats$Predictor == "Dr Effect beneath"] <- "Doctor effect, one SD beneath mean"
stats$names[stats$Predictor == "Dr Effect"] <- "Doctor effect, one SD above mean"
stats$names[stats$Predictor == "ATCD.EOL"] <- "Dependency for activities of daily living" 
stats$names[stats$Predictor == "Asystolie.RSP"] <- "Non-shockable inital rhythm" 
stats$names[stats$Predictor == "ATCD.Cardiovasculaire"] <- "Cardiovascular disease" 
stats$names[stats$Predictor == "ATCD.Diabete"] <- "Diabetes" 
stats$names[stats$Predictor == "ATCD.Respiratoire"] <- "Respiratory disease" 
stats$names[stats$Predictor == "racs"] <- "ROSC" 
stats$names[stats$Predictor == "witness"] <- "Witness" 
stats$names[stats$Predictor == "ATCD.Other"] <- "Oncologic or other relevant disease" 

if(!ExcludeSex) {
  stats$names[stats$Predictor == "sexe"] <- "Male gender" 
}



plotF <- stats %>%
  arrange(OR) %>%    # First sort by val. This sort the dataframe but NOT the factor levels
  mutate_if(is.numeric, round, digits = 2) %>%
  mutate(names=factor(names, levels=names)) %>%   # This trick update the factor levels
  ggplot( aes(y = names, x = OR, xmin = Lower, xmax = Upper, label=OR, size = 40)) +
    scale_x_log10() +
    geom_vline(xintercept = 1, color = "red") +

    geom_text(hjust=0.5, vjust=-1, size = 3) +
    
    geom_errorbar(width = 0.3, size = 0.5, color = "darkgrey") +
      geom_point( size=2, color="black") + 
    ylab("Factor") +
    xlab("Odds Ratio") +
    #ggtitle("Odds Ratios of TOR factors in OHCA") +
    theme_minimal() + 
  theme(axis.text.y = element_text(lineheight = 20)) +
  theme(plot.margin = margin(0.5,0.5,0.5,0.5, "cm")) 
  #theme(axis.x=element_text(margin = margin(t = 20))

plotF

ggsave(filename = "resultplot.jpg", plotF, dpi = 500, width = 9, height = 8, device = "jpg")
stats %>%
  arrange(OR) %>%    # First sort by val. This sort the dataframe but NOT the factor levels
  mutate_if(is.numeric, round, digits = 2) %>%
  mutate(names=factor(names, levels=names)) %>%   # This trick update the factor levels
  ggsave(filename = "resultplot", 
         ggplot(aes(y = names, x = OR, xmin = Lower, xmax = Upper, label=OR)) +
    scale_x_log10() +
    geom_vline(xintercept = 1, color = "red") +

    geom_text(hjust=0.5, vjust=-1, size = 3) +
    
    geom_errorbar(width = 0.3, size = 0.5, color = "darkgrey") +
      geom_point( size=2, color="black") + 
    ylab("Factor") +
    xlab("Odds Ratio") +
    #ggtitle("Odds Ratios of TOR factors in OHCA") +
    theme_minimal(), dpi = 500, device = "png") #+
  #theme(axis.x=element_text(margin = margin(t = 20))
#library(htmltools)
#library(htmlTable)
#stats %>% htmlTable

#Calculate pseudo-R2 of FitGLMM

if(computeRptR) {
  plan(multisession, workers = parallel::detectCores())
  R2_confint_marginal <- partR2(FitGLMM, partvars = c("noflow"),
  R2_type = "marginal", max_level = 1, nboot = nBootPartR2, CI = 0.95, parallel = TRUE, data=data)
  R2_confint_conditional <- partR2(FitGLMM, partvars = c("noflow"),
  R2_type = "conditional", max_level = 1, nboot = nBootPartR2, CI = 0.95, parallel = TRUE, data=data)
  
  R2_confint_marginal
  R2_confint_conditional
}
if(computeRptR) {
  plan(multisession, workers = parallel::detectCores())
  partvars = c("racs", "noflow", "witness", "`Asystolie/RSP`", "low.flow", "sexe", "age", "ATCD.Cardiovasculaire", "ATCD.Diabete", "ATCD.EOL", "ATCD.Respiratoire", "ATCD.Other")
  if(ExcludeSex) {
    partvars = partvars[partvars != "sexe"];
  }
  partR2resultn100 <- partR2(FitGLMM, partvars = partvars,
  R2_type = "conditional", max_level = 1, nboot = nBootPartR2, CI = 0.95, parallel = TRUE, data=data)
}
if(computeRptR) {
  library(ggplot2)
  library(partR2)
  partR2test <- partR2resultn100
  #partR2test$R2 <- partR2test$R2 %>% add_row(term = "Marginal R2", estimate = 0.563, CI_lower = 0.531, CI_upper = 0.581, ndf = 13)
  #partR2test$R2 <- partR2test$R2 %>% add_row(term = "Conditional R2", estimate = 0.06, CI_lower = 0.022, CI_upper = 0.08, ndf = 13)
  partR2test$R2 <- partR2test$R2 %>% add_row(term = "Doctor effect", estimate = rptRadjust100[["R"]][["dr"]][2], CI_lower = rptRadjust100[["CI_emp"]][["CI_link"]][["2.5%"]], CI_upper = rptRadjust100[["CI_emp"]][["CI_link"]][["97.5%"]], ndf = 13)
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "racs", "ROSC"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "noflow", "No-flow"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "witness", "Witness"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "`Asystolie/RSP`", "Asystole"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "low.flow", "Low-flow"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "sexe", "Sex"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "age", "Age"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "ATCD.Cardiovasculaire", "Cardiovascular disease"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "ATCD.Diabete", "Diabetes"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "ATCD.EOL", "Poor autonomy / end of life"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "ATCD.Respiratoire", "Respiratory disease"))
  partR2test$R2 <- partR2test$R2 %>% mutate(term = replace(term, term == "ATCD.Other", "Oncologic and other relevant disease"))
  partR2test$R2 <- arrange(partR2test$R2, desc(estimate), .by_group = FALSE)
  
  p1test <- forestplot(partR2test, type = "R2", text_size = 10)
  p1test + geom_text(aes(label = sprintf("%.2f [%.2f-%.2f]", partR2test$R2$estimate, partR2test$R2$CI_lower, partR2test$R2$CI_upper), hjust = -0.01, vjust = 0.5), nudge_x = (partR2test$R2$CI_upper - partR2test$R2$estimate)+0.005, nudge_y = 0.05, size = 3) + scale_x_continuous(expand = expansion(mult = 0.2))
  p1test
  
  partR2test
}
if(computeRptR) {
  plan(multisession, workers = parallel::detectCores())
  partR2resultn5 <- partR2(FitGLMM, partvars = c("racs", "noflow", "witness", "`Asystolie/RSP`", "low.flow", "sexe", "age", "ATCD.Cardiovasculaire", "ATCD.Diabete", "ATCD.EOL", "ATCD.Respiratoire", "ATCD.Other"),
  R2_type = "conditional", max_level = 1, nboot = 5, CI = 0.95, parallel = TRUE, data=data)
}
nbBootPrimary = 100

library(doParallel)
# Bootstrap iterations
nsamples <- nbBootPrimary

# Multithreading
ncores=12
cl = makeCluster(ncores)
registerDoParallel(cl)

factorToRemove = c("racs", "noflow", "witness", "`Asystolie/RSP`", "low.flow", "sexe", "age", "ATCD.Cardiovasculaire", "ATCD.Diabete", "ATCD.EOL", "ATCD.Respiratoire", "ATCD.Other")



# Define the bootstrapping function
estimated_varF <- function(dataB, index, formulaT) {
  sim_data <- dataB[sample(1:nrow(dataB), nrow(dataB), replace=TRUE), ]
  
  
  BootGLMM <- glmer(formulaT, family=binomial, data=sim_data)
  
  #OR of mixed effect (dr)
  Mixed <- exp(sd(ranef(BootGLMM)$dr[,]))
  
  return(Mixed)
}

# Bootstrapped estimates
#results <- boot(data=sim_data, statistic=estimated_var, R=nbBootPrimary, progress="text") #nbBootPrimary

# Initialize a vector to store the bootstrapped estimates



for (factor in factorToRemove) {
    resultsBF <- c() 

    # Bootstrapped estimates with progress counter
    resultsBF = foreach(i=1:nbBootPrimary) %dopar% { 
    #for (i in 1:nbBootPrimary) {
      library(lme4)
      library(buildmer)
      index <- sample(1:nrow(data), replace=TRUE)
      formulaT = remove.terms(formula, factor)
      resultsF <- estimated_varF(data, index, formulaT)
    
      return(resultsF)
    }
    
    resultsMixedF <- numeric(nbBootPrimary)
    
    resultsMixedF <- as.numeric(unlist(resultsBF))

    sprintf("Result %s", factor)
    print(mean(resultsMixedF))
    print(median(resultsMixedF))
    print(quantile(resultsMixedF, probs = c(0.025, 0.975)))
}

# Threads closing
  stopCluster(cl)
LS0tDQp0aXRsZTogIlF1YW50aWZ5aW5nIHBoeXNpY2lhbuKAmXMgYmlhcyB0byB0ZXJtaW5hdGUgcmVzdXNjaXRhdGlvbi4gVGhlIFRFUk1JTkFUT1IgU3R1ZHkiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQojTGlicmFyeSBsb2FkaW5nDQoNCmBgYHtyfQ0KI2xpYnJhcnkgbG9hZGluZy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KbGlicmFyeShsbWU0KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh4bHN4KQ0KbGlicmFyeShwYXJhbGxlbCkNCmxpYnJhcnkoc2ptaXNjKQ0KbGlicmFyeShzamxhYmVsbGVkKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZG9QYXJhbGxlbCkNCmxpYnJhcnkoc2pQbG90KQ0KI2xpYnJhcnkoTXVNSW4pDQpsaWJyYXJ5KGJvb3QpDQpsaWJyYXJ5KHRhYmxlMSkNCmxpYnJhcnkocGFydFIyKQ0KbGlicmFyeShidWlsZG1lcikNCmxpYnJhcnkocnB0UikNCmxpYnJhcnkoZnVycnIpDQpsaWJyYXJ5KGZ1dHVyZSkNCmxpYnJhcnkoZ2xtbVRNQikNCmBgYA0KDQojT3B0aW9ucw0KDQpgYGB7cn0NCkNhcE5vTG93RmxvdyA9IEZBTFNFDQpFeGNsdWRlRHJXaXRoRmV3T0hDQSA9IEZBTFNFDQpFeGNsdWRlU2V4ID0gRkFMU0UNCg0KQ2F0ZWdvcml6ZVZhciA9IFRSVUUNCnF1YWRyYXRpYyA9IEZBTFNFDQoNCmNvbXB1dGVScHRSID0gRkFMU0UNCmJvb3RzdHJhcFNpZ21hID0gRkFMU0UNCg0KbnVtYmVyT2ZSZXNpZHVhbFNpbXVsYXRpb25zID0gMTAgI2RoYXJtYQ0KbkJvb3RQYXJ0UjIgPSAxMCAjbmJvb3QgcnB0ciBhbmQgcGFydFIyDQpuQm9vdFBhcnRSMkNvbXBhcmUgPSAxMA0KbmJCb290UHJpbWFyeSA9IDEwDQpgYGANCg0KDQojRGF0YSBpbXBvcnRhdGlvbiAmIGNsZWFuaW5nDQoNCkNvcnJlY3Rpb24gb2YgZG9jdG9yIG5hbWVzIGFuZCBhbm9ueW1pc2F0aW9uIGhhcyBiZWVuIGRvbmUgYmVmb3JlIHRoZSBpbXBvcnRhdGlvbiBwcm9jZXNzDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpkYXRhIDwtIHJlYWQueGxzeCgiQzovVXNlcnMvdGhvbWEvRGVza3RvcC9yZWFjbGFzdC54bHN4IiwgMSkNCm5iIDwtIG5yb3coZGF0YSkNCmBgYA0KDQpEZWxldGUgY29ycnVwdGVkL2luY29tcGxldGUgZGF0YQ0KDQpgYGB7cn0NCmRhdGEgPC0gZmlsdGVyKGRhdGEsIHJ5dGhtID49IDApDQpwcmludCgiUmVtb3ZpbmcgY29ycnVwdCBvciB1bmtub3duIGRhdGEgYWJvdXQgcnl0aG0iKQ0KcHJpbnQobnJvdyhkYXRhKSkNCnByaW50KG5iIC0gbnJvdyhkYXRhKSkNCm5iIDwtIG5yb3coZGF0YSkNCg0KZGF0YSA8LSBmaWx0ZXIoZGF0YSwgc2V4ZSA8IDMpDQpwcmludCgiUmVtb3ZpbmcgY29ycnVwdCBvciB1bmtub3duIGRhdGEgYWJvdXQgc2V4IikNCnByaW50KG5yb3coZGF0YSkpDQpwcmludChuYiAtIG5yb3coZGF0YSkpDQpuYiA8LSBucm93KGRhdGEpDQoNCmRhdGEgPC0gZmlsdGVyKGRhdGEsIGxvd2Zsb3cgPj0gMCkNCnByaW50KCJSZW1vdmluZyBjb3JydXB0IG9yIHVua25vd24gZGF0YSBhYm91dCBsb3ctZmxvdyIpDQpwcmludChucm93KGRhdGEpKQ0KcHJpbnQobmIgLSBucm93KGRhdGEpKQ0KbmIgPC0gbnJvdyhkYXRhKQ0KDQpkYXRhIDwtIGZpbHRlcihkYXRhLCBub2Zsb3cgPj0gMCkNCnByaW50KCJSZW1vdmluZyBjb3JydXB0IG9yIHVua25vd24gZGF0YSBhYm91dCBuby1mbG93IikNCnByaW50KG5yb3coZGF0YSkpDQpwcmludChuYiAtIG5yb3coZGF0YSkpDQpuYiA8LSBucm93KGRhdGEpDQpgYGANCg0KUmVtb3ZlIHRyYXVtYXRpYyBhcnJlc3RzDQoNCmBgYHtyfQ0KZGF0YSA8LSBmaWx0ZXIoZGF0YSwgbWVkaWNhbCA+IDApDQpwcmludCgiUmVtb3ZpbmcgdHJhdW1hdGljIGFycmVzdHMiKQ0KcHJpbnQobnJvdyhkYXRhKSkNCnByaW50KG5iIC0gbnJvdyhkYXRhKSkNCm5iIDwtIG5yb3coZGF0YSkNCmBgYA0KDQpPcHRpb25zIDogDQpSZW1vdmUgYXJyZXN0IGxpbmtlZCB0byBEciB3aXRoIHRvIGZldyBhcnJlc3QgKG5vdCBpbiBwcmltYXJ5IGFuYWx5c2lzIGJ1dCB1c2VkIGluIGFwcGVuZGl4KQ0KDQpgYGB7ciBBcHBlbmRpeCA6IERvY3RvcnMgd2l0aCA+IDMgT0hDQSBvbmx5fQ0KaWYoRXhjbHVkZURyV2l0aEZld09IQ0EpIHsNCiAgZGF0YSA8LSBkYXRhICU+JSBncm91cF9ieShkcikgJT4lIGZpbHRlcihuKCkgPj0gNDApDQogIA0KICBkYXRhIDwtIGRhdGEgJT4lIHVuZ3JvdXANCiAgDQogIHByaW50KCJSZW1vdmluZyBhcnJlc3RzIGxpbmtlZCB3aXRoIERyIHdpdGggbGVzcyB0aGFuIDMgYXJyZXN0cyIpDQogIHByaW50KG5yb3coZGF0YSkpDQogIHByaW50KG5iIC0gbnJvdyhkYXRhKSkNCiAgbmIgPC0gbnJvdyhkYXRhKQ0KfQ0KYGBgDQoNCiNEYXRhIHByZXByb2Nlc3NpbmcNCg0KQ3JlYXRpb24gb2YgYmluYXJ5IHNjb3JlIGZvciB0aGUgcHJlc2VuY2Ugb3IgYWJzZW5jZSBmb3IgZWFjaCBvYnNlcnZlZCBtZWRpY2FsIGhpc3RvcnkNCg0KYGBge3J9DQpkYXRhIDwtIGRhdGEgJT4lIG11dGF0ZSgiQVRDRC5DYXJkaW92YXNjdWxhaXJlIiA9IHJlcGxhY2UoQVRDRC5DYXJkaW92YXNjdWxhaXJlLCBBVENELkNhcmRpb3Zhc2N1bGFpcmUgPT0gLTEsIDApKQ0KZGF0YSA8LSBkYXRhICU+JSBtdXRhdGUoIkFUQ0QuUmVzcGlyYXRvaXJlIiA9IHJlcGxhY2UoQVRDRC5SZXNwaXJhdG9pcmUsIEFUQ0QuUmVzcGlyYXRvaXJlID09IC0xLCAwKSkNCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKCJBVENELkRpYWJldGUiID0gcmVwbGFjZShBVENELkRpYWJldGUsIEFUQ0QuRGlhYmV0ZSA9PSAtMSwgMCkpDQpkYXRhIDwtIGRhdGEgJT4lIG11dGF0ZSgiQVRDRC5FT0wiID0gcmVwbGFjZShBVENELkVPTCwgQVRDRC5FT0wgPT0gLTEsIDApKQ0KZGF0YSA8LSBkYXRhICU+JSBtdXRhdGUoIkFUQ0QuT3RoZXIiID0gcmVwbGFjZShBVENELk90aGVyLCBBVENELk90aGVyID09IC0xLCAwKSkNCmBgYA0KDQpBZGp1c3Qgc2V4IHRvIGJpbmFyeSB2YWx1ZQ0KDQpgYGB7cn0NCiNUcmFuc2Zvcm1pbmcgbWVuID0gMSBldCB3b21lbiA9IDIgaW4gbWVuID0gMCBldCB3b21lbiA9IDENCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKCJzZXhlIiA9IGRhdGEkc2V4ZS0xKQ0KYGBgDQoNClJlZ3JvdXAgYXN5c3RvbGUgYW5kIHB1bHNlbGVzcyBlbGVjdHJpY2FsIGFjdGl2aXR5ICh0d28gZ3JvdXAgcmVtYWluaW5nIEFzeXN0b2xlL1BFQSBhbmQgb3RoZXIgcnl0aG1zKQ0KDQpgYGB7cn0NCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKCJBc3lzdG9saWUvUlNQIiA9IHJlcGxhY2UoY2hvY2FibGUsIGNob2NhYmxlID09IDMsIDEpKQ0KZGF0YSA8LSBkYXRhICU+JSBtdXRhdGUoIkFzeXN0b2xpZS9SU1AiID0gZGF0YSRgQXN5c3RvbGllL1JTUGAtMSkNCmBgYA0KDQpDYWxjdWxhdGUgbG93LWZsb3cgQkVGT1JFIFNBTVUtTUlDVSBhcnJpdmFsDQoNCmBgYHtyfQ0KI0NyZWF0aW9uIG9mIHNtdXJkZWxheSB1c2VmdWwgZm9yIGNhbGN1bGF0aW9uIGp1c3QgYmVsb3cNCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKGRlbGF5c211ciA9IGRpZmZ0aW1lKGRhdGEkc211ckhvdXIsIGRhdGEkYWNIb3VyLCB1bml0cyA9Im1pbnMiKSkNCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKGRlbGF5c211ciA9IGlmZWxzZShkYXRhJGRlbGF5c211ciA+IDcyMCwgZGlmZnRpbWUoKGFzLkRhdGUoZGF0YSRhY0hvdXIpKzEpLCBkYXRhJHNtdXJIb3VyLCB1bml0cyA9Im1pbnMiKSwgZGF0YSRkZWxheXNtdXIpKQ0KZGF0YSA8LSBkYXRhICU+JSBtdXRhdGUoZGVsYXlzbXVyID0gaWZlbHNlKGRhdGEkZGVsYXlzbXVyIDwgLTcyMCwgZGlmZnRpbWUoKGFzLkRhdGUoZGF0YSRzbXVySG91cikrMSksIGRhdGEkYWNIb3VyLCB1bml0cyA9Im1pbnMiKSwgZGF0YSRkZWxheXNtdXIpKQ0KDQojQ3JlYXRpb24gb2YgbG93ZmxvdyBiZWZvcmUgU01VUiBhcnJpdmFsDQpkYXRhIDwtIGRhdGEgJT4lIG11dGF0ZShsb3cuZmxvdyA9IGlmZWxzZShwbWluKGRhdGEkZGVsYXlzbXVyLWRhdGEkbm9mbG93LCBkYXRhJGxvd2Zsb3cpID4gMCwgcG1pbihkYXRhJGRlbGF5c211ci1kYXRhJG5vZmxvdywgZGF0YSRsb3dmbG93KSwgZGF0YSRsb3dmbG93KSkNCmBgYA0KDQpDYWxjdWxhdGUgdGhlIGV4aXN0ZW5jZSBvZiBhIFJPU0MgYmVmb3JlIFNBTVUtTUlDVSBhcnJpdmFsDQoNCmBgYHtyfQ0KZGF0YSA8LSBkYXRhICU+JSBtdXRhdGUocmFjcyA9IGlmZWxzZSgoZGF0YSRyYWNzZGVsYXkgPCBkYXRhJGRlbGF5c211cikgJiAoZGF0YSRyYWNzZGVsYXkgIT0gLTEpLCAxLCAwKSkNCmBgYA0KDQpDcmVhdGlvbiBvZiBUT1IgY29sdW1uICh0ZXJtaW5hdGlvbiBvZiByZXN1c2NpdGF0aW9uKQ0KDQpgYGB7cn0NCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKFRPUiA9IGlmZWxzZSghKGRhdGEkcmVhc211ciA9PSAxIHwgZGF0YSR0cmFuc3BvcnQgPT0gMSksIDEsIDApKQ0KYGBgDQoNCkNyZWF0aW9uIG9mIGRhdGEgbGFiZWxzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJGFnZSkgICA8LSAiQWdlIg0KbGFiZWwoZGF0YSRzZXhlKSAgIDwtICJTZXgiDQpsYWJlbChkYXRhJG5vZmxvdykgICA8LSAiTm8tZmxvdyINCmxhYmVsKGRhdGEkd2l0bmVzcykgICA8LSAiV2l0bmVzcyINCmxhYmVsKGRhdGEkZHIpICAgPC0gIkRvY3RvciINCmxhYmVsKGRhdGEkbG93LmZsb3cpICAgPC0gIkxvdy1mbG93Ig0KbGFiZWwoZGF0YSRyYWNzKSAgIDwtICJST1NDIGJlZm9yZSBTTVVSIg0KbGFiZWwoZGF0YSRUT1IpICAgPC0gIlRlcm1pbmF0aW9uIG9mIHJlc3N1c2l0YXRpb24iDQpsYWJlbChkYXRhJGBBVENELkNhcmRpb3Zhc2N1bGFpcmVgKSAgIDwtICJDYXJkaWFjIGhpc3RvcnkiDQpsYWJlbChkYXRhJGBBVENELlJlc3BpcmF0b2lyZWApICAgPC0gIlJlc3BpcmF0b3J5IGhpc3RvcnkiDQpsYWJlbChkYXRhJGBBVENELkVPTGApICAgPC0gIkVuZCBvZiBsaWZlIC8gZGVwZW5kZW5jeSINCmxhYmVsKGRhdGEkYEFUQ0QuRGlhYmV0ZWApICAgPC0gIkRpYWJldGVzIg0KbGFiZWwoZGF0YSRgQVRDRC5PdGhlcmApICAgPC0gIk90aGVyIG1lZGljYWwgaXNzdWUgaW5jbHVkaW5nIG9uY29sb2dpYyINCmxhYmVsKGRhdGEkYEFzeXN0b2xpZS9SU1BgKSAgIDwtICJSeXRobSINCg0KcHJpbnQocGFzdGUwKCJJbmNsdWRlZCBjYXJkaWFjIGFycmVzdHMgOiAiLCBucm93KGRhdGEpKSkNCmBgYA0KR3JhcGggb2YgY29udGludW91cyB2YXJpYWJsZXMNCmBgYHtyfQ0KaGlzdChkYXRhJGFnZSwgYnJlYWtzID0gNTApDQpkYXRhQ2FwcGVkIDwtIGRhdGENCmRhdGFDYXBwZWQgPC0gZGF0YUNhcHBlZCAlPiUgbXV0YXRlKCJub2Zsb3ciID0gcmVwbGFjZShub2Zsb3csIG5vZmxvdyA+PSAxMDAsIDEwMCkpDQpkYXRhQ2FwcGVkIDwtIGRhdGFDYXBwZWQgJT4lIG11dGF0ZSgibG93LmZsb3ciID0gcmVwbGFjZShsb3cuZmxvdywgbG93LmZsb3cgPj0gMTAwLCAxMDApKQ0KaGlzdChkYXRhQ2FwcGVkJG5vZmxvdywgYnJlYWtzID0gMTAwKQ0KaGlzdChkYXRhQ2FwcGVkJGxvdy5mbG93LCBicmVha3MgPSAxMDApDQpgYGANCg0KDQoNCk9wdGlvbiA6DQpDYXBwaW5nIGxvdyBmbG93IGFuZCBuby1mbG93DQpgYGB7ciBBcHBlbmRpeCA6IGNhcHBpbmcgbG93IGZsb3cgYW5kIG5vIGZsb3d9DQppZihDYXBOb0xvd0Zsb3cpIHsNCiAgZGF0YUNhcHBlZCA8LSBkYXRhDQogIGRhdGFDYXBwZWQgPC0gZGF0YUNhcHBlZCAlPiUgbXV0YXRlKCJub2Zsb3ciID0gcmVwbGFjZShub2Zsb3csIG5vZmxvdyA+PSAxMDAsIDEwMCkpDQogIGRhdGFDYXBwZWQgPC0gZGF0YUNhcHBlZCAlPiUgbXV0YXRlKCJsb3cuZmxvdyIgPSByZXBsYWNlKGxvdy5mbG93LCBsb3cuZmxvdyA+PSAxMDAsIDEwMCkpDQogIGRhdGEgPC0gZGF0YUNhcHBlZA0KfQ0KYGBgDQoNCk9wdGlvbiA6DQpDYXRlZ29yaXplIHZhcmlhYmxlcw0KYGBge3J9DQpkYXRhU3YgPC0gZGF0YQ0KaWYoQ2F0ZWdvcml6ZVZhcikgew0KICBkYXRhY2F0IDwtIGRhdGENCiAgZGF0YWNhdCRhZ2UgPC0gY3V0KGRhdGEkYWdlLCANCiAgICAgICAgICAgICAgICAgICBicmVha3M9YygtSW5mLCA2NSwgNzUsIDg1LCBJbmYpLCANCiAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiPCA2NSB5ZWFycyIsIjY1LTc1IHllYXJzIiwiNzUtODUgeWVhcnMiLCAiODUgeWVhcnMgYW5kIGJleW9uZCIpKQ0KICBkYXRhY2F0JG5vZmxvdyA8LSBjdXQoZGF0YSRub2Zsb3csIA0KICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKC1JbmYsIDEsIDUsIDEwLCAyMCwgSW5mKSwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjwgMSBtaW51dGUiLCAiMSB0byA1IG1pbnV0ZXMiLCAiNSB0byAxMCBtaW51dGVzIiwiMTAgdG8gMjAgbWludXRlcyIsICIyMCBtaW51dGVzIGFuZCBiZXlvbmQiKSkNCiAgZGF0YWNhdCRsb3cuZmxvdyA8LSBjdXQoZGF0YSRsb3cuZmxvdywgDQogICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoLUluZiwgMTAsIDIwLCA0MCwgSW5mKSwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjwgMTAgbWludXRlcyIsIjEwIHRvIDIwIG1pbnV0ZXMiLCIyMCB0byA0MCBtaW51dGVzIiwgIjQwIG1pbnV0ZXMgYW5kIGJleW9uZCIpKQ0KICBkYXRhIDwtIGRhdGFjYXQNCn0NCg0KYGBgDQoNCiNUYWJsZTEgOiBjaGFyYXN0ZXJpc3RpY3Mgb2YgcG9wdWxhdGlvbg0KQ3JlYXRpb24gb2YgdGFibGUxIDogQ2hhcmFjdGVyaXN0aWNzIG9mIHBvcHVsYXRpb24NCg0KYGBge3IgVGFibGUxLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KaWYoQ2F0ZWdvcml6ZVZhcikgew0KICBkYXRhY2F0IDwtIGRhdGFTdg0KICBkYXRhY2F0JGFnZSA8LSBjdXQoZGF0YVN2JGFnZSwgDQogICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoLUluZiwgNjUsIDc1LCA4NSwgSW5mKSwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIkFnZSDiiaQgNjUiLCJBZ2UgaW4gWzY2LCA3NV0iLCJBZ2UgaW4gWzc2LCA4NV0iLCAiQWdlID4gODUiKSkNCiAgZGF0YWNhdCRub2Zsb3cgPC0gY3V0KGRhdGFTdiRub2Zsb3csIA0KICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKC1JbmYsIDEsIDUsIDEwLCAyMCwgSW5mKSwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIk5vLWZsb3cg4omkIDEiLCAiTm8tZmxvdyBpbiBbMiwgNV0iLCAiTm8tZmxvdyBpbiBbNiwgMTBdIiwiTm8tZmxvdyBpbiBbMTEsIDIwXSIsICJOby1mbG93ID4gMjAiKSkNCiAgZGF0YWNhdCRsb3cuZmxvdyA8LSBjdXQoZGF0YVN2JGxvdy5mbG93LCANCiAgICAgICAgICAgICAgICAgICBicmVha3M9YygtSW5mLCAxMCwgMjAsIDQwLCBJbmYpLCANCiAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiTG93LWZsb3cg4omkIDEwIiwiTG93LWZsb3cgaW4gWzExLCAyMF0iLCJMb3ctZmxvdyBpbiBbMjEsIDQwXSIsICJMb3ctZmxvdyA+IDQwIikpDQogIGRhdGFUIDwtIGRhdGFjYXQNCn0gZWxzZSB7DQogIGRhdGFUIDwtIGRhdGENCn0NCg0KbGlicmFyeSh0YWJsZTEpDQojZGF0YVQgaXMgYSBjb3B5IG9mIGRhdGEgdXNlZCBmb3IgdGFibGUgZGlzcGxheQ0KDQoNCnJlbmRlciA8LSBmdW5jdGlvbih4LCBuYW1lLCBtaXNzaW5nKSB7DQogIGlmICghaXMubnVtZXJpYyh4KSkgcmV0dXJuKHJlbmRlci5jYXQoeCkpDQogIGVsc2UgaWYgKG5hbWUgPT0gImFnZSIpIHsNCiAgICB3aGF0IDwtIHN3aXRjaChuYW1lLA0KICAgICAgICBhZ2UgPSAiTWVhbiAoU0QpIikNCiAgICBwYXJzZS5hYmJyZXYucmVuZGVyLmNvZGUoYygiIiwgd2hhdCkpKHgpDQogICAgDQogICAgIyB3aGF0IDwtIHN3aXRjaChuYW1lLA0KICAgICMgICAgIGFnZSA9ICJNZWFuIChTRCkiLA0KICAgICMgICAgIGxvdy5mbG93ICA9ICJNZWRpYW4gKElRUikiLA0KICAgICMgICAgIG5vZmxvdyAgPSAiTWVkaWFuIChJUVIpIikNCiAgICAjIHBhcnNlLmFiYnJldi5yZW5kZXIuY29kZShjKCIiLCB3aGF0KSkoeCkNCiAgfSBlbHNlIHsNCiAgICB3aXRoKHN0YXRzLmFwcGx5LnJvdW5kaW5nKHN0YXRzLmRlZmF1bHQoeCksIGRpZ2l0cz0yKSwgYygiIiwNCiAgICAgICAgICAiTWVkaWFuIChJUVIpIj1zcHJpbnRmKCIlcyBbJXMtJXNdIiwgTUVESUFOLCBRMSwgUTMpKSkNCiAgfQ0KfQ0KDQoNCnJlbmRlci5jYXQgPC0gZnVuY3Rpb24oeCkgew0KICAgIGMoIiIsIHNhcHBseShzdGF0cy5kZWZhdWx0KHgpLCBmdW5jdGlvbih5KSB3aXRoKHksDQogICAgICAgIHNwcmludGYoIiVkICglMC4wZiAlJSkiLCBGUkVRLCBQQ1QpKSkpDQp9DQogIA0KZGF0YVQkVE9SIDwtIA0KICBmYWN0b3IoZGF0YVQkVE9SLCANCiAgICAgICAgIGxldmVscz1jKDAsMSksDQogICAgICAgICBsYWJlbHM9YygiQWR2YW5jZWQgbGlmZSBzdXBwb3J0IiwgIyBSZWZlcmVuY2UNCiAgICAgICAgICAgICAgICAgICJUZXJtaW5hdGlvbiBvZiByZXN1c2NpdGF0aW9uIikpDQoNCg0KDQpkYXRhVCRzZXhlIDwtIA0KICBmYWN0b3IoZGF0YVQkc2V4ZSwgbGV2ZWxzPWMoMSwwKSwNCiAgICAgICAgIGxhYmVscz1jKCJNZW4iLCANCiAgICAgICAgICAgICAgICAgICJXb21lbiIpKQ0KDQp1bml0cyhkYXRhVCRhZ2UpIDwtICJZZWFycyINCnVuaXRzKGRhdGFUJG5vZmxvdykgPC0gIk1pbnV0ZXMiDQp1bml0cyhkYXRhVCRsb3cuZmxvdykgPC0gIk1pbnV0ZXMiDQoNCmRhdGFUJGBBc3lzdG9saWUvUlNQYCA8LSANCiAgZmFjdG9yKGRhdGFUJGBBc3lzdG9saWUvUlNQYCwgbGV2ZWxzPWMoMSwwKSwNCiAgICAgICAgIGxhYmVscz1jKCJBc3lzdG9sZS9QRUEiLCANCiAgICAgICAgICAgICAgICAgICJWRi9WVC9TQSIpKQ0KDQpkYXRhVCR3aXRuZXNzIDwtIA0KICBmYWN0b3IoZGF0YVQkd2l0bmVzcywgbGV2ZWxzPWMoMSksDQogICAgICAgICBsYWJlbHM9YygiUHJlc2VudCIpKQ0KDQpkYXRhVCRyYWNzIDwtIA0KICBmYWN0b3IoZGF0YVQkcmFjcywgbGV2ZWxzPWMoMSksDQogICAgICAgICBsYWJlbHM9YygiUHJlc2VudCIpKQ0KDQpkYXRhVCRgQVRDRC5DYXJkaW92YXNjdWxhaXJlYCA8LSANCiAgZmFjdG9yKGRhdGFUJGBBVENELkNhcmRpb3Zhc2N1bGFpcmVgLCBsZXZlbHM9YygxKSwNCiAgICAgICAgIGxhYmVscz1jKCJQcmVzZW50IikpDQoNCmRhdGFUJGBBVENELkVPTGAgPC0gDQogIGZhY3RvcihkYXRhVCRgQVRDRC5FT0xgLCBsZXZlbHM9YygxKSwNCiAgICAgICAgIGxhYmVscz1jKCJQcmVzZW50IikpDQoNCmRhdGFUJGBBVENELlJlc3BpcmF0b2lyZWAgPC0gDQogIGZhY3RvcihkYXRhVCRgQVRDRC5SZXNwaXJhdG9pcmVgLCBsZXZlbHM9YygxKSwNCiAgICAgICAgIGxhYmVscz1jKCJQcmVzZW50IikpDQoNCmRhdGFUJGBBVENELkRpYWJldGVgIDwtIA0KICBmYWN0b3IoZGF0YVQkYEFUQ0QuRGlhYmV0ZWAsIGxldmVscz1jKDEpLA0KICAgICAgICAgbGFiZWxzPWMoIlByZXNlbnQiKSkNCg0KZGF0YVQkYEFUQ0QuT3RoZXJgIDwtIA0KICBmYWN0b3IoZGF0YVQkYEFUQ0QuT3RoZXJgLCBsZXZlbHM9YygxKSwNCiAgICAgICAgIGxhYmVscz1jKCJQcmVzZW50IikpDQoNCmxhYmVsKGRhdGFUJGFnZSkgICA8LSAiQWdlIg0KbGFiZWwoZGF0YVQkc2V4ZSkgICA8LSAiU2V4Ig0KbGFiZWwoZGF0YVQkbm9mbG93KSAgIDwtICJOby1mbG93Ig0KbGFiZWwoZGF0YVQkYHdpdG5lc3NgKSAgIDwtICJXaXRuZXNzIg0KbGFiZWwoZGF0YVQkZHIpICAgPC0gIkRvY3RvciINCmxhYmVsKGRhdGFUJGxvdy5mbG93KSAgIDwtICJMb3ctZmxvdyINCmxhYmVsKGRhdGFUJHJhY3MpICAgPC0gIlJPU0MgYmVmb3JlIFNBTVUtTUlDVSBhcnJpdmFsIg0KbGFiZWwoZGF0YVQkVE9SKSAgIDwtICJUZXJtaW5hdGlvbiBvZiByZXN1c2NpdGF0aW9uIg0KbGFiZWwoZGF0YVQkYEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZWApICAgPC0gIkNhcmRpYWMgaGlzdG9yeSINCmxhYmVsKGRhdGFUJGBBVENELlJlc3BpcmF0b2lyZWApICAgPC0gIlJlc3BpcmF0b3J5IGhpc3RvcnkiDQpsYWJlbChkYXRhVCRgQVRDRC5FT0xgKSAgIDwtICJFbmQgb2YgbGlmZSAvIGRlcGVuZGFuY3kiDQpsYWJlbChkYXRhVCRgQVRDRC5EaWFiZXRlYCkgICA8LSAiRGlhYmV0ZXMgaGlzdG9yeSINCmxhYmVsKGRhdGFUJGBBVENELk90aGVyYCkgICA8LSAiT3RoZXIgbWVkaWNhbCBpc3N1ZSBpbmNsdWRpbmcgb25jb2xvZ2ljIGhpc3RvcnkiDQpsYWJlbChkYXRhVCRgQXN5c3RvbGllL1JTUGApICAgPC0gIlJoeXRobSINCg0KdGFibGUgPC0gdGFibGUxKCB+IGFnZSArIHNleGUgKyBub2Zsb3cgKyBsb3cuZmxvdyArIGBBc3lzdG9saWUvUlNQYCArIHdpdG5lc3MgKyByYWNzICsgYEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZWAgKyBgQVRDRC5SZXNwaXJhdG9pcmVgICsgYEFUQ0QuRU9MYCArIGBBVENELkRpYWJldGVgICsgYEFUQ0QuT3RoZXJgIHwgVE9SLCBkYXRhPWRhdGFULCAgdG9wY2xhc3M9IlJ0YWJsZTEtemVicmEiLCBvdmVyYWxsPSJUb3RhbCIsIHJlbmRlcj1yZW5kZXIpDQoNCmBgYA0KDQoNCg0KDQojTWVhbiBhbmQgbWVkaWFuIG9mIE9IQ0EgYnkgZG9jdG9yDQoNCmBgYHtyfQ0KbWVkaWFuKGFnZ3JlZ2F0ZShkYXRhJGFnZSwgYnk9bGlzdChkYXRhJGRyKSwgRlVOPWxlbmd0aCkkeCkNCm1lYW4oYWdncmVnYXRlKGRhdGEkYWdlLCBieT1saXN0KGRhdGEkZHIpLCBGVU49bGVuZ3RoKSR4KQ0KDQp0LnRlc3QoYWdncmVnYXRlKGRhdGEkYWdlLCBieT1saXN0KGRhdGEkZHIpLCBGVU49bGVuZ3RoKSR4KQ0KcXVhbnRpbGUoYWdncmVnYXRlKGRhdGEkYWdlLCBieT1saXN0KGRhdGEkZHIpLCBGVU49bGVuZ3RoKSR4KQ0KYGBgDQoNCiNDcmVhdGluZyBmb3JtdWxhZQ0KDQpgYGB7cn0NCmZvcm11bGEgPSBgVE9SYCB+IGByYWNzYCArIGBub2Zsb3dgICsgYEFzeXN0b2xpZS9SU1BgICsgYGxvdy5mbG93YCArIGBzZXhlYCArIGB3aXRuZXNzYCArIGBhZ2VgICsgYEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZWAgKyBgQVRDRC5EaWFiZXRlYCsgYEFUQ0QuRU9MYCArIGBBVENELlJlc3BpcmF0b2lyZWAgKyBgQVRDRC5PdGhlcmAgKyAoMXxgZHJgKQ0KDQppZihxdWFkcmF0aWMpIHsNCiAgZm9ybXVsYU5vbkxpbmVhciA9IGBUT1JgIH4gYHJhY3NgICsgYG5vZmxvd2AgKyBJKGBub2Zsb3dgXjIpICsgYEFzeXN0b2xpZS9SU1BgICsgYGxvdy5mbG93YCArIEkoYGxvdy5mbG93YF4yKSArIGBzZXhlYCArIGB3aXRuZXNzYCArIGBhZ2VgICsgSShgYWdlYF4yKSArIGBBVENELkNhcmRpb3Zhc2N1bGFpcmVgICsgYEFUQ0QuRGlhYmV0ZWArIGBBVENELkVPTGAgKyBgQVRDRC5SZXNwaXJhdG9pcmVgICsgYEFUQ0QuT3RoZXJgICsgKDF8YGRyYCkNCn0NCg0KZm9ybXVsYUdMTSA9IGBUT1JgIH4gYHJhY3NgICsgYG5vZmxvd2AgKyBgQXN5c3RvbGllL1JTUGAgKyBgbG93LmZsb3dgICsgYHNleGVgICsgYHdpdG5lc3NgICsgYGFnZWAgKyBgQVRDRC5DYXJkaW92YXNjdWxhaXJlYCArIGBBVENELkRpYWJldGVgKyBgQVRDRC5FT0xgICsgYEFUQ0QuUmVzcGlyYXRvaXJlYCArIGBBVENELk90aGVyYA0KDQppZihFeGNsdWRlU2V4KSB7DQogIGZvcm11bGEgPSByZW1vdmUudGVybXMoZm9ybXVsYSwgInNleGUiKQ0KICBmb3JtdWxhR0xNID0gcmVtb3ZlLnRlcm1zKGZvcm11bGFHTE0sICJzZXhlIikNCiAgaWYocXVhZHJhdGljKSB7DQogICAgZm9ybXVsYU5vbkxpbmVhciA9IHJlbW92ZS50ZXJtcyhmb3JtdWxhTm9uTGluZWFyLCAic2V4ZSIpDQogIH0NCn0NCmBgYA0KDQoNCiNJbXBsZW1lbnRhdGlvbiBvZiBHTE1NIGFuZCBHTE0gbW9kZWxzIChGaXRHTE1NIGFuZCBSZWR1Y2VkR0xNKQ0KDQpGaXRHTE1NIDoNCi0gQmlub21pYWwgZmFtaWx5IHNpbmNlIG91dGNvbWUgaXMgYmluYXJ5DQotIERyIGVmZmVjdCAocmFuZG9tIGVmZmVjdCkgaW1wbGVtZW50ZWQgd2l0aG91dCByYW5kb20gc2xvcGUsIG9ubHkgaW50ZXJzZWN0Lg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShsbWU0KQ0KbGFiZWwoZGF0YSRUT1IpICAgPC0gIlRPUiINCkZpdEdMTU0gPC0gZ2xtZXIoZm9ybXVsYSwgZmFtaWx5PWJpbm9taWFsLCBkYXRhPWRhdGEpDQoNCmlmKHF1YWRyYXRpYykNCiAgRml0R0xNTW5vbkxpbmVhciA8LSBnbG1lcihmb3JtdWxhTm9uTGluZWFyLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9ZGF0YSkNCmBgYA0KDQpSZWR1Y2VkR0xNDQotIFNhbWUgYXMgZml0IEdMTU0gd2l0aG91dCBEciBlZmZlY3QgKG5vIHJhbmRvbSBlZmZlY3QpDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IHJhbmRvbSBlZmZlY3QpIg0KUmVkdWNlZEdMTSA8LSBnbG0oZm9ybXVsYUdMTSwgZmFtaWx5PWJpbm9taWFsLCBkYXRhPWRhdGEpDQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SIg0KYGBgDQoNCg0KI0ZpdHRpbmcgY29uY3VycmVudCBtb2RlbHMNCg0KV2UgZml0IGNvbmN1cnJlbnQgR0xNTSBtb2RlbHMgd2l0aCBzb21lIHByZWRpY3RvcnMgbWlzc2luZyB0byBhc3Nlc3MgdGhlIGltcGFjdC4NCg0KLSBXaXRob3V0IG1lZGljYWwgaGlzdG9yeSAvIGVuZCBvZiBsaWZlDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IG1lZGljYWwgaGlzdG9yeSAvIGVuZCBvZiBsaWZlKSINCmZvcm11bGFXaXRob3V0SGlzdG9yeUVPTCA9IHJlbW92ZS50ZXJtcyhmb3JtdWxhLCAiYEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZWAgKyBgQVRDRC5EaWFiZXRlYCsgYEFUQ0QuRU9MYCsgYEFUQ0QuUmVzcGlyYXRvaXJlYCArIGBBVENELk90aGVyYCIpDQpnbG1tV2l0aG91dEhpc3RvcnlFT0wgPC0gZ2xtZXIoZm9ybXVsYVdpdGhvdXRIaXN0b3J5RU9MLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9ZGF0YSkNCmBgYA0KDQotIFdpdGhvdXQgbWVkaWNhbCBoaXN0b3J5DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IG1lZGljYWwgaGlzdG9yeSkiDQpmb3JtdWxhV2l0aG91dEhpc3RvcnkgPSByZW1vdmUudGVybXMoZm9ybXVsYSwgIkFUQ0QuRU9MIikNCmdsbW1XaXRob3V0SGlzdG9yeSA8LSBnbG1lcihmb3JtdWxhV2l0aG91dEhpc3RvcnksIGZhbWlseT1iaW5vbWlhbCwgZGF0YT1kYXRhKQ0KYGBgDQoNCi0gV2l0aG91dCBuby1mbG93DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IG5vLWZsb3cpIg0KZm9ybXVsYVdpdGhvdXRORiA9IHJlbW92ZS50ZXJtcyhmb3JtdWxhLCAibm9mbG93IikNCmdsbW1XaXRob3V0TkYgPC0gZ2xtZXIoZm9ybXVsYVdpdGhvdXRORiwgZmFtaWx5PWJpbm9taWFsLCBkYXRhPWRhdGEpDQpgYGANCg0KLSBXaXRob3V0IGxvdy1mbG93DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IGxvdy1mbG93KSINCmZvcm11bGFXaXRob3V0TEYgPSByZW1vdmUudGVybXMoZm9ybXVsYSwgImxvdy5mbG93IikNCmdsbW1XaXRob3V0TEYgPC0gZ2xtZXIoZm9ybXVsYVdpdGhvdXRMRiwgZmFtaWx5PWJpbm9taWFsLCBkYXRhPWRhdGEpDQpgYGANCg0KLSBXaXRob3V0IHJ5dGhtIGFuZCBST1NDDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IHJ5dGhtIGFuZCBST1NDKSINCmZvcm11bGFXaXRob3V0Unl0aG0gPSByZW1vdmUudGVybXMoZm9ybXVsYSwgImByYWNzYCArIGBBc3lzdG9saWUvUlNQYCIpDQpnbG1tV2l0aG91dFJ5dGhtIDwtIGdsbWVyKGZvcm11bGFXaXRob3V0Unl0aG0sIGZhbWlseT1iaW5vbWlhbCwgZGF0YT1kYXRhKQ0KYGBgDQoNCi0gV2l0aG91dCBzZXgNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmxhYmVsKGRhdGEkVE9SKSAgIDwtICJUT1IgKHdpdGhvdXQgc2V4KSINCmZvcm11bGFXaXRob3V0U2V4ID0gcmVtb3ZlLnRlcm1zKGZvcm11bGEsICJzZXhlIikNCmdsbW1XaXRob3V0U2V4IDwtIGdsbWVyKGZvcm11bGFXaXRob3V0U2V4LCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9ZGF0YSkNCmBgYA0KDQotIFdpdGhvdXQgYWdlDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsYWJlbChkYXRhJFRPUikgICA8LSAiVE9SICh3aXRob3V0IGFnZSkiDQpmb3JtdWxhV2l0aG91dEFnZSA9IHJlbW92ZS50ZXJtcyhmb3JtdWxhLCAiYWdlIikNCmdsbW1XaXRob3V0QWdlIDwtIGdsbWVyKGZvcm11bGFXaXRob3V0QWdlLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9ZGF0YSkNCmBgYA0KDQotIFdpdGhvdXQgd2l0bmVzcw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KbGFiZWwoZGF0YSRUT1IpICAgPC0gIlRPUiAod2l0aG91dCB3aXRuZXNzKSINCmZvcm11bGFXaXRob3V0V2l0bmVzcyA9IHJlbW92ZS50ZXJtcyhmb3JtdWxhLCAid2l0bmVzcyIpDQpnbG1tV2l0aG91dFdpdG5lc3MgPC0gZ2xtZXIoZm9ybXVsYVdpdGhvdXRXaXRuZXNzLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9ZGF0YSkNCmBgYA0KDQojQ2hlY2tpbmcgR0xNTSBtb2RlbCBhc3VtcHRpb25zDQoNCi0gQmFzaWMgaW5mb3JtYXRpb24gb2YgbW9kZWxzDQoNCmBgYHtyfQ0KcyA8LSBzdW1tYXJ5KEZpdEdMTU0sIGNvcnJlbGF0aW9uID0gVFJVRSkNCnMNCnN1bW1hcnkoUmVkdWNlZEdMTSwgY29ycmVsYXRpb24gPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KY29uZmludChGaXRHTE1NLCBtZXRob2QgPSAiV2FsZCIpDQpgYGANCg0KDQotIENoZWNraW5nIHJlc2lkdWFscw0KDQpVc2luZyBEaGFybWEgd2hpY2ggY3JlYXRlIHZpc3VhbHkgaW50ZXJwcmV0YWJsZSByZXNpZHVhbHMgYnkgc2ltdWxhdGluZyBtYW55IHJlc3BvbnNlIGFuZCBhbmQgdXNpbmcgdGhlIGN1bXVsYXRpdmUgZGVuc2l0eSBmb3IgdGhlIG9ic2VydmVkIGRhdGEgcG9pbnQgdG8gY3JlYXRlIHJlc2lkdWFscyAobW9yZSBpbmZvcm1hdGlvbiBpbiBwYWNrYWdlIHZpZ25ldHRlKS4NCihSZWZpdCA9IFQgcG91ciB1biBib290c3RyYXAgcGFyYW3DqXRyaXF1ZSkNCg0KRnJvbSB0aGlzIGdyYXBoLCB3ZSBjaGVjayA6IG5vcm1hbGl0eSBvZiByZXNpZHVzLCBoZW1lZ2VuZWl0eSBvZiByZXNpZHVzIGZvciB0aGUgd2hvbGUgcGFja2FnZSBhbmQgYWxzbyBmb3IgZWFjaCBpbmRpdmlkdWFsIHByZWRpY3RvcnMNCg0KYGBge3J9DQpsaWJyYXJ5KERIQVJNYSkNCiNzaW1GaXQgPC0gc2ltdWxhdGVSZXNpZHVhbHMoZml0dGVkTW9kZWwgPSBGaXRHTE1NLCBuID0gbnVtYmVyT2ZSZXNpZHVhbFNpbXVsYXRpb25zLCByZWZpdCA9IFQpDQpzaW1GaXQgPC0gc2ltdWxhdGVSZXNpZHVhbHMoZml0dGVkTW9kZWwgPSBGaXRHTE1NLCBuID0gbnVtYmVyT2ZSZXNpZHVhbFNpbXVsYXRpb25zKQ0KcGxvdChzaW1GaXQpDQoNCnNpbVJlZHVjZWQgPC0gc2ltdWxhdGVSZXNpZHVhbHMoZml0dGVkTW9kZWwgPSBSZWR1Y2VkR0xNLCBuID0gbnVtYmVyT2ZSZXNpZHVhbFNpbXVsYXRpb25zKQ0KcGxvdChzaW1SZWR1Y2VkKQ0KDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkbG93LmZsb3cpDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkbm9mbG93KQ0KcGxvdFJlc2lkdWFscyhzaW11bGF0aW9uT3V0cHV0ID0gRml0R0xNTSwgZm9ybT1kYXRhJHJhY3MpDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkYEFzeXN0b2xpZS9SU1BgKQ0KcGxvdFJlc2lkdWFscyhzaW11bGF0aW9uT3V0cHV0ID0gRml0R0xNTSwgZm9ybT1kYXRhJGBzZXhlYCkNCnBsb3RSZXNpZHVhbHMoc2ltdWxhdGlvbk91dHB1dCA9IEZpdEdMTU0sIGZvcm09ZGF0YSRgd2l0bmVzc2ApDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkYGFnZWApDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkYEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZWApDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkYEFUQ0QuRGlhYmV0ZWApDQpwbG90UmVzaWR1YWxzKHNpbXVsYXRpb25PdXRwdXQgPSBGaXRHTE1NLCBmb3JtPWRhdGEkYEFUQ0QuRU9MYCkNCnBsb3RSZXNpZHVhbHMoc2ltdWxhdGlvbk91dHB1dCA9IEZpdEdMTU0sIGZvcm09ZGF0YSRgQVRDRC5SZXNwaXJhdG9pcmVgKQ0KcGxvdFJlc2lkdWFscyhzaW11bGF0aW9uT3V0cHV0ID0gRml0R0xNTSkNCnBsb3RSZXNpZHVhbHMoc2ltdWxhdGlvbk91dHB1dCA9IFJlZHVjZWRHTE0pDQpgYGANCg0KDQotIE5vcm1hbGl0eSBvZiByZXNpZHVhbHMNClRvIHRlc3QgZm9yIG5vcm1hbGl0eSBvZiByZXNpZHVhbHMgdGhlIHNpbXBsZXN0IGlzIHRvIHRyYW5zZm9ybSB0aGUgZGF0YSBnaXZlbiBieSBESEFSTWEgYW5kIHBsb3QgaXQgd2l0aCBhbiBoaXN0b2dyYW0NCg0KYGBge3J9DQojUXVhbnRpbGUgbm9ybWFsaXphdGlvbiBvZiBzY2FsZWQgcmVzaWR1YWxzIHRvIHZpc3VhbGl6ZSB0aGVtIGluIGEgDQpyZXNpZHVhbHNOb3JtIDwtIHJlc2lkdWFscyhzaW1GaXQsIHF1YW50aWxlRnVuY3Rpb24gPSBxbm9ybSwgb3V0bGllclZhbHVlcyA9IGMoMCwxKSkNCg0KaCA8LSBoaXN0KHJlc2lkdWFsc05vcm0sIGJyZWFrcyA9IDQwLCBkZW5zaXR5ID0gMTAsDQogICAgICAgICAgY29sID0gImJsYWNrIiwgeGxhYiA9ICJTY2FsZWQgcmVzaWR1ZXMgKGFmdGVyIHF1YW50aWxlIG5vcm1hbGlzYXRpb24pIiwgeWxhYiA9ICJOdW1iZXIgb2Ygb2JzZXJ2YXRpb24iLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiByZXNpZHVlcyIpIA0KeGZpdCA8LSBzZXEobWluKHJlc2lkdWFsc05vcm0pLCBtYXgocmVzaWR1YWxzTm9ybSksIGxlbmd0aCA9IDQwKSANCnlmaXQgPC0gZG5vcm0oeGZpdCwgbWVhbiA9IG1lYW4ocmVzaWR1YWxzTm9ybSksIHNkID0gc2QocmVzaWR1YWxzTm9ybSkpIA0KeWZpdCA8LSB5Zml0ICogZGlmZihoJG1pZHNbMToyXSkgKiBsZW5ndGgocmVzaWR1YWxzTm9ybSkgDQoNCmxpbmVzKHhmaXQsIHlmaXQsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQ0KcGxvdChoKQ0KYGBgDQoNCi0gQ2hlY2tpbmcgcmFuZG9tIGVmZmVjdCAoZG9jdG9yIGVmZmVjdCkgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KcGxvdF9tb2RlbChGaXRHTE1NLCB0eXBlPSJkaWFnIiwgc29ydC5lc3Q9VFJVRSwNCiAgICAgICAgICAgdmxpbmUuY29sb3I9IiNBOUE5QTkiLCBkb3Quc2l6ZT0xLjUsDQogICAgICAgICAgIHNob3cudmFsdWVzPVQsIHZhbHVlLm9mZnNldD0uMikNCmBgYA0KYGBge3J9DQpzYXZlX3Bsb3QoInFxcGxvdC5qcGciLCBkcGkgPSA1MDAsIHdpZHRoID0gMjAsIGhlaWdodCA9IDE1KQ0KYGBgDQoNCi0gQ2hlY2tpbmcgZml4ZWQgdmFyaWFibGUgaW5kZXBlbmRhbmNlDQoNCkhlcmUgd2UgbG9vayBhdCB0aGUgdmFyaWFuY2UtY292YXJpYW5jZSB0YWJsZSB3aGljaCBpbmZvcm1zIHVzIG9uIGxpbmVhciBjb3JyZWxhdGlvbnMNCg0KYGBge3J9DQpwcmludChzLCBjb3JyZWxhdGlvbiA9IFRSVUUpDQpzdW1tYXJ5KFJlZHVjZWRHTE0sIGNvcnJlbGF0aW9uID0gVFJVRSkNCmBgYA0KDQotIENoZWNraW5nIG9mIHJhbmRvbSBlZmZlY3QgaW5kZXBlbmRlbmNlIHRvIGZpeGVkIHByZWRpY3RvcnMgaXMgZG9uZSBiZWxvdyBieSBjaGVja2luZyB0aGUgaW5kZXBlbmRhbmNlIG9mIHJlcGVhdGFiaWxpdHkgZnJvbSB2YXJpYWJsZXMNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmlmKGNvbXB1dGVScHRSKSB7DQogIHJwdFJhZGp1c3QxMDAgPC0gcnB0Ujo6cnB0KGZvcm11bGEsICJkciIsIGRhdGEgPSBkYXRhLCBkYXRhdHlwZSA9ICJCaW5hcnkiLCBuYm9vdCA9IG5Cb290UGFydFIyLCBucGVybXV0ID0gbkJvb3RQYXJ0UjIsIHBhcmFsbGVsID0gVFJVRSwgbmNvcmVzID0gNiwgYWRqdXN0ZWQgPSBGQUxTRSkNCiAgcnB0UmFkanVzdDEwMA0KICANCiAgc3ByaW50ZigiUGFydCBvZiBleHBsYWluZWQgdmFyaWFuY2Ugb2YgRHIgZWZmZWN0IGZvciBmdWxsIG1vZGVsIDogJXMgJSUiLCB0cnVuYyhycHRSYWRqdXN0MTAwW1siUiJdXVtbImRyIl1dWzJdKjEwXjQpLzEwXjIpDQp9DQpgYGANCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmlmKGNvbXB1dGVScHRSKSB7DQogIHJwdFJhZGp1c3RXaXRob3V0TEYgPC0gcnB0Ujo6cnB0KGZvcm11bGFXaXRob3V0TEYsICJkciIsIGRhdGEgPSBkYXRhLCBkYXRhdHlwZSA9ICJCaW5hcnkiLCBuYm9vdCA9IG5Cb290UGFydFIyQ29tcGFyZSwgbnBlcm11dCA9IG5Cb290UGFydFIyQ29tcGFyZSwgcGFyYWxsZWwgPSBUUlVFLCBuY29yZXMgPSA2LCBhZGp1c3RlZCA9IEZBTFNFKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBEciBlZmZlY3QgKHdpdGhvdXQgbG93IGZsb3cpIDogJXMgJSUiLCB0cnVuYyhycHRSYWRqdXN0V2l0aG91dExGW1siUiJdXVtbImRyIl1dWzJdKjEwXjQpLzEwXjIpDQogIA0KICBycHRSYWRqdXN0V2l0aG91dE5GIDwtIHJwdFI6OnJwdChmb3JtdWxhV2l0aG91dE5GLCAiZHIiLCBkYXRhID0gZGF0YSwgZGF0YXR5cGUgPSAiQmluYXJ5IiwgbmJvb3QgPSBuQm9vdFBhcnRSMkNvbXBhcmUsIG5wZXJtdXQgPSBuQm9vdFBhcnRSMkNvbXBhcmUsIHBhcmFsbGVsID0gVFJVRSwgbmNvcmVzID0gNiwgYWRqdXN0ZWQgPSBGQUxTRSkNCiAgc3ByaW50ZigiUGFydCBvZiBleHBsYWluZWQgdmFyaWFuY2Ugb2YgRHIgZWZmZWN0ICh3aXRob3V0IG5vIGZsb3cpIDogJXMgJSUiLCB0cnVuYyhycHRSYWRqdXN0V2l0aG91dE5GW1siUiJdXVtbImRyIl1dWzJdKjEwXjQpLzEwXjIpDQogIA0KICBycHRSYWRqdXN0V2l0aG91dEhpc3RvcnlFT0wgPC0gcnB0Ujo6cnB0KGZvcm11bGFXaXRob3V0SGlzdG9yeUVPTCwgImRyIiwgZGF0YSA9IGRhdGEsIGRhdGF0eXBlID0gIkJpbmFyeSIsIG5ib290ID0gbkJvb3RQYXJ0UjJDb21wYXJlLCBucGVybXV0ID0gbkJvb3RQYXJ0UjJDb21wYXJlLCBwYXJhbGxlbCA9IFRSVUUsIG5jb3JlcyA9IDYsIGFkanVzdGVkID0gRkFMU0UpDQogIHNwcmludGYoIlBhcnQgb2YgZXhwbGFpbmVkIHZhcmlhbmNlIG9mIERyIGVmZmVjdCAod2l0aG91dCBoaXN0b3J5KSA6ICVzICUlIiwgdHJ1bmMocnB0UmFkanVzdFdpdGhvdXRIaXN0b3J5RU9MW1siUiJdXVtbImRyIl1dWzJdKjEwXjQpLzEwXjIpDQogIA0KICBycHRSYWRqdXN0V2l0aG91dEVPTCA8LSBycHRSOjpycHQoZm9ybXVsYVdpdGhvdXRIaXN0b3J5LCAiZHIiLCBkYXRhID0gZGF0YSwgZGF0YXR5cGUgPSAiQmluYXJ5IiwgbmJvb3QgPSBuQm9vdFBhcnRSMkNvbXBhcmUsIG5wZXJtdXQgPSBuQm9vdFBhcnRSMkNvbXBhcmUsIHBhcmFsbGVsID0gVFJVRSwgbmNvcmVzID0gNiwgYWRqdXN0ZWQgPSBGQUxTRSkNCiAgc3ByaW50ZigiUGFydCBvZiBleHBsYWluZWQgdmFyaWFuY2Ugb2YgRHIgZWZmZWN0ICh3aXRob3V0IGVuZCBvZiBsaWZlKSA6ICVzICUlIiwgdHJ1bmMocnB0UmFkanVzdFdpdGhvdXRFT0xbWyJSIl1dW1siZHIiXV1bMl0qMTBeNCkvMTBeMikNCiAgDQogIHJwdFJhZGp1c3RXaXRob3V0Unl0aG0gPC0gcnB0Ujo6cnB0KGZvcm11bGFXaXRob3V0Unl0aG0sICJkciIsIGRhdGEgPSBkYXRhLCBkYXRhdHlwZSA9ICJCaW5hcnkiLCBuYm9vdCA9IG5Cb290UGFydFIyQ29tcGFyZSwgbnBlcm11dCA9IG5Cb290UGFydFIyQ29tcGFyZSwgcGFyYWxsZWwgPSBUUlVFLCBuY29yZXMgPSA2LCBhZGp1c3RlZCA9IEZBTFNFKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBEciBlZmZlY3QgKHdpdGhvdXQgcnl0aG0pIDogJXMgJSUiLCB0cnVuYyhycHRSYWRqdXN0V2l0aG91dFJ5dGhtW1siUiJdXVtbImRyIl1dWzJdKjEwXjQpLzEwXjIpDQogIA0KICBycHRSYWRqdXN0V2l0aG91dFNleCA8LSBycHRSOjpycHQoZm9ybXVsYVdpdGhvdXRTZXgsICJkciIsIGRhdGEgPSBkYXRhLCBkYXRhdHlwZSA9ICJCaW5hcnkiLCBuYm9vdCA9IG5Cb290UGFydFIyQ29tcGFyZSwgbnBlcm11dCA9IG5Cb290UGFydFIyQ29tcGFyZSwgcGFyYWxsZWwgPSBUUlVFLCBuY29yZXMgPSA2LCBhZGp1c3RlZCA9IEZBTFNFKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBEciBlZmZlY3QgKHdpdGhvdXQgc2V4KSA6ICVzICUlIiwgdHJ1bmMocnB0UmFkanVzdFdpdGhvdXRTZXhbWyJSIl1dW1siZHIiXV1bMl0qMTBeNCkvMTBeMikNCiAgDQogIHJwdFJhZGp1c3RXaXRob3V0QWdlIDwtIHJwdFI6OnJwdChmb3JtdWxhV2l0aG91dEFnZSwgImRyIiwgZGF0YSA9IGRhdGEsIGRhdGF0eXBlID0gIkJpbmFyeSIsIG5ib290ID0gbkJvb3RQYXJ0UjJDb21wYXJlLCBucGVybXV0ID0gbkJvb3RQYXJ0UjJDb21wYXJlLCBwYXJhbGxlbCA9IFRSVUUsIG5jb3JlcyA9IDYsIGFkanVzdGVkID0gRkFMU0UpDQogIHNwcmludGYoIlBhcnQgb2YgZXhwbGFpbmVkIHZhcmlhbmNlIG9mIERyIGVmZmVjdCAod2l0aG91dCBhZ2UpIDogJXMgJSUiLCB0cnVuYyhycHRSYWRqdXN0V2l0aG91dEFnZVtbIlIiXV1bWyJkciJdXVsyXSoxMF40KS8xMF4yKQ0KICANCiAgcnB0UmFkanVzdFdpdGhvdXRXaXRuZXNzIDwtIHJwdFI6OnJwdChmb3JtdWxhV2l0aG91dFdpdG5lc3MsICJkciIsIGRhdGEgPSBkYXRhLCBkYXRhdHlwZSA9ICJCaW5hcnkiLCBuYm9vdCA9IG5Cb290UGFydFIyQ29tcGFyZSwgbnBlcm11dCA9IG5Cb290UGFydFIyQ29tcGFyZSwgcGFyYWxsZWwgPSBUUlVFLCBuY29yZXMgPSA2LCBhZGp1c3RlZCA9IEZBTFNFKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBEciBlZmZlY3QgKHdpdGhvdXQgd2l0bmVzcykgOiAlcyAlJSIsIHRydW5jKHJwdFJhZGp1c3RXaXRob3V0V2l0bmVzc1tbIlIiXV1bWyJkciJdXVsyXSoxMF40KS8xMF4yKQ0KfQ0KYGBgDQoNCg0KI0NoZWNraW5nIEZpdEdMTU0gbW9kZWwgcGVyZm9ybWFuY2UNCg0KQ29tcGFyaW5nIGFsbCBtb2RlbHMgdmlhIEFJQywgcHNldWRvLVIyIHRvIGNoZWNrIGZvciA6DQotIHJhbmRvbSBlZmZlY3QgaW5kZXBlbmRhbmNlIHRvIGZpeGVkIGVmZmVjdHMgY2hvaWNlDQotIFBlcnRpbmVuY2Ugb2YgY2hvc2VuIGZpeGVkIHZhcmlhYmxlcw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KYW5vdmEoRml0R0xNTSwgZ2xtbVdpdGhvdXRIaXN0b3J5RU9MLCBnbG1tV2l0aG91dEhpc3RvcnksIGdsbW1XaXRob3V0TkYsIGdsbW1XaXRob3V0TEYsIGdsbW1XaXRob3V0Unl0aG0sIGdsbW1XaXRob3V0U2V4LCBnbG1tV2l0aG91dEFnZSwgZ2xtbVdpdGhvdXRXaXRuZXNzLCBSZWR1Y2VkR0xNKQ0KDQppZihjb21wdXRlUnB0Uikgew0KICBSMmNGdWxsIDwtIHBhcnRSMihGaXRHTE1NLCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAoZnVsbCkgOiAlcyAlJSIsIHRydW5jKFIyY0Z1bGxbWyJSMiJdXVtbImVzdGltYXRlIl1dWzFdKjEwXjQpLzEwXjIpDQogIA0KICBSMmNXaXRob3V0TEYgPC0gcGFydFIyKGdsbW1XaXRob3V0TEYsIFIyX3R5cGUgPSAiY29uZGl0aW9uYWwiLCBtYXhfbGV2ZWwgPSAxLCBuYm9vdCA9IE5VTEwsIENJID0gMC45NSwgcGFyYWxsZWwgPSBUUlVFLCBkYXRhPWRhdGEpDQogIHNwcmludGYoIlBhcnQgb2YgZXhwbGFpbmVkIHZhcmlhbmNlIG9mIG1vZGVsICh3aXRob3V0IGxvdyBmbG93KSA6ICVzICUlIiwgdHJ1bmMoUjJjV2l0aG91dExGW1siUjIiXV1bWyJlc3RpbWF0ZSJdXVsxXSoxMF40KS8xMF4yKQ0KICANCiAgUjJjV2l0aG91dE5GIDwtIHBhcnRSMihnbG1tV2l0aG91dE5GLCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCBubyBmbG93KSA6ICVzICUlIiwgdHJ1bmMoUjJjV2l0aG91dE5GW1siUjIiXV1bWyJlc3RpbWF0ZSJdXVsxXSoxMF40KS8xMF4yKQ0KICANCiAgUjJjV2l0aG91dEVPTCA8LSBwYXJ0UjIoZ2xtbVdpdGhvdXRIaXN0b3J5LCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCBlbmQgb2YgbGlmZSkgOiAlcyAlJSIsIHRydW5jKFIyY1dpdGhvdXRFT0xbWyJSMiJdXVtbImVzdGltYXRlIl1dWzFdKjEwXjQpLzEwXjIpDQogIA0KICBSMmNXaXRob3V0SGlzdG9yeUVPTCA8LSBwYXJ0UjIoZ2xtbVdpdGhvdXRIaXN0b3J5RU9MLCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCBoaXN0b3J5IGFuZCBlbmQgb2YgbGlmZSkgOiAlcyAlJSIsIHRydW5jKFIyY1dpdGhvdXRIaXN0b3J5RU9MW1siUjIiXV1bWyJlc3RpbWF0ZSJdXVsxXSoxMF40KS8xMF4yKQ0KICANCiAgUjJjV2l0aG91dFJ5dGhtIDwtIHBhcnRSMihnbG1tV2l0aG91dFJ5dGhtLCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCByeXRobSkgOiAlcyAlJSIsIHRydW5jKFIyY1dpdGhvdXRSeXRobVtbIlIyIl1dW1siZXN0aW1hdGUiXV1bMV0qMTBeNCkvMTBeMikNCiAgDQogIFIyY1dpdGhvdXRTZXggPC0gcGFydFIyKGdsbW1XaXRob3V0U2V4LCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCBzZXgpIDogJXMgJSUiLCB0cnVuYyhSMmNXaXRob3V0U2V4W1siUjIiXV1bWyJlc3RpbWF0ZSJdXVsxXSoxMF40KS8xMF4yKQ0KICANCiAgUjJjV2l0aG91dEFnZSA8LSBwYXJ0UjIoZ2xtbVdpdGhvdXRBZ2UsIFIyX3R5cGUgPSAiY29uZGl0aW9uYWwiLCBtYXhfbGV2ZWwgPSAxLCBuYm9vdCA9IE5VTEwsIENJID0gMC45NSwgcGFyYWxsZWwgPSBUUlVFLCBkYXRhPWRhdGEpDQogIHNwcmludGYoIlBhcnQgb2YgZXhwbGFpbmVkIHZhcmlhbmNlIG9mIG1vZGVsICh3aXRob3V0IGFnZSkgOiAlcyAlJSIsIHRydW5jKFIyY1dpdGhvdXRBZ2VbWyJSMiJdXVtbImVzdGltYXRlIl1dWzFdKjEwXjQpLzEwXjIpDQogIA0KICBSMmNXaXRob3V0V2l0bmVzcyA8LSBwYXJ0UjIoZ2xtbVdpdGhvdXRXaXRuZXNzLCBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBOVUxMLCBDSSA9IDAuOTUsIHBhcmFsbGVsID0gVFJVRSwgZGF0YT1kYXRhKQ0KICBzcHJpbnRmKCJQYXJ0IG9mIGV4cGxhaW5lZCB2YXJpYW5jZSBvZiBtb2RlbCAod2l0aG91dCB3aXRuZXNzKSA6ICVzICUlIiwgdHJ1bmMoUjJjV2l0aG91dFdpdG5lc3NbWyJSMiJdXVtbImVzdGltYXRlIl1dWzFdKjEwXjQpLzEwXjIpDQp9DQoNCmNvbXBhcmVUYWIgPSB0YWJfbW9kZWwoRml0R0xNTSwgZ2xtbVdpdGhvdXRIaXN0b3J5RU9MLCBnbG1tV2l0aG91dEhpc3RvcnksIGdsbW1XaXRob3V0TkYsIGdsbW1XaXRob3V0TEYsIGdsbW1XaXRob3V0Unl0aG0sIGdsbW1XaXRob3V0U2V4LCBnbG1tV2l0aG91dEFnZSwgZ2xtbVdpdGhvdXRXaXRuZXNzLCBSZWR1Y2VkR0xNLCBwLnN0eWxlID0gInN0YXJzIiwgcHJlZC5sYWJlbHMgPSBjKCJJbnRlcmNlcHQiLCJST1NDIiwiTm8tZmxvdyIsICJBc3lzdG9sZS9QRUEiLCAiTG93LWZsb3ciLCAiU2V4IiwgIldpdG5lc3MiLCAiQWdlIiwgIkNhcmRpYWMgaGlzdG9yeSIsICJEaWFiZXRlcyIsICJFbmQgb2YgbGlmZSAvIGRlcGVuZGFuY3kiLCAiUmVzcGlyYXRvcnkgaGlzdG9yeSIsICJPdGhlciBtZWRpY2FsIGlzc3VlIGluY2x1ZGluZyBvbmNvbG9naWMgaGlzdG9yeSIpKQ0KYGBgDQoNCiNSRVNVTFRTDQojUHJpbWFyeSBlbmRwb2ludA0KDQojRXZhbHVhdGluZyB0aGUgc2lnbmlmaWNhbmNlIG9mIGRvY3RvciBlZmZlY3QgdGhyb3VnaCBjb21wYXJpc29uIG9mIFJlZHVjZWRHTE0gYW5kIEZpdEdMTU0gdGhyb3VnaCB3aWxrJ3MgdGVzdCAoTWF4aW11bSBsaWtlbGlob29kIHJhdGlvIHRlc3QpDQoNCmBgYHtyfQ0KYW5vdmEoRml0R0xNTSxSZWR1Y2VkR0xNLCB0ZXN0PSJMUlQiKQ0KYGBgDQoNCg0KI0NvbXB1dGluZyBzZCBvZiByYW5kb20gZWZmZWN0IGFuZCBpdCdzIHAtdmFsdWUgd2l0aCBwYXJhbWV0cmljIGJvb3RzdHJhcA0KDQpDb21wdXRpbmcgcHJpbWFyeSBvYmplY3RpdmUgYW5kIGl0J3MgY29uZmlkZW5jZSBpbnRlcnZhbC4NClBhcmFtZXRyaWMgYm9vdHN0cmFwIGJldHdlZW4gRml0R0xNTSBldCBSZWR1Y2VkR0xNLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KaWYoYm9vdHN0cmFwU2lnbWEpew0KICBsaWJyYXJ5KGRvUGFyYWxsZWwpDQogICMgQm9vdHN0cmFwIGl0ZXJhdGlvbnMNCiAgbnNhbXBsZXMgPC0gbmJCb290UHJpbWFyeQ0KICANCiAgIyBNdWx0aXRocmVhZGluZw0KICBuY29yZXM9Ng0KICBjbCA9IG1ha2VDbHVzdGVyKG5jb3JlcykNCiAgcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0KICANCiAgIyBWZWN0b3Igb2YgcmFuZG9tIGVmZmVjdCB2YXJpYW5jZSBvZiBGaXRHTE1NIG9uIGRhdGEgc2ltdWxhdGVkIHRocm91Z2ggUmVkdWNlZEdMTQ0KICBlc3RpbWF0ZWRfdmFyPC0gYygpIA0KICANCiAgIyBCb290c3RyYXAgbG9vcA0KICBlc3RpbWF0ZWRfdmFyID0gZm9yZWFjaChpPTE6bnNhbXBsZXMpICVkb3BhciUgeyANCiAgICBsaWJyYXJ5KGxtZTQpDQogICAgDQogICAgIyBDcmVhdGlvbiBvZiBzaW11bGF0ZWQgZGF0YSBmcm9tIGV4cGVyaW1lbnRhbCBkYXRhIGJ5IHJlcGxhY2luZw0KICAgIHNpbV9kYXRhIDwtIGRhdGFbc2FtcGxlKDE6bnJvdyhkYXRhKSwgbnJvdyhkYXRhKSwgcmVwbGFjZT1UUlVFKSwgXQ0KICAgIA0KICAgICMgU2ltdWxhdGlvbiBvZiByZXNwb25zZSAoVE9SKSBmb3Igc2ltdWxhdGVkIGRhdGEgdXNpbmcgUmVkdWNlZEdMTSBhbmQgYWRkaW5nIGEgbm9pc2Ugc2ltaWxhciB0byB0aGUgb25lIGZvdW5kIGluIGV4cGVyaW1lbnRhbCBkYXRhDQogICAgc2ltX3JlYXNtdXIgPC0gc2ltdWxhdGUoUmVkdWNlZEdMTSwgbnNpbSA9IG5yb3coZGF0YSksIG5ld2RhdGE9c2ltX2RhdGEpDQogICAgDQogICAgIyBJbnRlZ3JhdGlvbiBvZiB0aGUgcmVzcG9uc2VzIHRvIHNpbXVsYXRlZCBkYXRhIGZyYW1lIA0KICAgIHNpbV9kYXRhWyJUT1IiXSA8LSBzaW1fcmVhc211cg0KICAgICMgV2UgYXBwbHkgYSBtb2RlbCBzaW1pbGFyIGluIGV2ZXJ5IHdheSB0byBGaXRHTE1NIGNhbGxlZCBCb290R2xtbSBhbmQgd2UgZml0IGl0IG9uIHNpbWRhdGENCiAgICBCb290R2xtbSA8LSBnbG1lcihmb3JtdWxhLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9c2ltX2RhdGEpDQogIA0KICAgICMgV2UgYWRkIHNkIG9mIHJhbmRvbSBlZmZlY3QgdG8gZXN0aW1hdGVkX3Zhcg0KICAgIHZhciA8LSBhcy5kYXRhLmZyYW1lKFZhckNvcnIoQm9vdEdsbW0pKVsic2Rjb3IiXVsxXQ0KICAgIHZhcg0KICB9DQogIA0KICAjIFRocmVhZHMgY2xvc2luZw0KICBzdG9wQ2x1c3RlcihjbCkNCiAgDQogIGVzdGltYXRlZF92YXJfbGlzdCA8LSBlc3RpbWF0ZWRfdmFyDQogIGVzdGltYXRlZF92YXIgPC0gYXMubnVtZXJpYyh1bmxpc3QoZXN0aW1hdGVkX3ZhcikpDQogIA0KICAjIFN0YXRpc3RpYyB0ZXN0IGJldHdlZW4gc2Qgb2YgcmFuZG9tIGVmZmVjdCBvZiBleHBlcmltZW50YWwgZGF0YSBhbmQgc2ltdWxhdGVkIGRhdGENCiAgdGVzdEVmZmVjdERyIDwtIFZhckNvcnIoRml0R0xNTSkgPiBxdWFudGlsZShlc3RpbWF0ZWRfdmFyLC45NSkgDQogIHRlc3RFZmZlY3REclsiZHIiXQ0KICANCiAgIyBFeHRyYWN0aW9uIG9mIHF1YW50aWxlIG9mIHNkDQogIHF1YW50aWxlKGVzdGltYXRlZF92YXIsIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgDQogICMgQ2FsY3VsYXRpb24gb2YgcC12YWx1ZSBvZiBzZCBvZiByYW5kb20gZWZmZWN0DQogIHB2YWx1ZVNkRGV2RHJFZmZlY3Q8LSBtZWFuKFZhckNvcnIoRml0R0xNTSkgPCBlc3RpbWF0ZWRfdmFyKSANCiAgcHZhbHVlU2REZXZEckVmZmVjdFsxXQ0KICANCiAgcXBsb3QoZXN0aW1hdGVkX3ZhciwgZ2VvbT0iaGlzdG9ncmFtIikNCn0NCmBgYA0KDQojU2Vjb25kYXJ5IGVuZHBvaW50DQoNCiNPUiBvZiBmaXhlZCBlZmZlY3RzIChzdGFuZGFyZGl6ZWQgZm9yIDEgaW5jcmVhc2Ugb2YgU0QgdmFsdWUpDQoNCmBgYHtyfQ0KI09SX0xGID0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbImxvdy5mbG93IiwgIkVzdGltYXRlIl0qc3FydCh2YXIoZGF0YSRsb3cuZmxvdykpKQ0KYGBgDQoNCmBgYHtyfQ0KI2V4cChjb25maW50KEZpdEdMTU0pKQ0KDQpgYGANCg0KDQpgYGB7cn0NCnBsb3RfbW9kZWwoRml0R0xNTSwgc29ydC5lc3QgPSBUUlVFLCBzaG93LnZhbHVlcyA9IFRSVUUsIHZhbHVlLm9mZnNldCA9IC4zLCB0eXBlID0gInN0ZCIpDQpgYGANCg0KDQojT1Igb2YgcmFuZG9tIGVmZmVjdA0KI3BvaW50IGVzdGltYXRlIGZvciB0aGUgb2RkcyByYXRpbyBjYW4gYmUgb2J0YWluZWQgZm9yIGEgZG9jdG9yIG9uZSBTRCBhYm92ZSB0aGUgbWVhbiwgcmVsYXRpdmUgdG8gYSBkb2N0b3IgYXQgdGhlIG1lYW4sIGJ5IGV4cG9uZW50aWF0aW5nIHRoZSB2YWx1ZSBvZiBzaWdtYQ0KDQpgYGB7cn0NCiNleHAoc2QocmFuZWYoRml0R0xNTSkkZHJbMSwgXSkpDQpgYGANCiNPUiBzYW5zIGludGVydmFsIGRlIGNvbmZpYW5jZQ0KYGBge3J9DQpyYWNzT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbInJhY3MiLCAiRXN0aW1hdGUiXSkjKnNxcnQodmFyKGRhdGFCJHJhY3MpKSkNCnNwcmludGYoIk9SIFJhY3MgOiAlcyIsIHJhY3NPUikNCiAgDQpBc3lzdG9saWVPUiA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiYEFzeXN0b2xpZS9SU1BgIiwgIkVzdGltYXRlIl0pDQpzcHJpbnRmKCJPUiBhc3lzdG9saWUgOiAlcyIsIEFzeXN0b2xpZU9SKQ0KDQp3aXRuZXNzT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbIndpdG5lc3MiLCAiRXN0aW1hdGUiXSkNCnNwcmludGYoIk9SIHdpdG5lc3MgOiAlcyIsIHdpdG5lc3NPUikNCg0KQVRDRGNhcmRpb09SIDwtIGV4cChjb2VmKHN1bW1hcnkoRml0R0xNTSkpWyJBVENELkNhcmRpb3Zhc2N1bGFpcmUiLCAiRXN0aW1hdGUiXSkNCnNwcmludGYoIk9SIGF0Y2QgY2FyZGlvIDogJXMiLCBBVENEY2FyZGlvT1IpDQoNCkFUQ0RkaWFPUiA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiQVRDRC5EaWFiZXRlIiwgIkVzdGltYXRlIl0pDQpzcHJpbnRmKCJPUiBhdGNkIGRpYSA6ICVzIiwgQVRDRGRpYU9SKQ0KDQpBVENEX0VPTF9PUiA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiQVRDRC5FT0wiLCAiRXN0aW1hdGUiXSkNCnNwcmludGYoIk9SIEVPTCA6ICVzIiwgQVRDRF9FT0xfT1IpDQoNCkFUQ0RyZXNwT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbIkFUQ0QuUmVzcGlyYXRvaXJlIiwgIkVzdGltYXRlIl0pDQpzcHJpbnRmKCJPUiBhdGNkIHJlc3AgOiAlcyIsIEFUQ0RyZXNwT1IpDQoNCkFUQ0RvdGhlck9SIDwtIGV4cChjb2VmKHN1bW1hcnkoRml0R0xNTSkpWyJBVENELk90aGVyIiwgIkVzdGltYXRlIl0pDQpzcHJpbnRmKCJPUiBhdGNkIG90aGVyIDogJXMiLCBBVENEb3RoZXJPUikNCg0Kc2V4ZU9SIDwtIDANCiAgaWYoRXhjbHVkZVNleCA9PSBGQUxTRSkNCiAgICBzZXhlT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbInNleGUiLCAiRXN0aW1hdGUiXSkNCg0Kc3ByaW50ZigiT1Igc2V4IDogJXMiLCBzZXhlT1IpDQoNCmlmKENhdGVnb3JpemVWYXIpIHsNCiAgTEZfT1IxMCA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsibG93LmZsb3cxMCB0byAyMCBtaW51dGVzIiwgIkVzdGltYXRlIl0pDQogIExGX09SMjAgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbImxvdy5mbG93MjAgdG8gNDAgbWludXRlcyIsICJFc3RpbWF0ZSJdKQ0KICBMRl9PUjQwIDwtIGV4cChjb2VmKHN1bW1hcnkoRml0R0xNTSkpWyJsb3cuZmxvdzQwIG1pbnV0ZXMgYW5kIGJleW9uZCIsICJFc3RpbWF0ZSJdKQ0KICBwcmludChzcHJpbnRmKCJPUiBsZiA8IDIwIDogJXMiLCBMRl9PUjEwKSkNCiAgcHJpbnQoc3ByaW50ZigiT1IgbGYgPCA0MCA6ICVzIiwgTEZfT1IyMCkpDQogIHByaW50KHNwcmludGYoIk9SIGxmID4gNDAgOiAlcyIsIExGX09SNDApKQ0KICANCiAgbm9mbG93T1IxIDwtIGV4cChjb2VmKHN1bW1hcnkoRml0R0xNTSkpWyJub2Zsb3cxIHRvIDUgbWludXRlcyIsICJFc3RpbWF0ZSJdKQ0KICBub2Zsb3dPUjUgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbIm5vZmxvdzUgdG8gMTAgbWludXRlcyIsICJFc3RpbWF0ZSJdKQ0KICBub2Zsb3dPUjEwIDwtIGV4cChjb2VmKHN1bW1hcnkoRml0R0xNTSkpWyJub2Zsb3cxMCB0byAyMCBtaW51dGVzIiwgIkVzdGltYXRlIl0pDQogIG5vZmxvd09SMjAgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbIm5vZmxvdzIwIG1pbnV0ZXMgYW5kIGJleW9uZCIsICJFc3RpbWF0ZSJdKQ0KICBwcmludChzcHJpbnRmKCJPUiBuZiA+IDEgOiAlcyIsIG5vZmxvd09SMSkpDQogIHByaW50KHNwcmludGYoIk9SIG5mID4gNSA6ICVzIiwgbm9mbG93T1I1KSkNCiAgcHJpbnQoc3ByaW50ZigiT1IgbmYgPiAxMCA6ICVzIiwgbm9mbG93T1IxMCkpDQogIHByaW50KHNwcmludGYoIk9SIG5mID4gMjAgOiAlcyIsIG5vZmxvd09SMjApKQ0KICANCiAgYWdlT1I2NSA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiYWdlNjUtNzUgeWVhcnMiLCAiRXN0aW1hdGUiXSkNCiAgYWdlT1I3NSA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiYWdlNzUtODUgeWVhcnMiLCAiRXN0aW1hdGUiXSkNCiAgYWdlT1I4NSA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsiYWdlODUgeWVhcnMgYW5kIGJleW9uZCIsICJFc3RpbWF0ZSJdKQ0KICBwcmludChzcHJpbnRmKCJPUiBhZ2UgPiA2NSA6ICVzIiwgYWdlT1I2NSkpDQogIHByaW50KHNwcmludGYoIk9SIGFnZSA+IDc1IDogJXMiLCBhZ2VPUjc1KSkNCiAgcHJpbnQoc3ByaW50ZigiT1IgYWdlID4gODUgOiAlcyIsIGFnZU9SODUpKQ0KfSBlbHNlIHsNCiAgTEZfT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbImxvdy5mbG93IiwgIkVzdGltYXRlIl0qc3FydCh2YXIoZGF0YUIkbG93LmZsb3cpKSkNCiAgYWdlT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShGaXRHTE1NKSlbImFnZSIsICJFc3RpbWF0ZSJdKnNxcnQodmFyKGRhdGFCJGFnZSkpKQ0KICBub2Zsb3dPUiA8LSBleHAoY29lZihzdW1tYXJ5KEZpdEdMTU0pKVsibm9mbG93IiwgIkVzdGltYXRlIl0qc3FydCh2YXIoZGF0YUIkbm9mbG93KSkpDQogIHByaW50KHNwcmludGYoIk9SIGxmIDogJXMiLCBMRl9PUikpDQogIHByaW50KHNwcmludGYoIk9SIG5mIDogJXMiLCBub2Zsb3dPUikpDQogIHByaW50KHNwcmludGYoIk9SIGFnZSA6ICVzIiwgYWdlT1IpKQ0KfQ0KDQoNCg0KYGBgDQoNCg0KDQojYm9vdHN0cmFwcGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCm5iQm9vdFByaW1hcnkgPSAxMDAwDQoNCmxpYnJhcnkoZG9QYXJhbGxlbCkNCiMgQm9vdHN0cmFwIGl0ZXJhdGlvbnMNCm5zYW1wbGVzIDwtIG5iQm9vdFByaW1hcnkNCg0KIyBNdWx0aXRocmVhZGluZw0KbmNvcmVzPTYNCmNsID0gbWFrZUNsdXN0ZXIobmNvcmVzKQ0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0KDQojIERlZmluZSB0aGUgYm9vdHN0cmFwcGluZyBmdW5jdGlvbg0KZXN0aW1hdGVkX3ZhciA8LSBmdW5jdGlvbihkYXRhQiwgaW5kZXgpIHsNCiAgc2ltX2RhdGEgPC0gZGF0YUJbc2FtcGxlKDE6bnJvdyhkYXRhQiksIG5yb3coZGF0YUIpLCByZXBsYWNlPVRSVUUpLCBdDQogIGlmKHF1YWRyYXRpYykNCiAgICBCb290R0xNTSA8LSBnbG1lcihmb3JtdWxhTm9uTGluZWFyLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9c2ltX2RhdGEpDQogIGVsc2UNCiAgICBCb290R0xNTSA8LSBnbG1lcihmb3JtdWxhLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9c2ltX2RhdGEpDQogIA0KICAjT1Igb2YgbWl4ZWQgZWZmZWN0IChkcikNCiAgTWl4ZWQgPC0gZXhwKHNkKHJhbmVmKEJvb3RHTE1NKSRkclssXSkpDQogIA0KICAjT1Igb2YgZml4ZWQgZWZmZWN0cw0KICByYWNzT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShCb290R0xNTSkpWyJyYWNzIiwgIkVzdGltYXRlIl0pIypzcXJ0KHZhcihkYXRhQiRyYWNzKSkpDQogIEFzeXN0b2xpZU9SIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsiYEFzeXN0b2xpZS9SU1BgIiwgIkVzdGltYXRlIl0pIypzcXJ0KHZhcihkYXRhQiRgQXN5c3RvbGllL1JTUGApKSkNCiAgd2l0bmVzc09SIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsid2l0bmVzcyIsICJFc3RpbWF0ZSJdKSMqc3FydCh2YXIoZGF0YUIkd2l0bmVzcykpKQ0KICBBVENEY2FyZGlvT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShCb290R0xNTSkpWyJBVENELkNhcmRpb3Zhc2N1bGFpcmUiLCAiRXN0aW1hdGUiXSkjKnNxcnQodmFyKGRhdGFCJEFUQ0QuQ2FyZGlvdmFzY3VsYWlyZSkpKQ0KICBBVENEZGlhT1IgPC0gZXhwKGNvZWYoc3VtbWFyeShCb290R0xNTSkpWyJBVENELkRpYWJldGUiLCAiRXN0aW1hdGUiXSkjKnNxcnQodmFyKGRhdGFCJEFUQ0QuRGlhYmV0ZSkpKQ0KICBBVENEX0VPTF9PUiA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbIkFUQ0QuRU9MIiwgIkVzdGltYXRlIl0pIypzcXJ0KHZhcihkYXRhQiRBVENELkVPTCkpKQ0KICBBVENEcmVzcE9SIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsiQVRDRC5SZXNwaXJhdG9pcmUiLCAiRXN0aW1hdGUiXSkjKnNxcnQodmFyKGRhdGFCJEFUQ0QuUmVzcGlyYXRvaXJlKSkpDQogIEFUQ0RvdGhlck9SIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsiQVRDRC5PdGhlciIsICJFc3RpbWF0ZSJdKSMqc3FydCh2YXIoZGF0YUIkQVRDRC5PdGhlcikpKQ0KICANCiAgDQogIA0KICBzZXhlT1IgPC0gMA0KICBpZihFeGNsdWRlU2V4ID09IEZBTFNFKQ0KICAgIHNleGVPUiA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbInNleGUiLCAiRXN0aW1hdGUiXSkjKnNxcnQodmFyKGRhdGFCJHNleGUpKSkNCiAgDQogIGlmKENhdGVnb3JpemVWYXIpIHsNCiAgICBMRl9PUjEwIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibG93LmZsb3cxMCB0byAyMCBtaW51dGVzIiwgIkVzdGltYXRlIl0pDQogICAgTEZfT1IyMCA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImxvdy5mbG93MjAgdG8gNDAgbWludXRlcyIsICJFc3RpbWF0ZSJdKQ0KICAgIExGX09SNDAgPC0gZXhwKGNvZWYoc3VtbWFyeShCb290R0xNTSkpWyJsb3cuZmxvdzQwIG1pbnV0ZXMgYW5kIGJleW9uZCIsICJFc3RpbWF0ZSJdKQ0KICAgIA0KICAgIG5vZmxvd09SMSA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbIm5vZmxvdzEgdG8gNSBtaW51dGVzIiwgIkVzdGltYXRlIl0pDQogICAgbm9mbG93T1I1IDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibm9mbG93NSB0byAxMCBtaW51dGVzIiwgIkVzdGltYXRlIl0pDQogICAgbm9mbG93T1IxMCA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbIm5vZmxvdzEwIHRvIDIwIG1pbnV0ZXMiLCAiRXN0aW1hdGUiXSkNCiAgICBub2Zsb3dPUjIwIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibm9mbG93MjAgbWludXRlcyBhbmQgYmV5b25kIiwgIkVzdGltYXRlIl0pDQogICAgDQogICAgYWdlT1I2NSA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImFnZTY1LTc1IHllYXJzIiwgIkVzdGltYXRlIl0pDQogICAgYWdlT1I3NSA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImFnZTc1LTg1IHllYXJzIiwgIkVzdGltYXRlIl0pDQogICAgYWdlT1I4NSA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImFnZTg1IHllYXJzIGFuZCBiZXlvbmQiLCAiRXN0aW1hdGUiXSkNCiAgfSBlbHNlIHsNCiAgICANCiAgICBMRl9PUiA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImxvdy5mbG93IiwgIkVzdGltYXRlIl0qc3FydCh2YXIoZGF0YUIkbG93LmZsb3cpKSkNCiAgICBhZ2VPUiA8LSBleHAoY29lZihzdW1tYXJ5KEJvb3RHTE1NKSlbImFnZSIsICJFc3RpbWF0ZSJdKnNxcnQodmFyKGRhdGFCJGFnZSkpKQ0KICAgIG5vZmxvd09SIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibm9mbG93IiwgIkVzdGltYXRlIl0qc3FydCh2YXIoZGF0YUIkbm9mbG93KSkpDQogICAgDQogICAgbm9mbG93T1Jub1NEIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibm9mbG93IiwgIkVzdGltYXRlIl0pDQogICAgTEZfT1Jub1NEIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVsibG93LmZsb3ciLCAiRXN0aW1hdGUiXSkNCiAgICBhZ2VPUm5vU0QgPC0gZXhwKGNvZWYoc3VtbWFyeShCb290R0xNTSkpWyJhZ2UiLCAiRXN0aW1hdGUiXSkNCiAgfQ0KICANCmlmKENhdGVnb3JpemVWYXIpIHsNCiAgICAgIEZpeGVkIDwtIGRhdGEuZnJhbWUoInJhY3MiID0gcmFjc09SLCAibm9mbG93MSB0byA1IG1pbnV0ZXMiID0gbm9mbG93T1IxLCAibm9mbG93NSB0byAxMCBtaW51dGVzIiA9IG5vZmxvd09SNSwgIm5vZmxvdzEwIHRvIDIwIG1pbnV0ZXMiID0gbm9mbG93T1IxMCwgIm5vZmxvdzIwIG1pbnV0ZXMgYW5kIGJleW9uZCIgPSBub2Zsb3dPUjIwLCAiQXN5c3RvbGllL1JTUCIgPSBBc3lzdG9saWVPUiwgImxvdy5mbG93MTAgdG8gMjAgbWludXRlcyIgPSBMRl9PUjEwLCAibG93LmZsb3cyMCB0byA0MCBtaW51dGVzIiA9IExGX09SMjAsICJsb3cuZmxvdzQwIG1pbnV0ZXMgYW5kIGJleW9uZCIgPSBMRl9PUjQwLCAic2V4ZSI9IHNleGVPUiwgIndpdG5lc3MiID0gd2l0bmVzc09SLCAiYWdlNjUtNzUgeWVhcnMiPSBhZ2VPUjY1LCAiYWdlNzUtODUgeWVhcnMiPSBhZ2VPUjc1LCAiYWdlODUgeWVhcnMgYW5kIGJleW9uZCI9IGFnZU9SODUsICJBVENELkNhcmRpb3Zhc2N1bGFpcmUiPSBBVENEY2FyZGlvT1IsICJBVENELkRpYWJldGUiID0gQVRDRGRpYU9SLCAiQVRDRC5FT0wiID0gQVRDRF9FT0xfT1IsICJBVENELlJlc3BpcmF0b2lyZSIgPSBBVENEcmVzcE9SLCAiQVRDRC5PdGhlciI9IEFUQ0RvdGhlck9SKQ0KICAgICAgDQogICAgICBOb1NEIDwtIEZpeGVkDQogICAgICANCn0gZWxzZSB7DQogICNuYW1lZCB2ZWN0b3Igb2YgZml4ZWQgZWZmZWN0cyBPUg0KICAgIEZpeGVkIDwtIGRhdGEuZnJhbWUoInJhY3MiID0gcmFjc09SLCAibm9mbG93IiA9IG5vZmxvd09SLCAiQXN5c3RvbGllL1JTUCIgPSBBc3lzdG9saWVPUiwgImxvdy5mbG93IiA9IExGX09SLCAic2V4ZSI9IHNleGVPUiwgIndpdG5lc3MiID0gd2l0bmVzc09SLCAiYWdlIj0gYWdlT1IsICJBVENELkNhcmRpb3Zhc2N1bGFpcmUiPSBBVENEY2FyZGlvT1IsICJBVENELkRpYWJldGUiID0gQVRDRGRpYU9SLCAiQVRDRC5FT0wiID0gQVRDRF9FT0xfT1IsICJBVENELlJlc3BpcmF0b2lyZSIgPSBBVENEcmVzcE9SLCAiQVRDRC5PdGhlciI9IEFUQ0RvdGhlck9SKQ0KICAgIA0KICAgIE5vU0QgPC0gZGF0YS5mcmFtZSgicmFjcyIgPSByYWNzT1IsICJub2Zsb3ciID0gbm9mbG93T1Jub1NELCAiQXN5c3RvbGllL1JTUCIgPSBBc3lzdG9saWVPUiwgImxvdy5mbG93IiA9IExGX09Sbm9TRCwgInNleGUiPSBzZXhlT1IsICJ3aXRuZXNzIiA9IHdpdG5lc3NPUiwgImFnZSI9IGFnZU9Sbm9TRCwgIkFUQ0QuQ2FyZGlvdmFzY3VsYWlyZSI9IEFUQ0RjYXJkaW9PUiwgIkFUQ0QuRGlhYmV0ZSIgPSBBVENEZGlhT1IsICJBVENELkVPTCIgPSBBVENEX0VPTF9PUiwgIkFUQ0QuUmVzcGlyYXRvaXJlIiA9IEFUQ0RyZXNwT1IsICJBVENELk90aGVyIj0gQVRDRG90aGVyT1IpDQp9DQoNCiAgDQogIA0KICANCiAgI0ZpeGVkIDwtIGV4cChjb2VmKHN1bW1hcnkoQm9vdEdMTU0pKVssICJFc3RpbWF0ZSJdKnNxcnQodmFyKGRhdGFCJGxvdy5mbG93KSkpDQogIG91dHB1dDwtbGlzdChNaXhlZCxGaXhlZCwgTm9TRCkNCiAgcmV0dXJuKG91dHB1dCkNCn0NCg0KIyBCb290c3RyYXBwZWQgZXN0aW1hdGVzDQojcmVzdWx0cyA8LSBib290KGRhdGE9c2ltX2RhdGEsIHN0YXRpc3RpYz1lc3RpbWF0ZWRfdmFyLCBSPW5iQm9vdFByaW1hcnksIHByb2dyZXNzPSJ0ZXh0IikgI25iQm9vdFByaW1hcnkNCg0KIyBJbml0aWFsaXplIGEgdmVjdG9yIHRvIHN0b3JlIHRoZSBib290c3RyYXBwZWQgZXN0aW1hdGVzDQpyZXN1bHRzTWl4ZWQgPC0gbnVtZXJpYyhuYkJvb3RQcmltYXJ5KQ0KDQppZihDYXRlZ29yaXplVmFyKSB7DQogIHJlc3VsdHNGaXhlZCA8LSBkYXRhLmZyYW1lKCJyYWNzIiA9IG51bWVyaWMoKSwgIm5vZmxvdzEgdG8gNSBtaW51dGVzIiA9IG51bWVyaWMoKSwgIm5vZmxvdzUgdG8gMTAgbWludXRlcyIgPSBudW1lcmljKCksICJub2Zsb3cxMCB0byAyMCBtaW51dGVzIiA9IG51bWVyaWMoKSwgIm5vZmxvdzIwIG1pbnV0ZXMgYW5kIGJleW9uZCIgPSBudW1lcmljKCksICJBc3lzdG9saWUvUlNQIiA9IG51bWVyaWMoKSwgImxvdy5mbG93MTAgdG8gMjAgbWludXRlcyIgPSBudW1lcmljKCksICJsb3cuZmxvdzIwIHRvIDQwIG1pbnV0ZXMiID0gbnVtZXJpYygpLCAibG93LmZsb3c0MCBtaW51dGVzIGFuZCBiZXlvbmQiID0gbnVtZXJpYygpLCAic2V4ZSI9IG51bWVyaWMoKSwgIndpdG5lc3MiID0gbnVtZXJpYygpLCAiYWdlNjUtNzUgeWVhcnMiPSBudW1lcmljKCksICJhZ2U3NS04NSB5ZWFycyI9IG51bWVyaWMoKSwgImFnZTg1IHllYXJzIGFuZCBiZXlvbmQiPSBudW1lcmljKCksICJBVENELkNhcmRpb3Zhc2N1bGFpcmUiPSBudW1lcmljKCksICJBVENELkRpYWJldGUiID0gbnVtZXJpYygpLCAiQVRDRC5FT0wiID0gbnVtZXJpYygpLCAiQVRDRC5SZXNwaXJhdG9pcmUiID0gbnVtZXJpYygpLCAiQVRDRC5PdGhlciI9IG51bWVyaWMoKSkNCiAgDQogIHJlc3VsdHNOb1NEIDwtIHJlc3VsdHNGaXhlZA0KfSBlbHNlIHsNCiAgcmVzdWx0c0ZpeGVkIDwtIGRhdGEuZnJhbWUoInJhY3MiPSBudW1lcmljKCksICJub2Zsb3ciPSBudW1lcmljKCksICJBc3lzdG9saWUvUlNQIj0gbnVtZXJpYygpLCAibG93LmZsb3ciPSBudW1lcmljKCksICJzZXhlIj0gbnVtZXJpYygpLCAid2l0bmVzcyI9IG51bWVyaWMoKSwgImFnZSI9IG51bWVyaWMoKSwgIkFUQ0QuQ2FyZGlvdmFzY3VsYWlyZSI9IG51bWVyaWMoKSwgIkFUQ0QuRGlhYmV0ZSI9IG51bWVyaWMoKSwgIkFUQ0QuRU9MIj0gbnVtZXJpYygpLCAiQVRDRC5SZXNwaXJhdG9pcmUiPSBudW1lcmljKCksICJBVENELk90aGVyIj0gbnVtZXJpYygpKQ0KICByZXN1bHRzTm9TRCA8LSByZXN1bHRzRml4ZWQNCn0NCiNjb2xuYW1lcyhyZXN1bHRzRml4ZWQpID0gYygiSW50ZXJjZXB0IiwgInJhY3MiLCAibm9mbG93IiwgIkFzeXN0b2xpZS9SU1AiLCAibG93LmZsb3ciLCAic2V4ZSIsICJ3aXRuZXNzIiwgImFnZSIsICJBVENELkNhcmRpb3Zhc2N1bGFpcmUiLCAiQVRDRC5EaWFiZXRlIiwgIkFUQ0QuRU9MIiwgIkFUQ0QuUmVzcGlyYXRvaXJlIiwgIkFUQ0QuT3RoZXIiKQ0KDQogIGlmKEV4Y2x1ZGVTZXgpIHsNCiAgICByZXN1bHRzRml4ZWQgPC0gc2VsZWN0KHJlc3VsdHNGaXhlZCwgLXNleGUpDQogICAgcmVzdWx0c05vU0QgPC0gc2VsZWN0KHJlc3VsdHNOb1NELCAtc2V4ZSkNCiAgfQ0KDQpyZXN1bHRzQjwtIGMoKSANCg0KIyBCb290c3RyYXBwZWQgZXN0aW1hdGVzIHdpdGggcHJvZ3Jlc3MgY291bnRlcg0KcmVzdWx0c0IgPSBmb3JlYWNoKGk9MTpuYkJvb3RQcmltYXJ5KSAlZG9wYXIlIHsgDQojZm9yIChpIGluIDE6bmJCb290UHJpbWFyeSkgew0KICBsaWJyYXJ5KGxtZTQpDQogIGluZGV4IDwtIHNhbXBsZSgxOm5yb3coZGF0YSksIHJlcGxhY2U9VFJVRSkNCiAgcmVzdWx0cyA8LSBlc3RpbWF0ZWRfdmFyKGRhdGEsIGluZGV4KQ0KICANCiAgDQogICMgRGlzcGxheSB0aGUgcHJvZ3Jlc3MgY291bnRlcg0KICAjIGlmIChpICUlIDI1ID09IDApIHsNCiAgIyAgIGNhdCgiSXRlcmF0aW9uIiwgaSwgIm9mICIsIG5iQm9vdFByaW1hcnksICJcbiB0aW1lIDogIiwgU3lzLnRpbWUoKSkNCiAgIyB9DQogIA0KICByZXR1cm4ocmVzdWx0cykNCn0NCg0KIyByZXN1bHRzTWl4ZWRbaV0gPC0gcmVzdWx0c1sxXQ0KIyByZXN1bHRzRml4ZWQgPC0gcmJpbmQocmVzdWx0c0ZpeGVkLCBkYXRhLmZyYW1lKGFzLmxpc3QocmVzdWx0c1syXVtbMV1dKSkpDQojIHJlc3VsdHNOb1NEIDwtIHJiaW5kKHJlc3VsdHNOb1NELCBkYXRhLmZyYW1lKGFzLmxpc3QocmVzdWx0c1szXVtbMV1dKSkpDQoNCiMgVGhyZWFkcyBjbG9zaW5nDQogIHN0b3BDbHVzdGVyKGNsKQ0KDQpgYGANCg0KDQojDQpgYGB7cn0NCnJlc3VsdHNNaXhlZCA8LSBjKCkNCmZvciAoaSBpbiAxOmxlbmd0aChyZXN1bHRzQikpIHsNCiAgcmVzdWx0c01peGVkW2ldID0gcmVzdWx0c0JbW2ldXVsxXQ0KICByZXN1bHRzRml4ZWQgPC0gcmJpbmQocmVzdWx0c0ZpeGVkLCBkYXRhLmZyYW1lKGFzLmxpc3QocmVzdWx0c0JbW2ldXVsyXVtbMV1dKSkpDQogIHJlc3VsdHNOb1NEIDwtIHJiaW5kKHJlc3VsdHNOb1NELCBkYXRhLmZyYW1lKGFzLmxpc3QocmVzdWx0c0JbW2ldXVszXVtbMV1dKSkpDQp9DQoNCg0KICBpZihFeGNsdWRlU2V4KSB7DQogICAgcmVzdWx0c0ZpeGVkIDwtIHNlbGVjdChyZXN1bHRzRml4ZWQsIC1zZXhlKQ0KICAgIHJlc3VsdHNOb1NEIDwtIHNlbGVjdChyZXN1bHRzTm9TRCwgLXNleGUpDQogIH0NCg0KYGBgDQoNCg0KDQpgYGB7cn0NCnJlc3VsdHNNaXhlZCA8LSBhcy5udW1lcmljKHVubGlzdChyZXN1bHRzTWl4ZWQpKQ0KDQptZWFuKHJlc3VsdHNNaXhlZCkNCm1lZGlhbihyZXN1bHRzTWl4ZWQpDQpxdWFudGlsZShyZXN1bHRzTWl4ZWQsIHByb2JzID0gYygwLjAyNSwgMC45NzUpKQ0KYGBgDQpgYGB7cn0NCmhpc3QocmVzdWx0c01peGVkLCBtYWluID0gIkZyZXF1ZW5jeSBQbG90IG9mIEJvb3RzdHJhcHBlZCBNZWFucyIsIHhsYWIgPSAiQm9vdHN0cmFwcGVkIE1lYW5zIiwgeWxhYiA9ICJGcmVxdWVuY3kiLCBicmVha3MgPSAxMDApDQpgYGANCg0KYGBge3J9DQpzdGF0c0Jvb3RzdHJhcCA8LSBkYXRhLmZyYW1lKFByZWRpY3RvciA9ICJEciBFZmZlY3QiLCBPUiA9IG1lYW4ocmVzdWx0c01peGVkKSwgTG93ZXIgPSBxdWFudGlsZShyZXN1bHRzTWl4ZWQsIHByb2JzID0gYygwLjAyNSwgMC45NzUpKVsiMi41JSJdW1sxXV0sIFVwcGVyID0gcXVhbnRpbGUocmVzdWx0c01peGVkLCBwcm9icyA9IGMoMC4wMjUsIDAuOTc1KSlbIjk3LjUlIl1bWzFdXSkNCg0KZm9yIChpIGluIGNvbG5hbWVzKHJlc3VsdHNGaXhlZCkpew0KICAjcHJpbnQocmVzdWx0c0ZpeGVkW1tpXV0pDQogICNhcy5udW1lcmljKHVubGlzdChyZXN1bHRzTWl4ZWQpKQ0KICBwcmludChpKQ0KICBjYXQoIlxuIikNCg0KICBwcmludChtZWFuKHJlc3VsdHNGaXhlZFtbaV1dKSkNCiAgcHJpbnQobWVkaWFuKHJlc3VsdHNGaXhlZFtbaV1dKSkNCiAgcHJpbnQocXVhbnRpbGUocmVzdWx0c0ZpeGVkW1tpXV0sIHByb2JzID0gYygwLjAyNSwgMC45NzUpKSkNCiAgY2F0KCJcblxuIikNCiAgDQogIHN0YXRzQm9vdHN0cmFwIDwtIHN0YXRzQm9vdHN0cmFwICU+JSANCiAgIGFkZF9yb3coUHJlZGljdG9yID0gaSwgT1IgPSBtZWFuKHJlc3VsdHNGaXhlZFtbaV1dKSwgTG93ZXIgPSBxdWFudGlsZShyZXN1bHRzRml4ZWRbW2ldXSwgcHJvYnMgPSBjKDAuMDI1LCAwLjk3NSkpWyIyLjUlIl1bWzFdXSwgVXBwZXIgPSBxdWFudGlsZShyZXN1bHRzRml4ZWRbW2ldXSwgcHJvYnMgPSBjKDAuMDI1LCAwLjk3NSkpWyI5Ny41JSJdW1sxXV0pDQp9DQoNCnByaW50KCJOT04gTk9STUFMSVpFRCIpDQoNCmZvciAoaSBpbiBjb2xuYW1lcyhyZXN1bHRzTm9TRCkpew0KICAjcHJpbnQocmVzdWx0c05vU0RbW2ldXSkNCiAgI2FzLm51bWVyaWModW5saXN0KHJlc3VsdHNNaXhlZCkpDQogIHByaW50KGkpDQogIGNhdCgiXG4iKQ0KDQogIHByaW50KG1lYW4ocmVzdWx0c05vU0RbW2ldXSkpDQogIHByaW50KG1lZGlhbihyZXN1bHRzTm9TRFtbaV1dKSkNCiAgcHJpbnQocXVhbnRpbGUocmVzdWx0c05vU0RbW2ldXSwgcHJvYnMgPSBjKDAuMDI1LCAwLjk3NSkpKQ0KICBjYXQoIlxuXG4iKQ0KICANCn0NCg0KYGBgDQojUHJlcGFyZSBkYXRhIGZvciBwbG90DQpgYGB7cn0NCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpzdGF0cyA8LSBzdGF0c0Jvb3RzdHJhcFtvcmRlcihzdGF0c0Jvb3RzdHJhcCRPUiwgZGVjcmVhc2luZz1UUlVFKSxdDQpzdGF0cyA8LSBzdGF0cyAlPiUgbXV0YXRlKG5hbWVzPU5BKSAlPiUgYWRkX3JvdyhQcmVkaWN0b3IgPSAiRHIgRWZmZWN0IGJlbmVhdGgiLCBPUiA9IDEvc3RhdHMkT1Jbc3RhdHMkUHJlZGljdG9yID09ICJEciBFZmZlY3QiXSwgTG93ZXIgPTEvc3RhdHMkTG93ZXJbc3RhdHMkUHJlZGljdG9yID09ICJEciBFZmZlY3QiXSwgVXBwZXIgPSAxL3N0YXRzJFVwcGVyW3N0YXRzJFByZWRpY3RvciA9PSAiRHIgRWZmZWN0Il0pDQoNCmlmKENhdGVnb3JpemVWYXIpIHsNCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJhZ2U2NS43NS55ZWFycyJdIDwtICJBZ2UgaW4gWzY2LCA3NV0geWVhcnMiIA0KICBzdGF0cyRuYW1lc1tzdGF0cyRQcmVkaWN0b3IgPT0gImFnZTc1Ljg1LnllYXJzIl0gPC0gIkFnZSBpbiBbNzYsIDg1XSB5ZWFycyIgDQogIHN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAiYWdlODUueWVhcnMuYW5kLmJleW9uZCJdIDwtICJBZ2UgPiA4NSB5ZWFycyINCiAgDQogIHN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAibm9mbG93MS50by41Lm1pbnV0ZXMiXSA8LSAiTm8tZmxvdyBpbiBbMiwgNV0gbWluIiANCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJub2Zsb3c1LnRvLjEwLm1pbnV0ZXMiXSA8LSAiTm8tZmxvdyBpbiBbNiwgMTBdIG1pbiIgDQogIHN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAibm9mbG93MTAudG8uMjAubWludXRlcyJdIDwtICJOby1mbG93IGluIFsxMSwgMjBdIG1pbiIgDQogIHN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAibm9mbG93MjAubWludXRlcy5hbmQuYmV5b25kIl0gPC0gIk5vLWZsb3cgPiAyMCBtaW4iIA0KICANCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJsb3cuZmxvdzEwLnRvLjIwLm1pbnV0ZXMiXSA8LSAiTG93LWZsb3cgaW4gWzExLCAyMF0gbWluIiANCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJsb3cuZmxvdzIwLnRvLjQwLm1pbnV0ZXMiXSA8LSAiTG93LWZsb3cgaW4gWzIxLCA0MF0gbWluIiANCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJsb3cuZmxvdzQwLm1pbnV0ZXMuYW5kLmJleW9uZCJdIDwtICJMb3ctZmxvdyA+IDQwIG1pbiIgDQp9IGVsc2Ugew0KICBzdGF0cyRuYW1lc1tzdGF0cyRQcmVkaWN0b3IgPT0gImFnZSJdIDwtICJBZ2UiIA0KICBzdGF0cyRuYW1lc1tzdGF0cyRQcmVkaWN0b3IgPT0gImxvdy5mbG93Il0gPC0gIkxvdy1GbG93IiANCiAgc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJub2Zsb3ciXSA8LSAiTm8tRmxvdyIgDQp9DQoNCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAiRHIgRWZmZWN0IGJlbmVhdGgiXSA8LSAiRG9jdG9yIGVmZmVjdCwgb25lIFNEIGJlbmVhdGggbWVhbiINCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAiRHIgRWZmZWN0Il0gPC0gIkRvY3RvciBlZmZlY3QsIG9uZSBTRCBhYm92ZSBtZWFuIg0Kc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJBVENELkVPTCJdIDwtICJEZXBlbmRlbmN5IGZvciBhY3Rpdml0aWVzIG9mIGRhaWx5IGxpdmluZyIgDQpzdGF0cyRuYW1lc1tzdGF0cyRQcmVkaWN0b3IgPT0gIkFzeXN0b2xpZS5SU1AiXSA8LSAiTm9uLXNob2NrYWJsZSBpbml0YWwgcmh5dGhtIiANCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAiQVRDRC5DYXJkaW92YXNjdWxhaXJlIl0gPC0gIkNhcmRpb3Zhc2N1bGFyIGRpc2Vhc2UiIA0Kc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJBVENELkRpYWJldGUiXSA8LSAiRGlhYmV0ZXMiIA0Kc3RhdHMkbmFtZXNbc3RhdHMkUHJlZGljdG9yID09ICJBVENELlJlc3BpcmF0b2lyZSJdIDwtICJSZXNwaXJhdG9yeSBkaXNlYXNlIiANCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAicmFjcyJdIDwtICJST1NDIiANCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAid2l0bmVzcyJdIDwtICJXaXRuZXNzIiANCnN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAiQVRDRC5PdGhlciJdIDwtICJPbmNvbG9naWMgb3Igb3RoZXIgcmVsZXZhbnQgZGlzZWFzZSIgDQoNCmlmKCFFeGNsdWRlU2V4KSB7DQogIHN0YXRzJG5hbWVzW3N0YXRzJFByZWRpY3RvciA9PSAic2V4ZSJdIDwtICJNYWxlIGdlbmRlciIgDQp9DQoNCg0KDQpwbG90RiA8LSBzdGF0cyAlPiUNCiAgYXJyYW5nZShPUikgJT4lICAgICMgRmlyc3Qgc29ydCBieSB2YWwuIFRoaXMgc29ydCB0aGUgZGF0YWZyYW1lIGJ1dCBOT1QgdGhlIGZhY3RvciBsZXZlbHMNCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCBkaWdpdHMgPSAyKSAlPiUNCiAgbXV0YXRlKG5hbWVzPWZhY3RvcihuYW1lcywgbGV2ZWxzPW5hbWVzKSkgJT4lICAgIyBUaGlzIHRyaWNrIHVwZGF0ZSB0aGUgZmFjdG9yIGxldmVscw0KICBnZ3Bsb3QoIGFlcyh5ID0gbmFtZXMsIHggPSBPUiwgeG1pbiA9IExvd2VyLCB4bWF4ID0gVXBwZXIsIGxhYmVsPU9SLCBzaXplID0gNDApKSArDQogICAgc2NhbGVfeF9sb2cxMCgpICsNCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLCBjb2xvciA9ICJyZWQiKSArDQoNCiAgICBnZW9tX3RleHQoaGp1c3Q9MC41LCB2anVzdD0tMSwgc2l6ZSA9IDMpICsNCiAgICANCiAgICBnZW9tX2Vycm9yYmFyKHdpZHRoID0gMC4zLCBzaXplID0gMC41LCBjb2xvciA9ICJkYXJrZ3JleSIpICsNCiAgICAgIGdlb21fcG9pbnQoIHNpemU9MiwgY29sb3I9ImJsYWNrIikgKyANCiAgICB5bGFiKCJGYWN0b3IiKSArDQogICAgeGxhYigiT2RkcyBSYXRpbyIpICsNCiAgICAjZ2d0aXRsZSgiT2RkcyBSYXRpb3Mgb2YgVE9SIGZhY3RvcnMgaW4gT0hDQSIpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQobGluZWhlaWdodCA9IDIwKSkgKw0KICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjUsMC41LDAuNSwwLjUsICJjbSIpKSANCiAgI3RoZW1lKGF4aXMueD1lbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAyMCkpDQoNCnBsb3RGDQoNCmdnc2F2ZShmaWxlbmFtZSA9ICJyZXN1bHRwbG90LmpwZyIsIHBsb3RGLCBkcGkgPSA1MDAsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOCwgZGV2aWNlID0gImpwZyIpDQpgYGANCmBgYHtyfQ0Kc3RhdHMgJT4lDQogIGFycmFuZ2UoT1IpICU+JSAgICAjIEZpcnN0IHNvcnQgYnkgdmFsLiBUaGlzIHNvcnQgdGhlIGRhdGFmcmFtZSBidXQgTk9UIHRoZSBmYWN0b3IgbGV2ZWxzDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCByb3VuZCwgZGlnaXRzID0gMikgJT4lDQogIG11dGF0ZShuYW1lcz1mYWN0b3IobmFtZXMsIGxldmVscz1uYW1lcykpICU+JSAgICMgVGhpcyB0cmljayB1cGRhdGUgdGhlIGZhY3RvciBsZXZlbHMNCiAgZ2dzYXZlKGZpbGVuYW1lID0gInJlc3VsdHBsb3QiLCANCiAgICAgICAgIGdncGxvdChhZXMoeSA9IG5hbWVzLCB4ID0gT1IsIHhtaW4gPSBMb3dlciwgeG1heCA9IFVwcGVyLCBsYWJlbD1PUikpICsNCiAgICBzY2FsZV94X2xvZzEwKCkgKw0KICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsIGNvbG9yID0gInJlZCIpICsNCg0KICAgIGdlb21fdGV4dChoanVzdD0wLjUsIHZqdXN0PS0xLCBzaXplID0gMykgKw0KICAgIA0KICAgIGdlb21fZXJyb3JiYXIod2lkdGggPSAwLjMsIHNpemUgPSAwLjUsIGNvbG9yID0gImRhcmtncmV5IikgKw0KICAgICAgZ2VvbV9wb2ludCggc2l6ZT0yLCBjb2xvcj0iYmxhY2siKSArIA0KICAgIHlsYWIoIkZhY3RvciIpICsNCiAgICB4bGFiKCJPZGRzIFJhdGlvIikgKw0KICAgICNnZ3RpdGxlKCJPZGRzIFJhdGlvcyBvZiBUT1IgZmFjdG9ycyBpbiBPSENBIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSwgZHBpID0gNTAwLCBkZXZpY2UgPSAicG5nIikgIysNCiAgI3RoZW1lKGF4aXMueD1lbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAyMCkpDQpgYGANCg0KYGBge3J9DQojbGlicmFyeShodG1sdG9vbHMpDQojbGlicmFyeShodG1sVGFibGUpDQojc3RhdHMgJT4lIGh0bWxUYWJsZQ0KDQpgYGANCg0KYGBge3J9DQoNCg0KYGBgDQoNCiNDYWxjdWxhdGUgcHNldWRvLVIyIG9mIEZpdEdMTU0NCg0KLSBDYWxjdWxhdGlvbiBvZiBtYXJnaW5hbCBhbmQgY29uZGl0aW9uYWwgcHNldWRvLVIyIG9mIGZ1bGwgbW9kZWwgdXNpbmcgcGFydFIyDQpSMl9jb25maW50X2NvbmRpdGlvbmFsIC0gUjJfY29uZmludF9tYXJnaW5hbCA9IHJwdFIgdW5hZGp1c3RlZCByZXBlYXRhYmlsaXR5DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQppZihjb21wdXRlUnB0Uikgew0KICBwbGFuKG11bHRpc2Vzc2lvbiwgd29ya2VycyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpKQ0KICBSMl9jb25maW50X21hcmdpbmFsIDwtIHBhcnRSMihGaXRHTE1NLCBwYXJ0dmFycyA9IGMoIm5vZmxvdyIpLA0KICBSMl90eXBlID0gIm1hcmdpbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBuQm9vdFBhcnRSMiwgQ0kgPSAwLjk1LCBwYXJhbGxlbCA9IFRSVUUsIGRhdGE9ZGF0YSkNCiAgUjJfY29uZmludF9jb25kaXRpb25hbCA8LSBwYXJ0UjIoRml0R0xNTSwgcGFydHZhcnMgPSBjKCJub2Zsb3ciKSwNCiAgUjJfdHlwZSA9ICJjb25kaXRpb25hbCIsIG1heF9sZXZlbCA9IDEsIG5ib290ID0gbkJvb3RQYXJ0UjIsIENJID0gMC45NSwgcGFyYWxsZWwgPSBUUlVFLCBkYXRhPWRhdGEpDQogIA0KICBSMl9jb25maW50X21hcmdpbmFsDQogIFIyX2NvbmZpbnRfY29uZGl0aW9uYWwNCn0NCmBgYA0KDQotIFBzZXVkbyBwYXJ0LVLCsiBvZiBpbmRpdmlkdWFsIHByZWRpY3RvcnMNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmlmKGNvbXB1dGVScHRSKSB7DQogIHBsYW4obXVsdGlzZXNzaW9uLCB3b3JrZXJzID0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkpDQogIHBhcnR2YXJzID0gYygicmFjcyIsICJub2Zsb3ciLCAid2l0bmVzcyIsICJgQXN5c3RvbGllL1JTUGAiLCAibG93LmZsb3ciLCAic2V4ZSIsICJhZ2UiLCAiQVRDRC5DYXJkaW92YXNjdWxhaXJlIiwgIkFUQ0QuRGlhYmV0ZSIsICJBVENELkVPTCIsICJBVENELlJlc3BpcmF0b2lyZSIsICJBVENELk90aGVyIikNCiAgaWYoRXhjbHVkZVNleCkgew0KICAgIHBhcnR2YXJzID0gcGFydHZhcnNbcGFydHZhcnMgIT0gInNleGUiXTsNCiAgfQ0KICBwYXJ0UjJyZXN1bHRuMTAwIDwtIHBhcnRSMihGaXRHTE1NLCBwYXJ0dmFycyA9IHBhcnR2YXJzLA0KICBSMl90eXBlID0gImNvbmRpdGlvbmFsIiwgbWF4X2xldmVsID0gMSwgbmJvb3QgPSBuQm9vdFBhcnRSMiwgQ0kgPSAwLjk1LCBwYXJhbGxlbCA9IFRSVUUsIGRhdGE9ZGF0YSkNCn0NCmBgYA0KDQotIERpc3BsYXkgcmVzdWx0IGluIGEgbmljZSBmb3Jlc3QgcGxvdA0KU2luY2UgSUNDIGFuZCBwYXJ0LVIyIGFyZSBib3RoIG1lYXN1cmUgb2YgcHJvcG9ydGlvbiBvZiB2YXJpY3YgZmdiZmFuY2Ugb2YgdGhlIG1vZGVsLCB0aGV5IGFyZSBib3RoIGluY2x1ZGVkIGluIHRoZSByZXN1bHRzDQoNCmBgYHtyfQ0KaWYoY29tcHV0ZVJwdFIpIHsNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KICBsaWJyYXJ5KHBhcnRSMikNCiAgcGFydFIydGVzdCA8LSBwYXJ0UjJyZXN1bHRuMTAwDQogICNwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIGFkZF9yb3codGVybSA9ICJNYXJnaW5hbCBSMiIsIGVzdGltYXRlID0gMC41NjMsIENJX2xvd2VyID0gMC41MzEsIENJX3VwcGVyID0gMC41ODEsIG5kZiA9IDEzKQ0KICAjcGFydFIydGVzdCRSMiA8LSBwYXJ0UjJ0ZXN0JFIyICU+JSBhZGRfcm93KHRlcm0gPSAiQ29uZGl0aW9uYWwgUjIiLCBlc3RpbWF0ZSA9IDAuMDYsIENJX2xvd2VyID0gMC4wMjIsIENJX3VwcGVyID0gMC4wOCwgbmRmID0gMTMpDQogIHBhcnRSMnRlc3QkUjIgPC0gcGFydFIydGVzdCRSMiAlPiUgYWRkX3Jvdyh0ZXJtID0gIkRvY3RvciBlZmZlY3QiLCBlc3RpbWF0ZSA9IHJwdFJhZGp1c3QxMDBbWyJSIl1dW1siZHIiXV1bMl0sIENJX2xvd2VyID0gcnB0UmFkanVzdDEwMFtbIkNJX2VtcCJdXVtbIkNJX2xpbmsiXV1bWyIyLjUlIl1dLCBDSV91cHBlciA9IHJwdFJhZGp1c3QxMDBbWyJDSV9lbXAiXV1bWyJDSV9saW5rIl1dW1siOTcuNSUiXV0sIG5kZiA9IDEzKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJyYWNzIiwgIlJPU0MiKSkNCiAgcGFydFIydGVzdCRSMiA8LSBwYXJ0UjJ0ZXN0JFIyICU+JSBtdXRhdGUodGVybSA9IHJlcGxhY2UodGVybSwgdGVybSA9PSAibm9mbG93IiwgIk5vLWZsb3ciKSkNCiAgcGFydFIydGVzdCRSMiA8LSBwYXJ0UjJ0ZXN0JFIyICU+JSBtdXRhdGUodGVybSA9IHJlcGxhY2UodGVybSwgdGVybSA9PSAid2l0bmVzcyIsICJXaXRuZXNzIikpDQogIHBhcnRSMnRlc3QkUjIgPC0gcGFydFIydGVzdCRSMiAlPiUgbXV0YXRlKHRlcm0gPSByZXBsYWNlKHRlcm0sIHRlcm0gPT0gImBBc3lzdG9saWUvUlNQYCIsICJBc3lzdG9sZSIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJsb3cuZmxvdyIsICJMb3ctZmxvdyIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJzZXhlIiwgIlNleCIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJhZ2UiLCAiQWdlIikpDQogIHBhcnRSMnRlc3QkUjIgPC0gcGFydFIydGVzdCRSMiAlPiUgbXV0YXRlKHRlcm0gPSByZXBsYWNlKHRlcm0sIHRlcm0gPT0gIkFUQ0QuQ2FyZGlvdmFzY3VsYWlyZSIsICJDYXJkaW92YXNjdWxhciBkaXNlYXNlIikpDQogIHBhcnRSMnRlc3QkUjIgPC0gcGFydFIydGVzdCRSMiAlPiUgbXV0YXRlKHRlcm0gPSByZXBsYWNlKHRlcm0sIHRlcm0gPT0gIkFUQ0QuRGlhYmV0ZSIsICJEaWFiZXRlcyIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJBVENELkVPTCIsICJQb29yIGF1dG9ub215IC8gZW5kIG9mIGxpZmUiKSkNCiAgcGFydFIydGVzdCRSMiA8LSBwYXJ0UjJ0ZXN0JFIyICU+JSBtdXRhdGUodGVybSA9IHJlcGxhY2UodGVybSwgdGVybSA9PSAiQVRDRC5SZXNwaXJhdG9pcmUiLCAiUmVzcGlyYXRvcnkgZGlzZWFzZSIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIHBhcnRSMnRlc3QkUjIgJT4lIG11dGF0ZSh0ZXJtID0gcmVwbGFjZSh0ZXJtLCB0ZXJtID09ICJBVENELk90aGVyIiwgIk9uY29sb2dpYyBhbmQgb3RoZXIgcmVsZXZhbnQgZGlzZWFzZSIpKQ0KICBwYXJ0UjJ0ZXN0JFIyIDwtIGFycmFuZ2UocGFydFIydGVzdCRSMiwgZGVzYyhlc3RpbWF0ZSksIC5ieV9ncm91cCA9IEZBTFNFKQ0KICANCiAgcDF0ZXN0IDwtIGZvcmVzdHBsb3QocGFydFIydGVzdCwgdHlwZSA9ICJSMiIsIHRleHRfc2l6ZSA9IDEwKQ0KICBwMXRlc3QgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiBbJS4yZi0lLjJmXSIsIHBhcnRSMnRlc3QkUjIkZXN0aW1hdGUsIHBhcnRSMnRlc3QkUjIkQ0lfbG93ZXIsIHBhcnRSMnRlc3QkUjIkQ0lfdXBwZXIpLCBoanVzdCA9IC0wLjAxLCB2anVzdCA9IDAuNSksIG51ZGdlX3ggPSAocGFydFIydGVzdCRSMiRDSV91cHBlciAtIHBhcnRSMnRlc3QkUjIkZXN0aW1hdGUpKzAuMDA1LCBudWRnZV95ID0gMC4wNSwgc2l6ZSA9IDMpICsgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gMC4yKSkNCiAgcDF0ZXN0DQogIA0KICBwYXJ0UjJ0ZXN0DQp9DQpgYGANCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KaWYoY29tcHV0ZVJwdFIpIHsNCiAgcGxhbihtdWx0aXNlc3Npb24sIHdvcmtlcnMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkNCiAgcGFydFIycmVzdWx0bjUgPC0gcGFydFIyKEZpdEdMTU0sIHBhcnR2YXJzID0gYygicmFjcyIsICJub2Zsb3ciLCAid2l0bmVzcyIsICJgQXN5c3RvbGllL1JTUGAiLCAibG93LmZsb3ciLCAic2V4ZSIsICJhZ2UiLCAiQVRDRC5DYXJkaW92YXNjdWxhaXJlIiwgIkFUQ0QuRGlhYmV0ZSIsICJBVENELkVPTCIsICJBVENELlJlc3BpcmF0b2lyZSIsICJBVENELk90aGVyIiksDQogIFIyX3R5cGUgPSAiY29uZGl0aW9uYWwiLCBtYXhfbGV2ZWwgPSAxLCBuYm9vdCA9IDUsIENJID0gMC45NSwgcGFyYWxsZWwgPSBUUlVFLCBkYXRhPWRhdGEpDQp9DQpgYGANCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KbmJCb290UHJpbWFyeSA9IDEwMA0KDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQojIEJvb3RzdHJhcCBpdGVyYXRpb25zDQpuc2FtcGxlcyA8LSBuYkJvb3RQcmltYXJ5DQoNCiMgTXVsdGl0aHJlYWRpbmcNCm5jb3Jlcz0xMg0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCmZhY3RvclRvUmVtb3ZlID0gYygicmFjcyIsICJub2Zsb3ciLCAid2l0bmVzcyIsICJgQXN5c3RvbGllL1JTUGAiLCAibG93LmZsb3ciLCAic2V4ZSIsICJhZ2UiLCAiQVRDRC5DYXJkaW92YXNjdWxhaXJlIiwgIkFUQ0QuRGlhYmV0ZSIsICJBVENELkVPTCIsICJBVENELlJlc3BpcmF0b2lyZSIsICJBVENELk90aGVyIikNCg0KDQoNCiMgRGVmaW5lIHRoZSBib290c3RyYXBwaW5nIGZ1bmN0aW9uDQplc3RpbWF0ZWRfdmFyRiA8LSBmdW5jdGlvbihkYXRhQiwgaW5kZXgsIGZvcm11bGFUKSB7DQogIHNpbV9kYXRhIDwtIGRhdGFCW3NhbXBsZSgxOm5yb3coZGF0YUIpLCBucm93KGRhdGFCKSwgcmVwbGFjZT1UUlVFKSwgXQ0KICANCiAgDQogIEJvb3RHTE1NIDwtIGdsbWVyKGZvcm11bGFULCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9c2ltX2RhdGEpDQogIA0KICAjT1Igb2YgbWl4ZWQgZWZmZWN0IChkcikNCiAgTWl4ZWQgPC0gZXhwKHNkKHJhbmVmKEJvb3RHTE1NKSRkclssXSkpDQogIA0KICByZXR1cm4oTWl4ZWQpDQp9DQoNCiMgQm9vdHN0cmFwcGVkIGVzdGltYXRlcw0KI3Jlc3VsdHMgPC0gYm9vdChkYXRhPXNpbV9kYXRhLCBzdGF0aXN0aWM9ZXN0aW1hdGVkX3ZhciwgUj1uYkJvb3RQcmltYXJ5LCBwcm9ncmVzcz0idGV4dCIpICNuYkJvb3RQcmltYXJ5DQoNCiMgSW5pdGlhbGl6ZSBhIHZlY3RvciB0byBzdG9yZSB0aGUgYm9vdHN0cmFwcGVkIGVzdGltYXRlcw0KDQoNCg0KZm9yIChmYWN0b3IgaW4gZmFjdG9yVG9SZW1vdmUpIHsNCiAgICByZXN1bHRzQkYgPC0gYygpIA0KDQogICAgIyBCb290c3RyYXBwZWQgZXN0aW1hdGVzIHdpdGggcHJvZ3Jlc3MgY291bnRlcg0KICAgIHJlc3VsdHNCRiA9IGZvcmVhY2goaT0xOm5iQm9vdFByaW1hcnkpICVkb3BhciUgeyANCiAgICAjZm9yIChpIGluIDE6bmJCb290UHJpbWFyeSkgew0KICAgICAgbGlicmFyeShsbWU0KQ0KICAgICAgbGlicmFyeShidWlsZG1lcikNCiAgICAgIGluZGV4IDwtIHNhbXBsZSgxOm5yb3coZGF0YSksIHJlcGxhY2U9VFJVRSkNCiAgICAgIGZvcm11bGFUID0gcmVtb3ZlLnRlcm1zKGZvcm11bGEsIGZhY3RvcikNCiAgICAgIHJlc3VsdHNGIDwtIGVzdGltYXRlZF92YXJGKGRhdGEsIGluZGV4LCBmb3JtdWxhVCkNCiAgICANCiAgICAgIHJldHVybihyZXN1bHRzRikNCiAgICB9DQogICAgDQogICAgcmVzdWx0c01peGVkRiA8LSBudW1lcmljKG5iQm9vdFByaW1hcnkpDQogICAgDQogICAgcmVzdWx0c01peGVkRiA8LSBhcy5udW1lcmljKHVubGlzdChyZXN1bHRzQkYpKQ0KDQogICAgc3ByaW50ZigiUmVzdWx0ICVzIiwgZmFjdG9yKQ0KICAgIHByaW50KG1lYW4ocmVzdWx0c01peGVkRikpDQogICAgcHJpbnQobWVkaWFuKHJlc3VsdHNNaXhlZEYpKQ0KICAgIHByaW50KHF1YW50aWxlKHJlc3VsdHNNaXhlZEYsIHByb2JzID0gYygwLjAyNSwgMC45NzUpKSkNCn0NCg0KIyBUaHJlYWRzIGNsb3NpbmcNCiAgc3RvcENsdXN0ZXIoY2wpDQoNCmBgYA0K