Purpose

Analysis of OC43 Recovery and equations 1 to 4 in the manuscript.

Suppress warnings and messages

knitr::opts_chunk$set(message = FALSE, warning = FALSE)
rstan_options(auto_write = TRUE)
Error in rstan_options(auto_write = TRUE) : 
  could not find function "rstan_options"

R Libraries

library(future)
library(brms)
library(dplyr)
library(loo)
library(bayesplot)
library(posterior)
library(ggplot2)
library(tidybayes)
library(ggeffects)
library(glmmTMB)
library(bayestestR)
library(logspline)
library(MASS)
library(ggeffects)
library(tidybayes)
library(EnvStats)
library(moments)
library(emmeans)
library(rstan)
rstan_options(auto_write = TRUE)

Get OC43 Recovery Data and Calculate Averages per

oc43.data <- read.csv(paste0(c19.dir,"oc43_df.csv"))
bio.avg <- oc43.data %>% 
  group_by(site, date, bio_rep) %>% 
  summarise(across(starts_with("recovery"), ~ mean(.x, na.rm=TRUE)), .groups= 'drop')
#bio.avg
final.avg <- bio.avg %>% 
  group_by(site, date) %>% 
  summarise(across(starts_with("recovery"), ~ mean(.x, na.rm=TRUE)), .groups= 'drop')

final.avg$site <- factor(final.avg$site, levels = paste0("SS", 1:11) )
final.avg$date <- as.Date(final.avg$date)

final.avg <- final.avg %>% 
  mutate(epi_month = floor_date(date, "month")) 

#filter out 2020-10-01 because it is the earliest month in the study and has 0 or 1 recovery measurement.
final.avg <- final.avg %>%
  filter(epi_month != "2020-10-01")

#final.avg

Q-Q Plot of Recovery

qqnorm(log10(final.avg$recovery), main = "Q-Q Plot of OC43 Recovery")
qqline(log10(final.avg$recovery), col = "red")

Fit an Intercept Bayesian Model to the OC43 Recovery Data

To track the overall performance of laboratory methods used in our study of SARS-CoV-2 in wastewater samples, a Bayesian model was used to estimate the recovery of the OC43 process control spiked into these samples. It uses a student-t distribution for the recovery and is a simple intercept model with no predictors.

The model can be expressed as:

\[ y_i \sim \beta_0 + \epsilon_i \] Where:

Prepare Data for the Random Intercept Model

datefact.avg <- final.avg
datefact.avg$date <- as.factor(datefact.avg$date) #for investigating date effects, if needed
datefact.avg$epi_month <- as.factor(datefact.avg$epi_month) #for investigating month effects, if needed
#datefact.avg

Bayesian Intercept Model for OC43 Recovery

# brms.1 <- brm(
#   log10(recovery) ~ 1 ,
#   data = datefact.avg,
#   family =student(),
#   prior = c(
#     prior(normal(100, 10), class = "Intercept"),
#     prior(gamma(2, 0.1), class = "nu")        #degrees of freedom for student-t
#   ),
#   warmup = 500,
#   iter = 4000,
#   control=list(adapt_delta =0.95, max_treedepth=10),
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_1.rds',
#   save_model = 'brm_1_model.txt',
#   future=TRUE
# )

Prior Summary

prior_summary(brms.1.read)
                prior     class coef group resp dpar nlpar lb ub  source
      normal(100, 10) Intercept                                     user
        gamma(2, 0.1)        nu                             1       user
 student_t(3, 0, 2.5)     sigma                             0    default

Posterior Predictive Checking (PPC) of OC43 Recovery Intercept Model

PPC generates Leave-One-Out (LOO) intervals plot for PPC. It assesses the overall predictive performance of the model and detects potential issues with model specification or data quality (i.e., outliers).

Key Elements of the Plot:

  • Y-axis: Represents the response variable (OC43 Recovery).
  • X-axis: Represents the indexed order of observations (alphabetically SS1 to SS11 and temporally ordered).
  • Observed Data Points: Shown as dark dots.
  • LOO Prediction Intervals: Vertical lines for each observation show the predicted ranges.
  • Median Predictions: Light-blue points within the intervals.

The prob = 0.5 and prob_outer = 0.95 arguments generate 50% and 95% prediction intervals. For prob= 0.5, half of the observed data points should fall within these intervals if the model is well-calibrated. Likewise, for prob_outer =0.95, 95% of the observed data should fall within these intervals.

