library(tidyverse)
library(ggformula)
library(lme4)
library(car)
library(broom)
library(cowplot)
options(scipen = 999)
library(here)
library(bbmle)
library(latex2exp)
library(emmeans)
library(glue)

1 Read in Data

  1. Li-COR data
  2. SPAD meter data
  3. rainfall treatment data
(licor <- read_rds(here("cleaned_data", "photosynthesis data.rds")))
(spad <- read_rds(here("cleaned_data", "SPAD data.rds")))
(treatment <- read_rds(here("cleaned_data", "BACE_Treatments.rds")))

2 Data Specification

spad contains data collected using the SPAD-502 chlorophyll meter produced by Spectrum Technologies, INC (Plainfield, IL). I measured chlorophyll content on three leaves of each plant in the data frame, which is why each plant.id is repeated three times. SPAD is measured in SPAD units which is calculated as a ratio of intensities of two wavelengths of light (see manual for more detail). Each SPAD data point is a mean of three measurements, averaged using the instrument itself.

  • plot.id: Which plot in the BACE experiment the plant was grown in
  • plant.id: The ID number of the plant (1-11) in each plot
  • SPAD: Mean chlorophyll content in SPAD units for a leaf (n = 3 locations on the leaf)
  • Treatment: Which drought treatment received

licor contains data collected using a LI-COR LI6400 portable photosynthesis meter. Data import and cleaning are done in LI-COR data wrangling.Rmd.

  • plot.id: Which plot in the BACE experiment the plant was grown in
  • plant.id: The ID number of the plant (1-11) in each plot
  • leaf: Which of three leaves (a, b, c) the data were collected from
  • ...: The rest of the columns are explained in documentation for the LI6400 (LICOR System Variables.pdf)

3 Chlorophyll contents (SPAD)

3.1 Model Selection

spad.lmer <- lmer(SPAD ~ Treatment + (1|plot.id) + (1|unique.id), data = spad)
plot(spad.lmer)

shapiro.test(augment(spad.lmer)$.resid)

    Shapiro-Wilk normality test

data:  augment(spad.lmer)$.resid
W = 0.98416, p-value = 0.004362
tidy(spad.lmer)
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector
fixef(spad.lmer)
 (Intercept) Treatment75% Treatment50% 
   54.363441    -1.308996    -1.120912 
summary(spad.lmer)
Linear mixed model fit by REML ['lmerMod']
Formula: SPAD ~ Treatment + (1 | plot.id) + (1 | unique.id)
   Data: spad

REML criterion at convergence: 2137.5

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-1.90994 -0.62705 -0.04793  0.60822  2.45291 

Random effects:
 Groups    Name        Variance            Std.Dev.    
 unique.id (Intercept)  69.721054022779626  8.349913414
 plot.id   (Intercept)   0.000000000003814  0.000001953
 Residual              120.134444096770594 10.960585938
Number of obs: 270, groups:  unique.id, 90; plot.id, 9

Fixed effects:
             Estimate Std. Error t value
(Intercept)    54.363      1.882  28.890
Treatment75%   -1.309      2.683  -0.488
Treatment50%   -1.121      2.707  -0.414

Correlation of Fixed Effects:
            (Intr) Trt75%
Treatmnt75% -0.701       
Treatmnt50% -0.695  0.488

It looks like the effect of plot is very small relative to the effect of plant.

3.2 Model competition

Remove random effect of plot, then both random effects. Then compare all to null model.

spad.lmer.2 <- lmer(SPAD ~ Treatment + (1|unique.id), data = spad)
spad.lm <- lm(SPAD ~ Treatment, data = spad)
spad.null <- lm(SPAD ~ 1, data = spad)
AICtab(spad.lmer, spad.lmer.2, spad.lm, spad.null)
            dAIC df
spad.lmer.2  0.0 5 
spad.lmer    2.0 6 
spad.null   34.5 2 
spad.lm     38.0 4 
spad.posthoc <- emmeans(spad.lmer.2, pairwise ~ Treatment)

3.3 ANOVA

Anova(spad.lmer.2)
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: SPAD
           Chisq Df Pr(>Chisq)
Treatment 0.2788  2     0.8699

spad.lmer.2 wins. This model includes treatment as a main effect and unique plant ID as a random effect. However,the main effect of drought treatment is not significant.

3.4 Figure

spad.errbar <- spad.posthoc$emmeans %>% tidy()
# summarize data by plant for plots
spad.plotdata <- spad %>% 
  group_by(Treatment, unique.id) %>% 
  summarize(SPAD = mean(SPAD))
spad.bar <- ggplot(spad.plotdata, aes(x = Treatment, y = SPAD)) +
  geom_jitter(alpha = 0.5, width = 0.2) +
  geom_errorbar(aes(ymin = conf.low, ymax = conf.high,x = Treatment, y = estimate),
                width = 0.2,
                data = spad.errbar) +
  geom_col(aes(x = Treatment, y = estimate), alpha = 0.6, data = spad.errbar) +
  geom_label(aes(x = 3, y = 90, label ="p = 0.870"), data = data.frame()) +
  ylab("Chlorophyll Content (SPAD units)") +
  xlab("% Ambient Rainfall") +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9))
Ignoring unknown aesthetics: y
spad.bar

4 Photosynthesis

4.1 Wrangling

To start, I need to do a little bit of data wrangling since I took multiple measurements on each leaf. These are just technical replicates and represent only instrument variation, so I’m going to average them. I’m going to try using summarize_if to get means for all the columns, then remove some columns where averages don’t make sense (e.g. Obs which is just observation number)

#ammend treatment data to licor data. Spray data isn't relevant since photosynthesis done before spraying.
licor2 <- left_join(licor, treatment, by = c("plot.id" = "Plot", "plant.id" = "Plant")) %>%
  select(-Spray) %>% 
  select(Treatment, everything()) %>% 
  #some of the Treatment entries are "NA" because different plants were used for photosynthesis measurement than were used for spraying and chemistry.  Fill those in.
  fill(Treatment)
licor.avg <- licor2 %>% 
  group_by(Treatment, plot.id, plant.id, leaf) %>%
  summarise_if(is.double, mean) %>% 
  select(-Obs, -Date.Time, -FTime, -`EBal?`) %>% 
  #create unique.id column
  mutate(unique.id = paste0(plot.id, plant.id)) %>% 
  select(Treatment, plot.id, plant.id, unique.id, leaf, everything())

At this point leaf represents biological replicates, plant.id and plot.id are random effects and Treatment is our only fixed effect.

4.2 Model selection

I’m mostly interested in photo which is photosynthetic rate measured in units of \(\frac{\mu \textrm{mol CO}_2 /\textrm{s}}{\textrm{m}^2}\).

photo.lmer <- lmer(Photo ~ Treatment + (1|plot.id) + (1|unique.id), data = licor.avg) 
tidy(photo.lmer)
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector
summary(photo.lmer)
Linear mixed model fit by REML ['lmerMod']
Formula: Photo ~ Treatment + (1 | plot.id) + (1 | unique.id)
   Data: licor.avg

REML criterion at convergence: 271.3

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.3434 -0.5237 -0.0152  0.4390  1.7885 

Random effects:
 Groups    Name        Variance Std.Dev.
 unique.id (Intercept) 1.9733   1.4048  
 plot.id   (Intercept) 0.3694   0.6078  
 Residual              0.9062   0.9519  
Number of obs: 80, groups:  unique.id, 27; plot.id, 9

Fixed effects:
             Estimate Std. Error t value
(Intercept)    6.1003     0.6132   9.949
Treatment75%  -1.9435     0.8671  -2.241
Treatment50%  -3.4175     0.8682  -3.936

Correlation of Fixed Effects:
            (Intr) Trt75%
Treatmnt75% -0.707       
Treatmnt50% -0.706  0.499

Model diagnostics

plot(photo.lmer)

augment(photo.lmer) %>% 
  ggplot(aes(sample = .resid)) +
  geom_qq() +
  stat_qqline()+
  coord_flip() +
  theme_bw()

Looks great

Model competition

#remove plot effect
photo.lmer2 <- lmer(Photo ~ Treatment + (1|unique.id), data = licor.avg) 
# Only fixed effects
photo.lm <- lm(Photo ~ Treatment, data = licor.avg)
#null model
photo.null <- lm(Photo ~ 1, data = licor.avg)
AICtab(photo.lm, photo.lmer, photo.lmer2, photo.null)
            dAIC df
photo.lmer2  0.0 5 
photo.lmer   1.6 6 
photo.lm    38.0 4 
photo.null  74.7 2 

photo.lmer2 wins. This is the same specification as the SPAD model—a random effect of plant, but not plot.

4.3 ANOVA

Anova(photo.lmer2)
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: Photo
           Chisq Df Pr(>Chisq)    
Treatment 20.646  2 0.00003287 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
photo.posthoc <- emmeans(photo.lmer2, pairwise ~ Treatment)
photo.posthoc$contrasts
 contrast   estimate        SE    df t.ratio p.value
 100% - 75% 1.943454 0.7528227 23.90   2.582  0.0419
 100% - 50% 3.414586 0.7540121 24.04   4.529  0.0004
 75% - 50%  1.471132 0.7540121 24.04   1.951  0.1463

P value adjustment: tukey method for comparing a family of 3 estimates 
photo.lmer2.noint <- lmer(Photo ~ -1+ Treatment + (1|unique.id), data = licor.avg) 
fixef(photo.lmer2.noint)
Treatment100%  Treatment75%  Treatment50% 
     6.100260      4.156806      2.685674 

Significant effect of drought treatment. 100 = a; 75 = b; 50 = b

4.3.1 Plot results

letters_data <- licor.avg %>%
  group_by(Treatment) %>%
  summarise(max.p = max(Photo), max.c = max(Cond))
photo.errbar <- photo.posthoc$emmeans %>% tidy()
# photo.errbar
#summarize data for plots
licor.plotdata <- licor.avg %>% 
  group_by(Treatment, unique.id) %>% 
  summarize(Photo = mean(Photo),
            Cond = mean(Cond))
#jitter plot with mean ± CI
photo.bar <- ggplot(licor.plotdata, aes(x = Treatment, y = Photo)) +
  geom_jitter(alpha = 0.5, width = 0.2) +
  geom_errorbar(aes(ymin = conf.low, ymax = conf.high,x = Treatment, y = estimate),
                width = 0.2,
                data = photo.errbar) +
  geom_col(aes(x = Treatment, y = estimate), alpha = 0.6, data = photo.errbar) +
  geom_text(aes(y = max.p, label = c("a", "b", "b")), vjust = -1, data = letters_data, size = 4) +
  geom_label(aes(x = 3, y = 10, label = "p < 0.001"), data = data.frame()) +
  ylim(0, 10) +
  xlab("% Ambient Rainfall") +
  ylab(TeX("Net Assimilation Rate $(\\mu$ mol $CO_{2}$ $m^{-2}$ $s^{-1})$")) +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9))
Ignoring unknown aesthetics: y
photo.bar

5 Stomatal conductance

5.1 Model selection

cond.lmer <- lmer(log(Cond) ~ Treatment + (1|plot.id) + (1|unique.id), data = licor.avg) 
lmer(log(Cond) ~ -1 + Treatment + (1|plot.id) + (1|unique.id), data = licor.avg) %>% fixef() %>% exp()
Treatment100%  Treatment75%  Treatment50% 
   0.05532703    0.02877802    0.01721222 
tidy(cond.lmer)
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector

Model diagnostics

plot(cond.lmer)

augment(cond.lmer) %>% 
  ggplot(aes(sample = .resid)) +
  geom_qq() +
  stat_qqline()+
  coord_flip() +
  theme_bw()

Some slight pattern in residuals plot, qq plot looks fine.

Model competition

#remove plot effect
cond.lmer2 <- lmer(log(Cond) ~ Treatment + (1|unique.id), data = licor.avg) 
cond.lmer3 <- lmer(log(Cond) ~ 1 + (1|unique.id), data = licor.avg)
# fixed efects only
cond.lm <- lm(log(Cond) ~ Treatment, data = licor.avg)
#null model
cond.null <- lm(log(Cond) ~ 1, data = licor.avg)
AICtab(cond.lm, cond.lmer, cond.lmer2, cond.null, cond.lmer3)
           dAIC df
cond.lmer   0.0 6 
cond.lmer2  2.9 5 
cond.lmer3 10.1 3 
cond.lm    42.7 4 
cond.null  71.1 2 

cond.lmer is the best model, which takes plot and plant into account as random effects and drought treatment as a fixed effect.

5.2 ANOVA

Anova(cond.lmer)
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: log(Cond)
           Chisq Df Pr(>Chisq)  
Treatment 6.6552  2    0.03588 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
cond.posthoc <- emmeans(cond.lmer, pairwise ~ Treatment)
cond.posthoc$contrasts
 contrast    estimate        SE   df t.ratio p.value
 100% - 75% 0.6536496 0.4534570 5.99   1.441  0.3803
 100% - 50% 1.1676417 0.4537173 6.00   2.574  0.0929
 75% - 50%  0.5139921 0.4537173 6.00   1.133  0.5306