pp_check(brms.1.read , type="loo_intervals",prob = 0.5, prob_outer= 0.95)+
  ggplot2::ylab("Recovery") +
  ggplot2::xlab("Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

Observed Values within 95% Prediction Interval

pp.draws <- posterior_predict(brms.1.read)
lower.ci <- apply(pp.draws, 2, quantile, prob = 0.025)
upper.ci <- apply(pp.draws, 2, quantile, prob = 0.975)
observed.val <- brms.1.read$data$recovery
within.interval <- (observed.val > 10^lower.ci) & (observed.val < 10^upper.ci)
n.within.interval <- sum(within.interval)
proportion.within.interval <- n.within.interval / length(observed.val)

The number of observed values within the 95% prediction interval is 648, which is 95.43 percent. This indicates that the model is accurate, as most observed data points fall within the 95% prediction interval.

Residuals for Recovery

resid.mat <- residuals(brms.1.read, type="ordinary" )
#resid.mat
mean.resid  <- apply(resid.mat, 1, mean)
#mean.resid
oc43.withresiduals.df <- brms.1.read$data %>%
  mutate(mean.resid = mean.resid,
  row.index = row_number() )
#oc43.withresiduals.df

ggplot(oc43.withresiduals.df, aes(x= row.index, y=mean.resid))+
  geom_point() +
  labs(title ="Mean OC43 Residuals by Sample",
       x = "Sample",
       y = "Mean Residual"
       )

Q-Q Plot of Recovery Residuals

qqnorm(oc43.withresiduals.df$mean.resid, main = "Q-Q Plot of OC43 Recovery Residuals")
qqline(oc43.withresiduals.df$mean.resid, col = "red")

Summary of Residuals

The residuals are symmetrically centered around 0 between -1 and 1 and Q-Q residual plot indicates that the residuals are normally distributed. The consistent performance of the OC43 process control across all wastewater samples demonstrates that the laboratory methods used in our SARS-CoV-2 study are reliable.

SARS-CoV-2 Section

Get SARS-CoV-2 Data

c19.dir <- "D:/c19/seq_manuscript/r/"  
c19.data <- read.csv(paste0(c19.dir, "sewershed_data.csv"),header=TRUE,na.strings=c("","NA"))
c19.data$date <-as.Date(c19.data$date)
c19.data$site <-as.factor(c19.data$site)
c19.data$phase <- as.factor(c19.data$phase)
c19.data$phase <- relevel(c19.data$phase, ref = "pre-VOC" )

Section for Equation 1

Does SARS-CoV-2 shedding vary by sewershed communities?

The amount of SARS-CoV-2 entering wastewater treatment systems depends on the amount of feces excreted per person, the volume of wastewater per household, and the number of infected individuals.

The shedding function is based on the following equation (see Prasek et al. 2022;10.1016/j.scitotenv.2022.156535):

Shedding Function

\[ S_w= \frac{C_w \times F_w}{ M_f\times N_i} \tag{Eq. 1} \]

This equation shows how \(S_f\) (the amount of SARS-CoV-2 shed per gram) can be estimated by using the concentration of N2 gene in wastewater \(C_w\) (copies/L), the wastewater flow \(F_w\) (L/day), the mass of feces excreted by a person \(M_f\) (128 g/day), and the number of infected persons \(N_i\) (COVID-19 cases).

According to Rose (2015,DOI:10.1080/10643389.2014.1000761), the quantity of feces excreted per person/day ranges from 51–796 g with a median, mean, and sigma of 128, 149, and 95.

Random Intercept Model for Fecal Shedding

Regression was used to determine if there are differences in virus shedding. The model is a random intercept model with a Gaussian distribution. The model can be expressed as:

\[ y_i \sim \beta_0 + u_j + \epsilon_i \] Where:

  • \(y_i\) represents the outcome variable \(S_w\) (“fecal_load”) for observation \(i\), \(\beta_0\) is the fixed intercept

  • \(u_j\) is the random intercept for site \(j\)

  • \(\epsilon_i\) is the error term for observation \(i\)

Fecal Shedding BRMS Random Intercept Model

# brm.fecal.load.rand <- brm(
#   log10(fecal_load) ~ 1+ (1|site),
#   data = c19.data,
#   family =gaussian,
#   control=list(adapt_delta =0.95,max_treedepth=10), # try this 0.96 next
#   warmup = 500,
#   iter = 4000,
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_fecal_load_rand.rds', # this should be deleted in the Project directory each time model rerun
#   save_model = 'brm.fecal.load.rand_mode.txt',
#   future=TRUE
# )

Load and Print Saved Fecal Shedding Model Results

fs.mo1 <- brm(file="brm_fecal_load_rand.rds")
print(fs.mo1, digits=4)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: log10(fecal_load) ~ 1 + (1 | site) 
   Data: c19.data (Number of observations: 871) 
  Draws: 4 chains, each with iter = 4000; warmup = 500; thin = 1;
         total post-warmup draws = 14000

Multilevel Hyperparameters:
~site (Number of levels: 11) 
              Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sd(Intercept)   0.2945    0.0815   0.1836   0.4962 1.0010     2029     3134

Regression Coefficients:
          Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
Intercept   8.4814    0.0915   8.2975   8.6622 1.0012     1502     2565

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sigma   0.3173    0.0078   0.3024   0.3329 1.0006     6744     7175

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

Prior Summary

prior_summary(fs.mo1)
                  prior     class      coef group resp dpar nlpar lb ub       source
 student_t(3, 8.5, 2.5) Intercept                                            default
   student_t(3, 0, 2.5)        sd                                  0         default
   student_t(3, 0, 2.5)        sd            site                  0    (vectorized)
   student_t(3, 0, 2.5)        sd Intercept  site                  0    (vectorized)
   student_t(3, 0, 2.5)     sigma                                  0         default

Posterior Predictive Checking (PPC) of Fecal Shedding Random Intercept Model

pp_check(fs.mo1, type="loo_intervals",prob = 0.5,prob_outer= 0.95) +
  ggplot2::ylab("Fecal Load") +
  ggplot2::xlab("Sample Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

Halfeye Plot of the Sewershed Intercepts

site_order <- c("SS1", "SS2", "SS3", "SS4", "SS5", "SS6", "SS7", "SS8", "SS9", "SS10", "SS11")

#extract random intercepts
fs.mo1  %>%
  spread_draws(r_site[site,term]) %>%
  filter(term %in% c("Intercept")) %>%
  ungroup() %>%
  mutate(site = factor(site, levels = site_order, ordered = TRUE)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye(.width = c(.50, .95)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_wrap(~term, scales = "free_x") +
  labs(x = "Random Effect", y = "Site",
       title = "Random Effects by Site")+
  scale_y_discrete(limits = rev(site_order)) 

Leave-One-Out Cross-Validation (LOO-CV) Section for the Fecal Shedding Model

LOO-CV is a statistical method used to estimate the performance of models on data not used during the training of the model. It is a specific configuration of k-fold cross-validation where k is set to the number of examples in the dataset. For a dataset with n observations, LOO-CV will create n different models, each time leaving out one observation from the training set to evaluate performance.

LOO-CV

loo.fs.mo1<- loo(fs.mo1)

Fecal Shedding Model: Pareto Smoothed Importance Sampling (PSIS)

Interpretation of PSIS k values:

  • k < 0.5: The estimate is reliable

  • 0.5 < k < 0.7: The estimate is somewhat reliable

  • k > 0.7: The estimate is unreliable and should be treated with caution

All 3 models have k < 0.5, which means their estimates are reliable.

Pareto Smoothed Importance Sampling (PSIS) Estimates Diagnostic Plot

plot(loo.fs.mo1)

Contrasts of Fecal Shedding Intercepts

contrast.summary <- fs.mo1 %>%
  spread_draws(r_site[site,]) %>%
  compare_levels(r_site, by = site) %>%
  group_by(site) %>%
  summarize(
    median = median(r_site),
    lower_95 = quantile(r_site, 0.025),
    upper_95 = quantile(r_site, 0.975)
  ) 

contrast.summary %>% arrange(-desc(median))

Plot of Fecal Shedding Contrasts Between Sewersheds

#library(tidybayes)
fs.mo1  %>%
  spread_draws(r_site[site,]) %>%
  compare_levels(r_site, by = site) %>%
  ungroup() %>%
  mutate(site = reorder(site, r_site)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye(.width = c(.50, .95)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  theme(axis.text.y = element_text(size = 6))

This contrast plot of fecal shedding shows most paired sewersheds have credible differences (i.e., the difference does not contain 0).

Is SS1 fecal shedding of SARS-CoV-2 credibly greater than other 10 Sewersheds?

SS1 has the highest fecal shedding followed by SS6. All the other sewersheds have fecal shedding estimates that are less than SS6. If SS1 is credibly greater than SS6 then it is also greater than the others.

Bayesian Hypothesis: SS1 > SS6

fs.mo1.post <- posterior_samples(fs.mo1)
ss1.samples <- fs.mo1.post[, "r_site[SS1,Intercept]"]
ss6.samples <- fs.mo1.post[, "r_site[SS6,Intercept]"]
diff.samples <- ss1.samples - ss6.samples
prob.ss1.greater <- mean(diff.samples > 0)
bci.diff <- quantile(diff.samples, c(0.025, 0.975))
hist(diff.samples, main="95% Credible Interval for SS1 - SS6", xlab="Difference")

Conclusion of SS1 vs SS6

The histogram shows the 95% credible interval of the difference of SS1 minus SS6 posterior samples. The 95% CI of the difference is 0.2378 to 0.4169. The probability that SS1 is greater than SS6 is 1. This analysis seems to be at odds with the visual inspection of the half-eye plot (see Section “Halfeye Plot of the Sewershed Intercepts”), which appears to show that SS1 and SS6 share a common range with a marginal overlap of 95% credible intervals. However, the hypothesis test ‘SS1 > SS6’ is based on calculated posterior differences draw-by-draw using the joint distribution of both parameters. This underscores the importance of using numerical precision for hypothesis testing rather than relying solely on visual inspection of random effects. Also, the small overlap of distributions observed with the half-eye plot doesn’t necessarily contradict the hypothesis result; it is more a matter of how uncertainty is represented and combined.

Fecal Shedding BRMS Model with SARS-CoV-2 Phase Fixed Effect

The Fecal Shedding Random Intercept Model (fs.mo1) above shows estimated fecal shedding of SARS-CoV-2 varies by sewershed location, which accounts for 46% of the total variance. Accounting for SARS-CoV-2 VOC shedding rates may improve model performance and therefore better explain the dynamics of infections. VOC phases refers to the time when distinct variants of concern were predominant during the pandemic.

Below is the model with a fixed effect for phase. The model can be expressed as: \[ \log_{10}(y_{ij}) \sim \beta_0 + \beta x_{ij} + u_j + \epsilon_{ij} \\ u_j \sim N(0, \sigma_u^2)\\ \epsilon_{ij} \sim N(0, \sigma_\epsilon^2) \]

Where:

\(y_{ij}\) represents the outcome variable “fecal_load” for observation \(i\) in site \(j\)

\(\beta_0\) is the overall intercept

\(\beta\) is the coefficient for the fixed effect predictor \(x_{ij}\)

\(x_{ij}\) is the value of the fixed effect predictor for observation \(i\) in site \(j\)

\(u_j\) is the random intercept for site \(j\)

\(\epsilon_{ij}\) is the error term for observation \(i\) in site \(j\)

BRMS Code with Phase as a Fixed Effect

#use defaults priors
# brm.fecal.load.phase.rand <- brm(
#   log10(fecal_load) ~ 1+ phase + (1|site),
#   data = c19.data,
#   family =gaussian,
#   control=list(adapt_delta =0.95,max_treedepth=10), # try this 0.96 next
#   warmup = 500,
#   iter = 4000,
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_fs_phase.rds', # this should be deleted in the Project directory each time model rerun
#   save_model = 'brm_fs_phase_model.txt'
# )

Prior Summary

prior_summary(fs.mo2)
                  prior     class         coef group resp dpar nlpar lb ub       source
                 (flat)         b                                               default
                 (flat)         b   phasealpha                             (vectorized)
                 (flat)         b   phasedelta                             (vectorized)
                 (flat)         b phaseomicron                             (vectorized)
 student_t(3, 8.5, 2.5) Intercept                                               default
   student_t(3, 0, 2.5)        sd                                     0         default
   student_t(3, 0, 2.5)        sd               site                  0    (vectorized)
   student_t(3, 0, 2.5)        sd    Intercept  site                  0    (vectorized)
   student_t(3, 0, 2.5)     sigma                                     0         default

Plot of Pairwise Site Differences of the Means

The first sewershed in each pair has the greater COVID-19 log10(case/100k) mean. This plot compares pairwise differences of the means.

#library(tidybayes)
fs.mo2 %>%
  spread_draws(r_site[site,]) %>%
  compare_levels(r_site, by = site) %>%
  ungroup() %>%
  mutate(site = reorder(site, r_site)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye() +
  geom_vline(xintercept = 0, linetype = "dashed") 

PPC

pp_check(fs.mo2 , type="loo_intervals",prob = 0.5,prob_outer= 0.95) +
  ggplot2::ylab("Fecal Load") +
  ggplot2::xlab("Sample Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

LOO-CV for Fecal Shedding Model with Phase Fixed Effect

loo.phase <- loo(fs.mo2)

LOO-CV Results

loo.phase

Computed from 14000 by 871 log-likelihood matrix.
------
MCSE of elpd_loo is 0.0.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.4]).

All Pareto k estimates are good (k < 0.7).
See help('pareto-k-diagnostic') for details.

PSIS

plot(loo.phase)

Compare Models via LOO-CV

compare.loo <- loo_compare(loo.fs.mo1,loo.phase)
print(compare.loo, digits=4)
       elpd_diff se_diff 
fs.mo2   0.0000    0.0000
fs.mo1 -12.2493   42.3244

Summary of LOO-CV Comparisons of the Two Fecal Shedding Models: The 2SE Rule

Using the “2SE rule” to estimate 95% confidence intervals of the random intercept model, which does not contain the phase factor, has a 95% CI of-12.2 + c(-2,2) * 5.6 = (-23.4, -1.0). This CI does not contain 0 indicating the random intercept model is an inferior model in terms of predictive accuracy.

Hypothesis 1: Alpha Shedding is Greater than Delta

alpha.vs.delta.hyp <- brms::hypothesis(fs.mo2, "phasealpha - phasedelta > 0", alpha=0.05)
print(alpha.vs.delta.hyp, digits=4)
Hypothesis Tests for class b:
---
'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
'*': For one-sided hypotheses, the posterior probability exceeds 95%;
for two-sided hypotheses, the value tested against lies outside the 95%-CI.
Posterior probabilities of point hypotheses assume equal prior probabilities.

Manual Version for Examining if Alpha is Greater than Delta

fs.mo2.post <- posterior_samples(fs.mo2)
alpha.samples <- fs.mo2.post[, "b_phasealpha"]
delta.samples <- fs.mo2.post[, "b_phasedelta"]
phase1.diff.samples <- alpha.samples - delta.samples
prob.alpha.greater <- mean(phase1.diff.samples > 0)
phase1.diff <- quantile(phase1.diff.samples, c(0.025, 0.975))
hist(phase1.diff.samples, main="95% Credible Interval for Alpha - Delta", xlab="Difference")

The histogram shows the 95% credible interval of the difference of Alpha minus Delta posterior samples. The 95% CI of the difference is 0.0348082 to 0.1354397. The probability that Alpha is greater than Delta is 0.9995.

Hypothesis 2: Delta Shedding is Greater than Omicron

delta.vs.omicron.hyp <- brms::hypothesis(fs.mo2, "phasedelta - phaseomicron > 0", alpha=0.05)
print(delta.vs.omicron.hyp, digits=4)
Hypothesis Tests for class b:
---
'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
'*': For one-sided hypotheses, the posterior probability exceeds 95%;
for two-sided hypotheses, the value tested against lies outside the 95%-CI.
Posterior probabilities of point hypotheses assume equal prior probabilities.

Summary of Hypothesis Testing

The hypothesis tests for “Alpha > Delta” and “Delta > Omicron” show that Alpha shedding is credibly greater than Delta, Delta is credibly greater than Omicron, and therefore, Alpha is greater than Omicron.

Pairwise Comparisons: Contrasts

Another way to assess the differences between virus shedding is to use pairwise comparisons via the emmeans R package, which works well with brms objects and provides a convenient way to estimate marginal means and contrasts of the entire model. Its pairwise contrasts include additional uncertainty due to random effects and residuals, which can be useful for understanding the overall model structure.

Marginal Means and Contrasts of the Fecal Shedding Model with Phase Fixed Effect

#library(emmeans)
m6.pairwise <- emmeans(fs.mo2, pairwise ~ phase)
print(m6.pairwise, digits=4)
$emmeans
 phase   emmean lower.HPD upper.HPD
 pre-VOC   8.43      8.26      8.64
 alpha     8.55      8.36      8.73
 delta     8.46      8.27      8.64
 omicron   8.38      8.18      8.57

Point estimate displayed: median 
HPD interval probability: 0.95 

$contrasts
 contrast            estimate lower.HPD upper.HPD
 (pre-VOC) - alpha    -0.1105  -0.17018   -0.0504
 (pre-VOC) - delta    -0.0254  -0.09064    0.0398
 (pre-VOC) - omicron   0.0570  -0.02426    0.1389
 alpha - delta         0.0849   0.03412    0.1349
 alpha - omicron       0.1669   0.09450    0.2340
 delta - omicron       0.0819   0.00497    0.1558

Point estimate displayed: median 
HPD interval probability: 0.95 

Summary of emmeans Contrasts

  • HPD intervals: The presence of “lower.HPD” and “upper.HPD” columns indicates Highest Posterior Density intervals, which are Bayesian credible intervals.

  • HPD interval probability: The “HPD interval probability: 0.95” indicates that these are 95% credible intervals.

  • Major findings: The 95% HPD does not contain 0 for ‘Alpha - Delta’ and ‘Alpha - Omicron’ and ‘Delta - Omicron’ pairs, suggesting that Alpha shedding is credibly greater than Delta and Omicron, and Delta shedding is credibly greater than Omicron. These results agree with the brms::hypothesis tests above.

  • pre-VOC vs other: The 95% HPD contains 0 for ‘(pre-VOC) - delta’ and ’ (pre-VOC) - delta’ pairs, indicating pre-VOC is not credibly different from them. The 95% HPD does not contain 0 for ‘(pre-VOC) - alpha’ indicating pre-VOC is credibly less than Alpha.

Section for Equations 2, 3 and 4

Which model best predicts COVID-19 cases?

Three different multilevel Bayesian models were designed to predict COVID-19 cases using covariates such as N2 gene load, SARS-CoV-2 variants (e.g., pre-VOC, Alpha, Delta, and Omicron), and sewershed location.

Model 1: Bayesian linear regression model with a fixed effect for flow-adjusted N2 gene and random intercept for sewershed location.

\[ y_{ij} = \beta_0 + \beta_1 x_{ij} + b_{0j} + \epsilon_{ij} \tag {Eq. 2} \]

Explanation of Model 1 Terms

  • \(y_{ij}\): Response variable for the i-th observation in the j-th group, where group is sewershed location.

  • \(\beta_0\): Fixed intercept, representing the overall mean effect across all sewersheds.

  • \(\beta_1\): Fixed slope for the predictor \(x_{ij}\) (i.e., log_n2_flowadj), representing the effect of the predictor on the response variable.

  • \(b_{0j}\): Random intercept for the j-th group (i.e., sewershed site), representing the group-specific differences from the overall intercept.

  • \(\epsilon_{ij}\): Residual error for the i-th observation in the j-th group, representing the unexplained variability.

  • The Model 1 formula is log_case100000 ~ 1 + log_n2_flowadj + (1 | site), which means the log-transformed COVID-19 cases per 100,000 people is modeled as a function of the log-transformed adjusted flow (log_n2_flowadj) and a random intercept for each sewershed site (1 | site).

M1: BRMS Code

# #Define priors for the intercept and slope
# prior_intercept <- prior(normal(0, 100), class = Intercept)
# prior_slope <- prior(normal(0, 1), class = b)
# 
# #Define sigma prior
# prior_sigma <- set_prior("cauchy(0, 5)", class = "sigma")
# 
# brm.partpool.norm <- brm(
#   log_case100000 ~ 1 + log_n2_flowadj + (1| site),
#   data = c19.data,
#   family =gaussian,
#   prior = c(
#     prior_intercept,
#     prior_slope,
#     prior_sigma
#   ),
#   warmup = 500,
#   iter = 4000,
#   control=list(adapt_delta =0.95, max_treedepth=10),
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_partpool_norm_priors.rds',
#   save_model = 'brm_partpool_norm_priors_model.txt',
#   future=TRUE
# )

M1: Print Saved Results

mo1 <- brm(file="brm_partpool_norm_priors.rds")
print(mo1, digits=4)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: log_case100000 ~ 1 + log_n2_flowadj + (1 | site) 
   Data: c19.data (Number of observations: 892) 
  Draws: 4 chains, each with iter = 4000; warmup = 500; thin = 1;
         total post-warmup draws = 14000

Multilevel Hyperparameters:
~site (Number of levels: 11) 
              Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sd(Intercept)   0.5338    0.1406   0.3403   0.8809 1.0028     1754     3703

Regression Coefficients:
               Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
Intercept       -7.4963    0.2966  -8.0914  -6.9163 1.0007     3949     5948
log_n2_flowadj   0.7397    0.0203   0.6996   0.7793 1.0004     6763     7666

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sigma   0.3229    0.0077   0.3083   0.3386 1.0002     6696     6611

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

M1: Prior Summary

prior_summary(mo1)
                prior     class           coef group resp dpar nlpar lb ub       source
         normal(0, 1)         b                                                    user
         normal(0, 1)         b log_n2_flowadj                             (vectorized)
       normal(0, 100) Intercept                                                    user
 student_t(3, 0, 2.5)        sd                                       0         default
 student_t(3, 0, 2.5)        sd                 site                  0    (vectorized)
 student_t(3, 0, 2.5)        sd      Intercept  site                  0    (vectorized)
         cauchy(0, 5)     sigma                                       0            user

M1: Print Fit Results

print(mo1$fit, digits=4)
Inference for Stan model: anon_model.
4 chains, each with iter=4000; warmup=500; thin=1; 
post-warmup draws per chain=3500, total post-warmup draws=14000.

                            mean se_mean       sd      2.5%       25%       50%       75%     97.5% n_eff   Rhat
b_Intercept              -7.4963  0.0047   0.2966   -8.0914   -7.6923   -7.4932   -7.2954   -6.9163  3937 1.0003
b_log_n2_flowadj          0.7397  0.0002   0.0203    0.6996    0.7258    0.7398    0.7536    0.7793  6775 1.0000
sd_site__Intercept        0.5338  0.0033   0.1406    0.3403    0.4344    0.5081    0.6030    0.8809  1854 1.0026
sigma                     0.3229  0.0001   0.0077    0.3083    0.3177    0.3228    0.3279    0.3386  6641 1.0002
Intercept                 1.3456  0.0035   0.1679    1.0161    1.2396    1.3461    1.4529    1.6687  2243 1.0012
r_site[SS1,Intercept]    -0.6526  0.0035   0.1711   -0.9841   -0.7632   -0.6518   -0.5446   -0.3129  2328 1.0011
r_site[SS10,Intercept]    0.1741  0.0036   0.1717   -0.1527    0.0643    0.1725    0.2820    0.5155  2319 1.0011
r_site[SS11,Intercept]    0.1537  0.0036   0.1712   -0.1704    0.0424    0.1531    0.2617    0.4930  2298 1.0013
r_site[SS2,Intercept]     0.1288  0.0036   0.1714   -0.1966    0.0178    0.1275    0.2359    0.4722  2290 1.0012
r_site[SS3,Intercept]     0.2805  0.0036   0.1711   -0.0504    0.1695    0.2796    0.3883    0.6213  2315 1.0012
r_site[SS4,Intercept]    -0.3923  0.0035   0.1710   -0.7234   -0.5010   -0.3921   -0.2847   -0.0528  2322 1.0012
r_site[SS5,Intercept]     0.4650  0.0036   0.1726    0.1378    0.3532    0.4632    0.5718    0.8121  2364 1.0012
r_site[SS6,Intercept]    -0.7903  0.0035   0.1707   -1.1226   -0.9000   -0.7904   -0.6822   -0.4532  2331 1.0011
r_site[SS7,Intercept]    -0.0666  0.0036   0.1709   -0.3921   -0.1769   -0.0673    0.0407    0.2697  2275 1.0012
r_site[SS8,Intercept]     0.7655  0.0036   0.1737    0.4355    0.6524    0.7642    0.8730    1.1143  2351 1.0011
r_site[SS9,Intercept]    -0.0314  0.0036   0.1708   -0.3582   -0.1420   -0.0317    0.0762    0.3095  2315 1.0012
prior_Intercept          -0.2559  0.8378 100.2397 -196.1637  -68.9480    0.0552   67.0257  195.0874 14316 1.0001
prior_b                   0.0114  0.0085   1.0011   -1.9395   -0.6581    0.0109    0.6875    1.9818 13954 1.0000
prior_sigma              28.5709  2.9664 346.1256    0.1966    1.9786    4.8647   11.6964  122.5918 13614 0.9999
prior_sd_site             2.7630  0.0262   3.1019    0.0873    0.8867    1.9298    3.5581   10.4344 14057 0.9999
lprior                  -10.0383  0.0005   0.0248  -10.0949  -10.0510  -10.0357  -10.0220   -9.9981  2860 1.0014
lp__                   -283.2441  0.0781   3.5520 -291.1038 -285.4774 -282.9222 -280.6651 -277.2153  2067 1.0028
z_1[1,1]                 -1.2985  0.0099   0.4372   -2.1707   -1.5935   -1.2890   -0.9994   -0.4777  1938 1.0018
z_1[1,2]                  0.3438  0.0067   0.3218   -0.2677    0.1250    0.3403    0.5615    0.9880  2318 1.0014
z_1[1,3]                  0.3033  0.0067   0.3191   -0.2979    0.0832    0.3030    0.5168    0.9387  2289 1.0016
z_1[1,4]                  0.2538  0.0067   0.3174   -0.3506    0.0337    0.2530    0.4667    0.8930  2277 1.0013
z_1[1,5]                  0.5555  0.0070   0.3355   -0.0828    0.3222    0.5546    0.7788    1.2275  2326 1.0015
z_1[1,6]                 -0.7811  0.0081   0.3639   -1.4956   -1.0275   -0.7745   -0.5332   -0.0857  2037 1.0015
z_1[1,7]                  0.9218  0.0078   0.3759    0.2149    0.6615    0.9156    1.1756    1.6762  2330 1.0020
z_1[1,8]                 -1.5723  0.0111   0.4831   -2.5362   -1.8983   -1.5623   -1.2397   -0.6593  1900 1.0021
z_1[1,9]                 -0.1344  0.0067   0.3146   -0.7374   -0.3504   -0.1337    0.0790    0.4868  2183 1.0012
z_1[1,10]                 1.5188  0.0099   0.4663    0.6489    1.1957    1.5093    1.8332    2.4650  2240 1.0023
z_1[1,11]                -0.0641  0.0066   0.3129   -0.6596   -0.2811   -0.0641    0.1456    0.5533  2250 1.0013

Samples were drawn using NUTS(diag_e) at Tue Feb  4 18:01:44 2025.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at 
convergence, Rhat=1).

M1: Posterior Draws

mo1.draws <-mo1 %>% as_draws_array()
mo1.summary <- summarize_draws(mo1.draws)
mo1.summary 
write.csv(mo1.summary , "model1_results.csv")

M1: Post Predictive Check (PPC)

pp_check(mo1, type="loo_intervals",prob = 0.5, prob_outer= 0.95)+
  ggplot2::ylab("Cases per 100,000 (log10)") +
  ggplot2::xlab("Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

M1: Plot Conditional Effects

This plot shows how the response variable (log_case100000) changes as log_n2_flowadj varies, while holding other predictors constant.

conditional_effects(mo1, effects=c("log_n2_flowadj"))

M1: Plot for Intercept

This plot shows how the sites-specific baseline varies across the 11 sewersheds.

#library(tidybayes)
#define custom order for sewershed sites
site_order <- c("SS1", "SS2", "SS3", "SS4", "SS5", "SS6", "SS7", "SS8", "SS9", "SS10", "SS11")

#extract random intercepts
mo1  %>%
  spread_draws(r_site[site,term]) %>%
  filter(term %in% c("Intercept")) %>%
  ungroup() %>%
  mutate(site = factor(site, levels = site_order, ordered = TRUE)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye(.width = c(.50, .95)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_wrap(~term, scales = "free_x") +
  labs(x = "Random Effect", y = "Site",
       title = "Random Effects by Site")+
 
  scale_y_discrete(limits = rev(site_order))  #reverse site order for top-to-bottom layout

M1: Summary of Results

  • The model was fit using 4 MCMC chains, each with 4000 iterations (500 warmup), resulting in 14,000 (i.e., 16000 minus 4 * 500 burnins) total post-warmup draws.

  • The group-level (random) effect shows that the standard deviation of the sewershed intercept across sites is 0.5375 with a 95% credible interval of [0.3352, 0.8867].

Fixed Effects - The population-level (fixed) effects show that:

  • The estimated intercept is -7.4963 with a 95% credible interval of [-8.0914, -6.9163].

  • The estimated coefficient for log_n2_flowadj is 0.7397 with a 95% credible interval of [0.6996, 0.7793]. This indicates that for every 1-unit increase in log_n2_flowadj, log_case100000 increases by approximately 0.74 on average.

Model Fit

  • The residual standard deviation (sigma) is estimated to be 0.3229 with a 95% credible interval of [0.3083, 0.3386].

Model Diagnostics

  • The Rhat values are all close to 1, indicating good convergence of the MCMC chains. The Bulk_ESS and Tail_ESS values are also reasonably high, suggesting the estimates are well-informed by the data.

PPC and Conditional Effects

  • PPC: This showed the observed data fell within both 50% and 95% LOO intervals and the conditional effects plot show a positive, linear relationship between flow-adjusted N2 and cases per 100,000.

MCMC Intervals of Model 1

Random Effects for Intercepts

The model estimates site-specific intercepts, representing the baseline log cases per 100,000 when log_n2_flowadj is zero:

  • Highest intercepts: SS5 and SS8

  • Lowest intercepts: SS1, SS4, and SS6

  • Uncertainty: Intervals that don’t include zero suggest stronger evidence for a site-specific effect.

  • Precision: The standard errors are relatively consistent across sites, indicating similar precision in the estimates.

Intraclass Correlation Coefficient (ICC)

\[ICC=0.5338^2/(0.5338^2 + 0.3229^2)\approx 0.7321 \] The ICC is 73.2%, which indicates most of the variance is between sewershed locations rather than within them.

Model 2: Bayesian linear regression model with a random slope for flow-adjusted N2 gene and random intercept for sewershed location.

\[ y_{ij} = \beta_0 + \beta_1 x_{ij} + b_{0j} + b_{1j} x_{ij} + \epsilon_{ij} \tag{Eq. 3} \]

Explanation of Model 2 Terms

  • \(y_{ij}\): Response variable (log_case100000) for the i-th observation in the j-th group, where group is sewershed location. See Model 1 for the sewershed abbreviations.

  • \(\beta_0\): Fixed intercept, representing the overall mean effect across all sewershed groups.

  • \(\beta_1\): Fixed slope for the predictor \(x_{ij}\) (log_n2_flowadj ), representing the effect of the predictor on the response variable.

  • \(b_{0j}\): Random intercept for the j-th group, representing the sewershed group-specific differences from the overall intercept.

  • \(b_{1j}\): Random slope for the predictor \(x_{ij}\) in the j-th group, representing the sewershed group-specific differences in the effect of the predictor.

  • \(\epsilon_{ij}\): Residual error for the i-th observation in the j-th group, representing the unexplained variability.

M2: BRMS Code - Random Intercept, Random Slope

# #priors for the intercept and slope
# prior_intercept <- prior(normal(0, 100), class = Intercept)
# prior_slope <- prior(normal(0, 1), class = b)
# 
# #sigma prior
# prior_sigma <- set_prior("cauchy(0, 5)", class = "sigma")
# 
# brm.partpool.randrand <- brm(
#   log_case100000 ~ 1+ log_n2_flowadj + (1+log_n2_flowadj|site),
#   data = c19.data,
#   family =gaussian,
#   prior = c(
#     prior_intercept,
#     prior_slope,
#     prior_sigma
#   ),
#   control=list(adapt_delta =0.95,max_treedepth=10),
#   warmup = 500,
#   iter = 4000,
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_partpool_randrand.rds',
#   save_model = 'brm_partpool_randrand_model.txt',
#   future=TRUE
# )

M2: Load and Print Saved Results

mo2 <- brm(file="brm_partpool_randrand.rds")
print(mo2, digits=4)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: log_case100000 ~ 1 + log_n2_flowadj + (1 + log_n2_flowadj | site) 
   Data: c19.data (Number of observations: 892) 
  Draws: 4 chains, each with iter = 4000; warmup = 500; thin = 1;
         total post-warmup draws = 14000

Multilevel Hyperparameters:
~site (Number of levels: 11) 
                              Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sd(Intercept)                   1.8337    0.4975   1.0525   2.9867 1.0009     4266     6431
sd(log_n2_flowadj)              0.1275    0.0382   0.0664   0.2163 1.0005     3991     6364
cor(Intercept,log_n2_flowadj)  -0.9482    0.0479  -0.9917  -0.8196 1.0006     5519     7909

Regression Coefficients:
               Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
Intercept       -7.6546    0.6136  -8.8863  -6.4530 1.0016     4528     6533
log_n2_flowadj   0.7506    0.0446   0.6639   0.8402 1.0011     4894     6261

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sigma   0.3164    0.0076   0.3019   0.3317 1.0005    22241    10023

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

M2: Prior Summary

The priors for Model 2 are chosen to be weakly informative.

prior_summary(mo2)
                prior     class           coef group resp dpar nlpar lb ub       source
         normal(0, 1)         b                                                    user
         normal(0, 1)         b log_n2_flowadj                             (vectorized)
       normal(0, 100) Intercept                                                    user
 lkj_corr_cholesky(1)         L                                                 default
 lkj_corr_cholesky(1)         L                 site                       (vectorized)
 student_t(3, 0, 2.5)        sd                                       0         default
 student_t(3, 0, 2.5)        sd                 site                  0    (vectorized)
 student_t(3, 0, 2.5)        sd      Intercept  site                  0    (vectorized)
 student_t(3, 0, 2.5)        sd log_n2_flowadj  site                  0    (vectorized)
         cauchy(0, 5)     sigma                                       0            user

M2: Print Fit Results

print(mo2$fit, digits=4)
Inference for Stan model: anon_model.
4 chains, each with iter=4000; warmup=500; thin=1; 
post-warmup draws per chain=3500, total post-warmup draws=14000.

                                         mean se_mean       sd      2.5%       25%       50%       75%     97.5% n_eff   Rhat
b_Intercept                           -7.6546  0.0092   0.6136   -8.8863   -8.0406   -7.6477   -7.2607   -6.4530  4477 1.0017
b_log_n2_flowadj                       0.7506  0.0006   0.0446    0.6639    0.7222    0.7496    0.7783    0.8402  4826 1.0011
sd_site__Intercept                     1.8337  0.0076   0.4975    1.0525    1.4860    1.7697    2.1038    2.9867  4329 1.0008
sd_site__log_n2_flowadj                0.1275  0.0006   0.0382    0.0664    0.1011    0.1230    0.1483    0.2163  4025 1.0005
cor_site__Intercept__log_n2_flowadj   -0.9482  0.0006   0.0479   -0.9917   -0.9774   -0.9622   -0.9361   -0.8196  6018 1.0003
sigma                                  0.3164  0.0001   0.0076    0.3019    0.3112    0.3162    0.3214    0.3317 22004 1.0000
Intercept                              1.3168  0.0028   0.1823    0.9542    1.2027    1.3170    1.4308    1.6785  4365 1.0014
r_site[SS1,Intercept]                 -2.3239  0.0103   0.9735   -4.3252   -2.9518   -2.2821   -1.6728   -0.5028  8962 1.0006
r_site[SS10,Intercept]                 0.1749  0.0101   0.8655   -1.5518   -0.3844    0.1811    0.7366    1.8703  7367 1.0007
r_site[SS11,Intercept]                -0.8238  0.0105   0.8803   -2.6069   -1.3962   -0.8051   -0.2325    0.8451  7074 1.0005
r_site[SS2,Intercept]                  0.8720  0.0099   0.8095   -0.6867    0.3347    0.8510    1.4017    2.5017  6680 1.0006
r_site[SS3,Intercept]                  0.1292  0.0104   0.8583   -1.5789   -0.4241    0.1295    0.6827    1.8228  6829 1.0004
r_site[SS4,Intercept]                 -1.4667  0.0101   0.8560   -3.1831   -2.0188   -1.4425   -0.8959    0.1655  7162 1.0006
r_site[SS5,Intercept]                  1.9144  0.0099   0.8815    0.2718    1.3070    1.8920    2.4865    3.7186  7870 1.0005
r_site[SS6,Intercept]                 -1.1003  0.0099   0.8584   -2.7741   -1.6577   -1.1019   -0.5342    0.5699  7593 1.0008
r_site[SS7,Intercept]                  1.3272  0.0101   0.8264   -0.2462    0.7745    1.2980    1.8526    3.0261  6714 1.0008
r_site[SS8,Intercept]                  2.8467  0.0102   0.8606    1.2419    2.2556    2.8166    3.3954    4.6254  7175 1.0009
r_site[SS9,Intercept]                 -1.7206  0.0120   1.0169   -3.8258   -2.3625   -1.6857   -1.0279    0.1789  7187 1.0001
r_site[SS1,log_n2_flowadj]             0.1333  0.0007   0.0742   -0.0055    0.0834    0.1306    0.1812    0.2858 10032 1.0004
r_site[SS10,log_n2_flowadj]            0.0030  0.0007   0.0697   -0.1323   -0.0420    0.0021    0.0480    0.1431  8699 1.0003
r_site[SS11,log_n2_flowadj]            0.0858  0.0008   0.0698   -0.0442    0.0386    0.0838    0.1310    0.2297  8173 1.0001
r_site[SS2,log_n2_flowadj]            -0.0616  0.0007   0.0642   -0.1920   -0.1034   -0.0600   -0.0182    0.0615  7885 1.0003
r_site[SS3,log_n2_flowadj]             0.0156  0.0008   0.0680   -0.1174   -0.0289    0.0143    0.0592    0.1522  7860 1.0001
r_site[SS4,log_n2_flowadj]             0.0900  0.0007   0.0659   -0.0358    0.0457    0.0880    0.1331    0.2227  8123 1.0003
r_site[SS5,log_n2_flowadj]            -0.1213  0.0007   0.0702   -0.2648   -0.1667   -0.1192   -0.0732    0.0103  9368 1.0002
r_site[SS6,log_n2_flowadj]             0.0256  0.0007   0.0646   -0.1022   -0.0174    0.0269    0.0676    0.1521  8376 1.0005
r_site[SS7,log_n2_flowadj]            -0.1159  0.0007   0.0649   -0.2503   -0.1568   -0.1138   -0.0721    0.0069  7641 1.0005
r_site[SS8,log_n2_flowadj]            -0.1825  0.0008   0.0697   -0.3277   -0.2270   -0.1800   -0.1344   -0.0529  8570 1.0005
r_site[SS9,log_n2_flowadj]             0.1418  0.0009   0.0805   -0.0057    0.0864    0.1390    0.1925    0.3104  7844 1.0000
prior_Intercept                        0.6414  0.8601 100.2844 -196.1053  -67.3463    0.8525   68.3187  194.6846 13594 1.0000
prior_b                                0.0128  0.0083   0.9980   -1.9391   -0.6626    0.0144    0.7002    1.9554 14374 0.9999
prior_sigma                           33.3944  5.0353 596.7249    0.1957    2.1099    4.9905   12.0436  128.9708 14044 1.0000
prior_sd_site                          2.8048  0.0687   8.0890    0.0829    0.8827    1.8945    3.5310   10.1744 13856 1.0000
prior_cor_site                         0.0063  0.0048   0.5768   -0.9504   -0.4895    0.0037    0.5082    0.9520 14345 0.9999
lprior                               -12.2781  0.0027   0.1798  -12.7290  -12.3631  -12.2428  -12.1528  -12.0357  4528 1.0008
lp__                                -286.4031  0.0892   5.0099 -296.9129 -289.6187 -286.0476 -282.8270 -277.5582  3153 1.0010
z_1[1,1]                              -1.3213  0.0062   0.5680   -2.5017   -1.6919   -1.2953   -0.9307   -0.2749  8327 1.0006
z_1[1,2]                               0.1004  0.0055   0.4828   -0.8550   -0.2189    0.1028    0.4198    1.0481  7840 1.0008
z_1[1,3]                              -0.4641  0.0057   0.4925   -1.4694   -0.7818   -0.4567   -0.1323    0.4704  7588 1.0005
z_1[1,4]                               0.4961  0.0055   0.4553   -0.3757    0.1919    0.4834    0.7924    1.4202  6841 1.0004
z_1[1,5]                               0.0779  0.0057   0.4803   -0.8664   -0.2381    0.0739    0.3857    1.0420  7167 1.0004
z_1[1,6]                              -0.8393  0.0058   0.4965   -1.8774   -1.1571   -0.8170   -0.5063    0.0889  7262 1.0008
z_1[1,7]                               1.0878  0.0058   0.5064    0.1434    0.7425    1.0748    1.4164    2.1232  7708 1.0002
z_1[1,8]                              -0.6390  0.0060   0.5057   -1.6877   -0.9673   -0.6218   -0.2931    0.2996  7214 1.0009
z_1[1,9]                               0.7523  0.0056   0.4685   -0.1380    0.4346    0.7318    1.0575    1.7101  6942 1.0007
z_1[1,10]                              1.6264  0.0068   0.5353    0.6426    1.2534    1.6068    1.9745    2.7334  6247 1.0006
z_1[1,11]                             -0.9656  0.0062   0.5636   -2.1299   -1.3291   -0.9488   -0.5834    0.0994  8377 1.0002
z_1[2,1]                              -0.6156  0.0088   0.6582   -1.8278   -1.0650   -0.6395   -0.2072    0.7577  5640 1.0005
z_1[2,2]                               0.4327  0.0061   0.5554   -0.6655    0.0780    0.4276    0.7845    1.5549  8371 1.0001
z_1[2,3]                               0.9236  0.0060   0.5501   -0.0682    0.5445    0.8865    1.2744    2.0885  8497 1.0000
z_1[2,4]                              -0.1101  0.0058   0.5247   -1.2076   -0.4353   -0.0898    0.2420    0.8593  8185 1.0003
z_1[2,5]                               0.7184  0.0061   0.5446   -0.3087    0.3624    0.7019    1.0629    1.8439  7941 1.0000
z_1[2,6]                              -0.2062  0.0068   0.5485   -1.2063   -0.5777   -0.2345    0.1266    0.9721  6488 1.0001
z_1[2,7]                               0.1734  0.0078   0.6146   -1.0997   -0.2271    0.1965    0.5961    1.3110  6214 1.0005
z_1[2,8]                              -1.4170  0.0077   0.6014   -2.6100   -1.8146   -1.4134   -1.0186   -0.2281  6064 1.0000
z_1[2,9]                              -0.8377  0.0064   0.5497   -1.9876   -1.1861   -0.8026   -0.4591    0.1526  7385 1.0005
z_1[2,10]                              0.1874  0.0090   0.7124   -1.2665   -0.2767    0.2116    0.6737    1.5221  6201 1.0003
z_1[2,11]                              0.8069  0.0069   0.6013   -0.2725    0.3936    0.7745    1.1826    2.0850  7599 1.0003
L_1[1,1]                               1.0000     NaN   0.0000    1.0000    1.0000    1.0000    1.0000    1.0000   NaN    NaN
L_1[1,2]                               0.0000     NaN   0.0000    0.0000    0.0000    0.0000    0.0000    0.0000   NaN    NaN
L_1[2,1]                              -0.9482  0.0006   0.0479   -0.9917   -0.9774   -0.9622   -0.9361   -0.8196  6018 1.0003
L_1[2,2]                               0.2927  0.0015   0.1140    0.1288    0.2115    0.2722    0.3518    0.5729  5642 1.0005

Samples were drawn using NUTS(diag_e) at Wed Feb  5 12:23:11 2025.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at 
convergence, Rhat=1).

M2: Posteror Draws

mo2.draws <-mo2  %>% as_draws_array()
mo2.summary <- summarize_draws(mo2.draws )
mo2.summary
write.csv(mo2.summary, "model2_results.csv")

M2: PPC

pp_check(mo2, type="loo_intervals",prob = 0.5,prob_outer= 0.95)+# ,ndraws = 50) 
  ggplot2::ylab("Cases per 100,000 (log10)") +
  ggplot2::xlab("Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

M2: Plot of Conditional Effects

CE.m2 <- conditional_effects(mo2,effects="log_n2_flowadj",re_formula = NULL, conditions = data.frame(site = unique(c19.data$site) ) )
#NB, the re_formula = NULL includes the random effects in the predictions, allowing site-specific plots

ggplot(CE.m2[[1]], aes(x = log_n2_flowadj, y = estimate__, group = site, color = site)) +
  geom_line() +
  geom_ribbon(aes(ymin = lower__, ymax = upper__, fill = site), alpha = 0.2) +
  theme_minimal() +
  labs(title = "Conditional Effects of log_n2_flowadj by Site",
       x = "log_n2_flowadj",
       y = "log_case100000") +
  theme(legend.position = "right")

M2: Combination Plot of Random Intercepts and Slopes

#library(tidybayes) 
#define custom order for sewershed sites
site_order <- c("SS1", "SS2", "SS3", "SS4", "SS5", "SS6", "SS7", "SS8", "SS9", "SS10", "SS11")

#extract random intercepts and slopes
mo2  %>%
  spread_draws(r_site[site,term]) %>%
  filter(term %in% c("Intercept", "log_n2_flowadj")) %>%
  ungroup() %>%
  mutate(site = factor(site, levels = site_order, ordered = TRUE)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye(.width = c(.50, .95)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_wrap(~term, scales = "free_x") +
  labs(x = "Random Effect", y = "Site",
       title = "Random Effects by Site",
       subtitle = "Intercepts and Slopes for log_n2_flowadj") +
  scale_y_discrete(limits = rev(site_order))  #reverse site order for top-to-bottom layout

M2: Summary of Results

Model 2 predicts log_case100000 using log_n2_flowadj as a fixed effect, with random intercepts and slopes for each site. The formula for this model is: log_case100000 ~ 1 + log_n2_flowadj + (1 + log_n2_flowadj | site). Model 2 was fit using 4 MCMC chains, each with 4000 iterations (500 warmup each), resulting in 14,000 total post-warmup draws.

Fixed Effects

The fixed effects show the overall relationship between the predictor and response:

  • Intercept: 7.6546 (95% CI: -8.8863 to -6.4530)

  • log_n2_flowadj: 0.7506 (95% CI: 0.66389 to 0.8402)

This indicates that for every 1-unit increase in log_n2_flowadj, log_case100000 increases by approximately 0.75 on average.

Random Effects

The model includes random effects for 11 different sewershed locations:

  • sd(Intercept): The standard deviation of the intercept is 1.8337 (95% CI: 1.0525 to 2.9867)

  • sd(log_n2_flowadj): The standard deviation of the slope is 0.1275 (95% CI: 0.0664 to 0.2163)

  • cor(Intercept,log_n2_flowadj): The correlation between intercept and slope is -0.9482 (95% CI: -0.9917 to -0.8186)

This suggests considerable variation in intercepts across sites, with less variation in slopes. The strong negative correlation indicates that sites with higher intercepts tend to have lower slopes.

Model Fit

  • sigma: 0.3164 (95% CI: 0.3019 to 0.3317)

This represents the residual standard deviation, indicating the deviation of observed values from the Model 2’s predictions.

Model Diagnostics

The Rhat values are all close to 1, suggesting good convergence of the MCMC chains. The effective sample sizes (Bulk_ESS and Tail_ESS) are generally high, indicating reliable posterior estimates.

PPC and Conditional Effects

The observed data fell within both 50% and 95% LOO intervals and the conditional effects plot show a positive, linear relationship between flow-adjusted N2 and log cases per 100,000.

Random Effects for Intercepts

The model estimates site-specific intercepts, representing the baseline log cases per 100,000 when log_n2_flowadj is zero:

  • Highest intercepts: SS5, SS7, and SS8

  • Lowest intercepts: SS1, SS4, and SS9

Random Effects for Slopes

The relationship between flow-adjusted N2 and log case counts per 100000 varies across sites. The notable site-specific slopes for log_n2_flowadj are:

  • Strongest positive associations: SS1, SS4, SS9, and SS11

  • Strongest negative associations: SS5, SS7, and SS8

In summary, Model 2 results suggest a positive relationship between log_n2_flowadj and log_case100000, with significant variation across sites in both the baseline levels (intercepts) and slopes.

Model 3: Bayesian linear regression model with a random effect for flow-adjusted N2 gene (interacting with SARS-CoV-2 VOCs) and random intercept for sewershed location.

\[ y_{ij} = \beta_0 + \beta_1 x_{ij} + \beta_2 z_{ij} + \beta_3 (x_{ij} \times z_{ij}) + b_{0j} + b_{1j} x_{ij} + \epsilon_{ij} \tag{Eq. 4} \]

Explanation of Model 3 Terms

  • \(y_{ij}\): Response variable (log_case100000) for the i-th observation in the j-th group, where group is sewershed sites. See Model 1 for abbreviations.

  • \(\beta_0\): Fixed intercept, representing the overall mean effect across all groups.

  • \(\beta_1\): Fixed slope for the predictor \(x_{ij}\) (log_n2_flowadj), representing the effect of the predictor on the response variable.

  • \(\beta_2\): Fixed slope for the predictor \(z_{ij}\), representing the effect of the second predictor (VOC phase) on the response variable.

  • \(\beta_3\): Fixed slope for the interaction term \(x_{ij} \times z_{ij}\), representing the interactions of the two predictors (log_n2_flowadj and log_case100000) on the response variable.

  • \(b_{0j}\): Random intercept for the j-th group, representing the group-specific differences from the overall intercept.

  • \(b_{1j}\): Random slope for the predictor \(x_{ij}\) in the j-th group, representing the group-specific differences in the effect of the predictor.

  • \(\epsilon_{ij}\): Residual error for the i-th observation in the j-th group, representing the unexplained variability.

M3: BRMS code for Random intercept, Random Slope plut N2 Interaction with SARS-CoV-2 VOCs

# # Define priors for the intercept and slope
# prior_intercept <- prior(normal(0, 100), class = Intercept)
# prior_slope <- prior(normal(0, 1), class = b)
# 
# # Define sigma prior
# prior_sigma <- set_prior("cauchy(0, 5)", class = "sigma")
# 
# brm.partpool.rand.phase <- brm(
#   log_case100000 ~ 1+ log_n2_flowadj * phase + (1+log_n2_flowadj|site),
#   data = c19.data,
#   family =gaussian,
#   prior = c(
#     prior_intercept,
#     prior_slope,
#     prior_sigma
#   ),
#   control=list(adapt_delta =0.95,max_treedepth=10), # try this next
#   warmup = 500, # comment this and see if the divergent trans go away
#   iter = 4000, #increase
#   chains =4,
#   sample_prior = "yes",
#   seed = 513,
#   save_pars = save_pars(all = TRUE),
#   save_ranef = TRUE,
#   save_all_pars = TRUE,
#   file ='brm_partpool_rand.phase.rds', # this should be deleted in the Project directory each time model rerun
#   save_model = 'brm_partpool_rand_phase_model.txt',
#   future=TRUE
# )

M3: Print Saved Results

mo3 <- brm(file="brm_partpool_rand.phase.rds")
print(mo3, digits=4)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: log_case100000 ~ 1 + log_n2_flowadj * phase + (1 + log_n2_flowadj | site) 
   Data: c19.data (Number of observations: 892) 
  Draws: 4 chains, each with iter = 4000; warmup = 500; thin = 1;
         total post-warmup draws = 14000

Multilevel Hyperparameters:
~site (Number of levels: 11) 
                              Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sd(Intercept)                   1.5707    0.4482   0.8769   2.6264 1.0003     4673     6908
sd(log_n2_flowadj)              0.1099    0.0340   0.0563   0.1904 1.0005     4373     6769
cor(Intercept,log_n2_flowadj)  -0.9582    0.0427  -0.9938  -0.8486 1.0008     6312     8770

Regression Coefficients:
                            Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
Intercept                    -4.4266    0.6750  -5.7518  -3.0781 1.0005     4386     6338
log_n2_flowadj                0.5000    0.0512   0.3978   0.6008 1.0004     4327     6696
phasealpha                   -1.7622    0.4501  -2.6271  -0.8783 1.0001     5104     7414
phasedelta                    0.1541    0.4702  -0.7615   1.0876 1.0001     5838     8290
phaseomicron                 -1.7788    0.4935  -2.7411  -0.8160 1.0003     6070     8365
log_n2_flowadj:phasealpha     0.1119    0.0370   0.0395   0.1829 1.0001     5171     7544
log_n2_flowadj:phasedelta    -0.0259    0.0385  -0.1026   0.0489 1.0001     5850     8256
log_n2_flowadj:phaseomicron   0.1457    0.0403   0.0673   0.2249 1.0003     6116     8290

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI   Rhat Bulk_ESS Tail_ESS
sigma   0.2736    0.0066   0.2612   0.2869 1.0002    20233     9925

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

M3: Prior Summary

The priors for Model 3 are the same as Model 2 and are weakly informative.

prior_summary(mo3)
                prior     class                        coef group resp dpar nlpar lb ub       source
         normal(0, 1)         b                                                                 user
         normal(0, 1)         b              log_n2_flowadj                             (vectorized)
         normal(0, 1)         b   log_n2_flowadj:phasealpha                             (vectorized)
         normal(0, 1)         b   log_n2_flowadj:phasedelta                             (vectorized)
         normal(0, 1)         b log_n2_flowadj:phaseomicron                             (vectorized)
         normal(0, 1)         b                  phasealpha                             (vectorized)
         normal(0, 1)         b                  phasedelta                             (vectorized)
         normal(0, 1)         b                phaseomicron                             (vectorized)
       normal(0, 100) Intercept                                                                 user
 lkj_corr_cholesky(1)         L                                                              default
 lkj_corr_cholesky(1)         L                              site                       (vectorized)
 student_t(3, 0, 2.5)        sd                                                    0         default
 student_t(3, 0, 2.5)        sd                              site                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                   Intercept  site                  0    (vectorized)
 student_t(3, 0, 2.5)        sd              log_n2_flowadj  site                  0    (vectorized)
         cauchy(0, 5)     sigma                                                    0            user

M3: Print Fit Results

print(mo3$fit, digits=4)
Inference for Stan model: anon_model.
4 chains, each with iter=4000; warmup=500; thin=1; 
post-warmup draws per chain=3500, total post-warmup draws=14000.

                                         mean se_mean        sd      2.5%       25%       50%       75%     97.5% n_eff   Rhat
b_Intercept                           -4.4266  0.0102    0.6750   -5.7518   -4.8725   -4.4319   -3.9869   -3.0781  4379 1.0005
b_log_n2_flowadj                       0.5000  0.0008    0.0512    0.3978    0.4665    0.5000    0.5339    0.6008  4311 1.0004
b_phasealpha                          -1.7622  0.0063    0.4501   -2.6271   -2.0723   -1.7684   -1.4555   -0.8783  5081 1.0001
b_phasedelta                           0.1541  0.0062    0.4702   -0.7615   -0.1625    0.1538    0.4682    1.0876  5828 1.0001
b_phaseomicron                        -1.7788  0.0064    0.4935   -2.7411   -2.1171   -1.7829   -1.4469   -0.8160  6027 1.0003
b_log_n2_flowadj:phasealpha            0.1119  0.0005    0.0370    0.0395    0.0868    0.1123    0.1373    0.1829  5148 1.0001
b_log_n2_flowadj:phasedelta           -0.0259  0.0005    0.0385   -0.1026   -0.0516   -0.0259    0.0001    0.0489  5836 1.0001
b_log_n2_flowadj:phaseomicron          0.1457  0.0005    0.0403    0.0673    0.1186    0.1461    0.1732    0.2249  6067 1.0003
sd_site__Intercept                     1.5707  0.0066    0.4482    0.8769    1.2555    1.5079    1.8088    2.6264  4652 1.0004
sd_site__log_n2_flowadj                0.1099  0.0005    0.0340    0.0563    0.0862    0.1054    0.1280    0.1904  4436 1.0005
cor_site__Intercept__log_n2_flowadj   -0.9582  0.0005    0.0427   -0.9938   -0.9831   -0.9707   -0.9489   -0.8486  6494 1.0004
sigma                                  0.2736  0.0000    0.0066    0.2612    0.2690    0.2735    0.2779    0.2869 20371 0.9999
Intercept                              1.3075  0.0019    0.1435    1.0229    1.2173    1.3061    1.3957    1.6003  5463 1.0001
r_site[SS1,Intercept]                 -2.1159  0.0093    0.8576   -3.8755   -2.6574   -2.0791   -1.5361   -0.5029  8507 1.0007
r_site[SS10,Intercept]                 0.0770  0.0085    0.7449   -1.4551   -0.4004    0.0870    0.5642    1.5058  7697 1.0000
r_site[SS11,Intercept]                -0.5132  0.0090    0.7625   -2.0806   -1.0118   -0.4958    0.0021    0.9475  7217 1.0000
r_site[SS2,Intercept]                  0.9893  0.0087    0.7194   -0.3906    0.5126    0.9720    1.4526    2.4670  6833 1.0004
r_site[SS3,Intercept]                  0.3037  0.0085    0.7332   -1.1425   -0.1793    0.3068    0.7802    1.7434  7436 1.0003
r_site[SS4,Intercept]                 -1.5327  0.0084    0.7439   -3.0335   -2.0209   -1.5078   -1.0291   -0.1138  7810 1.0001
r_site[SS5,Intercept]                  1.6220  0.0084    0.7696    0.2013    1.0972    1.5973    2.1104    3.2258  8450 1.0002
r_site[SS6,Intercept]                 -0.9404  0.0088    0.7640   -2.4419   -1.4414   -0.9419   -0.4400    0.5618  7513 1.0006
r_site[SS7,Intercept]                  0.8500  0.0085    0.7204   -0.5146    0.3585    0.8329    1.3191    2.3140  7172 1.0006
r_site[SS8,Intercept]                  2.3240  0.0087    0.7430    0.9403    1.8189    2.2987    2.7971    3.8613  7358 1.0003
r_site[SS9,Intercept]                 -1.1853  0.0095    0.8679   -3.0291   -1.7405   -1.1476   -0.5813    0.3818  8300 0.9998
r_site[SS1,log_n2_flowadj]             0.1291  0.0007    0.0656    0.0058    0.0848    0.1272    0.1711    0.2630  9139 1.0007
r_site[SS10,log_n2_flowadj]            0.0020  0.0006    0.0600   -0.1135   -0.0373    0.0016    0.0402    0.1254  9108 1.0000
r_site[SS11,log_n2_flowadj]            0.0576  0.0007    0.0603   -0.0559    0.0167    0.0555    0.0971    0.1828  8130 0.9999
r_site[SS2,log_n2_flowadj]            -0.0776  0.0007    0.0569   -0.1941   -0.1144   -0.0761   -0.0390    0.0301  7477 1.0004
r_site[SS3,log_n2_flowadj]            -0.0027  0.0006    0.0580   -0.1166   -0.0411   -0.0040    0.0352    0.1138  8436 1.0003
r_site[SS4,log_n2_flowadj]             0.1007  0.0006    0.0575   -0.0080    0.0622    0.0985    0.1377    0.2179  8783 1.0001
r_site[SS5,log_n2_flowadj]            -0.1034  0.0006    0.0610   -0.2308   -0.1429   -0.1011   -0.0618    0.0105  9779 1.0001
r_site[SS6,log_n2_flowadj]             0.0276  0.0007    0.0576   -0.0867   -0.0097    0.0277    0.0653    0.1413  7834 1.0005
r_site[SS7,log_n2_flowadj]            -0.0772  0.0006    0.0566   -0.1942   -0.1137   -0.0759   -0.0384    0.0296  8026 1.0005
r_site[SS8,log_n2_flowadj]            -0.1514  0.0007    0.0602   -0.2777   -0.1897   -0.1492   -0.1107   -0.0381  8443 1.0003
r_site[SS9,log_n2_flowadj]             0.1008  0.0007    0.0686   -0.0210    0.0528    0.0974    0.1440    0.2463  9075 0.9998
prior_Intercept                        0.4701  0.8750  101.1153 -199.4187  -66.8473    1.2687   68.9080  196.2551 13353 1.0000
prior_b                               -0.0015  0.0084    0.9940   -1.9466   -0.6720    0.0042    0.6816    1.9284 14072 1.0000
prior_sigma                           36.0892  9.0622 1072.6967    0.1964    2.0905    5.0482   12.0938  124.0882 14011 1.0001
prior_sd_site                          2.7879  0.0300    3.5746    0.0904    0.8735    1.8911    3.5847   10.6203 14154 0.9999
prior_cor_site                         0.0011  0.0049    0.5774   -0.9486   -0.5016    0.0001    0.5016    0.9515 14008 0.9998
lprior                               -21.0501  0.0217    1.4914  -24.4567  -21.9145  -20.8633  -19.9398  -18.7751  4743 1.0004
lp__                                -166.5522  0.0968    5.4523 -178.2222 -170.0345 -166.2070 -162.6789 -156.9892  3173 1.0005
z_1[1,1]                              -1.4023  0.0061    0.5694   -2.5932   -1.7716   -1.3834   -1.0154   -0.3266  8597 1.0006
z_1[1,2]                               0.0522  0.0054    0.4857   -0.9232   -0.2672    0.0566    0.3755    1.0000  8195 1.0000
z_1[1,3]                              -0.3363  0.0055    0.4984   -1.3581   -0.6612   -0.3281    0.0014    0.6340  8172 1.0000
z_1[1,4]                               0.6569  0.0055    0.4730   -0.2457    0.3358    0.6455    0.9647    1.6286  7288 1.0002
z_1[1,5]                               0.2059  0.0056    0.4832   -0.7313   -0.1176    0.2048    0.5225    1.1641  7564 1.0001
z_1[1,6]                              -1.0252  0.0056    0.5097   -2.0830   -1.3588   -1.0034   -0.6727   -0.0694  8400 1.0002
z_1[1,7]                               1.0806  0.0057    0.5191    0.1185    0.7234    1.0591    1.4186    2.1418  8329 0.9999
z_1[1,8]                              -0.6371  0.0060    0.5235   -1.7206   -0.9694   -0.6287   -0.2853    0.3553  7515 1.0006
z_1[1,9]                               0.5635  0.0054    0.4758   -0.3358    0.2382    0.5504    0.8761    1.5104  7738 1.0004
z_1[1,10]                              1.5580  0.0068    0.5439    0.5542    1.1812    1.5378    1.9074    2.7000  6471 1.0000
z_1[1,11]                             -0.7757  0.0056    0.5630   -1.9418   -1.1358   -0.7589   -0.3909    0.2620 10078 0.9998
z_1[2,1]                              -0.5081  0.0082    0.6767   -1.7291   -0.9756   -0.5436   -0.0849    0.9122  6797 1.0000
z_1[2,2]                               0.2809  0.0053    0.5816   -0.8644   -0.0959    0.2790    0.6492    1.4412 12071 1.0000
z_1[2,3]                               0.9018  0.0059    0.5622   -0.1222    0.5145    0.8737    1.2579    2.0830  9113 0.9998
z_1[2,4]                              -0.4208  0.0056    0.5585   -1.6153   -0.7695   -0.3870   -0.0372    0.5932  9884 1.0001
z_1[2,5]                               0.6924  0.0060    0.5672   -0.4188    0.3272    0.6841    1.0465    1.8427  9024 1.0000
z_1[2,6]                              -0.0830  0.0066    0.5816   -1.1313   -0.4774   -0.1203    0.2758    1.1459  7713 1.0000
z_1[2,7]                               0.2360  0.0066    0.6355   -1.0749   -0.1689    0.2599    0.6720    1.4099  9235 1.0000
z_1[2,8]                              -1.3990  0.0072    0.5941   -2.5999   -1.7855   -1.3869   -0.9977   -0.2534  6779 1.0000
z_1[2,9]                              -0.7841  0.0056    0.5513   -1.9667   -1.1315   -0.7470   -0.4043    0.1863  9763 1.0000
z_1[2,10]                              0.2059  0.0079    0.7225   -1.3010   -0.2618    0.2340    0.6949    1.5464  8267 0.9999
z_1[2,11]                              0.8010  0.0059    0.5956   -0.2729    0.3928    0.7668    1.1804    2.0640 10181 0.9999
L_1[1,1]                               1.0000     NaN    0.0000    1.0000    1.0000    1.0000    1.0000    1.0000   NaN    NaN
L_1[1,2]                               0.0000     NaN    0.0000    0.0000    0.0000    0.0000    0.0000    0.0000   NaN    NaN
L_1[2,1]                              -0.9582  0.0005    0.0427   -0.9938   -0.9831   -0.9707   -0.9489   -0.8486  6494 1.0004
L_1[2,2]                               0.2610  0.0014    0.1093    0.1110    0.1833    0.2404    0.3156    0.5291  6218 1.0004

Samples were drawn using NUTS(diag_e) at Wed Feb  5 16:16:32 2025.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at 
convergence, Rhat=1).

M3: Posterior Draws

mo3.draws <-mo3  %>% as_draws_array()
mo3.summary <- summarize_draws(mo3.draws )
mo3.summary
write.csv(mo3.summary, "model3_results.csv")

M3: PPC

pp_check(mo3, type="loo_intervals",prob = 0.5,prob_outer= 0.95) +
  ggplot2::ylab("Cases per 100,000 (log10)") +
  ggplot2::xlab("Index") +
  ggplot2::theme(
    axis.text = ggplot2::element_text(size = 12),
    axis.title = ggplot2::element_text(size = 14)
  )
Using all posterior draws for ppc type 'loo_intervals' by default.

M3: Conditional Plot with Random Effects

conditional_effects(mo3,effects=c("log_n2_flowadj:phase"), re_formula = NULL)

M3: Combination Plot of Random Slopes and Intercepts

#library(tidybayes)
#define custom order for sewershed sites
site_order <- c("SS1", "SS2", "SS3", "SS4", "SS5", "SS6", "SS7", "SS8", "SS9", "SS10", "SS11")

#extract random intercepts and slopes
mo3 %>%
  spread_draws(r_site[site,term]) %>%
  filter(term %in% c("Intercept", "log_n2_flowadj")) %>% 
  ungroup() %>%
  mutate(site = factor(site, levels = site_order, ordered = TRUE)) %>%
  ggplot(aes(y = site, x = r_site)) +
  stat_halfeye(.width = c(.50, .95)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_wrap(~term, scales = "free_x") +
   labs(x = "Random Effect", y = "Sewershed" 
  #comment to format for inclusion of Figure 3 in main text of manuscript
  #      title = "Random Effects by Sewershed",
  #      subtitle = "Intercepts and Slopes"
  ) +
  scale_y_discrete(limits = rev(site_order)) +  #reverse site order for top-to-bottom layout
  theme(strip.text = element_blank()) # remove facet labels

M3: Summary of Results

Model 3 is log_case100000 ~ 1 + log_n2_flowadj * phase + (1 + log_n2_flowadj | site) and was fit using 4 MCMC chains, each with 4000 iterations (500 warmup), resulting in 14,000 total post-warmup draws.

Random Effects

  • The standard deviation of the random intercepts is 1.5707 (95% CI: 0.8769 to 2.6264).

  • The standard deviation of the random slopes for log_n2_flowadj is 0.1099 (95% CI: 0.0563 to 0.1904).

  • Correlation: There is a strong negative correlation (-0.9582) between the random intercepts and slopes.

Fixed Effects

  • The overall intercept is -4.4266 (95% CI: -5.7518 to -3.0781).

The main effect of log_n2_flowadj is 0.5000 (95% CI: 0.3978 to 0.6008), indicating a credible effect.

Compared to the reference phase (i.e., pre-VOC):

  • The Alpha phase has a credibly lower intercept (-1.7622; 95% CI: -2.6271 to -0.8783 ). This interval does not include 0.

  • The Delta phase is not credibly different (0.1541, 95% CI: -0.7615 to 1.0876). This interval includes 0.

  • The Omicron phase has a credibly lower intercept (-1.7788, 95% CI: -2.7411 to -0.8160). This interval does not include 0.

The interactions between log_n2_flowadj and SARS-CoV-2 VOCs:

  • Alpha: Credible positive interaction (0.1119, 95% CI: 0.0395 to 0.1829). This interval does not include 0.

  • Delta: No credible interaction (-0.0259, 95% CI: -0.1026 to 0.0489). This interval includes 0.

  • Omicron: Credible positive interaction (0.1457, 95% CI: 0.0673 to 0.2249). This interval does not include 0.

The interactions between log_n2_flowadj and the Alpha and Omicron phases is as follows:

  • Alpha: The interaction term log_n2_flowadj:phasealpha has an estimate of 0.1119. Thus, for every 1 unit increase in log_n2_flowadj during the Alpha phase, there is an additional 0.11 log unit increase in log_case100000 compared to the reference phase (i.e., pre_VOC). The total effect of log_n2_flowadj during the Alpha period is: 0.5000 (main effect) + 0.1119 (interaction) = 0.6119. This means that for every 1 unit increase in log_n2_flowadj during the Alpha phase, log_case100000 is expected to increase by 0.61 log units, holding other variables constant.

  • Omicron: The interaction term log_n2_flowadj:phaseomicron has an estimate of 0.1457. For every 1 unit increase in log_n2_flowadj during the Omicron phase, there is an additional 0.1454 log unit increase in log_case100000. This indicates a stronger relationship between N2 gene concentration and COVID-19 cases for Omicron than Alpha phases. The total effect of log_n2_flowadj for Omicron is: 0.5000 (main effect) + 0.1457 (interaction) = 0.6457. For every 1 unit increase in log_n2_flowadj during the Alpha phase, log_case100000 is expected to increase by 0.64 log units, holding other variables constant.

Model Fit

  • The residual standard deviation (sigma) is 0.2736 (95% CI: 0.2612 to 0.2869).

  • The Rhat values are all close to 1, indicating good convergence.

  • The effective sample sizes (ESS) are generally high, suggesting reliable posterior estimates.

PPC and Conditional Effects

The observed data fell within both 50% and 95% LOO intervals and the conditional effects plot show a positive, linear relationship between flow-adjusted N2 and COVID-19 cases, with visual differences in the slopes for Alpha and Omicron compared to pre-VOC.

In summary, Model 3 suggests that the relationship between flow-adjusted N2 and COVID-19 cases varies across different variant phases, with credible differences for Alpha and Omicron (but not Delta) variants in both intercepts and slopes when compared to pre-VOC (the reference phase).

Overview of Random Effects for Intercepts

These represent how much each site’s intercept deviates from the grand mean intercept:

  • Highest intercepts: SS2, SS5, SS7, and SS8

  • Lowest intercepts: SS1, SS4, SS6, and SS9

Overview of Random Effects for Slopes

These results show how the effect of log_n2_flowadj varies by site:

  • Highest slopes: SS1, SS4, SS9, and SS11

  • Lowest slopes: SS2, SS5, SS7, and SS8

Model Precision

The residual standard deviation (sigma) is estimated at 0.2736 (95% CI: 0.2612 to 0.2869), indicating the unexplained variability in the model.

Random Effects Correlation

The correlation between random intercepts and slopes (cor_site__Intercept__log_n2_flowadj) is strongly negative (-0.9582), suggesting that sites with higher baseline log case counts tend to have negative associations between log_n2_flowadj and population-normalized log case counts, and vice versa. In other words, the reciprocal relationship between the effect sizes of the intercepts and slopes for SS2, SS5, SS7, and SS8 suggests that populations with more severe outbreaks stabilize or decrease more quickly, while those with less severe outbreaks tend to increase more quickly over time.

Summary

In summary, Model 3 reveals credible variation across sites in both baseline log case counts and the strength of the association between N2 load interacting with VOCs and COVID-19 cases. The phase-specific effects of Alpha and Omicron varied across the sewersheds.

Leave-One-Out Cross-Validation (LOO-CV) Section: Compare Models 1, 2 and 3

Model LOO-CVs

loo.m1 <- loo(mo1)
loo.m2 <- loo(mo2)
loo.m3 <- loo(mo3)

M1 L00-CV

loo.m1

Computed from 14000 by 892 log-likelihood matrix.
------
MCSE of elpd_loo is 0.0.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.5, 1.3]).

All Pareto k estimates are good (k < 0.7).
See help('pareto-k-diagnostic') for details.

M2 L00-CV

loo.m2

Computed from 14000 by 892 log-likelihood matrix.
------
MCSE of elpd_loo is 0.1.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.4]).

All Pareto k estimates are good (k < 0.7).
See help('pareto-k-diagnostic') for details.

M3 L00-CV

loo.m3

Computed from 14000 by 892 log-likelihood matrix.
------
MCSE of elpd_loo is 0.1.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.5, 1.2]).

All Pareto k estimates are good (k < 0.7).
See help('pareto-k-diagnostic') for details.

Compare M1, M2 and M3 LOO-CVs

loo_compare(loo.m1,loo.m2,loo.m3)
    elpd_diff se_diff
mo3    0.0       0.0 
mo2 -126.4      15.1 
mo1 -139.6      15.6 

Summary of LOO-CV

The models are ordered from best to worst predictive performance.

  • elpd_diff: This column shows the difference in expected log predictive density (ELPD) between each model and the top-performing model. A higher ELPD indicates better predictive performance.

  • se_diff: This column shows the standard error of the difference in ELPD.

Model 3:

  • ELPD difference: 0.0

This is the best-performing model because it has the highest predictive accuracy for the models.

Model 2:

The ELPD difference: -126.4. This model performs worse than Model 3 because the difference is substantial (more than 2 SE away from 0).

Model 1:

  • ELPD difference: -139.6. This model has the worst predictive performance among the models. The difference from the top model is also substantial.

2SE Rule

Using the “2SE rule” to estimate 95% confidence intervals, the second best performing model (Model 2) has a 95% CI of -126.4 + c(-2,2)*15.1 = (-156.6 and -0.96.2), which does not contain 0. The ratio of abs(elpd_diff/se_diff) = 8.371, which is greater than 2. A ratio of 2 is a common threshold for evaluating performance comparisons. Model 3 is the worst performing model with a CI of (-170.8, -108.4) that also does not contain 0. Model 3 clearly outperforms the other two models in terms of predictive accuracy because it accounts for the interaction between N2 gene and VOCs while allowing the slope and intercepts to vary by sewershed site.

PSIS Plots

M1

plot(loo.m1)

M2

plot(loo.m2)

M3

plot(loo.m3)

Bayesian Model Stan Code Section

Fecal Models Stan Code

m01

fs.mo1$model
// generated with brms 2.21.0
functions {
}
data {
  int<lower=1> N;  // total number of observations
  vector[N] Y;  // response variable
  // data for group-level effects of ID 1
  int<lower=1> N_1;  // number of grouping levels
  int<lower=1> M_1;  // number of coefficients per level
  array[N] int<lower=1> J_1;  // grouping indicator per observation
  // group-level predictor values
  vector[N] Z_1_1;
  int prior_only;  // should the likelihood be ignored?
}
transformed data {
}
parameters {
  real Intercept;  // temporary intercept for centered predictors
  real<lower=0> sigma;  // dispersion parameter
  vector<lower=0>[M_1] sd_1;  // group-level standard deviations
  array[M_1] vector[N_1] z_1;  // standardized group-level effects
}
transformed parameters {
  vector[N_1] r_1_1;  // actual group-level effects
  real lprior = 0;  // prior contributions to the log posterior
  r_1_1 = (sd_1[1] * (z_1[1]));
  lprior += student_t_lpdf(Intercept | 3, 8.5, 2.5);
  lprior += student_t_lpdf(sigma | 3, 0, 2.5)
    - 1 * student_t_lccdf(0 | 3, 0, 2.5);
  lprior += student_t_lpdf(sd_1 | 3, 0, 2.5)
    - 1 * student_t_lccdf(0 | 3, 0, 2.5);
}
model {
  // likelihood including constants
  if (!prior_only) {
    // initialize linear predictor term
    vector[N] mu = rep_vector(0.0, N);
    mu += Intercept;
    for (n in 1:N) {
      // add more terms to the linear predictor
      mu[n] += r_1_1[J_1[n]] * Z_1_1[n];
    }
    target += normal_lpdf(Y | mu, sigma);
  }
  // priors including constants
  target += lprior;
  target += std_normal_lpdf(z_1[1]);
}
generated quantities {
  // actual population-level intercept
  real b_Intercept = Intercept;
  // additionally sample draws from priors
  real prior_Intercept = student_t_rng(3,8.5,2.5);
  real prior_sigma = student_t_rng(3,0,2.5);
  real prior_sd_1 = student_t_rng(3,0,2.5);
  // use rejection sampling for truncated priors
  while (prior_sigma < 0) {
    prior_sigma = student_t_rng(3,0,2.5);
  }
  while (prior_sd_1 < 0) {
    prior_sd_1 = student_t_rng(3,0,2.5);
  }
}

m02

fs.mo2$model
// generated with brms 2.21.0
functions {
}
data {
  int<lower=1> N;  // total number of observations
  vector[N] Y;  // response variable
  int<lower=1> K;  // number of population-level effects
  matrix[N, K] X;  // population-level design matrix
  int<lower=1> Kc;  // number of population-level effects after centering
  // data for group-level effects of ID 1
  int<lower=1> N_1;  // number of grouping levels
  int<lower=1> M_1;  // number of coefficients per level
  array[N] int<lower=1> J_1;  // grouping indicator per observation
  // group-level predictor values
  vector[N] Z_1_1;
  int prior_only;  // should the likelihood be ignored?
}
transformed data {
  matrix[N, Kc] Xc;  // centered version of X without an intercept
  vector[Kc] means_X;  // column means of X before centering
  for (i in 2:K) {
    means_X[i - 1] = mean(X[, i]);
    Xc[, i - 1] = X[, i] - means_X[i - 1];
  }
}
parameters {
  vector[Kc] b;  // regression coefficients
  real Intercept;  // temporary intercept for centered predictors
  real<lower=0> sigma;  // dispersion parameter
  vector<lower=0>[M_1] sd_1;  // group-level standard deviations
  array[M_1] vector[N_1] z_1;  // standardized group-level effects
}
transformed parameters {
  vector[N_1] r_1_1;  // actual group-level effects
  real lprior = 0;  // prior contributions to the log posterior
  r_1_1 = (sd_1[1] * (z_1[1]));
  lprior += student_t_lpdf(Intercept | 3, 8.5, 2.5);
  lprior += student_t_lpdf(sigma | 3, 0, 2.5)
    - 1 * student_t_lccdf(0 | 3, 0, 2.5);
  lprior += student_t_lpdf(sd_1 | 3, 0, 2.5)
    - 1 * student_t_lccdf(0 | 3, 0, 2.5);
}
model {
  // likelihood including constants
  if (!prior_only) {
    // initialize linear predictor term
    vector[N] mu = rep_vector(0.0, N);
    mu += Intercept;
    for (n in 1:N) {
      // add more terms to the linear predictor
      mu[n] += r_1_1[J_1[n]] * Z_1_1[n];
    }
    target += normal_id_glm_lpdf(Y | Xc, mu, b, sigma);
  }
  // priors including constants
  target += lprior;
  target += std_normal_lpdf(z_1[1]);
}
generated quantities {
  // actual population-level intercept
  real b_Intercept = Intercept - dot_product(means_X, b);
  // additionally sample draws from priors
  real prior_Intercept = student_t_rng(3,8.5,2.5);
  real prior_sigma = student_t_rng(3,0,2.5);
  real prior_sd_1 = student_t_rng(3,0,2.5);
  // use rejection sampling for truncated priors
  while (prior_sigma < 0) {
    prior_sigma = student_t_rng(3,0,2.5);
  }
  while (prior_sd_1 < 0) {
    prior_sd_1 = student_t_rng(3,0,2.5);
  }
}

Model 1 Stan Code

mo1$model
// generated with brms 2.21.0
functions {
}
data {
  int<lower=1> N;  // total number of observations
  vector[N] Y;  // response variable
  int<lower=1> K;  // number of population-level effects
  matrix[N, K] X;  // population-level design matrix
  int<lower=1> Kc;  // number of population-level effects after centering
  // data for group-level effects of ID 1
  int<lower=1> N_1;  // number of grouping levels
  int<lower=1> M_1;  // number of coefficients per level
  array[N] int<lower=1> J_1;  // grouping indicator per observation
  // group-level predictor values
  vector[N] Z_1_1;
  int prior_only;  // should the likelihood be ignored?
}
transformed data {
  matrix[N, Kc] Xc;  // centered version of X without an intercept
  vector[Kc] means_X;  // column means of X before centering
  for (i in 2:K) {
    means_X[i - 1] = mean(X[, i]);
    Xc[, i - 1] = X[, i] - means_X[i - 1];
  }
}
parameters {
  vector[Kc] b;  // regression coefficients
  real Intercept;  // temporary intercept for centered predictors
  real<lower=0> sigma;  // dispersion parameter
  vector<lower=0>[M_1] sd_1;  // group-level standard deviations
  array[M_1] vector[N_1] z_1;  // standardized group-level effects
}
transformed parameters {
  vector[N_1] r_1_1;  // actual group-level effects
  real lprior = 0;  // prior contributions to the log posterior
  r_1_1 = (sd_1[1] * (z_1[1]));
  lprior += normal_lpdf(b | 0, 1);
  lprior += normal_lpdf(Intercept | 0, 100);
  lprior += cauchy_lpdf(sigma | 0, 5)
    - 1 * cauchy_lccdf(0 | 0, 5);
  lprior += student_t_lpdf(sd_1 | 3, 0, 2.5)
    - 1 * student_t_lccdf(0 | 3, 0, 2.5);
}
model {
  // likelihood including constants
  if (!prior_only) {
    // initialize linear predictor term
    vector[N] mu = rep_vector(0.0, N);
    mu += Intercept;
    for (n in 1:N) {
      // add more terms to the linear predictor
      mu[n] += r_1_1[J_1[n]] * Z_1_1[n];
    }
    target += normal_id_glm_lpdf(Y | Xc, mu, b, sigma);
  }
  // priors including constants
  target += lprior;
  target += std_normal_lpdf(z_1[1]);
}
generated quantities {
  // actual population-level intercept
  real b_Intercept = Intercept - dot_product(means_X, b);
  // additionally sample draws from priors
  real prior_b = normal_rng(0,1);
  real prior_Intercept = normal_rng(0,100);
  real prior_sigma = cauchy_rng(0,5);
  real prior_sd_1 = student_t_rng(3,0,2.5);
  // use rejection sampling for truncated priors
  while (prior_sigma < 0) {
    prior_sigma = cauchy_rng(0,5);
  }
  while (prior_sd_1 < 0) {
    prior_sd_1 = student_t_rng(3,0,2.5);
  }
}

Model 2 Stan Code

mo2$model
// generated with brms 2.21.0
functions {
 /* compute correlated group-level effects
  * Args:
  *   z: matrix of unscaled group-level effects
  *   SD: vector of standard deviation parameters
  *   L: cholesky factor correlation matrix
  * Returns:
  *   matrix of scaled group-level effects
  */
  matrix scale_r_cor(matrix z, vector SD, matrix L) {
    // r is stored in another dimension order than z
    return transpose(diag_pre_multiply(SD, L) * z);
  }
}
data {
  int<lower=1> N;  // total number of observations
  vector[N] Y;  // response variable
  int<lower=1> K;  // number of population-level effects
  matrix[N, K] X;  // population-level design matrix
  int<lower=1> Kc;  // number of population-level effects after centering
  // data for group-level effects of ID 1
  int<lower=1> N_1;  // number of grouping levels
  int<lower=1> M_1;  // number of coefficients per level
  array[N] int<lower=1> J_1;  // grouping indicator per observation
  // group-level predictor values
  vector[N] Z_1_1;
  vector[N] Z_1_2;
  int<lower=1> NC_1;  // number of group-level correlations
  int prior_only;  // should the likelihood be ignored?
}
transformed data {
  matrix[N, Kc] Xc;  // centered version of X without an intercept
  vector[Kc] means_X;  // column means of X before centering
  for (i in 2:K) {
    means_X[i - 1] = mean(X[, i]);
    Xc[, i - 1] = X[, i] - means_X[i - 1];
  }
}
parameters {
  vector[Kc] b;  // regression coefficients
  real Intercept;  // temporary intercept for centered predictors
  real<lower=0> sigma;  // dispersion parameter
  vector<lower=0>[M_1] sd_1;  // group-level standard deviations
  matrix[M_1, N_1] z_1;  // standardized group-level effects
  cholesky_factor_corr[M_1] L_1;  // cholesky factor of correlation matrix
}
transformed parameters {
  matrix[N_1, M_1] r_1;  // actual group-level effects
  // using vectors speeds up indexing in loops
  vector[N_1] r_1_1;
  vector[N_1] r_1_2;
  real lprior = 0;  // prior contributions to the log posterior
  // compute actual group-level effects
  r_1 = scale_r_cor(z_1, sd_1, L_1);
  r_1_1 = r_1[, 1];
  r_1_2 = r_1[, 2];
  lprior += normal_lpdf(b | 0, 1);
  lprior += normal_lpdf(Intercept | 0, 100);
  lprior += cauchy_lpdf(sigma | 0, 5)
    - 1 * cauchy_lccdf(0 | 0, 5);
  lprior += student_t_lpdf(sd_1 | 3, 0, 2.5)
    - 2 * student_t_lccdf(0 | 3, 0, 2.5);
  lprior += lkj_corr_cholesky_lpdf(L_1 | 1);
}
model {
  // likelihood including constants
  if (!prior_only) {
    // initialize linear predictor term
    vector[N] mu = rep_vector(0.0, N);
    mu += Intercept;
    for (n in 1:N) {
      // add more terms to the linear predictor
      mu[n] += r_1_1[J_1[n]] * Z_1_1[n] + r_1_2[J_1[n]] * Z_1_2[n];
    }
    target += normal_id_glm_lpdf(Y | Xc, mu, b, sigma);
  }
  // priors including constants
  target += lprior;
  target += std_normal_lpdf(to_vector(z_1));
}
generated quantities {
  // actual population-level intercept
  real b_Intercept = Intercept - dot_product(means_X, b);
  // compute group-level correlations
  corr_matrix[M_1] Cor_1 = multiply_lower_tri_self_transpose(L_1);
  vector<lower=-1,upper=1>[NC_1] cor_1;
  // additionally sample draws from priors
  real prior_b = normal_rng(0,1);
  real prior_Intercept = normal_rng(0,100);
  real prior_sigma = cauchy_rng(0,5);
  real prior_sd_1 = student_t_rng(3,0,2.5);
  real prior_cor_1 = lkj_corr_rng(M_1,1)[1, 2];
  // extract upper diagonal of correlation matrix
  for (k in 1:M_1) {
    for (j in 1:(k - 1)) {
      cor_1[choose(k - 1, 2) + j] = Cor_1[j, k];
    }
  }
  // use rejection sampling for truncated priors
  while (prior_sigma < 0) {
    prior_sigma = cauchy_rng(0,5);
  }
  while (prior_sd_1 < 0) {
    prior_sd_1 = student_t_rng(3,0,2.5);
  }
}

Model 3 Stan Code

mo3$model
// generated with brms 2.21.0
functions {
 /* compute correlated group-level effects
  * Args:
  *   z: matrix of unscaled group-level effects
  *   SD: vector of standard deviation parameters
  *   L: cholesky factor correlation matrix
  * Returns:
  *   matrix of scaled group-level effects
  */
  matrix scale_r_cor(matrix z, vector SD, matrix L) {
    // r is stored in another dimension order than z
    return transpose(diag_pre_multiply(SD, L) * z);
  }
}
data {
  int<lower=1> N;  // total number of observations
  vector[N] Y;  // response variable
  int<lower=1> K;  // number of population-level effects
  matrix[N, K] X;  // population-level design matrix
  int<lower=1> Kc;  // number of population-level effects after centering
  // data for group-level effects of ID 1
  int<lower=1> N_1;  // number of grouping levels
  int<lower=1> M_1;  // number of coefficients per level
  array[N] int<lower=1> J_1;  // grouping indicator per observation
  // group-level predictor values
  vector[N] Z_1_1;
  vector[N] Z_1_2;
  int<lower=1> NC_1;  // number of group-level correlations
  int prior_only;  // should the likelihood be ignored?
}
transformed data {
  matrix[N, Kc] Xc;  // centered version of X without an intercept
  vector[Kc] means_X;  // column means of X before centering
  for (i in 2:K) {
    means_X[i - 1] = mean(X[, i]);
    Xc[, i - 1] = X[, i] - means_X[i - 1];
  }
}
parameters {
  vector[Kc] b;  // regression coefficients
  real Intercept;  // temporary intercept for centered predictors
  real<lower=0> sigma;  // dispersion parameter
  vector<lower=0>[M_1] sd_1;  // group-level standard deviations
  matrix[M_1, N_1] z_1;  // standardized group-level effects
  cholesky_factor_corr[M_1] L_1;  // cholesky factor of correlation matrix
}
transformed parameters {
  matrix[N_1, M_1] r_1;  // actual group-level effects
  // using vectors speeds up indexing in loops
  vector[N_1] r_1_1;
  vector[N_1] r_1_2;
  real lprior = 0;  // prior contributions to the log posterior
  // compute actual group-level effects
  r_1 = scale_r_cor(z_1, sd_1, L_1);
  r_1_1 = r_1[, 1];
  r_1_2 = r_1[, 2];
  lprior += normal_lpdf(b | 0, 1);
  lprior += normal_lpdf(Intercept | 0, 100);
  lprior += cauchy_lpdf(sigma | 0, 5)
    - 1 * cauchy_lccdf(0 | 0, 5);
  lprior += student_t_lpdf(sd_1 | 3, 0, 2.5)
    - 2 * student_t_lccdf(0 | 3, 0, 2.5);
  lprior += lkj_corr_cholesky_lpdf(L_1 | 1);
}
model {
  // likelihood including constants
  if (!prior_only) {
    // initialize linear predictor term
    vector[N] mu = rep_vector(0.0, N);
    mu += Intercept;
    for (n in 1:N) {
      // add more terms to the linear predictor
      mu[n] += r_1_1[J_1[n]] * Z_1_1[n] + r_1_2[J_1[n]] * Z_1_2[n];
    }
    target += normal_id_glm_lpdf(Y | Xc, mu, b, sigma);
  }
  // priors including constants
  target += lprior;
  target += std_normal_lpdf(to_vector(z_1));
}
generated quantities {
  // actual population-level intercept
  real b_Intercept = Intercept - dot_product(means_X, b);
  // compute group-level correlations
  corr_matrix[M_1] Cor_1 = multiply_lower_tri_self_transpose(L_1);
  vector<lower=-1,upper=1>[NC_1] cor_1;
  // additionally sample draws from priors
  real prior_b = normal_rng(0,1);
  real prior_Intercept = normal_rng(0,100);
  real prior_sigma = cauchy_rng(0,5);
  real prior_sd_1 = student_t_rng(3,0,2.5);
  real prior_cor_1 = lkj_corr_rng(M_1,1)[1, 2];
  // extract upper diagonal of correlation matrix
  for (k in 1:M_1) {
    for (j in 1:(k - 1)) {
      cor_1[choose(k - 1, 2) + j] = Cor_1[j, k];
    }
  }
  // use rejection sampling for truncated priors
  while (prior_sigma < 0) {
    prior_sigma = cauchy_rng(0,5);
  }
  while (prior_sd_1 < 0) {
    prior_sd_1 = student_t_rng(3,0,2.5);
  }
}

Session Information

sessionInfo()
R version 4.4.1 (2024-06-14 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22631)

Matrix products: default


locale:
[1] LC_COLLATE=English_United States.utf8  LC_CTYPE=English_United States.utf8    LC_MONETARY=English_United States.utf8
[4] LC_NUMERIC=C                           LC_TIME=English_United States.utf8    

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] rstan_2.32.6        StanHeaders_2.32.10 emmeans_1.10.4      moments_0.14.1      EnvStats_3.0.0      MASS_7.3-60.2      
 [7] logspline_2.1.22    bayestestR_0.14.0   glmmTMB_1.1.9       ggeffects_1.7.0     tidybayes_3.0.6     ggplot2_3.5.1      
[13] posterior_1.6.0     bayesplot_1.11.1    loo_2.8.0           dplyr_1.1.4         brms_2.21.0         Rcpp_1.0.13        
[19] future_1.34.0      

loaded via a namespace (and not attached):
  [1] RColorBrewer_1.1-3    tensorA_0.36.2.1      rstudioapi_0.16.0     jsonlite_1.8.8        shape_1.4.6.1         magrittr_2.0.3       
  [7] TH.data_1.1-2         estimability_1.5.1    nloptr_2.1.1          GlobalOptions_0.1.2   vctrs_0.6.5           minqa_1.2.7          
 [13] terra_1.7-78          htmltools_0.5.8.1     distributional_0.4.0  curl_5.2.1            raster_3.6-26         sass_0.4.9           
 [19] parallelly_1.38.0     bslib_0.8.0           sandwich_3.1-1        zoo_1.8-12            lubridate_1.9.3       cachem_1.1.0         
 [25] TMB_1.9.14            mime_0.12             lifecycle_1.0.4       iterators_1.0.14      pkgconfig_2.0.3       Matrix_1.7-0         
 [31] R6_2.5.1              fastmap_1.2.0         shiny_1.9.1           clue_0.3-65           digest_0.6.36         numDeriv_2016.8-1.1  
 [37] colorspace_2.1-1      S4Vectors_0.42.1      fansi_1.0.6           timechange_0.3.0      abind_1.4-5           mgcv_1.9-1           
 [43] compiler_4.4.1        withr_3.0.1           doParallel_1.0.17     backports_1.5.0       inline_0.3.19         QuickJSR_1.3.1       
 [49] hexbin_1.28.3         pkgbuild_1.4.4        rjson_0.2.21          rasterVis_0.51.6      prophet_1.0           tools_4.4.1          
 [55] httpuv_1.6.15         glue_1.7.0            nlme_3.1-164          promises_1.3.0        grid_4.4.1            checkmate_2.3.2      
 [61] cluster_2.1.6         generics_0.1.3        diffobj_0.3.5         gtable_0.3.5          tidyr_1.3.1           sp_2.1-4             
 [67] utf8_1.2.4            BiocGenerics_0.50.0   foreach_1.5.2         pillar_1.9.0          ggdist_3.3.2          stringr_1.5.1        
 [73] later_1.3.2           circlize_0.4.16       splines_4.4.1         lattice_0.22-6        survival_3.6-4        deldir_2.0-4         
 [79] tidyselect_1.2.1      ComplexHeatmap_2.20.0 knitr_1.48            arrayhelpers_1.1-0    gridExtra_2.3         V8_5.0.0             
 [85] IRanges_2.38.1        stats4_4.4.1          xfun_0.46             bridgesampling_1.1-2  matrixStats_1.3.0     stringi_1.8.4        
 [91] boot_1.3-30           codetools_0.2-20      interp_1.1-6          tibble_3.2.1          cli_3.6.3             RcppParallel_5.1.8   
 [97] xtable_1.8-4          munsell_0.5.1         jquerylib_0.1.4       globals_0.16.3        coda_0.19-4.1         png_0.1-8            
[103] svUnit_1.0.6          parallel_4.4.1        rstantools_2.4.0      latticeExtra_0.6-30   jpeg_0.1-10           Brobdingnag_1.2-9    
[109] lme4_1.1-35.5         listenv_0.9.1         viridisLite_0.4.2     mvtnorm_1.2-5         scales_1.3.0          insight_0.20.3       
[115] purrr_1.0.2           crayon_1.5.3          GetoptLong_1.0.5      rlang_1.1.4           multcomp_1.4-26      
LS0tDQp0aXRsZTogU3VwcGxlbWVudCBmb3IgIkR5bmFtaWNzIG9mIFNBUlMtQ29WLTIgVmFyaWFudHMgaW4gU291dGh3ZXN0IE9oaW8gTXVuaWNpcGFsIFdhc3Rld2F0ZXIuIg0KYXV0aG9yOiAiYHIgcGFzdGUoYygnTmFnYXJrYXIgTScsICdLZWVseSBTJywgJ1doZWF0b24gRScsICdIYXJ0IEMnLCAnSmFobmUgTScsICdHYXJsYW5kIEonLCAnVmFydWdoZXNlIEUnLCANCidCcmlua21hbiBOJyksIGNvbGxhcHNlID0gJywgJylgIg0KDQpvdXRwdXQ6DQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzQnDQogIGh0bWxfbm90ZWJvb2s6DQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCi0tLQ0KDQojIFB1cnBvc2UNCg0KQW5hbHlzaXMgb2YgT0M0MyBSZWNvdmVyeSBhbmQgZXF1YXRpb25zIDEgdG8gNCBpbiB0aGUgbWFudXNjcmlwdC4gDQoNCg0KIyBTdXBwcmVzcyB3YXJuaW5ncyBhbmQgbWVzc2FnZXMNCg0KYGBge3J9DQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpDQpgYGANCg0KDQojIFIgTGlicmFyaWVzDQoNCmBgYHtyfQ0KbGlicmFyeShmdXR1cmUpDQpsaWJyYXJ5KGJybXMpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsb28pDQpsaWJyYXJ5KGJheWVzcGxvdCkNCmxpYnJhcnkocG9zdGVyaW9yKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5YmF5ZXMpDQpsaWJyYXJ5KGdnZWZmZWN0cykNCmxpYnJhcnkoZ2xtbVRNQikNCmxpYnJhcnkoYmF5ZXN0ZXN0UikNCmxpYnJhcnkobG9nc3BsaW5lKQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeShnZ2VmZmVjdHMpDQpsaWJyYXJ5KHRpZHliYXllcykNCmxpYnJhcnkoRW52U3RhdHMpDQpsaWJyYXJ5KG1vbWVudHMpDQpsaWJyYXJ5KGVtbWVhbnMpDQpsaWJyYXJ5KHJzdGFuKQ0KYGBgDQoNCg0KYGBge3J9DQpyc3Rhbl9vcHRpb25zKGF1dG9fd3JpdGUgPSBUUlVFKQ0KYGBgDQoNCg0KIyBHZXQgT0M0MyBSZWNvdmVyeSBEYXRhIGFuZCBDYWxjdWxhdGUgQXZlcmFnZXMgcGVyDQoNCmBgYHtyfQ0Kb2M0My5kYXRhIDwtIHJlYWQuY3N2KHBhc3RlMChjMTkuZGlyLCJvYzQzX2RmLmNzdiIpKQ0KYmlvLmF2ZyA8LSBvYzQzLmRhdGEgJT4lIA0KICBncm91cF9ieShzaXRlLCBkYXRlLCBiaW9fcmVwKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3Moc3RhcnRzX3dpdGgoInJlY292ZXJ5IiksIH4gbWVhbigueCwgbmEucm09VFJVRSkpLCAuZ3JvdXBzPSAnZHJvcCcpDQojYmlvLmF2Zw0KZmluYWwuYXZnIDwtIGJpby5hdmcgJT4lIA0KICBncm91cF9ieShzaXRlLCBkYXRlKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3Moc3RhcnRzX3dpdGgoInJlY292ZXJ5IiksIH4gbWVhbigueCwgbmEucm09VFJVRSkpLCAuZ3JvdXBzPSAnZHJvcCcpDQoNCmZpbmFsLmF2ZyRzaXRlIDwtIGZhY3RvcihmaW5hbC5hdmckc2l0ZSwgbGV2ZWxzID0gcGFzdGUwKCJTUyIsIDE6MTEpICkNCmZpbmFsLmF2ZyRkYXRlIDwtIGFzLkRhdGUoZmluYWwuYXZnJGRhdGUpDQoNCmZpbmFsLmF2ZyA8LSBmaW5hbC5hdmcgJT4lIA0KICBtdXRhdGUoZXBpX21vbnRoID0gZmxvb3JfZGF0ZShkYXRlLCAibW9udGgiKSkgDQoNCiNmaWx0ZXIgb3V0IDIwMjAtMTAtMDEgYmVjYXVzZSBpdCBpcyB0aGUgZWFybGllc3QgbW9udGggaW4gdGhlIHN0dWR5IGFuZCBoYXMgMCBvciAxIHJlY292ZXJ5IG1lYXN1cmVtZW50cy4NCmZpbmFsLmF2ZyA8LSBmaW5hbC5hdmcgJT4lDQogIGZpbHRlcihlcGlfbW9udGggIT0gIjIwMjAtMTAtMDEiKQ0KI2ZpbmFsLmF2Zw0KYGBgDQoNCg0KIyMgUS1RIFBsb3Qgb2YgUmVjb3ZlcnkNCmBgYHtyfQ0KcXFub3JtKGxvZzEwKGZpbmFsLmF2ZyRyZWNvdmVyeSksIG1haW4gPSAiUS1RIFBsb3Qgb2YgT0M0MyBSZWNvdmVyeSIpDQpxcWxpbmUobG9nMTAoZmluYWwuYXZnJHJlY292ZXJ5KSwgY29sID0gInJlZCIpDQpgYGANCg0KIyBGaXQgYW4gSW50ZXJjZXB0IEJheWVzaWFuIE1vZGVsIHRvIHRoZSBPQzQzIFJlY292ZXJ5IERhdGENCg0KVG8gdHJhY2sgdGhlIG92ZXJhbGwgcGVyZm9ybWFuY2Ugb2YgbGFib3JhdG9yeSBtZXRob2RzIHVzZWQgaW4gb3VyIHN0dWR5IG9mIFNBUlMtQ29WLTIgaW4gd2FzdGV3YXRlciBzYW1wbGVzLCBhIEJheWVzaWFuIG1vZGVsIHdhcyB1c2VkIHRvIGVzdGltYXRlIHRoZSByZWNvdmVyeSBvZiB0aGUgT0M0MyBwcm9jZXNzIGNvbnRyb2wgc3Bpa2VkIGludG8gdGhlc2Ugc2FtcGxlcy4gSXQgdXNlcyBhIHN0dWRlbnQtdCBkaXN0cmlidXRpb24gZm9yIHRoZSByZWNvdmVyeSBhbmQgaXMgYSBzaW1wbGUgaW50ZXJjZXB0IG1vZGVsIHdpdGggbm8gcHJlZGljdG9ycy4gDQoNClRoZSBtb2RlbCBjYW4gYmUgZXhwcmVzc2VkIGFzOg0KDQokJA0KeV9pIFxzaW0gXGJldGFfMCArICBcZXBzaWxvbl9pIA0KJCQNCldoZXJlOg0KDQotICR5X2kkIHJlcHJlc2VudHMgdGhlIGxvZzEwIHNjYWxlIG91dGNvbWUgdmFyaWFibGUgKCJQZXJjZW50IE9DNDMgUmVjb3ZlcnkiKSBmb3Igb2JzZXJ2YXRpb24gJGkkDQoNCi0gJFxiZXRhXzAkIGlzIHRoZSBmaXhlZCBpbnRlcmNlcHQNCg0KLSAkXGVwc2lsb25faSQgaXMgdGhlIGVycm9yIHRlcm0gZm9yIG9ic2VydmF0aW9uICRpJA0KDQoNCg0KDQojIyBQcmVwYXJlIERhdGEgZm9yIHRoZSBSYW5kb20gSW50ZXJjZXB0IE1vZGVsDQoNCmBgYHtyfQ0KZGF0ZWZhY3QuYXZnIDwtIGZpbmFsLmF2Zw0KZGF0ZWZhY3QuYXZnJGRhdGUgPC0gYXMuZmFjdG9yKGRhdGVmYWN0LmF2ZyRkYXRlKSAjZm9yIGludmVzdGlnYXRpbmcgZGF0ZSBlZmZlY3RzLCBpZiBuZWVkZWQNCmRhdGVmYWN0LmF2ZyRlcGlfbW9udGggPC0gYXMuZmFjdG9yKGRhdGVmYWN0LmF2ZyRlcGlfbW9udGgpICNmb3IgaW52ZXN0aWdhdGluZyBtb250aCBlZmZlY3RzLCBpZiBuZWVkZWQNCiNkYXRlZmFjdC5hdmcNCmBgYA0KDQojIyBCYXllc2lhbiBJbnRlcmNlcHQgTW9kZWwgZm9yIE9DNDMgUmVjb3ZlcnkNCmBgYHtyfQ0KIyBicm1zLjEgPC0gYnJtKA0KIyAgIGxvZzEwKHJlY292ZXJ5KSB+IDEgLA0KIyAgIGRhdGEgPSBkYXRlZmFjdC5hdmcsDQojICAgZmFtaWx5ID1zdHVkZW50KCksDQojICAgcHJpb3IgPSBjKA0KIyAgICAgcHJpb3Iobm9ybWFsKDEwMCwgMTApLCBjbGFzcyA9ICJJbnRlcmNlcHQiKSwNCiMgICAgIHByaW9yKGdhbW1hKDIsIDAuMSksIGNsYXNzID0gIm51IikgICAgICAgICNkZWdyZWVzIG9mIGZyZWVkb20gZm9yIHN0dWRlbnQtdA0KIyAgICksDQojICAgd2FybXVwID0gNTAwLA0KIyAgIGl0ZXIgPSA0MDAwLA0KIyAgIGNvbnRyb2w9bGlzdChhZGFwdF9kZWx0YSA9MC45NSwgbWF4X3RyZWVkZXB0aD0xMCksDQojICAgY2hhaW5zID00LA0KIyAgIHNhbXBsZV9wcmlvciA9ICJ5ZXMiLA0KIyAgIHNlZWQgPSA1MTMsDQojICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLA0KIyAgIHNhdmVfcmFuZWYgPSBUUlVFLA0KIyAgIHNhdmVfYWxsX3BhcnMgPSBUUlVFLA0KIyAgIGZpbGUgPSdicm1fMS5yZHMnLA0KIyAgIHNhdmVfbW9kZWwgPSAnYnJtXzFfbW9kZWwudHh0JywNCiMgICBmdXR1cmU9VFJVRQ0KIyApDQpgYGANCg0KIyMgUHJpbnQgU2F2ZWQgTW9kZWwgUmVzdWx0cw0KYGBge3J9DQpicm1zLjEucmVhZCA8LSBicm0oZmlsZT0iYnJtXzEucmRzIikNCnByaW50KGJybXMuMS5yZWFkLCBkaWdpdHMgPSA0KQ0KYGBgDQojIyBQcmlvciBTdW1tYXJ5DQoNCmBgYHtyfQ0KcHJpb3Jfc3VtbWFyeShicm1zLjEucmVhZCkNCmBgYA0KDQoNCiMjIFByaW50IEZpdCBFc3RpbWF0ZXMNCmBgYHtyfQ0KcHJpbnQoYnJtcy4xLnJlYWQkZml0LCBkaWdpdHMgPSA0KQ0KYGBgDQpUaGUgbWVhbiByZWNvdmVyeSBpcyBgciAxMF4xLjY3NTkgYCAoNDcuNDElKSB3aXRoIGEgOTUlIGNyZWRpYmxlIGludGVydmFsIG9mIGByIDEwXjEuNjQ2NiBgIHRvICBgciAxMF4xLjcwNDdgICg0NC4zMiB0byA1MC42NikuIA0KDQoNCiMjIFBvc3RlcmlvciBQcmVkaWN0aXZlIENoZWNraW5nIChQUEMpIG9mIE9DNDMgUmVjb3ZlcnkgSW50ZXJjZXB0IE1vZGVsDQoNClBQQyBnZW5lcmF0ZXMgTGVhdmUtT25lLU91dCAoTE9PKSBpbnRlcnZhbHMgcGxvdCBmb3IgUFBDLiBJdCBhc3Nlc3NlcyB0aGUgb3ZlcmFsbCBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbCBhbmQgZGV0ZWN0cyBwb3RlbnRpYWwgaXNzdWVzIHdpdGggbW9kZWwgc3BlY2lmaWNhdGlvbiBvciBkYXRhIHF1YWxpdHkgKGkuZS4sIG91dGxpZXJzKS4NCg0KS2V5IEVsZW1lbnRzIG9mIHRoZSBQbG90Og0KDQotIFktYXhpczogUmVwcmVzZW50cyB0aGUgcmVzcG9uc2UgdmFyaWFibGUgKE9DNDMgUmVjb3ZlcnkpLg0KLSBYLWF4aXM6IFJlcHJlc2VudHMgdGhlIGluZGV4ZWQgb3JkZXIgb2Ygb2JzZXJ2YXRpb25zIChhbHBoYWJldGljYWxseSBTUzEgdG8gU1MxMSBhbmQgdGVtcG9yYWxseSBvcmRlcmVkKS4NCi0gT2JzZXJ2ZWQgRGF0YSBQb2ludHM6IFNob3duIGFzIGRhcmsgZG90cy4NCi0gTE9PIFByZWRpY3Rpb24gSW50ZXJ2YWxzOiBWZXJ0aWNhbCBsaW5lcyBmb3IgZWFjaCBvYnNlcnZhdGlvbiBzaG93IHRoZSBwcmVkaWN0ZWQgcmFuZ2VzLg0KLSBNZWRpYW4gUHJlZGljdGlvbnM6IExpZ2h0LWJsdWUgcG9pbnRzIHdpdGhpbiB0aGUgaW50ZXJ2YWxzLg0KDQpUaGUgcHJvYiA9IDAuNSBhbmQgcHJvYl9vdXRlciA9IDAuOTUgYXJndW1lbnRzIGdlbmVyYXRlIDUwJSBhbmQgOTUlIHByZWRpY3Rpb24gaW50ZXJ2YWxzLiBGb3IgcHJvYj0gMC41LCBoYWxmIG9mIHRoZSBvYnNlcnZlZCBkYXRhIHBvaW50cyBzaG91bGQgZmFsbCB3aXRoaW4gdGhlc2UgaW50ZXJ2YWxzIGlmIHRoZSBtb2RlbCBpcyB3ZWxsLWNhbGlicmF0ZWQuIExpa2V3aXNlLCBmb3IgcHJvYl9vdXRlciA9MC45NSwgOTUlIG9mIHRoZSBvYnNlcnZlZCBkYXRhIHNob3VsZCBmYWxsIHdpdGhpbiB0aGVzZSBpbnRlcnZhbHMuDQoNCg0KYGBge3Igd2FybmluZ3M9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpwcF9jaGVjayhicm1zLjEucmVhZCAsIHR5cGU9Imxvb19pbnRlcnZhbHMiLHByb2IgPSAwLjUsIHByb2Jfb3V0ZXI9IDAuOTUpKw0KICBnZ3Bsb3QyOjp5bGFiKCJSZWNvdmVyeSIpICsNCiAgZ2dwbG90Mjo6eGxhYigiSW5kZXgiKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE0KQ0KICApDQpgYGANCg0KIyMgT2JzZXJ2ZWQgVmFsdWVzIHdpdGhpbiA5NSUgUHJlZGljdGlvbiBJbnRlcnZhbA0KYGBge3J9DQpwcC5kcmF3cyA8LSBwb3N0ZXJpb3JfcHJlZGljdChicm1zLjEucmVhZCkNCmxvd2VyLmNpIDwtIGFwcGx5KHBwLmRyYXdzLCAyLCBxdWFudGlsZSwgcHJvYiA9IDAuMDI1KQ0KdXBwZXIuY2kgPC0gYXBwbHkocHAuZHJhd3MsIDIsIHF1YW50aWxlLCBwcm9iID0gMC45NzUpDQpvYnNlcnZlZC52YWwgPC0gYnJtcy4xLnJlYWQkZGF0YSRyZWNvdmVyeQ0Kd2l0aGluLmludGVydmFsIDwtIChvYnNlcnZlZC52YWwgPiAxMF5sb3dlci5jaSkgJiAob2JzZXJ2ZWQudmFsIDwgMTBedXBwZXIuY2kpDQpuLndpdGhpbi5pbnRlcnZhbCA8LSBzdW0od2l0aGluLmludGVydmFsKQ0KcHJvcG9ydGlvbi53aXRoaW4uaW50ZXJ2YWwgPC0gbi53aXRoaW4uaW50ZXJ2YWwgLyBsZW5ndGgob2JzZXJ2ZWQudmFsKQ0KYGBgDQoNClRoZSBudW1iZXIgb2Ygb2JzZXJ2ZWQgdmFsdWVzIHdpdGhpbiB0aGUgOTUlIHByZWRpY3Rpb24gaW50ZXJ2YWwgaXMgYHIgbi53aXRoaW4uaW50ZXJ2YWwgYCwgd2hpY2ggaXMgYHIgcm91bmQoIHByb3BvcnRpb24ud2l0aGluLmludGVydmFsICogMTAwLCAyKWAgcGVyY2VudC4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgbW9kZWwgaXMgYWNjdXJhdGUsIGFzIG1vc3Qgb2JzZXJ2ZWQgZGF0YSBwb2ludHMgZmFsbCB3aXRoaW4gdGhlIDk1JSBwcmVkaWN0aW9uIGludGVydmFsLg0KDQojIyBSZXNpZHVhbHMgZm9yIFJlY292ZXJ5DQoNCmBgYHtyfQ0KcmVzaWQubWF0IDwtIHJlc2lkdWFscyhicm1zLjEucmVhZCwgdHlwZT0ib3JkaW5hcnkiICkNCiNyZXNpZC5tYXQNCm1lYW4ucmVzaWQgIDwtIGFwcGx5KHJlc2lkLm1hdCwgMSwgbWVhbikNCiNtZWFuLnJlc2lkDQpvYzQzLndpdGhyZXNpZHVhbHMuZGYgPC0gYnJtcy4xLnJlYWQkZGF0YSAlPiUNCiAgbXV0YXRlKG1lYW4ucmVzaWQgPSBtZWFuLnJlc2lkLA0KICByb3cuaW5kZXggPSByb3dfbnVtYmVyKCkgKQ0KI29jNDMud2l0aHJlc2lkdWFscy5kZg0KDQpnZ3Bsb3Qob2M0My53aXRocmVzaWR1YWxzLmRmLCBhZXMoeD0gcm93LmluZGV4LCB5PW1lYW4ucmVzaWQpKSsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh0aXRsZSA9Ik1lYW4gT0M0MyBSZXNpZHVhbHMgYnkgU2FtcGxlIiwNCiAgICAgICB4ID0gIlNhbXBsZSIsDQogICAgICAgeSA9ICJNZWFuIFJlc2lkdWFsIg0KICAgICAgICkNCmBgYA0KDQojIyBRLVEgUGxvdCBvZiBSZWNvdmVyeSBSZXNpZHVhbHMNCmBgYHtyfQ0KcXFub3JtKG9jNDMud2l0aHJlc2lkdWFscy5kZiRtZWFuLnJlc2lkLCBtYWluID0gIlEtUSBQbG90IG9mIE9DNDMgUmVjb3ZlcnkgUmVzaWR1YWxzIikNCnFxbGluZShvYzQzLndpdGhyZXNpZHVhbHMuZGYkbWVhbi5yZXNpZCwgY29sID0gInJlZCIpDQpgYGANCg0KIyMjIFN1bW1hcnkgb2YgUmVzaWR1YWxzDQoNClRoZSByZXNpZHVhbHMgYXJlIHN5bW1ldHJpY2FsbHkgY2VudGVyZWQgYXJvdW5kIDAgYmV0d2VlbiAtMSBhbmQgMSBhbmQgUS1RIHJlc2lkdWFsIHBsb3QgaW5kaWNhdGVzIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFRoZSBjb25zaXN0ZW50IHBlcmZvcm1hbmNlIG9mIHRoZSBPQzQzIHByb2Nlc3MgY29udHJvbCBhY3Jvc3MgYWxsIHdhc3Rld2F0ZXIgc2FtcGxlcyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgbGFib3JhdG9yeSBtZXRob2RzIHVzZWQgaW4gb3VyIFNBUlMtQ29WLTIgc3R1ZHkgYXJlIHJlbGlhYmxlLiANCg0KDQojIFNBUlMtQ29WLTIgU2VjdGlvbg0KIyMgR2V0IFNBUlMtQ29WLTIgRGF0YQ0KYGBge3J9DQpjMTkuZGlyIDwtICJEOi9jMTkvc2VxX21hbnVzY3JpcHQvci8iICANCmMxOS5kYXRhIDwtIHJlYWQuY3N2KHBhc3RlMChjMTkuZGlyLCAic2V3ZXJzaGVkX2RhdGEuY3N2IiksaGVhZGVyPVRSVUUsbmEuc3RyaW5ncz1jKCIiLCJOQSIpKQ0KYzE5LmRhdGEkZGF0ZSA8LWFzLkRhdGUoYzE5LmRhdGEkZGF0ZSkNCmMxOS5kYXRhJHNpdGUgPC1hcy5mYWN0b3IoYzE5LmRhdGEkc2l0ZSkNCmMxOS5kYXRhJHBoYXNlIDwtIGFzLmZhY3RvcihjMTkuZGF0YSRwaGFzZSkNCmMxOS5kYXRhJHBoYXNlIDwtIHJlbGV2ZWwoYzE5LmRhdGEkcGhhc2UsIHJlZiA9ICJwcmUtVk9DIiApDQpgYGANCg0KDQojIFNlY3Rpb24gZm9yIEVxdWF0aW9uIDENCg0KKipEb2VzIFNBUlMtQ29WLTIgc2hlZGRpbmcgdmFyeSBieSBzZXdlcnNoZWQgY29tbXVuaXRpZXM/KioNCg0KVGhlIGFtb3VudCBvZiBTQVJTLUNvVi0yIGVudGVyaW5nIHdhc3Rld2F0ZXIgdHJlYXRtZW50IHN5c3RlbXMgZGVwZW5kcyBvbiB0aGUgYW1vdW50IG9mIGZlY2VzIGV4Y3JldGVkIHBlciBwZXJzb24sIHRoZSB2b2x1bWUgb2Ygd2FzdGV3YXRlciBwZXIgaG91c2Vob2xkLCBhbmQgdGhlIG51bWJlciBvZiBpbmZlY3RlZCBpbmRpdmlkdWFscy4gDQoNClRoZSBzaGVkZGluZyBmdW5jdGlvbiBpcyBiYXNlZCBvbiB0aGUgZm9sbG93aW5nIGVxdWF0aW9uIChzZWUgUHJhc2VrIGV0IGFsLiAyMDIyOzEwLjEwMTYvai5zY2l0b3RlbnYuMjAyMi4xNTY1MzUpOg0KDQojIyBTaGVkZGluZyBGdW5jdGlvbg0KJCQNClNfdz0gXGZyYWN7Q193IFx0aW1lcyBGX3d9eyBNX2ZcdGltZXMgTl9pfSBcdGFne0VxLiAxfSANCiQkDQoNClRoaXMgZXF1YXRpb24gc2hvd3MgaG93ICRTX2YkICh0aGUgYW1vdW50IG9mIFNBUlMtQ29WLTIgc2hlZCBwZXIgZ3JhbSkgY2FuIGJlIGVzdGltYXRlZCBieSB1c2luZyB0aGUgY29uY2VudHJhdGlvbiBvZiBOMiBnZW5lIGluIHdhc3Rld2F0ZXIgJENfdyQgKGNvcGllcy9MKSwgdGhlIHdhc3Rld2F0ZXIgZmxvdyAkRl93JCAoTC9kYXkpLCB0aGUgbWFzcyBvZiBmZWNlcyBleGNyZXRlZCBieSBhIHBlcnNvbiAkTV9mJCAoMTI4IGcvZGF5KSwgYW5kIHRoZSBudW1iZXIgb2YgaW5mZWN0ZWQgcGVyc29ucyAkTl9pJCAoQ09WSUQtMTkgY2FzZXMpLg0KDQpBY2NvcmRpbmcgdG8gUm9zZSAoMjAxNSxET0k6MTAuMTA4MC8xMDY0MzM4OS4yMDE0LjEwMDA3NjEpLCB0aGUgcXVhbnRpdHkgb2YgZmVjZXMgZXhjcmV0ZWQgcGVyIHBlcnNvbi9kYXkgcmFuZ2VzIGZyb20gNTHigJM3OTYgZyB3aXRoIGEgbWVkaWFuLCBtZWFuLCBhbmQgc2lnbWEgb2YgMTI4LCAxNDksIGFuZCA5NS4NCg0KDQojIyBSYW5kb20gSW50ZXJjZXB0IE1vZGVsIGZvciBGZWNhbCBTaGVkZGluZw0KDQpSZWdyZXNzaW9uIHdhcyB1c2VkIHRvIGRldGVybWluZSBpZiB0aGVyZSBhcmUgZGlmZmVyZW5jZXMgaW4gdmlydXMgc2hlZGRpbmcuIFRoZSBtb2RlbCBpcyBhIHJhbmRvbSBpbnRlcmNlcHQgbW9kZWwgd2l0aCBhIEdhdXNzaWFuIGRpc3RyaWJ1dGlvbi4gVGhlIG1vZGVsIGNhbiBiZSBleHByZXNzZWQgYXM6DQoNCiQkDQp5X2kgXHNpbSBcYmV0YV8wICsgdV9qICsgXGVwc2lsb25faSANCiQkDQpXaGVyZToNCg0KLSAkeV9pJCByZXByZXNlbnRzIHRoZSBvdXRjb21lIHZhcmlhYmxlICRTX3ckICgiZmVjYWxfbG9hZCIpIGZvciBvYnNlcnZhdGlvbiAkaSQsICRcYmV0YV8wJCBpcyB0aGUgZml4ZWQgaW50ZXJjZXB0DQoNCi0gJHVfaiQgaXMgdGhlIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHNpdGUgJGokDQoNCi0gJFxlcHNpbG9uX2kkIGlzIHRoZSBlcnJvciB0ZXJtIGZvciBvYnNlcnZhdGlvbiAkaSQNCg0KDQoNCiMjIyBGZWNhbCBTaGVkZGluZyBCUk1TIFJhbmRvbSBJbnRlcmNlcHQgTW9kZWwNCmBgYHtyfQ0KIyBicm0uZmVjYWwubG9hZC5yYW5kIDwtIGJybSgNCiMgICBsb2cxMChmZWNhbF9sb2FkKSB+IDErICgxfHNpdGUpLA0KIyAgIGRhdGEgPSBjMTkuZGF0YSwNCiMgICBmYW1pbHkgPWdhdXNzaWFuLA0KIyAgIGNvbnRyb2w9bGlzdChhZGFwdF9kZWx0YSA9MC45NSxtYXhfdHJlZWRlcHRoPTEwKSwgIyB0cnkgdGhpcyAwLjk2IG5leHQNCiMgICB3YXJtdXAgPSA1MDAsDQojICAgaXRlciA9IDQwMDAsDQojICAgY2hhaW5zID00LA0KIyAgIHNhbXBsZV9wcmlvciA9ICJ5ZXMiLA0KIyAgIHNlZWQgPSA1MTMsDQojICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLA0KIyAgIHNhdmVfcmFuZWYgPSBUUlVFLA0KIyAgIHNhdmVfYWxsX3BhcnMgPSBUUlVFLA0KIyAgIGZpbGUgPSdicm1fZmVjYWxfbG9hZF9yYW5kLnJkcycsICMgdGhpcyBzaG91bGQgYmUgZGVsZXRlZCBpbiB0aGUgUHJvamVjdCBkaXJlY3RvcnkgZWFjaCB0aW1lIG1vZGVsIHJlcnVuDQojICAgc2F2ZV9tb2RlbCA9ICdicm0uZmVjYWwubG9hZC5yYW5kX21vZGUudHh0JywNCiMgICBmdXR1cmU9VFJVRQ0KIyApDQpgYGANCg0KDQojIyMgTG9hZCBhbmQgUHJpbnQgU2F2ZWQgRmVjYWwgU2hlZGRpbmcgTW9kZWwgUmVzdWx0cw0KYGBge3J9DQpmcy5tbzEgPC0gYnJtKGZpbGU9ImJybV9mZWNhbF9sb2FkX3JhbmQucmRzIikNCnByaW50KGZzLm1vMSwgZGlnaXRzPTQpDQpgYGANCiMjIFByaW9yIFN1bW1hcnkNCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KGZzLm1vMSkNCmBgYA0KDQoNCiMjIyBQcmludCBGaXQgRXN0aW1hdGVzDQpgYGB7cn0NCnByaW50KGZzLm1vMSRmaXQsIGRpZ2l0cz00KQ0KYGBgDQoNCioqU3VtbWFyeSBvZiBGZWNhbCBTaGVkZGluZyBNb2RlbCoqDQoNCioqT3ZlcmFsbCBNb2RlbCBTdHJ1Y3R1cmU6KioNCg0KVGhlcmUgYXJlIGNyZWRpYmxlIGRpZmZlcmVuY2VzIGJldHdlZW4gc2V3ZXJzaGVkIHNpdGVzIGFzIGV2aWRlbmNlZCBieSB0aGUgcmFuZG9tIGVmZmVjdCBzdGFuZGFyZCBkZXZpYXRpb24gKDAuMjk0NTogOTUlIENJOiAwLjE4MzYgdG8gMC40OTYyKSBub3QgY29udGFpbmluZyAwLg0KDQoqKkZpeGVkIEVmZmVjdCAoT3ZlcmFsbCBNZWFuKToqKg0KDQotIEludGVyY2VwdDogOC40ODE0ICg5NSUgQ0k6IDguMjk3NSB0byA4LjY2MjIpLiBUaGlzIHJlcHJlc2VudHMgdGhlIG92ZXJhbGwgYXZlcmFnZSBsb2cxMChmZWNhbF9sb2FkKSBhY3Jvc3MgYWxsIHNpdGVzLg0KDQoqKlJhbmRvbSBFZmZlY3QgKFNpdGUtU3BlY2lmaWMgVmFyaWF0aW9uKToqKg0KDQotIHNkKEludGVyY2VwdCk6IDAuMjk0NSAoOTUlIENJOiAwLjE4MzYgdG8gMC40OTYyKS4gVGhpcyByZXByZXNlbnRzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNpdGUtc3BlY2lmaWMgaW50ZXJjZXB0cyBhcm91bmQgdGhlIG92ZXJhbGwgbWVhbi4NCg0KKipSZXNpZHVhbCBWYXJpYXRpb246KioNCg0KLSBzaWdtYTogMC4zMTczICg5NSUgQ0k6IDAuMzAyNCB0byAwLjMzMjkpLiBUaGlzIHJlcHJlc2VudHMgdGhlIHVuZXhwbGFpbmVkIHZhcmlhdGlvbiB3aXRoaW4gc2l0ZXMuDQoNCioqSW50cmFjbGFzcyBDb3JyZWxhdGlvbiBDb2VmZmljaWVudCAoSUNDKToqKg0KDQotIElDQyA9IHZhcihzaXRlKSAvICh2YXIoc2l0ZSkgKyB2YXIocmVzaWR1YWwpKS4gVGhlIElDQyBlc3RpbWF0ZSBpcyAwLjI5NDVeMiAvICgwLjI5NDVeMiArIDAuMzE3M14yKSA9IDAuNDYzLCB3aGljaCBzdWdnZXN0cyB0aGF0IGFib3V0IDQ2JSBvZiB0aGUgdG90YWwgdmFyaWF0aW9uIGluIGxvZzEwKGZlY2FsX2xvYWQpIGlzIGR1ZSB0byBkaWZmZXJlbmNlcyBiZXR3ZWVuIHNpdGVzLiANCg0KVGhlIHJhbmRvbSBlZmZlY3Qgc3RhbmRhcmQgZGV2aWF0aW9uICgwLjI5NDUpIGlzIHJlbGF0aXZlbHkgc21hbGwgY29tcGFyZWQgdG8gdGhlIG92ZXJhbGwgbWVhbiAoOC40ODE0KSBpbmRpY2F0aW5nIHRoYXQgd2hpbGUgdGhlcmUgYXJlIHNpdGUtc3BlY2lmaWMgZGlmZmVyZW5jZXMsIHRoZXkgYXJlIG5vdCBsYXJnZSByZWxhdGl2ZSB0byB0aGUgb3ZlcmFsbCBtZWFuLg0KDQoNCg0KIyMjIFBvc3RlcmlvciBQcmVkaWN0aXZlIENoZWNraW5nIChQUEMpIG9mIEZlY2FsIFNoZWRkaW5nIFJhbmRvbSBJbnRlcmNlcHQgTW9kZWwgDQoNCmBgYHtyfQ0KcHBfY2hlY2soZnMubW8xLCB0eXBlPSJsb29faW50ZXJ2YWxzIixwcm9iID0gMC41LHByb2Jfb3V0ZXI9IDAuOTUpICsNCiAgZ2dwbG90Mjo6eWxhYigiRmVjYWwgTG9hZCIpICsNCiAgZ2dwbG90Mjo6eGxhYigiU2FtcGxlIEluZGV4IikgKw0KICBnZ3Bsb3QyOjp0aGVtZSgNCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNCkNCiAgKQ0KYGBgDQoNCiMjIyBIYWxmZXllIFBsb3Qgb2YgdGhlIFNld2Vyc2hlZCBJbnRlcmNlcHRzIA0KYGBge3J9DQpzaXRlX29yZGVyIDwtIGMoIlNTMSIsICJTUzIiLCAiU1MzIiwgIlNTNCIsICJTUzUiLCAiU1M2IiwgIlNTNyIsICJTUzgiLCAiU1M5IiwgIlNTMTAiLCAiU1MxMSIpDQoNCiNleHRyYWN0IHJhbmRvbSBpbnRlcmNlcHRzDQpmcy5tbzEgICU+JQ0KICBzcHJlYWRfZHJhd3Mocl9zaXRlW3NpdGUsdGVybV0pICU+JQ0KICBmaWx0ZXIodGVybSAlaW4lIGMoIkludGVyY2VwdCIpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2l0ZSA9IGZhY3RvcihzaXRlLCBsZXZlbHMgPSBzaXRlX29yZGVyLCBvcmRlcmVkID0gVFJVRSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBzaXRlLCB4ID0gcl9zaXRlKSkgKw0KICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNTAsIC45NSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBmYWNldF93cmFwKH50ZXJtLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBsYWJzKHggPSAiUmFuZG9tIEVmZmVjdCIsIHkgPSAiU2l0ZSIsDQogICAgICAgdGl0bGUgPSAiUmFuZG9tIEVmZmVjdHMgYnkgU2l0ZSIpKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldihzaXRlX29yZGVyKSkgDQpgYGANCg0KDQojIyMgTGVhdmUtT25lLU91dCBDcm9zcy1WYWxpZGF0aW9uIChMT08tQ1YpIFNlY3Rpb24gZm9yIHRoZSBGZWNhbCBTaGVkZGluZyBNb2RlbCANCg0KTE9PLUNWIGlzIGEgc3RhdGlzdGljYWwgbWV0aG9kIHVzZWQgdG8gZXN0aW1hdGUgdGhlIHBlcmZvcm1hbmNlIG9mIG1vZGVscyBvbiBkYXRhIG5vdCB1c2VkIGR1cmluZyB0aGUgdHJhaW5pbmcgb2YgdGhlIG1vZGVsLiBJdCBpcyBhIHNwZWNpZmljIGNvbmZpZ3VyYXRpb24gb2Ygay1mb2xkIGNyb3NzLXZhbGlkYXRpb24gd2hlcmUgayBpcyBzZXQgdG8gdGhlIG51bWJlciBvZiBleGFtcGxlcyBpbiB0aGUgZGF0YXNldC4gRm9yIGEgZGF0YXNldCB3aXRoIG4gb2JzZXJ2YXRpb25zLCBMT08tQ1Ygd2lsbCBjcmVhdGUgbiBkaWZmZXJlbnQgbW9kZWxzLCBlYWNoIHRpbWUgbGVhdmluZyBvdXQgb25lIG9ic2VydmF0aW9uIGZyb20gdGhlIHRyYWluaW5nIHNldCB0byBldmFsdWF0ZSBwZXJmb3JtYW5jZS4NCg0KIyMjIExPTy1DVg0KYGBge3J9DQpsb28uZnMubW8xPC0gbG9vKGZzLm1vMSkNCmBgYA0KDQojIyMgUHJpbnQgTE9PLUNWIFJlc3VsdHMNCmBgYHtyfQ0KbG9vLmZzLm1vMQ0KYGBgDQoNCg0KIyMjIEZlY2FsIFNoZWRkaW5nIE1vZGVsOiBQYXJldG8gU21vb3RoZWQgSW1wb3J0YW5jZSBTYW1wbGluZyAoUFNJUykgDQoNCioqSW50ZXJwcmV0YXRpb24gb2YgUFNJUyBrIHZhbHVlczoqKg0KDQotIGsgPCAwLjU6IFRoZSBlc3RpbWF0ZSBpcyByZWxpYWJsZQ0KDQotIDAuNSA8IGsgPCAwLjc6IFRoZSBlc3RpbWF0ZSBpcyBzb21ld2hhdCByZWxpYWJsZQ0KDQotIGsgPiAwLjc6IFRoZSBlc3RpbWF0ZSBpcyB1bnJlbGlhYmxlIGFuZCBzaG91bGQgYmUgdHJlYXRlZCB3aXRoIGNhdXRpb24NCg0KQWxsIDMgbW9kZWxzIGhhdmUgayA8IDAuNSwgd2hpY2ggbWVhbnMgdGhlaXIgZXN0aW1hdGVzIGFyZSByZWxpYWJsZS4NCg0KDQojIyMgUGFyZXRvIFNtb290aGVkIEltcG9ydGFuY2UgU2FtcGxpbmcgKFBTSVMpIEVzdGltYXRlcyBEaWFnbm9zdGljIFBsb3QNCmBgYHtyfQ0KcGxvdChsb28uZnMubW8xKQ0KYGBgDQoNCg0KIyMjIENvbnRyYXN0cyBvZiBGZWNhbCBTaGVkZGluZyBJbnRlcmNlcHRzDQoNCmBgYHtyfQ0KY29udHJhc3Quc3VtbWFyeSA8LSBmcy5tbzEgJT4lDQogIHNwcmVhZF9kcmF3cyhyX3NpdGVbc2l0ZSxdKSAlPiUNCiAgY29tcGFyZV9sZXZlbHMocl9zaXRlLCBieSA9IHNpdGUpICU+JQ0KICBncm91cF9ieShzaXRlKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIG1lZGlhbiA9IG1lZGlhbihyX3NpdGUpLA0KICAgIGxvd2VyXzk1ID0gcXVhbnRpbGUocl9zaXRlLCAwLjAyNSksDQogICAgdXBwZXJfOTUgPSBxdWFudGlsZShyX3NpdGUsIDAuOTc1KQ0KICApIA0KDQpjb250cmFzdC5zdW1tYXJ5ICU+JSBhcnJhbmdlKC1kZXNjKG1lZGlhbikpDQpgYGANCg0KIyMjIFBsb3Qgb2YgRmVjYWwgU2hlZGRpbmcgQ29udHJhc3RzIEJldHdlZW4gU2V3ZXJzaGVkcw0KYGBge3J9DQojbGlicmFyeSh0aWR5YmF5ZXMpDQpmcy5tbzEgICU+JQ0KICBzcHJlYWRfZHJhd3Mocl9zaXRlW3NpdGUsXSkgJT4lDQogIGNvbXBhcmVfbGV2ZWxzKHJfc2l0ZSwgYnkgPSBzaXRlKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2l0ZSA9IHJlb3JkZXIoc2l0ZSwgcl9zaXRlKSkgJT4lDQogIGdncGxvdChhZXMoeSA9IHNpdGUsIHggPSByX3NpdGUpKSArDQogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKC41MCwgLjk1KSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkNCmBgYA0KDQoNClRoaXMgY29udHJhc3QgcGxvdCBvZiBmZWNhbCBzaGVkZGluZyBzaG93cyBtb3N0IHBhaXJlZCBzZXdlcnNoZWRzIGhhdmUgY3JlZGlibGUgZGlmZmVyZW5jZXMgKGkuZS4sIHRoZSBkaWZmZXJlbmNlIGRvZXMgbm90IGNvbnRhaW4gMCkuDQoNCiMjIyBJcyBTUzEgZmVjYWwgc2hlZGRpbmcgb2YgU0FSUy1Db1YtMiBjcmVkaWJseSBncmVhdGVyIHRoYW4gb3RoZXIgMTAgU2V3ZXJzaGVkcz8NCg0KU1MxIGhhcyB0aGUgaGlnaGVzdCBmZWNhbCBzaGVkZGluZyBmb2xsb3dlZCBieSBTUzYuIEFsbCB0aGUgb3RoZXIgc2V3ZXJzaGVkcyBoYXZlIGZlY2FsIHNoZWRkaW5nIGVzdGltYXRlcyB0aGF0IGFyZSBsZXNzIHRoYW4gU1M2LiBJZiBTUzEgaXMgY3JlZGlibHkgZ3JlYXRlciB0aGFuIFNTNiB0aGVuIGl0IGlzIGFsc28gZ3JlYXRlciB0aGFuIHRoZSBvdGhlcnMuIA0KDQoNCiMjIyBCYXllc2lhbiBIeXBvdGhlc2lzOiBTUzEgPiBTUzYNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmZzLm1vMS5wb3N0IDwtIHBvc3Rlcmlvcl9zYW1wbGVzKGZzLm1vMSkNCnNzMS5zYW1wbGVzIDwtIGZzLm1vMS5wb3N0WywgInJfc2l0ZVtTUzEsSW50ZXJjZXB0XSJdDQpzczYuc2FtcGxlcyA8LSBmcy5tbzEucG9zdFssICJyX3NpdGVbU1M2LEludGVyY2VwdF0iXQ0KZGlmZi5zYW1wbGVzIDwtIHNzMS5zYW1wbGVzIC0gc3M2LnNhbXBsZXMNCnByb2Iuc3MxLmdyZWF0ZXIgPC0gbWVhbihkaWZmLnNhbXBsZXMgPiAwKQ0KYmNpLmRpZmYgPC0gcXVhbnRpbGUoZGlmZi5zYW1wbGVzLCBjKDAuMDI1LCAwLjk3NSkpDQpoaXN0KGRpZmYuc2FtcGxlcywgbWFpbj0iOTUlIENyZWRpYmxlIEludGVydmFsIGZvciBTUzEgLSBTUzYiLCB4bGFiPSJEaWZmZXJlbmNlIikNCmBgYA0KDQoqKkNvbmNsdXNpb24gb2YgU1MxIHZzIFNTNioqDQoNClRoZSBoaXN0b2dyYW0gc2hvd3MgdGhlIDk1JSBjcmVkaWJsZSBpbnRlcnZhbCBvZiB0aGUgZGlmZmVyZW5jZSBvZiBTUzEgbWludXMgU1M2IHBvc3RlcmlvciBzYW1wbGVzLiBUaGUgOTUlIENJIG9mIHRoZSBkaWZmZXJlbmNlIGlzIGByIHJvdW5kKGJjaS5kaWZmWzFdLCA0KWAgdG8gYHIgcm91bmQoYmNpLmRpZmZbMl0sNClgLiBUaGUgcHJvYmFiaWxpdHkgdGhhdCBTUzEgaXMgZ3JlYXRlciB0aGFuIFNTNiBpcyBgciBwcm9iLnNzMS5ncmVhdGVyYC4gVGhpcyBhbmFseXNpcyBzZWVtcyB0byBiZSBhdCBvZGRzIHdpdGggdGhlIHZpc3VhbCBpbnNwZWN0aW9uIG9mIHRoZSBoYWxmLWV5ZSBwbG90IChzZWUgU2VjdGlvbiAiSGFsZmV5ZSBQbG90IG9mIHRoZSBTZXdlcnNoZWQgSW50ZXJjZXB0cyIpLCB3aGljaCBhcHBlYXJzIHRvIHNob3cgdGhhdCBTUzEgYW5kIFNTNiBzaGFyZSBhIGNvbW1vbiByYW5nZSB3aXRoIGEgbWFyZ2luYWwgb3ZlcmxhcCBvZiA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzLiBIb3dldmVyLCB0aGUgaHlwb3RoZXNpcyB0ZXN0ICdTUzEgPiBTUzYnIGlzIGJhc2VkIG9uIGNhbGN1bGF0ZWQgcG9zdGVyaW9yIGRpZmZlcmVuY2VzIGRyYXctYnktZHJhdyB1c2luZyB0aGUgam9pbnQgZGlzdHJpYnV0aW9uIG9mIGJvdGggcGFyYW1ldGVycy4gVGhpcyB1bmRlcnNjb3JlcyB0aGUgaW1wb3J0YW5jZSBvZiB1c2luZyBudW1lcmljYWwgcHJlY2lzaW9uIGZvciBoeXBvdGhlc2lzIHRlc3RpbmcgcmF0aGVyIHRoYW4gcmVseWluZyBzb2xlbHkgb24gdmlzdWFsIGluc3BlY3Rpb24gb2YgcmFuZG9tIGVmZmVjdHMuIEFsc28sIHRoZSBzbWFsbCBvdmVybGFwIG9mIGRpc3RyaWJ1dGlvbnMgb2JzZXJ2ZWQgd2l0aCB0aGUgaGFsZi1leWUgcGxvdCBkb2Vzbid0IG5lY2Vzc2FyaWx5IGNvbnRyYWRpY3QgdGhlIGh5cG90aGVzaXMgcmVzdWx0OyBpdCBpcyBtb3JlIGEgbWF0dGVyIG9mIGhvdyB1bmNlcnRhaW50eSBpcyByZXByZXNlbnRlZCBhbmQgY29tYmluZWQuIA0KDQoNCiMjIEZlY2FsIFNoZWRkaW5nIEJSTVMgTW9kZWwgd2l0aCBTQVJTLUNvVi0yIFBoYXNlIEZpeGVkIEVmZmVjdA0KDQpUaGUgRmVjYWwgU2hlZGRpbmcgUmFuZG9tIEludGVyY2VwdCBNb2RlbCAoZnMubW8xKSBhYm92ZSBzaG93cyBlc3RpbWF0ZWQgZmVjYWwgc2hlZGRpbmcgb2YgU0FSUy1Db1YtMiB2YXJpZXMgYnkgc2V3ZXJzaGVkIGxvY2F0aW9uLCB3aGljaCBhY2NvdW50cyBmb3IgNDYlIG9mIHRoZSB0b3RhbCB2YXJpYW5jZS4gQWNjb3VudGluZyBmb3IgU0FSUy1Db1YtMiBWT0Mgc2hlZGRpbmcgcmF0ZXMgbWF5IGltcHJvdmUgbW9kZWwgcGVyZm9ybWFuY2UgYW5kIHRoZXJlZm9yZSBiZXR0ZXIgZXhwbGFpbiB0aGUgZHluYW1pY3Mgb2YgaW5mZWN0aW9ucy4gVk9DIHBoYXNlcyByZWZlcnMgdG8gdGhlIHRpbWUgd2hlbiBkaXN0aW5jdCB2YXJpYW50cyBvZiBjb25jZXJuIHdlcmUgcHJlZG9taW5hbnQgZHVyaW5nIHRoZSBwYW5kZW1pYy4NCg0KQmVsb3cgaXMgdGhlIG1vZGVsIHdpdGggYSBmaXhlZCBlZmZlY3QgZm9yIHBoYXNlLiBUaGUgbW9kZWwgY2FuIGJlIGV4cHJlc3NlZCBhczoNCiQkDQpcbG9nX3sxMH0oeV97aWp9KSBcc2ltIFxiZXRhXzAgKyBcYmV0YSB4X3tpan0gKyB1X2ogKyBcZXBzaWxvbl97aWp9IFxcDQp1X2ogXHNpbSBOKDAsIFxzaWdtYV91XjIpXFwNClxlcHNpbG9uX3tpan0gXHNpbSBOKDAsIFxzaWdtYV9cZXBzaWxvbl4yKQ0KJCQNCg0KV2hlcmU6DQoNCiR5X3tpan0kIHJlcHJlc2VudHMgdGhlIG91dGNvbWUgdmFyaWFibGUgImZlY2FsX2xvYWQiIGZvciBvYnNlcnZhdGlvbiAkaSQgaW4gc2l0ZSAkaiQNCg0KJFxiZXRhXzAkIGlzIHRoZSBvdmVyYWxsIGludGVyY2VwdA0KDQokXGJldGEkIGlzIHRoZSBjb2VmZmljaWVudCBmb3IgdGhlIGZpeGVkIGVmZmVjdCBwcmVkaWN0b3IgJHhfe2lqfSQNCg0KJHhfe2lqfSQgaXMgdGhlIHZhbHVlIG9mIHRoZSBmaXhlZCBlZmZlY3QgcHJlZGljdG9yIGZvciBvYnNlcnZhdGlvbiAkaSQgaW4gc2l0ZSAkaiQNCg0KJHVfaiQgaXMgdGhlIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHNpdGUgJGokDQoNCiRcZXBzaWxvbl97aWp9JCBpcyB0aGUgZXJyb3IgdGVybSBmb3Igb2JzZXJ2YXRpb24gJGkkIGluIHNpdGUgJGokDQoNCg0KIyMjIEJSTVMgQ29kZSB3aXRoIFBoYXNlIGFzIGEgRml4ZWQgRWZmZWN0DQpgYGB7cn0NCiN1c2UgZGVmYXVsdHMgcHJpb3JzDQojIGJybS5mZWNhbC5sb2FkLnBoYXNlLnJhbmQgPC0gYnJtKA0KIyAgIGxvZzEwKGZlY2FsX2xvYWQpIH4gMSsgcGhhc2UgKyAoMXxzaXRlKSwNCiMgICBkYXRhID0gYzE5LmRhdGEsDQojICAgZmFtaWx5ID1nYXVzc2lhbiwNCiMgICBjb250cm9sPWxpc3QoYWRhcHRfZGVsdGEgPTAuOTUsbWF4X3RyZWVkZXB0aD0xMCksICMgdHJ5IHRoaXMgMC45NiBuZXh0DQojICAgd2FybXVwID0gNTAwLA0KIyAgIGl0ZXIgPSA0MDAwLA0KIyAgIGNoYWlucyA9NCwNCiMgICBzYW1wbGVfcHJpb3IgPSAieWVzIiwNCiMgICBzZWVkID0gNTEzLA0KIyAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwNCiMgICBzYXZlX3JhbmVmID0gVFJVRSwNCiMgICBzYXZlX2FsbF9wYXJzID0gVFJVRSwNCiMgICBmaWxlID0nYnJtX2ZzX3BoYXNlLnJkcycsICMgdGhpcyBzaG91bGQgYmUgZGVsZXRlZCBpbiB0aGUgUHJvamVjdCBkaXJlY3RvcnkgZWFjaCB0aW1lIG1vZGVsIHJlcnVuDQojICAgc2F2ZV9tb2RlbCA9ICdicm1fZnNfcGhhc2VfbW9kZWwudHh0Jw0KIyApDQpgYGANCg0KDQojIyMgUHJpbnQgU2F2ZWQgUmVzdWx0cw0KDQpgYGB7cn0NCmZzLm1vMjwtIGJybShmaWxlPSJicm1fZnNfcGhhc2UucmRzIikNCnByaW50KGZzLm1vMiwgZGlnaXRzPTQpDQpgYGANCiMjIyBQcmlvciBTdW1tYXJ5DQoNCmBgYHtyfQ0KcHJpb3Jfc3VtbWFyeShmcy5tbzIpDQpgYGANCg0KIyMjIFByaW50IEZpdCBFc3RpbWF0ZXMNCmBgYHtyfQ0KcHJpbnQoZnMubW8yJGZpdCwgZGlnaXRzPTQpDQpgYGANCg0KDQojIyMgUGxvdCBvZiBQYWlyd2lzZSBTaXRlIERpZmZlcmVuY2VzIG9mIHRoZSBNZWFucw0KDQpUaGUgZmlyc3Qgc2V3ZXJzaGVkIGluIGVhY2ggcGFpciBoYXMgdGhlIGdyZWF0ZXIgQ09WSUQtMTkgbG9nMTAoY2FzZS8xMDBrKSBtZWFuLiBUaGlzIHBsb3QgY29tcGFyZXMgcGFpcndpc2UgZGlmZmVyZW5jZXMgb2YgdGhlIG1lYW5zLg0KDQpgYGB7cn0NCiNsaWJyYXJ5KHRpZHliYXllcykNCmZzLm1vMiAlPiUNCiAgc3ByZWFkX2RyYXdzKHJfc2l0ZVtzaXRlLF0pICU+JQ0KICBjb21wYXJlX2xldmVscyhyX3NpdGUsIGJ5ID0gc2l0ZSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHNpdGUgPSByZW9yZGVyKHNpdGUsIHJfc2l0ZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBzaXRlLCB4ID0gcl9zaXRlKSkgKw0KICBzdGF0X2hhbGZleWUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpIA0KYGBgDQoNCiMjIyBQUEMNCmBgYHtyfQ0KcHBfY2hlY2soZnMubW8yICwgdHlwZT0ibG9vX2ludGVydmFscyIscHJvYiA9IDAuNSxwcm9iX291dGVyPSAwLjk1KSArDQogIGdncGxvdDI6OnlsYWIoIkZlY2FsIExvYWQiKSArDQogIGdncGxvdDI6OnhsYWIoIlNhbXBsZSBJbmRleCIpICsNCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICkNCmBgYA0KDQoNCiMjIyBMT08tQ1YgZm9yIEZlY2FsIFNoZWRkaW5nIE1vZGVsIHdpdGggUGhhc2UgRml4ZWQgRWZmZWN0DQoNCmBgYHtyfQ0KbG9vLnBoYXNlIDwtIGxvbyhmcy5tbzIpDQpgYGANCg0KIyMjIyBMT08tQ1YgUmVzdWx0cw0KYGBge3J9DQpsb28ucGhhc2UNCmBgYA0KIyMjIyBQU0lTDQpgYGB7cn0NCnBsb3QobG9vLnBoYXNlKQ0KYGBgDQoNCg0KIyMjIyBDb21wYXJlIE1vZGVscyB2aWEgTE9PLUNWDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KY29tcGFyZS5sb28gPC0gbG9vX2NvbXBhcmUobG9vLmZzLm1vMSxsb28ucGhhc2UpDQpwcmludChjb21wYXJlLmxvbywgZGlnaXRzPTQpDQpgYGANCg0KKipTdW1tYXJ5IG9mIExPTy1DViBDb21wYXJpc29ucyBvZiB0aGUgVHdvIEZlY2FsIFNoZWRkaW5nIE1vZGVsczogVGhlIDJTRSBSdWxlKioNCg0KVXNpbmcgdGhlICIyU0UgcnVsZSIgdG8gZXN0aW1hdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIHRoZSByYW5kb20gaW50ZXJjZXB0IG1vZGVsLCB3aGljaCBkb2VzIG5vdCBjb250YWluIHRoZSBwaGFzZSBmYWN0b3IsIGhhcyBhIDk1JSBDSSBvZmAtMTIuMiArIGMoLTIsMikgKiA1LjYgPSAoLTIzLjQsIC0xLjApYC4gVGhpcyBDSSBkb2VzIG5vdCBjb250YWluIDAgaW5kaWNhdGluZyB0aGUgcmFuZG9tIGludGVyY2VwdCBtb2RlbCBpcyBhbiBpbmZlcmlvciBtb2RlbCBpbiB0ZXJtcyBvZiBwcmVkaWN0aXZlIGFjY3VyYWN5Lg0KDQoNCg0KIyMjIEh5cG90aGVzaXMgMTogQWxwaGEgU2hlZGRpbmcgaXMgR3JlYXRlciB0aGFuIERlbHRhDQoNCmBgYHtyfQ0KYWxwaGEudnMuZGVsdGEuaHlwIDwtIGJybXM6Omh5cG90aGVzaXMoZnMubW8yLCAicGhhc2VhbHBoYSAtIHBoYXNlZGVsdGEgPiAwIiwgYWxwaGE9MC4wNSkNCnByaW50KGFscGhhLnZzLmRlbHRhLmh5cCwgZGlnaXRzPTQpDQpgYGANCg0KIyMjIyBNYW51YWwgVmVyc2lvbiBmb3IgRXhhbWluaW5nIGlmIEFscGhhIGlzIEdyZWF0ZXIgdGhhbiBEZWx0YQ0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZnMubW8yLnBvc3QgPC0gcG9zdGVyaW9yX3NhbXBsZXMoZnMubW8yKQ0KYWxwaGEuc2FtcGxlcyA8LSBmcy5tbzIucG9zdFssICJiX3BoYXNlYWxwaGEiXQ0KZGVsdGEuc2FtcGxlcyA8LSBmcy5tbzIucG9zdFssICJiX3BoYXNlZGVsdGEiXQ0KcGhhc2UxLmRpZmYuc2FtcGxlcyA8LSBhbHBoYS5zYW1wbGVzIC0gZGVsdGEuc2FtcGxlcw0KcHJvYi5hbHBoYS5ncmVhdGVyIDwtIG1lYW4ocGhhc2UxLmRpZmYuc2FtcGxlcyA+IDApDQpwaGFzZTEuZGlmZiA8LSBxdWFudGlsZShwaGFzZTEuZGlmZi5zYW1wbGVzLCBjKDAuMDI1LCAwLjk3NSkpDQpoaXN0KHBoYXNlMS5kaWZmLnNhbXBsZXMsIG1haW49Ijk1JSBDcmVkaWJsZSBJbnRlcnZhbCBmb3IgQWxwaGEgLSBEZWx0YSIsIHhsYWI9IkRpZmZlcmVuY2UiKQ0KYGBgDQoNClRoZSBoaXN0b2dyYW0gc2hvd3MgdGhlIDk1JSBjcmVkaWJsZSBpbnRlcnZhbCBvZiB0aGUgZGlmZmVyZW5jZSBvZiBBbHBoYSBtaW51cyBEZWx0YSBwb3N0ZXJpb3Igc2FtcGxlcy4gVGhlIDk1JSBDSSBvZiB0aGUgZGlmZmVyZW5jZSBpcyBgciBwaGFzZTEuZGlmZlsxXWAgdG8gYHIgcGhhc2UxLmRpZmZbMl1gLiBUaGUgcHJvYmFiaWxpdHkgdGhhdCBBbHBoYSBpcyBncmVhdGVyIHRoYW4gRGVsdGEgaXMgYHIgcHJvYi5hbHBoYS5ncmVhdGVyYC4NCg0KIyMjIEh5cG90aGVzaXMgMjogRGVsdGEgU2hlZGRpbmcgaXMgR3JlYXRlciB0aGFuIE9taWNyb24NCg0KYGBge3J9DQpkZWx0YS52cy5vbWljcm9uLmh5cCA8LSBicm1zOjpoeXBvdGhlc2lzKGZzLm1vMiwgInBoYXNlZGVsdGEgLSBwaGFzZW9taWNyb24gPiAwIiwgYWxwaGE9MC4wNSkNCnByaW50KGRlbHRhLnZzLm9taWNyb24uaHlwLCBkaWdpdHM9NCkNCmBgYA0KIyMjIyBTdW1tYXJ5IG9mIEh5cG90aGVzaXMgVGVzdGluZw0KDQpUaGUgaHlwb3RoZXNpcyB0ZXN0cyBmb3IgIkFscGhhID4gRGVsdGEiIGFuZCAiRGVsdGEgPiBPbWljcm9uIiBzaG93IHRoYXQgQWxwaGEgc2hlZGRpbmcgaXMgY3JlZGlibHkgZ3JlYXRlciB0aGFuIERlbHRhLCBEZWx0YSBpcyBjcmVkaWJseSBncmVhdGVyIHRoYW4gT21pY3JvbiwgYW5kIHRoZXJlZm9yZSwgQWxwaGEgaXMgZ3JlYXRlciB0aGFuIE9taWNyb24uIA0KDQoNCiMjIyBQYWlyd2lzZSBDb21wYXJpc29uczogQ29udHJhc3RzIA0KDQpBbm90aGVyIHdheSB0byBhc3Nlc3MgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdmlydXMgc2hlZGRpbmcgaXMgdG8gdXNlIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHZpYSB0aGUgZW1tZWFucyBSIHBhY2thZ2UsIHdoaWNoIHdvcmtzIHdlbGwgd2l0aCBicm1zIG9iamVjdHMgYW5kIHByb3ZpZGVzIGEgY29udmVuaWVudCB3YXkgdG8gZXN0aW1hdGUgbWFyZ2luYWwgbWVhbnMgYW5kIGNvbnRyYXN0cyBvZiB0aGUgZW50aXJlIG1vZGVsLiBJdHMgcGFpcndpc2UgY29udHJhc3RzIGluY2x1ZGUgYWRkaXRpb25hbCB1bmNlcnRhaW50eSBkdWUgdG8gcmFuZG9tIGVmZmVjdHMgYW5kIHJlc2lkdWFscywgd2hpY2ggY2FuIGJlIHVzZWZ1bCBmb3IgdW5kZXJzdGFuZGluZyB0aGUgb3ZlcmFsbCBtb2RlbCBzdHJ1Y3R1cmUuIA0KDQojIyMjIE1hcmdpbmFsIE1lYW5zIGFuZCBDb250cmFzdHMgb2YgdGhlIEZlY2FsIFNoZWRkaW5nIE1vZGVsIHdpdGggUGhhc2UgRml4ZWQgRWZmZWN0DQpgYGB7cn0NCiNsaWJyYXJ5KGVtbWVhbnMpDQptNi5wYWlyd2lzZSA8LSBlbW1lYW5zKGZzLm1vMiwgcGFpcndpc2UgfiBwaGFzZSkNCnByaW50KG02LnBhaXJ3aXNlLCBkaWdpdHM9NCkNCmBgYA0KKipTdW1tYXJ5IG9mIGVtbWVhbnMgQ29udHJhc3RzKioNCg0KLSBIUEQgaW50ZXJ2YWxzOiBUaGUgcHJlc2VuY2Ugb2YgImxvd2VyLkhQRCIgYW5kICJ1cHBlci5IUEQiIGNvbHVtbnMgaW5kaWNhdGVzIEhpZ2hlc3QgUG9zdGVyaW9yIERlbnNpdHkgaW50ZXJ2YWxzLCB3aGljaCBhcmUgQmF5ZXNpYW4gY3JlZGlibGUgaW50ZXJ2YWxzLg0KDQotIEhQRCBpbnRlcnZhbCBwcm9iYWJpbGl0eTogVGhlICJIUEQgaW50ZXJ2YWwgcHJvYmFiaWxpdHk6IDAuOTUiIGluZGljYXRlcyB0aGF0IHRoZXNlIGFyZSA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzLg0KDQotIE1ham9yIGZpbmRpbmdzOiBUaGUgOTUlIEhQRCBkb2VzIG5vdCBjb250YWluIDAgZm9yICdBbHBoYSAtIERlbHRhJyBhbmQgJ0FscGhhIC0gT21pY3JvbicgYW5kICdEZWx0YSAtIE9taWNyb24nIHBhaXJzLCBzdWdnZXN0aW5nIHRoYXQgQWxwaGEgc2hlZGRpbmcgaXMgY3JlZGlibHkgZ3JlYXRlciB0aGFuIERlbHRhIGFuZCBPbWljcm9uLCBhbmQgRGVsdGEgc2hlZGRpbmcgaXMgY3JlZGlibHkgZ3JlYXRlciB0aGFuIE9taWNyb24uIFRoZXNlIHJlc3VsdHMgYWdyZWUgd2l0aCB0aGUgYnJtczo6aHlwb3RoZXNpcyB0ZXN0cyBhYm92ZS4NCg0KLSBwcmUtVk9DIHZzIG90aGVyOiBUaGUgOTUlIEhQRCBjb250YWlucyAwIGZvciAnKHByZS1WT0MpIC0gZGVsdGEnIGFuZCAnIChwcmUtVk9DKSAtIGRlbHRhJyBwYWlycywgaW5kaWNhdGluZyBwcmUtVk9DIGlzIG5vdCBjcmVkaWJseSBkaWZmZXJlbnQgZnJvbSB0aGVtLiBUaGUgOTUlIEhQRCBkb2VzIG5vdCBjb250YWluIDAgZm9yICcocHJlLVZPQykgLSBhbHBoYScgaW5kaWNhdGluZyBwcmUtVk9DIGlzIGNyZWRpYmx5IGxlc3MgdGhhbiBBbHBoYS4NCg0KDQoNCiMgU2VjdGlvbiBmb3IgRXF1YXRpb25zIDIsIDMgYW5kIDQNCg0KDQoqKldoaWNoIG1vZGVsIGJlc3QgcHJlZGljdHMgQ09WSUQtMTkgY2FzZXM/KioNCg0KVGhyZWUgZGlmZmVyZW50IG11bHRpbGV2ZWwgQmF5ZXNpYW4gbW9kZWxzIHdlcmUgZGVzaWduZWQgdG8gcHJlZGljdCBDT1ZJRC0xOSBjYXNlcyB1c2luZyBjb3ZhcmlhdGVzIHN1Y2ggYXMgTjIgZ2VuZSBsb2FkLCBTQVJTLUNvVi0yIHZhcmlhbnRzIChlLmcuLCBwcmUtVk9DLCBBbHBoYSwgRGVsdGEsIGFuZCBPbWljcm9uKSwgYW5kIHNld2Vyc2hlZCBsb2NhdGlvbi4gIA0KDQoNCiMjIE1vZGVsIDE6IEJheWVzaWFuIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdpdGggYSBmaXhlZCBlZmZlY3QgZm9yIGZsb3ctYWRqdXN0ZWQgTjIgZ2VuZSBhbmQgcmFuZG9tIGludGVyY2VwdCBmb3Igc2V3ZXJzaGVkIGxvY2F0aW9uLg0KDQokJA0KeV97aWp9ID0gXGJldGFfMCArIFxiZXRhXzEgeF97aWp9ICsgYl97MGp9ICsgXGVwc2lsb25fe2lqfSBcdGFnIHtFcS4gMn0NCiQkDQoNCioqRXhwbGFuYXRpb24gb2YgTW9kZWwgMSBUZXJtcyoqDQoNCi0gJHlfe2lqfSQ6IFJlc3BvbnNlIHZhcmlhYmxlIGZvciB0aGUgaS10aCBvYnNlcnZhdGlvbiBpbiB0aGUgai10aCBncm91cCwgd2hlcmUgZ3JvdXAgaXMgc2V3ZXJzaGVkIGxvY2F0aW9uLg0KDQotICRcYmV0YV8wJDogRml4ZWQgaW50ZXJjZXB0LCByZXByZXNlbnRpbmcgdGhlIG92ZXJhbGwgbWVhbiBlZmZlY3QgYWNyb3NzIGFsbCBzZXdlcnNoZWRzLg0KDQotICRcYmV0YV8xJDogRml4ZWQgc2xvcGUgZm9yIHRoZSBwcmVkaWN0b3IgJHhfe2lqfSQgKGkuZS4sIGxvZ19uMl9mbG93YWRqKSwgcmVwcmVzZW50aW5nIHRoZSBlZmZlY3Qgb2YgdGhlIHByZWRpY3RvciBvbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuDQoNCi0gJGJfezBqfSQ6IFJhbmRvbSBpbnRlcmNlcHQgZm9yIHRoZSBqLXRoIGdyb3VwIChpLmUuLCBzZXdlcnNoZWQgc2l0ZSksIHJlcHJlc2VudGluZyB0aGUgZ3JvdXAtc3BlY2lmaWMgZGlmZmVyZW5jZXMgZnJvbSB0aGUgb3ZlcmFsbCBpbnRlcmNlcHQuDQoNCi0gJFxlcHNpbG9uX3tpan0kOiBSZXNpZHVhbCBlcnJvciBmb3IgdGhlIGktdGggb2JzZXJ2YXRpb24gaW4gdGhlIGotdGggZ3JvdXAsIHJlcHJlc2VudGluZyB0aGUgdW5leHBsYWluZWQgdmFyaWFiaWxpdHkuDQoNCi0gVGhlIE1vZGVsIDEgZm9ybXVsYSBpcyBsb2dfY2FzZTEwMDAwMCB+IDEgKyBsb2dfbjJfZmxvd2FkaiArICgxIHwgc2l0ZSksIHdoaWNoIG1lYW5zIHRoZSBsb2ctdHJhbnNmb3JtZWQgQ09WSUQtMTkgY2FzZXMgcGVyIDEwMCwwMDAgcGVvcGxlIGlzIG1vZGVsZWQgYXMgYSBmdW5jdGlvbiBvZiB0aGUgbG9nLXRyYW5zZm9ybWVkIGFkanVzdGVkIGZsb3cgKGxvZ19uMl9mbG93YWRqKSBhbmQgYSByYW5kb20gaW50ZXJjZXB0IGZvciBlYWNoIHNld2Vyc2hlZCBzaXRlICgxIHwgc2l0ZSkuDQoNCg0KDQoNCiMjIyBNMTogQlJNUyBDb2RlDQpgYGB7cn0NCiMgI0RlZmluZSBwcmlvcnMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlDQojIHByaW9yX2ludGVyY2VwdCA8LSBwcmlvcihub3JtYWwoMCwgMTAwKSwgY2xhc3MgPSBJbnRlcmNlcHQpDQojIHByaW9yX3Nsb3BlIDwtIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKQ0KIyANCiMgI0RlZmluZSBzaWdtYSBwcmlvcg0KIyBwcmlvcl9zaWdtYSA8LSBzZXRfcHJpb3IoImNhdWNoeSgwLCA1KSIsIGNsYXNzID0gInNpZ21hIikNCiMgDQojIGJybS5wYXJ0cG9vbC5ub3JtIDwtIGJybSgNCiMgICBsb2dfY2FzZTEwMDAwMCB+IDEgKyBsb2dfbjJfZmxvd2FkaiArICgxfCBzaXRlKSwNCiMgICBkYXRhID0gYzE5LmRhdGEsDQojICAgZmFtaWx5ID1nYXVzc2lhbiwNCiMgICBwcmlvciA9IGMoDQojICAgICBwcmlvcl9pbnRlcmNlcHQsDQojICAgICBwcmlvcl9zbG9wZSwNCiMgICAgIHByaW9yX3NpZ21hDQojICAgKSwNCiMgICB3YXJtdXAgPSA1MDAsDQojICAgaXRlciA9IDQwMDAsDQojICAgY29udHJvbD1saXN0KGFkYXB0X2RlbHRhID0wLjk1LCBtYXhfdHJlZWRlcHRoPTEwKSwNCiMgICBjaGFpbnMgPTQsDQojICAgc2FtcGxlX3ByaW9yID0gInllcyIsDQojICAgc2VlZCA9IDUxMywNCiMgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksDQojICAgc2F2ZV9yYW5lZiA9IFRSVUUsDQojICAgc2F2ZV9hbGxfcGFycyA9IFRSVUUsDQojICAgZmlsZSA9J2JybV9wYXJ0cG9vbF9ub3JtX3ByaW9ycy5yZHMnLA0KIyAgIHNhdmVfbW9kZWwgPSAnYnJtX3BhcnRwb29sX25vcm1fcHJpb3JzX21vZGVsLnR4dCcsDQojICAgZnV0dXJlPVRSVUUNCiMgKQ0KYGBgDQoNCg0KIyMjIE0xOiBQcmludCBTYXZlZCBSZXN1bHRzDQpgYGB7cn0NCm1vMSA8LSBicm0oZmlsZT0iYnJtX3BhcnRwb29sX25vcm1fcHJpb3JzLnJkcyIpDQpwcmludChtbzEsIGRpZ2l0cz00KQ0KYGBgDQojIyMgTTE6IFByaW9yIFN1bW1hcnkNCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KG1vMSkNCmBgYA0KDQoNCiMjIyBNMTogUHJpbnQgRml0IFJlc3VsdHMNCmBgYHtyfQ0KcHJpbnQobW8xJGZpdCwgZGlnaXRzPTQpDQpgYGANCg0KIyMjIE0xOiBQb3N0ZXJpb3IgRHJhd3MNCmBgYHtyfQ0KbW8xLmRyYXdzIDwtbW8xICU+JSBhc19kcmF3c19hcnJheSgpDQptbzEuc3VtbWFyeSA8LSBzdW1tYXJpemVfZHJhd3MobW8xLmRyYXdzKQ0KbW8xLnN1bW1hcnkgDQojd3JpdGUuY3N2KG1vMS5zdW1tYXJ5ICwgIm1vZGVsMV9yZXN1bHRzLmNzdiIpDQpgYGANCg0KIyMjIE0xOiBQb3N0IFByZWRpY3RpdmUgQ2hlY2sgKFBQQykgDQoNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCnBwX2NoZWNrKG1vMSwgdHlwZT0ibG9vX2ludGVydmFscyIscHJvYiA9IDAuNSwgcHJvYl9vdXRlcj0gMC45NSkrDQogIGdncGxvdDI6OnlsYWIoIkNhc2VzIHBlciAxMDAsMDAwIChsb2cxMCkiKSArDQogIGdncGxvdDI6OnhsYWIoIkluZGV4IikgKw0KICBnZ3Bsb3QyOjp0aGVtZSgNCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNCkNCiAgKQ0KYGBgDQoNCg0KIyMjIE0xOiBQbG90IENvbmRpdGlvbmFsIEVmZmVjdHMNCg0KVGhpcyBwbG90IHNob3dzIGhvdyB0aGUgcmVzcG9uc2UgdmFyaWFibGUgKGxvZ19jYXNlMTAwMDAwKSBjaGFuZ2VzIGFzIGxvZ19uMl9mbG93YWRqIHZhcmllcywgd2hpbGUgaG9sZGluZyBvdGhlciBwcmVkaWN0b3JzIGNvbnN0YW50Lg0KDQpgYGB7cn0NCmNvbmRpdGlvbmFsX2VmZmVjdHMobW8xLCBlZmZlY3RzPWMoImxvZ19uMl9mbG93YWRqIikpDQpgYGANCg0KDQoNCiMjIyBNMTogUGxvdCBmb3IgSW50ZXJjZXB0DQoNClRoaXMgcGxvdCBzaG93cyBob3cgdGhlIHNpdGVzLXNwZWNpZmljIGJhc2VsaW5lIHZhcmllcyBhY3Jvc3MgdGhlIDExIHNld2Vyc2hlZHMuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQojbGlicmFyeSh0aWR5YmF5ZXMpDQojZGVmaW5lIGN1c3RvbSBvcmRlciBmb3Igc2V3ZXJzaGVkIHNpdGVzDQpzaXRlX29yZGVyIDwtIGMoIlNTMSIsICJTUzIiLCAiU1MzIiwgIlNTNCIsICJTUzUiLCAiU1M2IiwgIlNTNyIsICJTUzgiLCAiU1M5IiwgIlNTMTAiLCAiU1MxMSIpDQoNCiNleHRyYWN0IHJhbmRvbSBpbnRlcmNlcHRzDQptbzEgICU+JQ0KICBzcHJlYWRfZHJhd3Mocl9zaXRlW3NpdGUsdGVybV0pICU+JQ0KICBmaWx0ZXIodGVybSAlaW4lIGMoIkludGVyY2VwdCIpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2l0ZSA9IGZhY3RvcihzaXRlLCBsZXZlbHMgPSBzaXRlX29yZGVyLCBvcmRlcmVkID0gVFJVRSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBzaXRlLCB4ID0gcl9zaXRlKSkgKw0KICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNTAsIC45NSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBmYWNldF93cmFwKH50ZXJtLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBsYWJzKHggPSAiUmFuZG9tIEVmZmVjdCIsIHkgPSAiU2l0ZSIsDQogICAgICAgdGl0bGUgPSAiUmFuZG9tIEVmZmVjdHMgYnkgU2l0ZSIpKw0KIA0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldihzaXRlX29yZGVyKSkgICNyZXZlcnNlIHNpdGUgb3JkZXIgZm9yIHRvcC10by1ib3R0b20gbGF5b3V0DQpgYGANCg0KIyMjIE0xOiBTdW1tYXJ5IG9mIFJlc3VsdHMNCg0KLSBUaGUgbW9kZWwgd2FzIGZpdCB1c2luZyA0IE1DTUMgY2hhaW5zLCBlYWNoIHdpdGggNDAwMCBpdGVyYXRpb25zICg1MDAgd2FybXVwKSwgcmVzdWx0aW5nIGluIDE0LDAwMCAoaS5lLiwgMTYwMDAgbWludXMgNCAqIDUwMCBidXJuaW5zKSB0b3RhbCBwb3N0LXdhcm11cCBkcmF3cy4NCg0KLSBUaGUgZ3JvdXAtbGV2ZWwgKHJhbmRvbSkgZWZmZWN0IHNob3dzIHRoYXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgc2V3ZXJzaGVkIGludGVyY2VwdCBhY3Jvc3Mgc2l0ZXMgaXMgMC41Mzc1IHdpdGggYSA5NSUgY3JlZGlibGUgaW50ZXJ2YWwgb2YgWzAuMzM1MiwgMC44ODY3XS4NCg0KKipGaXhlZCBFZmZlY3RzKioNCi0gVGhlIHBvcHVsYXRpb24tbGV2ZWwgKGZpeGVkKSBlZmZlY3RzIHNob3cgdGhhdDoNCg0KICAtIFRoZSBlc3RpbWF0ZWQgaW50ZXJjZXB0IGlzIC03LjQ5NjMgd2l0aCBhIDk1JSBjcmVkaWJsZSBpbnRlcnZhbCBvZiBbLTguMDkxNCwgLTYuOTE2M10uDQogIA0KICAtIFRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnQgZm9yIGxvZ19uMl9mbG93YWRqIGlzIDAuNzM5NyB3aXRoIGEgOTUlIGNyZWRpYmxlIGludGVydmFsIG9mIFswLjY5OTYsIDAuNzc5M10uIFRoaXMgaW5kaWNhdGVzIHRoYXQgZm9yIGV2ZXJ5IDEtdW5pdCBpbmNyZWFzZSBpbiBsb2dfbjJfZmxvd2FkaiwgbG9nX2Nhc2UxMDAwMDAgaW5jcmVhc2VzIGJ5IGFwcHJveGltYXRlbHkgMC43NCBvbiBhdmVyYWdlLg0KICANCioqTW9kZWwgRml0KioNCg0KLSBUaGUgcmVzaWR1YWwgc3RhbmRhcmQgZGV2aWF0aW9uIChzaWdtYSkgaXMgZXN0aW1hdGVkIHRvIGJlIDAuMzIyOSB3aXRoIGEgOTUlIGNyZWRpYmxlIGludGVydmFsIG9mIFswLjMwODMsIDAuMzM4Nl0uDQoNCioqTW9kZWwgRGlhZ25vc3RpY3MqKiANCg0KLSBUaGUgUmhhdCB2YWx1ZXMgYXJlIGFsbCBjbG9zZSB0byAxLCBpbmRpY2F0aW5nIGdvb2QgY29udmVyZ2VuY2Ugb2YgdGhlIE1DTUMgY2hhaW5zLiBUaGUgQnVsa19FU1MgYW5kIFRhaWxfRVNTIHZhbHVlcyBhcmUgYWxzbyByZWFzb25hYmx5IGhpZ2gsIHN1Z2dlc3RpbmcgdGhlIGVzdGltYXRlcyBhcmUgd2VsbC1pbmZvcm1lZCBieSB0aGUgZGF0YS4NCg0KKipQUEMgYW5kIENvbmRpdGlvbmFsIEVmZmVjdHMqKiANCg0KLSBQUEM6IFRoaXMgc2hvd2VkIHRoZSBvYnNlcnZlZCBkYXRhIGZlbGwgd2l0aGluIGJvdGggNTAlIGFuZCA5NSUgTE9PIGludGVydmFscyBhbmQgdGhlIGNvbmRpdGlvbmFsIGVmZmVjdHMgcGxvdCBzaG93IGEgcG9zaXRpdmUsIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBmbG93LWFkanVzdGVkIE4yIGFuZCBjYXNlcyBwZXIgMTAwLDAwMC4NCg0KTUNNQyBJbnRlcnZhbHMgb2YgTW9kZWwgMQ0KDQoqKlJhbmRvbSBFZmZlY3RzIGZvciBJbnRlcmNlcHRzKioNCg0KVGhlIG1vZGVsIGVzdGltYXRlcyBzaXRlLXNwZWNpZmljIGludGVyY2VwdHMsIHJlcHJlc2VudGluZyB0aGUgYmFzZWxpbmUgbG9nIGNhc2VzIHBlciAxMDAsMDAwIHdoZW4gbG9nX24yX2Zsb3dhZGogaXMgemVybzoNCg0KLSBIaWdoZXN0IGludGVyY2VwdHM6IFNTNSBhbmQgU1M4DQoNCi0gTG93ZXN0IGludGVyY2VwdHM6IFNTMSwgU1M0LCBhbmQgU1M2DQoNCi0gVW5jZXJ0YWludHk6IEludGVydmFscyB0aGF0IGRvbid0IGluY2x1ZGUgemVybyBzdWdnZXN0IHN0cm9uZ2VyIGV2aWRlbmNlIGZvciBhIHNpdGUtc3BlY2lmaWMgZWZmZWN0Lg0KDQotIFByZWNpc2lvbjogVGhlIHN0YW5kYXJkIGVycm9ycyBhcmUgcmVsYXRpdmVseSBjb25zaXN0ZW50IGFjcm9zcyBzaXRlcywgaW5kaWNhdGluZyBzaW1pbGFyIHByZWNpc2lvbiBpbiB0aGUgZXN0aW1hdGVzLg0KDQoqKkludHJhY2xhc3MgQ29ycmVsYXRpb24gQ29lZmZpY2llbnQgKElDQykqKg0KDQokJElDQz0wLjUzMzheMi8oMC41MzM4XjIgKyAwLjMyMjleMilcYXBwcm94IDAuNzMyMSAkJA0KVGhlIElDQyBpcyA3My4yJSwgd2hpY2ggaW5kaWNhdGVzIG1vc3Qgb2YgdGhlIHZhcmlhbmNlIGlzIGJldHdlZW4gc2V3ZXJzaGVkIGxvY2F0aW9ucyByYXRoZXIgdGhhbiB3aXRoaW4gdGhlbS4gDQoNCg0KDQojIyBNb2RlbCAyOiBCYXllc2lhbiBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGEgcmFuZG9tIHNsb3BlIGZvciBmbG93LWFkanVzdGVkIE4yIGdlbmUgYW5kIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHNld2Vyc2hlZCBsb2NhdGlvbi4NCg0KDQokJA0KeV97aWp9ID0gXGJldGFfMCArIFxiZXRhXzEgeF97aWp9ICsgYl97MGp9ICsgYl97MWp9IHhfe2lqfSArIFxlcHNpbG9uX3tpan0gXHRhZ3tFcS4gM30NCiQkDQoNCioqRXhwbGFuYXRpb24gb2YgTW9kZWwgMiBUZXJtcyoqDQoNCi0gJHlfe2lqfSQ6IFJlc3BvbnNlIHZhcmlhYmxlIChsb2dfY2FzZTEwMDAwMCkgZm9yIHRoZSBpLXRoIG9ic2VydmF0aW9uIGluIHRoZSBqLXRoIGdyb3VwLCB3aGVyZSBncm91cCBpcyBzZXdlcnNoZWQgbG9jYXRpb24uIFNlZSBNb2RlbCAxIGZvciB0aGUgc2V3ZXJzaGVkIGFiYnJldmlhdGlvbnMuDQoNCi0gJFxiZXRhXzAkOiBGaXhlZCBpbnRlcmNlcHQsIHJlcHJlc2VudGluZyB0aGUgb3ZlcmFsbCBtZWFuIGVmZmVjdCBhY3Jvc3MgYWxsIHNld2Vyc2hlZCBncm91cHMuDQoNCi0gJFxiZXRhXzEkOiBGaXhlZCBzbG9wZSBmb3IgdGhlIHByZWRpY3RvciAkeF97aWp9JCAobG9nX24yX2Zsb3dhZGogKSwgcmVwcmVzZW50aW5nIHRoZSBlZmZlY3Qgb2YgdGhlIHByZWRpY3RvciBvbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuDQoNCi0gJGJfezBqfSQ6IFJhbmRvbSBpbnRlcmNlcHQgZm9yIHRoZSBqLXRoIGdyb3VwLCByZXByZXNlbnRpbmcgdGhlIHNld2Vyc2hlZCBncm91cC1zcGVjaWZpYyBkaWZmZXJlbmNlcyBmcm9tIHRoZSBvdmVyYWxsIGludGVyY2VwdC4NCg0KLSAkYl97MWp9JDogUmFuZG9tIHNsb3BlIGZvciB0aGUgcHJlZGljdG9yICR4X3tpan0kIGluIHRoZSBqLXRoIGdyb3VwLCByZXByZXNlbnRpbmcgdGhlIHNld2Vyc2hlZCBncm91cC1zcGVjaWZpYyBkaWZmZXJlbmNlcyBpbiB0aGUgZWZmZWN0IG9mIHRoZSBwcmVkaWN0b3IuDQoNCi0gJFxlcHNpbG9uX3tpan0kOiBSZXNpZHVhbCBlcnJvciBmb3IgdGhlIGktdGggb2JzZXJ2YXRpb24gaW4gdGhlIGotdGggZ3JvdXAsIHJlcHJlc2VudGluZyB0aGUgdW5leHBsYWluZWQgdmFyaWFiaWxpdHkuDQoNCg0KIyMjIE0yOiBCUk1TIENvZGUgLSBSYW5kb20gSW50ZXJjZXB0LCBSYW5kb20gU2xvcGUNCg0KYGBge3J9DQojICNwcmlvcnMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlDQojIHByaW9yX2ludGVyY2VwdCA8LSBwcmlvcihub3JtYWwoMCwgMTAwKSwgY2xhc3MgPSBJbnRlcmNlcHQpDQojIHByaW9yX3Nsb3BlIDwtIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKQ0KIyANCiMgI3NpZ21hIHByaW9yDQojIHByaW9yX3NpZ21hIDwtIHNldF9wcmlvcigiY2F1Y2h5KDAsIDUpIiwgY2xhc3MgPSAic2lnbWEiKQ0KIyANCiMgYnJtLnBhcnRwb29sLnJhbmRyYW5kIDwtIGJybSgNCiMgICBsb2dfY2FzZTEwMDAwMCB+IDErIGxvZ19uMl9mbG93YWRqICsgKDErbG9nX24yX2Zsb3dhZGp8c2l0ZSksDQojICAgZGF0YSA9IGMxOS5kYXRhLA0KIyAgIGZhbWlseSA9Z2F1c3NpYW4sDQojICAgcHJpb3IgPSBjKA0KIyAgICAgcHJpb3JfaW50ZXJjZXB0LA0KIyAgICAgcHJpb3Jfc2xvcGUsDQojICAgICBwcmlvcl9zaWdtYQ0KIyAgICksDQojICAgY29udHJvbD1saXN0KGFkYXB0X2RlbHRhID0wLjk1LG1heF90cmVlZGVwdGg9MTApLA0KIyAgIHdhcm11cCA9IDUwMCwNCiMgICBpdGVyID0gNDAwMCwNCiMgICBjaGFpbnMgPTQsDQojICAgc2FtcGxlX3ByaW9yID0gInllcyIsDQojICAgc2VlZCA9IDUxMywNCiMgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksDQojICAgc2F2ZV9yYW5lZiA9IFRSVUUsDQojICAgc2F2ZV9hbGxfcGFycyA9IFRSVUUsDQojICAgZmlsZSA9J2JybV9wYXJ0cG9vbF9yYW5kcmFuZC5yZHMnLA0KIyAgIHNhdmVfbW9kZWwgPSAnYnJtX3BhcnRwb29sX3JhbmRyYW5kX21vZGVsLnR4dCcsDQojICAgZnV0dXJlPVRSVUUNCiMgKQ0KYGBgDQoNCg0KDQojIyMgTTI6IExvYWQgYW5kIFByaW50IFNhdmVkIFJlc3VsdHMNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCm1vMiA8LSBicm0oZmlsZT0iYnJtX3BhcnRwb29sX3JhbmRyYW5kLnJkcyIpDQpwcmludChtbzIsIGRpZ2l0cz00KQ0KYGBgDQojIyMgTTI6IFByaW9yIFN1bW1hcnkNCg0KVGhlIHByaW9ycyBmb3IgTW9kZWwgMiBhcmUgY2hvc2VuIHRvIGJlIHdlYWtseSBpbmZvcm1hdGl2ZS4NCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KG1vMikNCmBgYA0KDQoNCiMjIyBNMjogUHJpbnQgRml0IFJlc3VsdHMNCg0KYGBge3J9DQpwcmludChtbzIkZml0LCBkaWdpdHM9NCkNCmBgYA0KDQoNCg0KIyMjIE0yOiBQb3N0ZXJvciBEcmF3cw0KDQpgYGB7cn0NCm1vMi5kcmF3cyA8LW1vMiAgJT4lIGFzX2RyYXdzX2FycmF5KCkNCm1vMi5zdW1tYXJ5IDwtIHN1bW1hcml6ZV9kcmF3cyhtbzIuZHJhd3MgKQ0KbW8yLnN1bW1hcnkNCiN3cml0ZS5jc3YobW8yLnN1bW1hcnksICJtb2RlbDJfcmVzdWx0cy5jc3YiKQ0KYGBgDQoNCg0KIyMjIE0yOiBQUEMNCg0KYGBge3J9DQpwcF9jaGVjayhtbzIsIHR5cGU9Imxvb19pbnRlcnZhbHMiLHByb2IgPSAwLjUscHJvYl9vdXRlcj0gMC45NSkrIyAsbmRyYXdzID0gNTApIA0KICBnZ3Bsb3QyOjp5bGFiKCJDYXNlcyBwZXIgMTAwLDAwMCAobG9nMTApIikgKw0KICBnZ3Bsb3QyOjp4bGFiKCJJbmRleCIpICsNCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICkNCmBgYA0KDQoNCiMjIyBNMjogUGxvdCBvZiBDb25kaXRpb25hbCBFZmZlY3RzDQoNCmBgYHtyfQ0KQ0UubTIgPC0gY29uZGl0aW9uYWxfZWZmZWN0cyhtbzIsZWZmZWN0cz0ibG9nX24yX2Zsb3dhZGoiLHJlX2Zvcm11bGEgPSBOVUxMLCBjb25kaXRpb25zID0gZGF0YS5mcmFtZShzaXRlID0gdW5pcXVlKGMxOS5kYXRhJHNpdGUpICkgKQ0KI05CLCB0aGUgcmVfZm9ybXVsYSA9IE5VTEwgaW5jbHVkZXMgdGhlIHJhbmRvbSBlZmZlY3RzIGluIHRoZSBwcmVkaWN0aW9ucywgYWxsb3dpbmcgc2l0ZS1zcGVjaWZpYyBwbG90cw0KDQpnZ3Bsb3QoQ0UubTJbWzFdXSwgYWVzKHggPSBsb2dfbjJfZmxvd2FkaiwgeSA9IGVzdGltYXRlX18sIGdyb3VwID0gc2l0ZSwgY29sb3IgPSBzaXRlKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluID0gbG93ZXJfXywgeW1heCA9IHVwcGVyX18sIGZpbGwgPSBzaXRlKSwgYWxwaGEgPSAwLjIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJDb25kaXRpb25hbCBFZmZlY3RzIG9mIGxvZ19uMl9mbG93YWRqIGJ5IFNpdGUiLA0KICAgICAgIHggPSAibG9nX24yX2Zsb3dhZGoiLA0KICAgICAgIHkgPSAibG9nX2Nhc2UxMDAwMDAiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpDQoNCmBgYA0KDQoNCg0KIyMjIE0yOiBDb21iaW5hdGlvbiBQbG90IG9mIFJhbmRvbSBJbnRlcmNlcHRzIGFuZCBTbG9wZXMNCg0KYGBge3J9DQojbGlicmFyeSh0aWR5YmF5ZXMpIA0KI2RlZmluZSBjdXN0b20gb3JkZXIgZm9yIHNld2Vyc2hlZCBzaXRlcw0Kc2l0ZV9vcmRlciA8LSBjKCJTUzEiLCAiU1MyIiwgIlNTMyIsICJTUzQiLCAiU1M1IiwgIlNTNiIsICJTUzciLCAiU1M4IiwgIlNTOSIsICJTUzEwIiwgIlNTMTEiKQ0KDQojZXh0cmFjdCByYW5kb20gaW50ZXJjZXB0cyBhbmQgc2xvcGVzDQptbzIgICU+JQ0KICBzcHJlYWRfZHJhd3Mocl9zaXRlW3NpdGUsdGVybV0pICU+JQ0KICBmaWx0ZXIodGVybSAlaW4lIGMoIkludGVyY2VwdCIsICJsb2dfbjJfZmxvd2FkaiIpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2l0ZSA9IGZhY3RvcihzaXRlLCBsZXZlbHMgPSBzaXRlX29yZGVyLCBvcmRlcmVkID0gVFJVRSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBzaXRlLCB4ID0gcl9zaXRlKSkgKw0KICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNTAsIC45NSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBmYWNldF93cmFwKH50ZXJtLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBsYWJzKHggPSAiUmFuZG9tIEVmZmVjdCIsIHkgPSAiU2l0ZSIsDQogICAgICAgdGl0bGUgPSAiUmFuZG9tIEVmZmVjdHMgYnkgU2l0ZSIsDQogICAgICAgc3VidGl0bGUgPSAiSW50ZXJjZXB0cyBhbmQgU2xvcGVzIGZvciBsb2dfbjJfZmxvd2FkaiIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYoc2l0ZV9vcmRlcikpICAjcmV2ZXJzZSBzaXRlIG9yZGVyIGZvciB0b3AtdG8tYm90dG9tIGxheW91dA0KYGBgDQoNCg0KDQojIyMgTTI6IFN1bW1hcnkgb2YgUmVzdWx0cw0KDQpNb2RlbCAyIHByZWRpY3RzIGxvZ19jYXNlMTAwMDAwIHVzaW5nIGxvZ19uMl9mbG93YWRqIGFzIGEgZml4ZWQgZWZmZWN0LCB3aXRoIHJhbmRvbSBpbnRlcmNlcHRzIGFuZCBzbG9wZXMgZm9yIGVhY2ggc2l0ZS4gVGhlIGZvcm11bGEgZm9yIHRoaXMgbW9kZWwgaXM6IGxvZ19jYXNlMTAwMDAwIH4gMSArIGxvZ19uMl9mbG93YWRqICsgKDEgKyBsb2dfbjJfZmxvd2FkaiB8IHNpdGUpLiBNb2RlbCAyIHdhcyBmaXQgdXNpbmcgNCBNQ01DIGNoYWlucywgZWFjaCB3aXRoIDQwMDAgaXRlcmF0aW9ucyAoNTAwIHdhcm11cCBlYWNoKSwgcmVzdWx0aW5nIGluIDE0LDAwMCB0b3RhbCBwb3N0LXdhcm11cCBkcmF3cy4NCg0KKipGaXhlZCBFZmZlY3RzKioNCg0KVGhlIGZpeGVkIGVmZmVjdHMgc2hvdyB0aGUgb3ZlcmFsbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgcHJlZGljdG9yIGFuZCByZXNwb25zZToNCg0KLSBJbnRlcmNlcHQ6IDcuNjU0NiAoOTUlIENJOiAtOC44ODYzIHRvIC02LjQ1MzApDQoNCi0gbG9nX24yX2Zsb3dhZGo6IDAuNzUwNiAoOTUlIENJOiAwLjY2Mzg5IHRvIDAuODQwMikNCg0KVGhpcyBpbmRpY2F0ZXMgdGhhdCBmb3IgZXZlcnkgMS11bml0IGluY3JlYXNlIGluIGxvZ19uMl9mbG93YWRqLCBsb2dfY2FzZTEwMDAwMCBpbmNyZWFzZXMgYnkgYXBwcm94aW1hdGVseSAwLjc1IG9uIGF2ZXJhZ2UuDQoNCioqUmFuZG9tIEVmZmVjdHMqKg0KDQpUaGUgbW9kZWwgaW5jbHVkZXMgcmFuZG9tIGVmZmVjdHMgZm9yIDExIGRpZmZlcmVudCBzZXdlcnNoZWQgbG9jYXRpb25zOg0KDQotIHNkKEludGVyY2VwdCk6IFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGludGVyY2VwdCBpcyAxLjgzMzcgKDk1JSBDSTogMS4wNTI1IHRvIDIuOTg2NykNCg0KLSBzZChsb2dfbjJfZmxvd2Fkaik6IFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNsb3BlIGlzIDAuMTI3NSAoOTUlIENJOiAwLjA2NjQgdG8gMC4yMTYzKQ0KDQotIGNvcihJbnRlcmNlcHQsbG9nX24yX2Zsb3dhZGopOiBUaGUgY29ycmVsYXRpb24gYmV0d2VlbiBpbnRlcmNlcHQgYW5kIHNsb3BlIGlzIC0wLjk0ODIgKDk1JSBDSTogLTAuOTkxNyB0byAtMC44MTg2KQ0KDQpUaGlzIHN1Z2dlc3RzIGNvbnNpZGVyYWJsZSB2YXJpYXRpb24gaW4gaW50ZXJjZXB0cyBhY3Jvc3Mgc2l0ZXMsIHdpdGggbGVzcyB2YXJpYXRpb24gaW4gc2xvcGVzLiBUaGUgc3Ryb25nIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGluZGljYXRlcyB0aGF0IHNpdGVzIHdpdGggaGlnaGVyIGludGVyY2VwdHMgdGVuZCB0byBoYXZlIGxvd2VyIHNsb3Blcy4NCg0KKipNb2RlbCBGaXQqKg0KDQotIHNpZ21hOiAwLjMxNjQgKDk1JSBDSTogMC4zMDE5IHRvIDAuMzMxNykNCg0KVGhpcyByZXByZXNlbnRzIHRoZSByZXNpZHVhbCBzdGFuZGFyZCBkZXZpYXRpb24sIGluZGljYXRpbmcgdGhlIGRldmlhdGlvbiBvZiBvYnNlcnZlZCB2YWx1ZXMgZnJvbSB0aGUgTW9kZWwgMidzIHByZWRpY3Rpb25zLg0KDQoqKk1vZGVsIERpYWdub3N0aWNzKiogDQoNClRoZSBSaGF0IHZhbHVlcyBhcmUgYWxsIGNsb3NlIHRvIDEsIHN1Z2dlc3RpbmcgZ29vZCBjb252ZXJnZW5jZSBvZiB0aGUgTUNNQyBjaGFpbnMuIFRoZSBlZmZlY3RpdmUgc2FtcGxlIHNpemVzIChCdWxrX0VTUyBhbmQgVGFpbF9FU1MpIGFyZSBnZW5lcmFsbHkgaGlnaCwgaW5kaWNhdGluZyByZWxpYWJsZSBwb3N0ZXJpb3IgZXN0aW1hdGVzLg0KDQoqKlBQQyBhbmQgQ29uZGl0aW9uYWwgRWZmZWN0cyoqIA0KDQpUaGUgb2JzZXJ2ZWQgZGF0YSBmZWxsIHdpdGhpbiBib3RoIDUwJSBhbmQgOTUlIExPTyBpbnRlcnZhbHMgYW5kIHRoZSBjb25kaXRpb25hbCBlZmZlY3RzIHBsb3Qgc2hvdyBhIHBvc2l0aXZlLCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxvdy1hZGp1c3RlZCBOMiBhbmQgbG9nIGNhc2VzIHBlciAxMDAsMDAwLg0KDQoqKlJhbmRvbSBFZmZlY3RzIGZvciBJbnRlcmNlcHRzKioNCg0KVGhlIG1vZGVsIGVzdGltYXRlcyBzaXRlLXNwZWNpZmljIGludGVyY2VwdHMsIHJlcHJlc2VudGluZyB0aGUgYmFzZWxpbmUgbG9nIGNhc2VzIHBlciAxMDAsMDAwIHdoZW4gbG9nX24yX2Zsb3dhZGogaXMgemVybzoNCg0KLSBIaWdoZXN0IGludGVyY2VwdHM6IFNTNSwgU1M3LCBhbmQgU1M4DQoNCi0gTG93ZXN0IGludGVyY2VwdHM6IFNTMSwgU1M0LCBhbmQgU1M5DQoNCioqUmFuZG9tIEVmZmVjdHMgZm9yIFNsb3BlcyoqDQoNClRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBmbG93LWFkanVzdGVkIE4yIGFuZCBsb2cgY2FzZSBjb3VudHMgcGVyIDEwMDAwMCB2YXJpZXMgYWNyb3NzIHNpdGVzLiBUaGUgbm90YWJsZSBzaXRlLXNwZWNpZmljIHNsb3BlcyBmb3IgbG9nX24yX2Zsb3dhZGogYXJlOg0KDQotIFN0cm9uZ2VzdCBwb3NpdGl2ZSBhc3NvY2lhdGlvbnM6IFNTMSwgU1M0LCBTUzksIGFuZCBTUzExDQoNCi0gU3Ryb25nZXN0IG5lZ2F0aXZlIGFzc29jaWF0aW9uczogU1M1LCBTUzcsIGFuZCBTUzgNCg0KDQpJbiBzdW1tYXJ5LCBNb2RlbCAyIHJlc3VsdHMgc3VnZ2VzdCBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxvZ19uMl9mbG93YWRqIGFuZCBsb2dfY2FzZTEwMDAwMCwgd2l0aCBzaWduaWZpY2FudCB2YXJpYXRpb24gYWNyb3NzIHNpdGVzIGluIGJvdGggdGhlIGJhc2VsaW5lIGxldmVscyAoaW50ZXJjZXB0cykgYW5kIHNsb3Blcy4NCg0KDQojIyBNb2RlbCAzOiBCYXllc2lhbiBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGEgcmFuZG9tIGVmZmVjdCBmb3IgZmxvdy1hZGp1c3RlZCBOMiBnZW5lIChpbnRlcmFjdGluZyB3aXRoIFNBUlMtQ29WLTIgVk9DcykgYW5kIHJhbmRvbSBpbnRlcmNlcHQgZm9yIHNld2Vyc2hlZCBsb2NhdGlvbi4NCg0KDQokJCANCnlfe2lqfSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe2lqfSArIFxiZXRhXzIgel97aWp9ICsgXGJldGFfMyAoeF97aWp9IFx0aW1lcyB6X3tpan0pICsgYl97MGp9ICsgYl97MWp9IHhfe2lqfSArIFxlcHNpbG9uX3tpan0gXHRhZ3tFcS4gNH0NCiQkDQoNCioqRXhwbGFuYXRpb24gb2YgTW9kZWwgMyBUZXJtcyoqDQoNCi0gJHlfe2lqfSQ6IFJlc3BvbnNlIHZhcmlhYmxlIChsb2dfY2FzZTEwMDAwMCkgZm9yIHRoZSBpLXRoIG9ic2VydmF0aW9uIGluIHRoZSBqLXRoIGdyb3VwLCB3aGVyZSBncm91cCBpcyBzZXdlcnNoZWQgc2l0ZXMuIFNlZSBNb2RlbCAxIGZvciBhYmJyZXZpYXRpb25zLg0KDQotICRcYmV0YV8wJDogRml4ZWQgaW50ZXJjZXB0LCByZXByZXNlbnRpbmcgdGhlIG92ZXJhbGwgbWVhbiBlZmZlY3QgYWNyb3NzIGFsbCBncm91cHMuDQoNCi0gJFxiZXRhXzEkOiBGaXhlZCBzbG9wZSBmb3IgdGhlIHByZWRpY3RvciAkeF97aWp9JCAobG9nX24yX2Zsb3dhZGopLCByZXByZXNlbnRpbmcgdGhlIGVmZmVjdCBvZiB0aGUgcHJlZGljdG9yIG9uIHRoZSByZXNwb25zZSB2YXJpYWJsZS4NCg0KLSAkXGJldGFfMiQ6IEZpeGVkIHNsb3BlIGZvciB0aGUgcHJlZGljdG9yICR6X3tpan0kLCByZXByZXNlbnRpbmcgdGhlIGVmZmVjdCBvZiB0aGUgc2Vjb25kIHByZWRpY3RvciAoVk9DIHBoYXNlKSBvbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuDQoNCi0gJFxiZXRhXzMkOiBGaXhlZCBzbG9wZSBmb3IgdGhlIGludGVyYWN0aW9uIHRlcm0gJHhfe2lqfSBcdGltZXMgel97aWp9JCwgcmVwcmVzZW50aW5nIHRoZSBpbnRlcmFjdGlvbnMgb2YgdGhlIHR3byBwcmVkaWN0b3JzIChsb2dfbjJfZmxvd2FkaiBhbmQgbG9nX2Nhc2UxMDAwMDApIG9uIHRoZSByZXNwb25zZSB2YXJpYWJsZS4NCg0KLSAkYl97MGp9JDogUmFuZG9tIGludGVyY2VwdCBmb3IgdGhlIGotdGggZ3JvdXAsIHJlcHJlc2VudGluZyB0aGUgZ3JvdXAtc3BlY2lmaWMgZGlmZmVyZW5jZXMgZnJvbSB0aGUgb3ZlcmFsbCBpbnRlcmNlcHQuDQoNCi0gJGJfezFqfSQ6IFJhbmRvbSBzbG9wZSBmb3IgdGhlIHByZWRpY3RvciAkeF97aWp9JCBpbiB0aGUgai10aCBncm91cCwgcmVwcmVzZW50aW5nIHRoZSBncm91cC1zcGVjaWZpYyBkaWZmZXJlbmNlcyBpbiB0aGUgZWZmZWN0IG9mIHRoZSBwcmVkaWN0b3IuDQoNCi0gJFxlcHNpbG9uX3tpan0kOiBSZXNpZHVhbCBlcnJvciBmb3IgdGhlIGktdGggb2JzZXJ2YXRpb24gaW4gdGhlIGotdGggZ3JvdXAsIHJlcHJlc2VudGluZyB0aGUgdW5leHBsYWluZWQgdmFyaWFiaWxpdHkuDQoNCg0KIyMjIE0zOiBCUk1TIGNvZGUgZm9yIFJhbmRvbSBpbnRlcmNlcHQsIFJhbmRvbSBTbG9wZSBwbHV0IE4yIEludGVyYWN0aW9uIHdpdGggU0FSUy1Db1YtMiBWT0NzDQoNCmBgYHtyfQ0KIyAjIERlZmluZSBwcmlvcnMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlDQojIHByaW9yX2ludGVyY2VwdCA8LSBwcmlvcihub3JtYWwoMCwgMTAwKSwgY2xhc3MgPSBJbnRlcmNlcHQpDQojIHByaW9yX3Nsb3BlIDwtIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKQ0KIyANCiMgIyBEZWZpbmUgc2lnbWEgcHJpb3INCiMgcHJpb3Jfc2lnbWEgPC0gc2V0X3ByaW9yKCJjYXVjaHkoMCwgNSkiLCBjbGFzcyA9ICJzaWdtYSIpDQojIA0KIyBicm0ucGFydHBvb2wucmFuZC5waGFzZSA8LSBicm0oDQojICAgbG9nX2Nhc2UxMDAwMDAgfiAxKyBsb2dfbjJfZmxvd2FkaiAqIHBoYXNlICsgKDErbG9nX24yX2Zsb3dhZGp8c2l0ZSksDQojICAgZGF0YSA9IGMxOS5kYXRhLA0KIyAgIGZhbWlseSA9Z2F1c3NpYW4sDQojICAgcHJpb3IgPSBjKA0KIyAgICAgcHJpb3JfaW50ZXJjZXB0LA0KIyAgICAgcHJpb3Jfc2xvcGUsDQojICAgICBwcmlvcl9zaWdtYQ0KIyAgICksDQojICAgY29udHJvbD1saXN0KGFkYXB0X2RlbHRhID0wLjk1LG1heF90cmVlZGVwdGg9MTApLCAjIHRyeSB0aGlzIG5leHQNCiMgICB3YXJtdXAgPSA1MDAsICMgY29tbWVudCB0aGlzIGFuZCBzZWUgaWYgdGhlIGRpdmVyZ2VudCB0cmFucyBnbyBhd2F5DQojICAgaXRlciA9IDQwMDAsICNpbmNyZWFzZQ0KIyAgIGNoYWlucyA9NCwNCiMgICBzYW1wbGVfcHJpb3IgPSAieWVzIiwNCiMgICBzZWVkID0gNTEzLA0KIyAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwNCiMgICBzYXZlX3JhbmVmID0gVFJVRSwNCiMgICBzYXZlX2FsbF9wYXJzID0gVFJVRSwNCiMgICBmaWxlID0nYnJtX3BhcnRwb29sX3JhbmQucGhhc2UucmRzJywgIyB0aGlzIHNob3VsZCBiZSBkZWxldGVkIGluIHRoZSBQcm9qZWN0IGRpcmVjdG9yeSBlYWNoIHRpbWUgbW9kZWwgcmVydW4NCiMgICBzYXZlX21vZGVsID0gJ2JybV9wYXJ0cG9vbF9yYW5kX3BoYXNlX21vZGVsLnR4dCcsDQojICAgZnV0dXJlPVRSVUUNCiMgKQ0KYGBgDQoNCg0KIyMjIE0zOiBQcmludCBTYXZlZCBSZXN1bHRzDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQptbzMgPC0gYnJtKGZpbGU9ImJybV9wYXJ0cG9vbF9yYW5kLnBoYXNlLnJkcyIpDQpwcmludChtbzMsIGRpZ2l0cz00KQ0KYGBgDQojIyMgTTM6IFByaW9yIFN1bW1hcnkNCg0KVGhlIHByaW9ycyBmb3IgTW9kZWwgMyBhcmUgdGhlIHNhbWUgYXMgTW9kZWwgMiBhbmQgYXJlIHdlYWtseSBpbmZvcm1hdGl2ZS4NCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KG1vMykNCmBgYA0KDQoNCiMjIyBNMzogUHJpbnQgRml0IFJlc3VsdHMNCg0KYGBge3J9DQpwcmludChtbzMkZml0LCBkaWdpdHM9NCkNCmBgYA0KDQojIyMgTTM6IFBvc3RlcmlvciBEcmF3cw0KDQpgYGB7cn0NCm1vMy5kcmF3cyA8LW1vMyAgJT4lIGFzX2RyYXdzX2FycmF5KCkNCm1vMy5zdW1tYXJ5IDwtIHN1bW1hcml6ZV9kcmF3cyhtbzMuZHJhd3MgKQ0KbW8zLnN1bW1hcnkNCiN3cml0ZS5jc3YobW8zLnN1bW1hcnksICJtb2RlbDNfcmVzdWx0cy5jc3YiKQ0KYGBgDQoNCg0KIyMjIE0zOiBQUEMNCg0KYGBge3J9DQpwcF9jaGVjayhtbzMsIHR5cGU9Imxvb19pbnRlcnZhbHMiLHByb2IgPSAwLjUscHJvYl9vdXRlcj0gMC45NSkgKw0KICBnZ3Bsb3QyOjp5bGFiKCJDYXNlcyBwZXIgMTAwLDAwMCAobG9nMTApIikgKw0KICBnZ3Bsb3QyOjp4bGFiKCJJbmRleCIpICsNCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICkNCmBgYA0KDQojIyMgTTM6IENvbmRpdGlvbmFsIFBsb3Qgd2l0aCBSYW5kb20gRWZmZWN0cw0KDQpgYGB7cn0NCmNvbmRpdGlvbmFsX2VmZmVjdHMobW8zLGVmZmVjdHM9YygibG9nX24yX2Zsb3dhZGo6cGhhc2UiKSwgcmVfZm9ybXVsYSA9IE5VTEwpDQpgYGANCg0KDQojIyMgTTM6IENvbWJpbmF0aW9uIFBsb3Qgb2YgUmFuZG9tIFNsb3BlcyBhbmQgSW50ZXJjZXB0cw0KDQpgYGB7cn0NCiNsaWJyYXJ5KHRpZHliYXllcykNCiNkZWZpbmUgY3VzdG9tIG9yZGVyIGZvciBzZXdlcnNoZWQgc2l0ZXMNCnNpdGVfb3JkZXIgPC0gYygiU1MxIiwgIlNTMiIsICJTUzMiLCAiU1M0IiwgIlNTNSIsICJTUzYiLCAiU1M3IiwgIlNTOCIsICJTUzkiLCAiU1MxMCIsICJTUzExIikNCg0KI2V4dHJhY3QgcmFuZG9tIGludGVyY2VwdHMgYW5kIHNsb3Blcw0KbW8zICU+JQ0KICBzcHJlYWRfZHJhd3Mocl9zaXRlW3NpdGUsdGVybV0pICU+JQ0KICBmaWx0ZXIodGVybSAlaW4lIGMoIkludGVyY2VwdCIsICJsb2dfbjJfZmxvd2FkaiIpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHNpdGUgPSBmYWN0b3Ioc2l0ZSwgbGV2ZWxzID0gc2l0ZV9vcmRlciwgb3JkZXJlZCA9IFRSVUUpKSAlPiUNCiAgZ2dwbG90KGFlcyh5ID0gc2l0ZSwgeCA9IHJfc2l0ZSkpICsNCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoLjUwLCAuOTUpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZmFjZXRfd3JhcCh+dGVybSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIGxhYnMoeCA9ICJSYW5kb20gRWZmZWN0IiwgeSA9ICJTZXdlcnNoZWQiIA0KICAjY29tbWVudCB0byBmb3JtYXQgZm9yIGluY2x1c2lvbiBvZiBGaWd1cmUgMyBpbiBtYWluIHRleHQgb2YgbWFudXNjcmlwdA0KICAjICAgICAgdGl0bGUgPSAiUmFuZG9tIEVmZmVjdHMgYnkgU2V3ZXJzaGVkIiwNCiAgIyAgICAgIHN1YnRpdGxlID0gIkludGVyY2VwdHMgYW5kIFNsb3BlcyINCiAgKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KHNpdGVfb3JkZXIpKSArICAjcmV2ZXJzZSBzaXRlIG9yZGVyIGZvciB0b3AtdG8tYm90dG9tIGxheW91dA0KICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSAjIHJlbW92ZSBmYWNldCBsYWJlbHMNCmBgYA0KDQoNCiMjIyBNMzogU3VtbWFyeSBvZiBSZXN1bHRzDQoNCk1vZGVsIDMgaXMgbG9nX2Nhc2UxMDAwMDAgfiAxICsgbG9nX24yX2Zsb3dhZGogKiBwaGFzZSArICgxICsgbG9nX24yX2Zsb3dhZGogfCBzaXRlKSBhbmQgd2FzIGZpdCB1c2luZyA0IE1DTUMgY2hhaW5zLCBlYWNoIHdpdGggNDAwMCBpdGVyYXRpb25zICg1MDAgd2FybXVwKSwgcmVzdWx0aW5nIGluIDE0LDAwMCB0b3RhbCBwb3N0LXdhcm11cCBkcmF3cy4NCg0KKipSYW5kb20gRWZmZWN0cyoqDQoNCi0gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgcmFuZG9tIGludGVyY2VwdHMgaXMgMS41NzA3ICg5NSUgQ0k6IDAuODc2OSB0byAyLjYyNjQpLg0KDQotIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHJhbmRvbSBzbG9wZXMgZm9yIGxvZ19uMl9mbG93YWRqIGlzIDAuMTA5OSAoOTUlIENJOiAwLjA1NjMgdG8gMC4xOTA0KS4NCg0KLSBDb3JyZWxhdGlvbjogVGhlcmUgaXMgYSBzdHJvbmcgbmVnYXRpdmUgY29ycmVsYXRpb24gKC0wLjk1ODIpIGJldHdlZW4gdGhlIHJhbmRvbSBpbnRlcmNlcHRzIGFuZCBzbG9wZXMuDQoNCg0KKipGaXhlZCBFZmZlY3RzKioNCg0KLSBUaGUgb3ZlcmFsbCBpbnRlcmNlcHQgaXMgLTQuNDI2NiAoOTUlIENJOiAtNS43NTE4IHRvIC0zLjA3ODEpLg0KDQpUaGUgbWFpbiBlZmZlY3Qgb2YgbG9nX24yX2Zsb3dhZGogaXMgMC41MDAwICg5NSUgQ0k6IDAuMzk3OCB0byAwLjYwMDgpLCBpbmRpY2F0aW5nIGEgY3JlZGlibGUgZWZmZWN0LiANCg0KQ29tcGFyZWQgdG8gdGhlIHJlZmVyZW5jZSBwaGFzZSAoaS5lLiwgcHJlLVZPQyk6DQoNCi0gVGhlIEFscGhhIHBoYXNlIGhhcyBhIGNyZWRpYmx5IGxvd2VyIGludGVyY2VwdCAoLTEuNzYyMjsgOTUlIENJOiAtMi42MjcxICB0byAtMC44NzgzICkuIFRoaXMgaW50ZXJ2YWwgZG9lcyBub3QgaW5jbHVkZSAwLg0KDQotIFRoZSBEZWx0YSBwaGFzZSBpcyBub3QgY3JlZGlibHkgZGlmZmVyZW50ICgwLjE1NDEsIDk1JSBDSTogLTAuNzYxNSB0byAxLjA4NzYpLiBUaGlzIGludGVydmFsIGluY2x1ZGVzIDAuDQoNCi0gVGhlIE9taWNyb24gcGhhc2UgaGFzIGEgY3JlZGlibHkgbG93ZXIgaW50ZXJjZXB0ICgtMS43Nzg4LCA5NSUgQ0k6IC0yLjc0MTEgdG8gLTAuODE2MCkuIFRoaXMgaW50ZXJ2YWwgZG9lcyBub3QgaW5jbHVkZSAwLg0KDQpUaGUgaW50ZXJhY3Rpb25zIGJldHdlZW4gbG9nX24yX2Zsb3dhZGogYW5kIFNBUlMtQ29WLTIgVk9DczoNCg0KLSBBbHBoYTogQ3JlZGlibGUgcG9zaXRpdmUgaW50ZXJhY3Rpb24gKDAuMTExOSwgOTUlIENJOiAwLjAzOTUgdG8gMC4xODI5KS4gVGhpcyBpbnRlcnZhbCBkb2VzIG5vdCBpbmNsdWRlIDAuDQoNCi0gRGVsdGE6IE5vIGNyZWRpYmxlIGludGVyYWN0aW9uICgtMC4wMjU5LCA5NSUgQ0k6IC0wLjEwMjYgdG8gMC4wNDg5KS4gVGhpcyBpbnRlcnZhbCBpbmNsdWRlcyAwLg0KDQotIE9taWNyb246IENyZWRpYmxlIHBvc2l0aXZlIGludGVyYWN0aW9uICgwLjE0NTcsIDk1JSBDSTogMC4wNjczIHRvIDAuMjI0OSkuIFRoaXMgaW50ZXJ2YWwgZG9lcyBub3QgaW5jbHVkZSAwLg0KDQoNClRoZSBpbnRlcmFjdGlvbnMgYmV0d2VlbiBsb2dfbjJfZmxvd2FkaiBhbmQgdGhlIEFscGhhIGFuZCBPbWljcm9uIHBoYXNlcyBpcyBhcyBmb2xsb3dzOg0KDQotIEFscGhhOiBUaGUgaW50ZXJhY3Rpb24gdGVybSBsb2dfbjJfZmxvd2FkajpwaGFzZWFscGhhIGhhcyBhbiBlc3RpbWF0ZSBvZiAwLjExMTkuIFRodXMsIGZvciBldmVyeSAxIHVuaXQgaW5jcmVhc2UgaW4gbG9nX24yX2Zsb3dhZGogZHVyaW5nIHRoZSBBbHBoYSBwaGFzZSwgdGhlcmUgaXMgYW4gYWRkaXRpb25hbCAwLjExIGxvZyB1bml0IGluY3JlYXNlIGluIGxvZ19jYXNlMTAwMDAwIGNvbXBhcmVkIHRvIHRoZSByZWZlcmVuY2UgcGhhc2UgKGkuZS4sIHByZV9WT0MpLiBUaGUgdG90YWwgZWZmZWN0IG9mIGxvZ19uMl9mbG93YWRqIGR1cmluZyB0aGUgQWxwaGEgcGVyaW9kIGlzOiAwLjUwMDAgKG1haW4gZWZmZWN0KSArIDAuMTExOSAoaW50ZXJhY3Rpb24pID0gMC42MTE5LiBUaGlzIG1lYW5zIHRoYXQgZm9yIGV2ZXJ5IDEgdW5pdCBpbmNyZWFzZSBpbiBsb2dfbjJfZmxvd2FkaiBkdXJpbmcgdGhlIEFscGhhIHBoYXNlLCBsb2dfY2FzZTEwMDAwMCBpcyBleHBlY3RlZCB0byBpbmNyZWFzZSBieSAwLjYxIGxvZyB1bml0cywgaG9sZGluZyBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQuDQoNCi0gT21pY3JvbjogVGhlIGludGVyYWN0aW9uIHRlcm0gbG9nX24yX2Zsb3dhZGo6cGhhc2VvbWljcm9uIGhhcyBhbiBlc3RpbWF0ZSBvZiAwLjE0NTcuIEZvciBldmVyeSAxIHVuaXQgaW5jcmVhc2UgaW4gbG9nX24yX2Zsb3dhZGogZHVyaW5nIHRoZSBPbWljcm9uIHBoYXNlLCB0aGVyZSBpcyBhbiBhZGRpdGlvbmFsIDAuMTQ1NCBsb2cgdW5pdCBpbmNyZWFzZSBpbiBsb2dfY2FzZTEwMDAwMC4gVGhpcyBpbmRpY2F0ZXMgYSBzdHJvbmdlciByZWxhdGlvbnNoaXAgYmV0d2VlbiBOMiBnZW5lIGNvbmNlbnRyYXRpb24gYW5kIENPVklELTE5IGNhc2VzIGZvciBPbWljcm9uIHRoYW4gQWxwaGEgcGhhc2VzLiBUaGUgdG90YWwgZWZmZWN0IG9mIGxvZ19uMl9mbG93YWRqIGZvciBPbWljcm9uIGlzOiAwLjUwMDAgKG1haW4gZWZmZWN0KSArIDAuMTQ1NyAoaW50ZXJhY3Rpb24pID0gMC42NDU3LiBGb3IgZXZlcnkgMSB1bml0IGluY3JlYXNlIGluIGxvZ19uMl9mbG93YWRqIGR1cmluZyB0aGUgQWxwaGEgcGhhc2UsIGxvZ19jYXNlMTAwMDAwIGlzIGV4cGVjdGVkIHRvIGluY3JlYXNlIGJ5IDAuNjQgbG9nIHVuaXRzLCBob2xkaW5nIG90aGVyIHZhcmlhYmxlcyBjb25zdGFudC4NCg0KDQoqKk1vZGVsIEZpdCoqDQoNCi0gVGhlIHJlc2lkdWFsIHN0YW5kYXJkIGRldmlhdGlvbiAoc2lnbWEpIGlzIDAuMjczNiAoOTUlIENJOiAwLjI2MTIgdG8gMC4yODY5KS4NCg0KLSBUaGUgUmhhdCB2YWx1ZXMgYXJlIGFsbCBjbG9zZSB0byAxLCBpbmRpY2F0aW5nIGdvb2QgY29udmVyZ2VuY2UuDQoNCi0gVGhlIGVmZmVjdGl2ZSBzYW1wbGUgc2l6ZXMgKEVTUykgYXJlIGdlbmVyYWxseSBoaWdoLCBzdWdnZXN0aW5nIHJlbGlhYmxlIHBvc3RlcmlvciBlc3RpbWF0ZXMuDQoNCg0KKipQUEMgYW5kIENvbmRpdGlvbmFsIEVmZmVjdHMqKg0KDQpUaGUgb2JzZXJ2ZWQgZGF0YSBmZWxsIHdpdGhpbiBib3RoIDUwJSBhbmQgOTUlIExPTyBpbnRlcnZhbHMgYW5kIHRoZSBjb25kaXRpb25hbCBlZmZlY3RzIHBsb3Qgc2hvdyBhIHBvc2l0aXZlLCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxvdy1hZGp1c3RlZCBOMiBhbmQgQ09WSUQtMTkgY2FzZXMsIHdpdGggdmlzdWFsIGRpZmZlcmVuY2VzIGluIHRoZSBzbG9wZXMgZm9yIEFscGhhIGFuZCBPbWljcm9uIGNvbXBhcmVkIHRvIHByZS1WT0MuDQoNCkluIHN1bW1hcnksIE1vZGVsIDMgc3VnZ2VzdHMgdGhhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxvdy1hZGp1c3RlZCBOMiBhbmQgQ09WSUQtMTkgY2FzZXMgdmFyaWVzIGFjcm9zcyBkaWZmZXJlbnQgdmFyaWFudCBwaGFzZXMsIHdpdGggY3JlZGlibGUgZGlmZmVyZW5jZXMgZm9yIEFscGhhIGFuZCBPbWljcm9uIChidXQgbm90IERlbHRhKSB2YXJpYW50cyBpbiBib3RoIGludGVyY2VwdHMgYW5kIHNsb3BlcyB3aGVuIGNvbXBhcmVkIHRvIHByZS1WT0MgKHRoZSByZWZlcmVuY2UgcGhhc2UpLg0KDQoNCioqT3ZlcnZpZXcgb2YgUmFuZG9tIEVmZmVjdHMgZm9yIEludGVyY2VwdHMqKg0KDQpUaGVzZSByZXByZXNlbnQgaG93IG11Y2ggZWFjaCBzaXRlJ3MgaW50ZXJjZXB0IGRldmlhdGVzIGZyb20gdGhlIGdyYW5kIG1lYW4gaW50ZXJjZXB0Og0KDQotIEhpZ2hlc3QgaW50ZXJjZXB0czogU1MyLCBTUzUsIFNTNywgYW5kIFNTOA0KDQotIExvd2VzdCBpbnRlcmNlcHRzOiBTUzEsIFNTNCwgU1M2LCBhbmQgU1M5DQoNCg0KKipPdmVydmlldyBvZiBSYW5kb20gRWZmZWN0cyBmb3IgU2xvcGVzKioNCg0KVGhlc2UgcmVzdWx0cyBzaG93IGhvdyB0aGUgZWZmZWN0IG9mIGxvZ19uMl9mbG93YWRqIHZhcmllcyBieSBzaXRlOg0KDQotIEhpZ2hlc3Qgc2xvcGVzOiBTUzEsIFNTNCwgU1M5LCBhbmQgU1MxMQ0KDQotIExvd2VzdCBzbG9wZXM6IFNTMiwgU1M1LCBTUzcsIGFuZCBTUzgNCg0KDQoqKk1vZGVsIFByZWNpc2lvbioqDQoNClRoZSByZXNpZHVhbCBzdGFuZGFyZCBkZXZpYXRpb24gKHNpZ21hKSBpcyBlc3RpbWF0ZWQgYXQgMC4yNzM2ICg5NSUgQ0k6IDAuMjYxMiB0byAwLjI4NjkpLCBpbmRpY2F0aW5nIHRoZSB1bmV4cGxhaW5lZCB2YXJpYWJpbGl0eSBpbiB0aGUgbW9kZWwuDQoNCioqUmFuZG9tIEVmZmVjdHMgQ29ycmVsYXRpb24qKg0KDQpUaGUgY29ycmVsYXRpb24gYmV0d2VlbiByYW5kb20gaW50ZXJjZXB0cyBhbmQgc2xvcGVzIChjb3Jfc2l0ZV9fSW50ZXJjZXB0X19sb2dfbjJfZmxvd2FkaikgaXMgc3Ryb25nbHkgbmVnYXRpdmUgKC0wLjk1ODIpLCBzdWdnZXN0aW5nIHRoYXQgc2l0ZXMgd2l0aCBoaWdoZXIgYmFzZWxpbmUgbG9nIGNhc2UgY291bnRzIHRlbmQgdG8gaGF2ZSBuZWdhdGl2ZSBhc3NvY2lhdGlvbnMgYmV0d2VlbiBsb2dfbjJfZmxvd2FkaiBhbmQgcG9wdWxhdGlvbi1ub3JtYWxpemVkIGxvZyBjYXNlIGNvdW50cywgYW5kIHZpY2UgdmVyc2EuIEluIG90aGVyIHdvcmRzLCB0aGUgcmVjaXByb2NhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZWZmZWN0IHNpemVzIG9mIHRoZSBpbnRlcmNlcHRzIGFuZCBzbG9wZXMgZm9yIFNTMiwgU1M1LCBTUzcsIGFuZCBTUzggc3VnZ2VzdHMgdGhhdCBwb3B1bGF0aW9ucyB3aXRoIG1vcmUgc2V2ZXJlIG91dGJyZWFrcyBzdGFiaWxpemUgb3IgZGVjcmVhc2UgbW9yZSBxdWlja2x5LCB3aGlsZSB0aG9zZSB3aXRoIGxlc3Mgc2V2ZXJlIG91dGJyZWFrcyB0ZW5kIHRvIGluY3JlYXNlIG1vcmUgcXVpY2tseSBvdmVyIHRpbWUuDQoNCioqU3VtbWFyeSoqDQoNCkluIHN1bW1hcnksIE1vZGVsIDMgcmV2ZWFscyBjcmVkaWJsZSB2YXJpYXRpb24gYWNyb3NzIHNpdGVzIGluIGJvdGggYmFzZWxpbmUgbG9nIGNhc2UgY291bnRzIGFuZCB0aGUgc3RyZW5ndGggb2YgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gTjIgbG9hZCBpbnRlcmFjdGluZyB3aXRoIFZPQ3MgYW5kIENPVklELTE5IGNhc2VzLiBUaGUgcGhhc2Utc3BlY2lmaWMgZWZmZWN0cyBvZiBBbHBoYSBhbmQgT21pY3JvbiB2YXJpZWQgYWNyb3NzIHRoZSBzZXdlcnNoZWRzLg0KDQoNCiMjIExlYXZlLU9uZS1PdXQgQ3Jvc3MtVmFsaWRhdGlvbiAoTE9PLUNWKSBTZWN0aW9uOiBDb21wYXJlIE1vZGVscyAxLCAyIGFuZCAzIA0KDQoNCiMjIyBNb2RlbCBMT08tQ1ZzDQoNCmBgYHtyfQ0KbG9vLm0xIDwtIGxvbyhtbzEpDQpsb28ubTIgPC0gbG9vKG1vMikNCmxvby5tMyA8LSBsb28obW8zKQ0KYGBgDQoNCiMjIyBNMSBMMDAtQ1YNCg0KYGBge3J9DQpsb28ubTENCmBgYA0KDQojIyMgTTIgTDAwLUNWDQoNCmBgYHtyfQ0KbG9vLm0yDQpgYGANCg0KIyMjIE0zIEwwMC1DVg0KDQpgYGB7cn0NCmxvby5tMw0KYGBgDQoNCiMjIyBDb21wYXJlIE0xLCBNMiBhbmQgTTMgTE9PLUNWcw0KDQpgYGB7cn0NCmxvb19jb21wYXJlKGxvby5tMSxsb28ubTIsbG9vLm0zKQ0KYGBgDQoqKlN1bW1hcnkgb2YgTE9PLUNWKioNCg0KVGhlIG1vZGVscyBhcmUgb3JkZXJlZCBmcm9tIGJlc3QgdG8gd29yc3QgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4NCg0KLSBlbHBkX2RpZmY6IFRoaXMgY29sdW1uIHNob3dzIHRoZSBkaWZmZXJlbmNlIGluIGV4cGVjdGVkIGxvZyBwcmVkaWN0aXZlIGRlbnNpdHkgKEVMUEQpIGJldHdlZW4gZWFjaCBtb2RlbCBhbmQgdGhlIHRvcC1wZXJmb3JtaW5nIG1vZGVsLiBBIGhpZ2hlciBFTFBEIGluZGljYXRlcyBiZXR0ZXIgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4NCg0KLSBzZV9kaWZmOiBUaGlzIGNvbHVtbiBzaG93cyB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIGRpZmZlcmVuY2UgaW4gRUxQRC4NCg0KTW9kZWwgMzoNCg0KLSBFTFBEIGRpZmZlcmVuY2U6IDAuMA0KDQpUaGlzIGlzIHRoZSBiZXN0LXBlcmZvcm1pbmcgbW9kZWwgYmVjYXVzZSBpdCBoYXMgdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBhY2N1cmFjeSBmb3IgdGhlIG1vZGVscy4NCg0KTW9kZWwgMjoNCg0KVGhlIEVMUEQgZGlmZmVyZW5jZTogLTEyNi40LiBUaGlzIG1vZGVsIHBlcmZvcm1zIHdvcnNlIHRoYW4gTW9kZWwgMyBiZWNhdXNlIHRoZSBkaWZmZXJlbmNlIGlzIHN1YnN0YW50aWFsIChtb3JlIHRoYW4gMiBTRSBhd2F5IGZyb20gMCkuDQoNCk1vZGVsIDE6DQoNCi0gRUxQRCBkaWZmZXJlbmNlOiAtMTM5LjYuIFRoaXMgbW9kZWwgaGFzIHRoZSB3b3JzdCBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIGFtb25nIHRoZSBtb2RlbHMuIFRoZSBkaWZmZXJlbmNlIGZyb20gdGhlIHRvcCBtb2RlbCBpcyBhbHNvIHN1YnN0YW50aWFsLg0KDQoqKjJTRSBSdWxlKioNCg0KVXNpbmcgdGhlICIyU0UgcnVsZSIgdG8gZXN0aW1hdGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLCB0aGUgc2Vjb25kIGJlc3QgcGVyZm9ybWluZyBtb2RlbCAoTW9kZWwgMikgaGFzIGEgOTUlIENJIG9mIC0xMjYuNCArIGMoLTIsMikqMTUuMSA9ICgtMTU2LjYgYW5kIC0wLjk2LjIpLCB3aGljaCBkb2VzIG5vdCBjb250YWluIDAuIFRoZSByYXRpbyBvZiBhYnMoZWxwZF9kaWZmL3NlX2RpZmYpID0gOC4zNzEsIHdoaWNoIGlzIGdyZWF0ZXIgdGhhbiAyLiBBIHJhdGlvIG9mIDIgaXMgYSBjb21tb24gdGhyZXNob2xkIGZvciBldmFsdWF0aW5nIHBlcmZvcm1hbmNlIGNvbXBhcmlzb25zLiBNb2RlbCAzIGlzIHRoZSB3b3JzdCBwZXJmb3JtaW5nIG1vZGVsIHdpdGggYSBDSSBvZiAoLTE3MC44LCAtMTA4LjQpIHRoYXQgYWxzbyBkb2VzIG5vdCBjb250YWluIDAuIE1vZGVsIDMgY2xlYXJseSBvdXRwZXJmb3JtcyB0aGUgb3RoZXIgdHdvIG1vZGVscyBpbiB0ZXJtcyBvZiBwcmVkaWN0aXZlIGFjY3VyYWN5IGJlY2F1c2UgaXQgYWNjb3VudHMgZm9yIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIE4yIGdlbmUgYW5kIFZPQ3Mgd2hpbGUgYWxsb3dpbmcgdGhlIHNsb3BlIGFuZCBpbnRlcmNlcHRzIHRvIHZhcnkgYnkgc2V3ZXJzaGVkIHNpdGUuDQoNCg0KIyMjIFBTSVMgUGxvdHMNCg0KIyMjIE0xDQpgYGB7cn0NCnBsb3QobG9vLm0xKQ0KYGBgDQoNCg0KDQojIyMgTTIgDQoNCmBgYHtyfQ0KcGxvdChsb28ubTIpDQpgYGANCg0KDQojIyMgTTMNCg0KYGBge3J9DQpwbG90KGxvby5tMykNCmBgYA0KDQoNCg0KIyBCYXllc2lhbiBNb2RlbCBTdGFuIENvZGUgU2VjdGlvbiANCg0KDQojIyBGZWNhbCBNb2RlbHMgU3RhbiBDb2RlDQoNCiMjIyBtMDENCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpmcy5tbzEkbW9kZWwNCmBgYA0KDQojIyMgbTAyDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZnMubW8yJG1vZGVsDQpgYGANCg0KIyMgTW9kZWwgMSBTdGFuIENvZGUNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCm1vMSRtb2RlbA0KYGBgDQoNCiMjIE1vZGVsIDIgU3RhbiBDb2RlDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQptbzIkbW9kZWwNCmBgYA0KDQojIyBNb2RlbCAzIFN0YW4gQ29kZQ0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KbW8zJG1vZGVsDQpgYGANCg0KDQoNCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbg0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA0KDQo=