Results are given on the log (not the response) scale. 
P value adjustment: tukey method for comparing a family of 3 estimates 

Treatment is significant. Anova of cond.lmer2 shows treatment as MUCH more significant. Must mean there is an interaction between plot and treatment. Post-hoc tests show no significant pairwise differences.

This could also be done by modeling with a log-link rather than log transforming. However, the advantage of log transforming is that it takes care of the linearity assumption and the heterosketasticity assumption which are both violated by these data (I think). Using a log-link only takes care of the lineartiy assumption because the it transforms the means instead of taking the means of transformed data. More info here: https://stats.stackexchange.com/questions/47840/linear-model-with-log-transformed-response-vs-generalized-linear-model-with-log

# build models
cond.glmer <- glmer(Cond ~ Treatment + (1|plot.id) + (1|unique.id), family = gaussian(link = "log"), data = licor.avg)
cond.glmer2 <- glmer(Cond ~ Treatment + (1|unique.id), family = gaussian(link = "log"), data = licor.avg)
cond.glmer3 <- glmer(Cond ~ Treatment + (1|plot.id), family = gaussian(link = "log"), data = licor.avg)
cond.glm <- glm(Cond ~ Treatment, family = gaussian(link = "log"), data = licor.avg)
cond.glmer4 <- glmer(Cond ~ 1 + (1|plot.id) + (1|unique.id), family = gaussian(link = "log"), data = licor.avg)
cond.gnull <- glm(Cond ~ 1, family = gaussian(link = "log"), data = licor.avg)

#model competition
AICtab(cond.lmer, cond.glmer, cond.glmer2, cond.glmer3, cond.glm, cond.glmer4, cond.gnull)

#plot diagnostics
Anova(cond.glmer2)
plot(cond.glmer2)
augment(cond.glmer2) %>% 
  ggplot(aes(sample = .resid)) +
  geom_qq() +
  stat_qqline()+
  coord_flip() +
  theme_bw()
#remake bar plot
test <- emmeans(cond.glmer2, pairwise~Treatment)
test2 <- confint(test)$emmeans
test2
ggplot(licor.avg, aes(x = Treatment, y = Cond)) +
  geom_jitter(alpha = 0.5, width = 0.2) +
  geom_errorbar(aes(ymin = exp(asymp.LCL), ymax = exp(asymp.UCL),x = Treatment, y = exp(emmean)),
                width = 0.2,
                data = test2) +
  geom_col(aes(x = Treatment, y = exp(emmean)), alpha = 0.6, data = test2) +
  geom_label(aes(x = 3, y = 0.15, label = paste0("p = ", Anova(cond.glmer2)$`Pr(>Chisq)` %>% round(3))), data = data.frame()) +
  ylim(0, 0.15) +
  xlab("% Ambient Rainfall") +
  ylab(TeX("Stomatal conductance $($mol $H_{2}O$ $m^{-2}$ $s^{-1})$")) +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9))

Results in tighter error bars and non-significant ANOVA (in fact, the best model is a null model with only random effects). However, diagnostics on residuals look much worse.

5.3 Figure

cond.errbar <- cond.posthoc$emmeans %>% tidy()
#jitter plot with mean ± CI
cond.bar <- ggplot(licor.plotdata, aes(x = Treatment, y = Cond)) +
  geom_jitter(alpha = 0.5, width = 0.2, height = 0) +
  geom_errorbar(aes(ymin = exp(conf.low), ymax = exp(conf.high),x = Treatment, y = exp(estimate)),
                width = 0.2,
                data = cond.errbar) +
  geom_col(aes(x = Treatment, y = exp(estimate)), alpha = 0.6,data = cond.errbar) +
  geom_text(aes(y = max.c, label = c("a", "a", "a")), vjust = -1, data = letters_data) +
  geom_label(aes(x = 3, y = 0.15, label = paste0("p = ", Anova(cond.lmer)$`Pr(>Chisq)` %>% round(3))), data = data.frame()) +
  ylim(0, 0.15) +
  xlab("% Ambient Rainfall") +
  ylab(TeX("Stomatal conductance $($mol $H_{2}O$ $m^{-2}$ $s^{-1})$")) +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9))
Ignoring unknown aesthetics: y

6 Export figure

fig1plots <- plot_grid(photo.bar, cond.bar, spad.bar,
          ncol = 2,
          nrow = 2,
          align = "v",
          axis = "l",
          labels = "AUTO",
          label_x = 0)
save_plot(here("figs", "photoplots.png"), fig1plots, ncol = 2, nrow = 2, base_width = 3)
LS0tCnRpdGxlOiAiUGhvdG9zeW50aGVzaXMgQW5hbHlzaXMiCmRhdGU6IDIwMTgtMDEtMDkKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KYGBge3IgcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdnZm9ybXVsYSkKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGNhcikKbGlicmFyeShicm9vbSkKbGlicmFyeShjb3dwbG90KQpvcHRpb25zKHNjaXBlbiA9IDk5OSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGJibWxlKQpsaWJyYXJ5KGxhdGV4MmV4cCkKbGlicmFyeShlbW1lYW5zKQpsaWJyYXJ5KGdsdWUpCmBgYAoKCiMgUmVhZCBpbiBEYXRhCgoxLiBMaS1DT1IgZGF0YQoyLiBTUEFEIG1ldGVyIGRhdGEKMy4gcmFpbmZhbGwgdHJlYXRtZW50IGRhdGEKYGBge3J9CihsaWNvciA8LSByZWFkX3JkcyhoZXJlKCJjbGVhbmVkX2RhdGEiLCAicGhvdG9zeW50aGVzaXMgZGF0YS5yZHMiKSkpCihzcGFkIDwtIHJlYWRfcmRzKGhlcmUoImNsZWFuZWRfZGF0YSIsICJTUEFEIGRhdGEucmRzIikpKQoodHJlYXRtZW50IDwtIHJlYWRfcmRzKGhlcmUoImNsZWFuZWRfZGF0YSIsICJCQUNFX1RyZWF0bWVudHMucmRzIikpKQpgYGAKCgojIERhdGEgU3BlY2lmaWNhdGlvbgpgc3BhZGAgY29udGFpbnMgZGF0YSBjb2xsZWN0ZWQgdXNpbmcgdGhlIFNQQUQtNTAyIGNobG9yb3BoeWxsIG1ldGVyIHByb2R1Y2VkIGJ5IFNwZWN0cnVtIFRlY2hub2xvZ2llcywgSU5DIChQbGFpbmZpZWxkLCBJTCkuIEkgbWVhc3VyZWQgY2hsb3JvcGh5bGwgY29udGVudCBvbiB0aHJlZSBsZWF2ZXMgb2YgZWFjaCBwbGFudCBpbiB0aGUgZGF0YSBmcmFtZSwgd2hpY2ggaXMgd2h5IGVhY2ggYHBsYW50LmlkYCBpcyByZXBlYXRlZCB0aHJlZSB0aW1lcy4gIFNQQUQgaXMgbWVhc3VyZWQgaW4gU1BBRCB1bml0cyB3aGljaCBpcyBjYWxjdWxhdGVkIGFzIGEgcmF0aW8gb2YgaW50ZW5zaXRpZXMgb2YgdHdvIHdhdmVsZW5ndGhzIG9mIGxpZ2h0IChzZWUgbWFudWFsIGZvciBtb3JlIGRldGFpbCkuICBFYWNoIFNQQUQgZGF0YSBwb2ludCBpcyBhIG1lYW4gb2YgdGhyZWUgbWVhc3VyZW1lbnRzLCBhdmVyYWdlZCB1c2luZyB0aGUgaW5zdHJ1bWVudCBpdHNlbGYuCgotIGBwbG90LmlkYDogV2hpY2ggcGxvdCBpbiB0aGUgQkFDRSBleHBlcmltZW50IHRoZSBwbGFudCB3YXMgZ3Jvd24gaW4KLSBgcGxhbnQuaWRgOiBUaGUgSUQgbnVtYmVyIG9mIHRoZSBwbGFudCAoMS0xMSkgaW4gZWFjaCBwbG90Ci0gYFNQQURgOiBNZWFuIGNobG9yb3BoeWxsIGNvbnRlbnQgaW4gU1BBRCB1bml0cyBmb3IgYSBsZWFmIChuID0gMyBsb2NhdGlvbnMgb24gdGhlIGxlYWYpCi0gYFRyZWF0bWVudGA6IFdoaWNoIGRyb3VnaHQgdHJlYXRtZW50IHJlY2VpdmVkCgoKYGxpY29yYCBjb250YWlucyBkYXRhIGNvbGxlY3RlZCB1c2luZyBhIExJLUNPUiBMSTY0MDAgcG9ydGFibGUgcGhvdG9zeW50aGVzaXMgbWV0ZXIuICBEYXRhIGltcG9ydCBhbmQgY2xlYW5pbmcgYXJlIGRvbmUgaW4gKkxJLUNPUiBkYXRhIHdyYW5nbGluZy5SbWQqLgoKLSBgcGxvdC5pZGA6IFdoaWNoIHBsb3QgaW4gdGhlIEJBQ0UgZXhwZXJpbWVudCB0aGUgcGxhbnQgd2FzIGdyb3duIGluCi0gYHBsYW50LmlkYDogVGhlIElEIG51bWJlciBvZiB0aGUgcGxhbnQgKDEtMTEpIGluIGVhY2ggcGxvdAotIGBsZWFmYDogV2hpY2ggb2YgdGhyZWUgbGVhdmVzIChhLCBiLCBjKSB0aGUgZGF0YSB3ZXJlIGNvbGxlY3RlZCBmcm9tCi0gYC4uLmA6IFRoZSByZXN0IG9mIHRoZSBjb2x1bW5zIGFyZSBleHBsYWluZWQgaW4gZG9jdW1lbnRhdGlvbiBmb3IgdGhlIExJNjQwMCAoKkxJQ09SIFN5c3RlbSBWYXJpYWJsZXMucGRmKikKCgojIENobG9yb3BoeWxsIGNvbnRlbnRzIChTUEFEKQojIyBNb2RlbCBTZWxlY3Rpb24KCmBgYHtyfQpzcGFkLmxtZXIgPC0gbG1lcihTUEFEIH4gVHJlYXRtZW50ICsgKDF8cGxvdC5pZCkgKyAoMXx1bmlxdWUuaWQpLCBkYXRhID0gc3BhZCkKcGxvdChzcGFkLmxtZXIpCnNoYXBpcm8udGVzdChhdWdtZW50KHNwYWQubG1lcikkLnJlc2lkKQpgYGAKCmBgYHtyfQp0aWR5KHNwYWQubG1lcikKZml4ZWYoc3BhZC5sbWVyKQpzdW1tYXJ5KHNwYWQubG1lcikKYGBgCkl0IGxvb2tzIGxpa2UgdGhlIGVmZmVjdCBvZiBwbG90IGlzICp2ZXJ5KiBzbWFsbCByZWxhdGl2ZSB0byB0aGUgZWZmZWN0IG9mIHBsYW50LgoKIyMgTW9kZWwgY29tcGV0aXRpb24KUmVtb3ZlIHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCwgdGhlbiBib3RoIHJhbmRvbSBlZmZlY3RzLiBUaGVuIGNvbXBhcmUgYWxsIHRvIG51bGwgbW9kZWwuCmBgYHtyfQpzcGFkLmxtZXIuMiA8LSBsbWVyKFNQQUQgfiBUcmVhdG1lbnQgKyAoMXx1bmlxdWUuaWQpLCBkYXRhID0gc3BhZCkKc3BhZC5sbSA8LSBsbShTUEFEIH4gVHJlYXRtZW50LCBkYXRhID0gc3BhZCkKc3BhZC5udWxsIDwtIGxtKFNQQUQgfiAxLCBkYXRhID0gc3BhZCkKQUlDdGFiKHNwYWQubG1lciwgc3BhZC5sbWVyLjIsIHNwYWQubG0sIHNwYWQubnVsbCkKCnNwYWQucG9zdGhvYyA8LSBlbW1lYW5zKHNwYWQubG1lci4yLCBwYWlyd2lzZSB+IFRyZWF0bWVudCkKYGBgCiMjIEFOT1ZBCmBgYHtyfQpBbm92YShzcGFkLmxtZXIuMikKYGBgCgpgc3BhZC5sbWVyLjJgIHdpbnMuICBUaGlzIG1vZGVsIGluY2x1ZGVzIHRyZWF0bWVudCBhcyBhIG1haW4gZWZmZWN0IGFuZCB1bmlxdWUgcGxhbnQgSUQgYXMgYSByYW5kb20gZWZmZWN0LiAgSG93ZXZlcix0aGUgbWFpbiBlZmZlY3Qgb2YgZHJvdWdodCB0cmVhdG1lbnQgaXMgbm90IHNpZ25pZmljYW50LgoKIyMgRmlndXJlCmBgYHtyIHNwYWQgcGxvdH0Kc3BhZC5lcnJiYXIgPC0gc3BhZC5wb3N0aG9jJGVtbWVhbnMgJT4lIHRpZHkoKQoKIyBzdW1tYXJpemUgZGF0YSBieSBwbGFudCBmb3IgcGxvdHMKc3BhZC5wbG90ZGF0YSA8LSBzcGFkICU+JSAKICBncm91cF9ieShUcmVhdG1lbnQsIHVuaXF1ZS5pZCkgJT4lIAogIHN1bW1hcml6ZShTUEFEID0gbWVhbihTUEFEKSkKCnNwYWQuYmFyIDwtIGdncGxvdChzcGFkLnBsb3RkYXRhLCBhZXMoeCA9IFRyZWF0bWVudCwgeSA9IFNQQUQpKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjUsIHdpZHRoID0gMC4yKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoLHggPSBUcmVhdG1lbnQsIHkgPSBlc3RpbWF0ZSksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMiwKICAgICAgICAgICAgICAgIGRhdGEgPSBzcGFkLmVycmJhcikgKwogIGdlb21fY29sKGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gZXN0aW1hdGUpLCBhbHBoYSA9IDAuNiwgZGF0YSA9IHNwYWQuZXJyYmFyKSArCiAgZ2VvbV9sYWJlbChhZXMoeCA9IDMsIHkgPSA5MCwgbGFiZWwgPSJwID0gMC44NzAiKSwgZGF0YSA9IGRhdGEuZnJhbWUoKSkgKwogIHlsYWIoIkNobG9yb3BoeWxsIENvbnRlbnQgKFNQQUQgdW5pdHMpIikgKwogIHhsYWIoIiUgQW1iaWVudCBSYWluZmFsbCIpICsKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkKc3BhZC5iYXIKYGBgCgoKIyBQaG90b3N5bnRoZXNpcwojIyBXcmFuZ2xpbmcKVG8gc3RhcnQsIEkgbmVlZCB0byBkbyBhIGxpdHRsZSBiaXQgb2YgZGF0YSB3cmFuZ2xpbmcgc2luY2UgSSB0b29rIG11bHRpcGxlIG1lYXN1cmVtZW50cyBvbiBlYWNoIGxlYWYuICBUaGVzZSBhcmUganVzdCB0ZWNobmljYWwgcmVwbGljYXRlcyBhbmQgcmVwcmVzZW50IG9ubHkgaW5zdHJ1bWVudCB2YXJpYXRpb24sIHNvIEknbSBnb2luZyB0byBhdmVyYWdlIHRoZW0uIEknbSBnb2luZyB0byB0cnkgdXNpbmcgYHN1bW1hcml6ZV9pZmAgdG8gZ2V0IG1lYW5zIGZvciBhbGwgdGhlIGNvbHVtbnMsIHRoZW4gcmVtb3ZlIHNvbWUgY29sdW1ucyB3aGVyZSBhdmVyYWdlcyBkb24ndCBtYWtlIHNlbnNlIChlLmcuIGBPYnNgIHdoaWNoIGlzIGp1c3Qgb2JzZXJ2YXRpb24gbnVtYmVyKQpgYGB7cn0KI2FtbWVuZCB0cmVhdG1lbnQgZGF0YSB0byBsaWNvciBkYXRhLiBTcHJheSBkYXRhIGlzbid0IHJlbGV2YW50IHNpbmNlIHBob3Rvc3ludGhlc2lzIGRvbmUgYmVmb3JlIHNwcmF5aW5nLgpsaWNvcjIgPC0gbGVmdF9qb2luKGxpY29yLCB0cmVhdG1lbnQsIGJ5ID0gYygicGxvdC5pZCIgPSAiUGxvdCIsICJwbGFudC5pZCIgPSAiUGxhbnQiKSkgJT4lCiAgc2VsZWN0KC1TcHJheSkgJT4lIAogIHNlbGVjdChUcmVhdG1lbnQsIGV2ZXJ5dGhpbmcoKSkgJT4lIAogICNzb21lIG9mIHRoZSBUcmVhdG1lbnQgZW50cmllcyBhcmUgIk5BIiBiZWNhdXNlIGRpZmZlcmVudCBwbGFudHMgd2VyZSB1c2VkIGZvciBwaG90b3N5bnRoZXNpcyBtZWFzdXJlbWVudCB0aGFuIHdlcmUgdXNlZCBmb3Igc3ByYXlpbmcgYW5kIGNoZW1pc3RyeS4gIEZpbGwgdGhvc2UgaW4uCiAgZmlsbChUcmVhdG1lbnQpCgpsaWNvci5hdmcgPC0gbGljb3IyICU+JSAKICBncm91cF9ieShUcmVhdG1lbnQsIHBsb3QuaWQsIHBsYW50LmlkLCBsZWFmKSAlPiUKICBzdW1tYXJpc2VfaWYoaXMuZG91YmxlLCBtZWFuKSAlPiUgCiAgc2VsZWN0KC1PYnMsIC1EYXRlLlRpbWUsIC1GVGltZSwgLWBFQmFsP2ApICU+JSAKICAjY3JlYXRlIHVuaXF1ZS5pZCBjb2x1bW4KICBtdXRhdGUodW5pcXVlLmlkID0gcGFzdGUwKHBsb3QuaWQsIHBsYW50LmlkKSkgJT4lIAogIHNlbGVjdChUcmVhdG1lbnQsIHBsb3QuaWQsIHBsYW50LmlkLCB1bmlxdWUuaWQsIGxlYWYsIGV2ZXJ5dGhpbmcoKSkKYGBgCgpBdCB0aGlzIHBvaW50IGBsZWFmYCByZXByZXNlbnRzIGJpb2xvZ2ljYWwgcmVwbGljYXRlcywgYHBsYW50LmlkYCBhbmQgYHBsb3QuaWRgIGFyZSByYW5kb20gZWZmZWN0cyBhbmQgYFRyZWF0bWVudGAgaXMgb3VyIG9ubHkgZml4ZWQgZWZmZWN0LgoKIyMgTW9kZWwgc2VsZWN0aW9uCkknbSBtb3N0bHkgaW50ZXJlc3RlZCBpbiBgcGhvdG9gIHdoaWNoIGlzIHBob3Rvc3ludGhldGljIHJhdGUgbWVhc3VyZWQgaW4gdW5pdHMgb2YgJFxmcmFje1xtdSBcdGV4dHJte21vbCBDT31fMiAvXHRleHRybXtzfX17XHRleHRybXttfV4yfSQuCgpgYGB7cn0KcGhvdG8ubG1lciA8LSBsbWVyKFBob3RvIH4gVHJlYXRtZW50ICsgKDF8cGxvdC5pZCkgKyAoMXx1bmlxdWUuaWQpLCBkYXRhID0gbGljb3IuYXZnKSAKdGlkeShwaG90by5sbWVyKQpzdW1tYXJ5KHBob3RvLmxtZXIpCmBgYAoKTW9kZWwgZGlhZ25vc3RpY3MKYGBge3IgcGhvdG8gZGlhZ25vc3RpY3N9CnBsb3QocGhvdG8ubG1lcikKYXVnbWVudChwaG90by5sbWVyKSAlPiUgCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSAucmVzaWQpKSArCiAgZ2VvbV9xcSgpICsKICBzdGF0X3FxbGluZSgpKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKQpgYGAKTG9va3MgZ3JlYXQKCk1vZGVsIGNvbXBldGl0aW9uCmBgYHtyIHBob3RvIGNvbXBldGl0aW9ufQojcmVtb3ZlIHBsb3QgZWZmZWN0CnBob3RvLmxtZXIyIDwtIGxtZXIoUGhvdG8gfiBUcmVhdG1lbnQgKyAoMXx1bmlxdWUuaWQpLCBkYXRhID0gbGljb3IuYXZnKSAKCiMgT25seSBmaXhlZCBlZmZlY3RzCnBob3RvLmxtIDwtIGxtKFBob3RvIH4gVHJlYXRtZW50LCBkYXRhID0gbGljb3IuYXZnKQoKI251bGwgbW9kZWwKcGhvdG8ubnVsbCA8LSBsbShQaG90byB+IDEsIGRhdGEgPSBsaWNvci5hdmcpCgpBSUN0YWIocGhvdG8ubG0sIHBob3RvLmxtZXIsIHBob3RvLmxtZXIyLCBwaG90by5udWxsKQpgYGAKYHBob3RvLmxtZXIyYCB3aW5zLiAgVGhpcyBpcyB0aGUgc2FtZSBzcGVjaWZpY2F0aW9uIGFzIHRoZSBTUEFEIG1vZGVsLS0tYSByYW5kb20gZWZmZWN0IG9mIHBsYW50LCBidXQgbm90IHBsb3QuCgojIyBBTk9WQQpgYGB7cn0KQW5vdmEocGhvdG8ubG1lcjIpCnBob3RvLnBvc3Rob2MgPC0gZW1tZWFucyhwaG90by5sbWVyMiwgcGFpcndpc2UgfiBUcmVhdG1lbnQpCnBob3RvLnBvc3Rob2MkY29udHJhc3RzCnBob3RvLmxtZXIyLm5vaW50IDwtIGxtZXIoUGhvdG8gfiAtMSsgVHJlYXRtZW50ICsgKDF8dW5pcXVlLmlkKSwgZGF0YSA9IGxpY29yLmF2ZykgCgpmaXhlZihwaG90by5sbWVyMi5ub2ludCkKYGBgClNpZ25pZmljYW50IGVmZmVjdCBvZiBkcm91Z2h0IHRyZWF0bWVudC4gIDEwMCA9IGE7IDc1ID0gYjsgNTAgPSBiCgojIyMgUGxvdCByZXN1bHRzCmBgYHtyIHBob3Rvc3ludGhlc2lzIHBsb3R9CmxldHRlcnNfZGF0YSA8LSBsaWNvci5hdmcgJT4lCiAgZ3JvdXBfYnkoVHJlYXRtZW50KSAlPiUKICBzdW1tYXJpc2UobWF4LnAgPSBtYXgoUGhvdG8pLCBtYXguYyA9IG1heChDb25kKSkKCnBob3RvLmVycmJhciA8LSBwaG90by5wb3N0aG9jJGVtbWVhbnMgJT4lIHRpZHkoKQojIHBob3RvLmVycmJhcgoKI3N1bW1hcml6ZSBkYXRhIGZvciBwbG90cwpsaWNvci5wbG90ZGF0YSA8LSBsaWNvci5hdmcgJT4lIAogIGdyb3VwX2J5KFRyZWF0bWVudCwgdW5pcXVlLmlkKSAlPiUgCiAgc3VtbWFyaXplKFBob3RvID0gbWVhbihQaG90byksCiAgICAgICAgICAgIENvbmQgPSBtZWFuKENvbmQpKQoKI2ppdHRlciBwbG90IHdpdGggbWVhbiDCsSBDSQpwaG90by5iYXIgPC0gZ2dwbG90KGxpY29yLnBsb3RkYXRhLCBhZXMoeCA9IFRyZWF0bWVudCwgeSA9IFBob3RvKSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC41LCB3aWR0aCA9IDAuMikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBjb25mLmxvdywgeW1heCA9IGNvbmYuaGlnaCx4ID0gVHJlYXRtZW50LCB5ID0gZXN0aW1hdGUpLAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjIsCiAgICAgICAgICAgICAgICBkYXRhID0gcGhvdG8uZXJyYmFyKSArCiAgZ2VvbV9jb2woYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBlc3RpbWF0ZSksIGFscGhhID0gMC42LCBkYXRhID0gcGhvdG8uZXJyYmFyKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gbWF4LnAsIGxhYmVsID0gYygiYSIsICJiIiwgImIiKSksIHZqdXN0ID0gLTEsIGRhdGEgPSBsZXR0ZXJzX2RhdGEsIHNpemUgPSA0KSArCiAgZ2VvbV9sYWJlbChhZXMoeCA9IDMsIHkgPSAxMCwgbGFiZWwgPSAicCA8IDAuMDAxIiksIGRhdGEgPSBkYXRhLmZyYW1lKCkpICsKICB5bGltKDAsIDEwKSArCiAgeGxhYigiJSBBbWJpZW50IFJhaW5mYWxsIikgKwogIHlsYWIoVGVYKCJOZXQgQXNzaW1pbGF0aW9uIFJhdGUgJChcXG11JCBtb2wgJENPX3syfSQgJG1eey0yfSQgJHNeey0xfSkkIikpICsKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkKCnBob3RvLmJhcgpgYGAKCiMgU3RvbWF0YWwgY29uZHVjdGFuY2UKIyMgTW9kZWwgc2VsZWN0aW9uCmBgYHtyfQpjb25kLmxtZXIgPC0gbG1lcihsb2coQ29uZCkgfiBUcmVhdG1lbnQgKyAoMXxwbG90LmlkKSArICgxfHVuaXF1ZS5pZCksIGRhdGEgPSBsaWNvci5hdmcpIApsbWVyKGxvZyhDb25kKSB+IC0xICsgVHJlYXRtZW50ICsgKDF8cGxvdC5pZCkgKyAoMXx1bmlxdWUuaWQpLCBkYXRhID0gbGljb3IuYXZnKSAlPiUgZml4ZWYoKSAlPiUgZXhwKCkKdGlkeShjb25kLmxtZXIpCmBgYApNb2RlbCBkaWFnbm9zdGljcwpgYGB7ciBjb25kIGRpYWdub3N0aWNzfQpwbG90KGNvbmQubG1lcikKYXVnbWVudChjb25kLmxtZXIpICU+JSAKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IC5yZXNpZCkpICsKICBnZW9tX3FxKCkgKwogIHN0YXRfcXFsaW5lKCkrCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9idygpCmBgYApTb21lIHNsaWdodCBwYXR0ZXJuIGluIHJlc2lkdWFscyBwbG90LCBxcSBwbG90IGxvb2tzIGZpbmUuCgoKTW9kZWwgY29tcGV0aXRpb24KYGBge3IgY29uZCBjb21wZXRpdGlvbn0KI3JlbW92ZSBwbG90IGVmZmVjdApjb25kLmxtZXIyIDwtIGxtZXIobG9nKENvbmQpIH4gVHJlYXRtZW50ICsgKDF8dW5pcXVlLmlkKSwgZGF0YSA9IGxpY29yLmF2ZykgCmNvbmQubG1lcjMgPC0gbG1lcihsb2coQ29uZCkgfiAxICsgKDF8dW5pcXVlLmlkKSwgZGF0YSA9IGxpY29yLmF2ZykKCiMgZml4ZWQgZWZlY3RzIG9ubHkKY29uZC5sbSA8LSBsbShsb2coQ29uZCkgfiBUcmVhdG1lbnQsIGRhdGEgPSBsaWNvci5hdmcpCgojbnVsbCBtb2RlbApjb25kLm51bGwgPC0gbG0obG9nKENvbmQpIH4gMSwgZGF0YSA9IGxpY29yLmF2ZykKCkFJQ3RhYihjb25kLmxtLCBjb25kLmxtZXIsIGNvbmQubG1lcjIsIGNvbmQubnVsbCwgY29uZC5sbWVyMykKYGBgCmBjb25kLmxtZXJgIGlzIHRoZSBiZXN0IG1vZGVsLCB3aGljaCB0YWtlcyBwbG90IGFuZCBwbGFudCBpbnRvIGFjY291bnQgYXMgcmFuZG9tIGVmZmVjdHMgYW5kIGRyb3VnaHQgdHJlYXRtZW50IGFzIGEgZml4ZWQgZWZmZWN0LgoKIyMgQU5PVkEKYGBge3J9CkFub3ZhKGNvbmQubG1lcikKY29uZC5wb3N0aG9jIDwtIGVtbWVhbnMoY29uZC5sbWVyLCBwYWlyd2lzZSB+IFRyZWF0bWVudCkKY29uZC5wb3N0aG9jJGNvbnRyYXN0cwpgYGAKVHJlYXRtZW50IGlzIHNpZ25pZmljYW50LiAgQW5vdmEgb2YgYGNvbmQubG1lcjJgIHNob3dzIHRyZWF0bWVudCBhcyBNVUNIIG1vcmUgc2lnbmlmaWNhbnQuICBNdXN0IG1lYW4gdGhlcmUgaXMgYW4gaW50ZXJhY3Rpb24gYmV0d2VlbiBwbG90IGFuZCB0cmVhdG1lbnQuIFBvc3QtaG9jIHRlc3RzIHNob3cgbm8gc2lnbmlmaWNhbnQgcGFpcndpc2UgZGlmZmVyZW5jZXMuCgpUaGlzIGNvdWxkIGFsc28gYmUgZG9uZSBieSBtb2RlbGluZyB3aXRoIGEgbG9nLWxpbmsgcmF0aGVyIHRoYW4gbG9nIHRyYW5zZm9ybWluZy4gIEhvd2V2ZXIsIHRoZSBhZHZhbnRhZ2Ugb2YgbG9nIHRyYW5zZm9ybWluZyBpcyB0aGF0IGl0IHRha2VzIGNhcmUgb2YgdGhlIGxpbmVhcml0eSBhc3N1bXB0aW9uIGFuZCB0aGUgaGV0ZXJvc2tldGFzdGljaXR5IGFzc3VtcHRpb24gd2hpY2ggYXJlIGJvdGggdmlvbGF0ZWQgYnkgdGhlc2UgZGF0YSAoSSB0aGluaykuICBVc2luZyBhIGxvZy1saW5rIG9ubHkgdGFrZXMgY2FyZSBvZiB0aGUgbGluZWFydGl5IGFzc3VtcHRpb24gYmVjYXVzZSB0aGUgaXQgdHJhbnNmb3JtcyB0aGUgbWVhbnMgaW5zdGVhZCBvZiB0YWtpbmcgdGhlIG1lYW5zIG9mIHRyYW5zZm9ybWVkIGRhdGEuICBNb3JlIGluZm8gaGVyZTogaHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvNDc4NDAvbGluZWFyLW1vZGVsLXdpdGgtbG9nLXRyYW5zZm9ybWVkLXJlc3BvbnNlLXZzLWdlbmVyYWxpemVkLWxpbmVhci1tb2RlbC13aXRoLWxvZwpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPVRSVUV9CiMgYnVpbGQgbW9kZWxzCmNvbmQuZ2xtZXIgPC0gZ2xtZXIoQ29uZCB+IFRyZWF0bWVudCArICgxfHBsb3QuaWQpICsgKDF8dW5pcXVlLmlkKSwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJsb2ciKSwgZGF0YSA9IGxpY29yLmF2ZykKY29uZC5nbG1lcjIgPC0gZ2xtZXIoQ29uZCB+IFRyZWF0bWVudCArICgxfHVuaXF1ZS5pZCksIGZhbWlseSA9IGdhdXNzaWFuKGxpbmsgPSAibG9nIiksIGRhdGEgPSBsaWNvci5hdmcpCmNvbmQuZ2xtZXIzIDwtIGdsbWVyKENvbmQgfiBUcmVhdG1lbnQgKyAoMXxwbG90LmlkKSwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJsb2ciKSwgZGF0YSA9IGxpY29yLmF2ZykKY29uZC5nbG0gPC0gZ2xtKENvbmQgfiBUcmVhdG1lbnQsIGZhbWlseSA9IGdhdXNzaWFuKGxpbmsgPSAibG9nIiksIGRhdGEgPSBsaWNvci5hdmcpCmNvbmQuZ2xtZXI0IDwtIGdsbWVyKENvbmQgfiAxICsgKDF8cGxvdC5pZCkgKyAoMXx1bmlxdWUuaWQpLCBmYW1pbHkgPSBnYXVzc2lhbihsaW5rID0gImxvZyIpLCBkYXRhID0gbGljb3IuYXZnKQpjb25kLmdudWxsIDwtIGdsbShDb25kIH4gMSwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJsb2ciKSwgZGF0YSA9IGxpY29yLmF2ZykKCiNtb2RlbCBjb21wZXRpdGlvbgpBSUN0YWIoY29uZC5sbWVyLCBjb25kLmdsbWVyLCBjb25kLmdsbWVyMiwgY29uZC5nbG1lcjMsIGNvbmQuZ2xtLCBjb25kLmdsbWVyNCwgY29uZC5nbnVsbCkKCiNwbG90IGRpYWdub3N0aWNzCkFub3ZhKGNvbmQuZ2xtZXIyKQpwbG90KGNvbmQuZ2xtZXIyKQphdWdtZW50KGNvbmQuZ2xtZXIyKSAlPiUgCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSAucmVzaWQpKSArCiAgZ2VvbV9xcSgpICsKICBzdGF0X3FxbGluZSgpKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKQojcmVtYWtlIGJhciBwbG90CnRlc3QgPC0gZW1tZWFucyhjb25kLmdsbWVyMiwgcGFpcndpc2V+VHJlYXRtZW50KQp0ZXN0MiA8LSBjb25maW50KHRlc3QpJGVtbWVhbnMKdGVzdDIKZ2dwbG90KGxpY29yLmF2ZywgYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBDb25kKSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC41LCB3aWR0aCA9IDAuMikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBleHAoYXN5bXAuTENMKSwgeW1heCA9IGV4cChhc3ltcC5VQ0wpLHggPSBUcmVhdG1lbnQsIHkgPSBleHAoZW1tZWFuKSksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMiwKICAgICAgICAgICAgICAgIGRhdGEgPSB0ZXN0MikgKwogIGdlb21fY29sKGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gZXhwKGVtbWVhbikpLCBhbHBoYSA9IDAuNiwgZGF0YSA9IHRlc3QyKSArCiAgZ2VvbV9sYWJlbChhZXMoeCA9IDMsIHkgPSAwLjE1LCBsYWJlbCA9IHBhc3RlMCgicCA9ICIsIEFub3ZhKGNvbmQuZ2xtZXIyKSRgUHIoPkNoaXNxKWAgJT4lIHJvdW5kKDMpKSksIGRhdGEgPSBkYXRhLmZyYW1lKCkpICsKICB5bGltKDAsIDAuMTUpICsKICB4bGFiKCIlIEFtYmllbnQgUmFpbmZhbGwiKSArCiAgeWxhYihUZVgoIlN0b21hdGFsIGNvbmR1Y3RhbmNlICQoJG1vbCAkSF97Mn1PJCAkbV57LTJ9JCAkc157LTF9KSQiKSkgKwogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKQpgYGAKUmVzdWx0cyBpbiB0aWdodGVyIGVycm9yIGJhcnMgYW5kIG5vbi1zaWduaWZpY2FudCBBTk9WQSAoaW4gZmFjdCwgdGhlIGJlc3QgbW9kZWwgaXMgYSBudWxsIG1vZGVsIHdpdGggb25seSByYW5kb20gZWZmZWN0cykuICBIb3dldmVyLCBkaWFnbm9zdGljcyBvbiByZXNpZHVhbHMgbG9vayBtdWNoIHdvcnNlLgoKIyMgRmlndXJlCgpgYGB7ciBzdG9tYXRhbCBjb25kdWN0YW5jZSBwbG90fQpjb25kLmVycmJhciA8LSBjb25kLnBvc3Rob2MkZW1tZWFucyAlPiUgdGlkeSgpCgojaml0dGVyIHBsb3Qgd2l0aCBtZWFuIMKxIENJCmNvbmQuYmFyIDwtIGdncGxvdChsaWNvci5wbG90ZGF0YSwgYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBDb25kKSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC41LCB3aWR0aCA9IDAuMiwgaGVpZ2h0ID0gMCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBleHAoY29uZi5sb3cpLCB5bWF4ID0gZXhwKGNvbmYuaGlnaCkseCA9IFRyZWF0bWVudCwgeSA9IGV4cChlc3RpbWF0ZSkpLAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjIsCiAgICAgICAgICAgICAgICBkYXRhID0gY29uZC5lcnJiYXIpICsKICBnZW9tX2NvbChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IGV4cChlc3RpbWF0ZSkpLCBhbHBoYSA9IDAuNixkYXRhID0gY29uZC5lcnJiYXIpICsKICBnZW9tX3RleHQoYWVzKHkgPSBtYXguYywgbGFiZWwgPSBjKCJhIiwgImEiLCAiYSIpKSwgdmp1c3QgPSAtMSwgZGF0YSA9IGxldHRlcnNfZGF0YSkgKwogIGdlb21fbGFiZWwoYWVzKHggPSAzLCB5ID0gMC4xNSwgbGFiZWwgPSBwYXN0ZTAoInAgPSAiLCBBbm92YShjb25kLmxtZXIpJGBQcig+Q2hpc3EpYCAlPiUgcm91bmQoMykpKSwgZGF0YSA9IGRhdGEuZnJhbWUoKSkgKwogIHlsaW0oMCwgMC4xNSkgKwogIHhsYWIoIiUgQW1iaWVudCBSYWluZmFsbCIpICsKICB5bGFiKFRlWCgiU3RvbWF0YWwgY29uZHVjdGFuY2UgJCgkbW9sICRIX3syfU8kICRtXnstMn0kICRzXnstMX0pJCIpKSArCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCmBgYAojIEV4cG9ydCBmaWd1cmUKYGBge3IgZXhwb3J0IGZpZ3VyZX0KZmlnMXBsb3RzIDwtIHBsb3RfZ3JpZChwaG90by5iYXIsIGNvbmQuYmFyLCBzcGFkLmJhciwKICAgICAgICAgIG5jb2wgPSAyLAogICAgICAgICAgbnJvdyA9IDIsCiAgICAgICAgICBhbGlnbiA9ICJ2IiwKICAgICAgICAgIGF4aXMgPSAibCIsCiAgICAgICAgICBsYWJlbHMgPSAiQVVUTyIsCiAgICAgICAgICBsYWJlbF94ID0gMCkKCnNhdmVfcGxvdChoZXJlKCJmaWdzIiwgInBob3RvcGxvdHMucG5nIiksIGZpZzFwbG90cywgbmNvbCA9IDIsIG5yb3cgPSAyLCBiYXNlX3dpZHRoID0gMykKYGBg