1 Cuckoo dataset

The common cuckoo does not build its own nest: it prefers to lay its eggs in another birds’ nest. It is known, since 1892, that the type of cuckoo bird eggs are different between different locations. In a study from 1940, it was shown that cuckoos return to the same nesting area each year, and that they always pick the same bird species to be a “foster parent” for their eggs.

Over the years, this has lead to the development of geographically determined subspecies of cuckoos. These subspecies have evolved in such a way that their eggs look as similar as possible as those of their foster parents.

The cuckoo dataset contains information on 120 Cuckoo eggs, obtained from randomly selected “foster” nests. For these eggs, researchers have measured the length (in mm) and established the type (species) of foster parent. The type column is coded as follows:

  • type=1: Meadow pipit
  • type=2: Tree pipit
  • type=3: Dunnock
  • type=4: European robin
  • type=5: White wagtail
  • type=6: Eurasian wren

2 Goal

The researchers want totest if the type of foster parent has an effect on the average length of the cuckoo eggs.

In theory, they want to study this for all six species. Previously, we looked at a single pairwise comparison between the European robin and the Eurasian wren with a t-test. Here, we will analyse all types simultaneously with ANOVA.

Load the required libraries

library(tidyverse)
library(multcomp)

2.1 Import the data

Cuckoo <- read_tsv("https://raw.githubusercontent.com/statOmics/PSLSData/main/Cuckoo.txt")
head(Cuckoo)

3 Data tidying

It seems that the tpye column is a double rather than a factor. Let’s fix this:

Cuckoo <- Cuckoo %>%
  mutate(type = as.factor(type)) %>%
  mutate(type = recode(type,
    "1" = "meadow",
    "2" = "tree",
    "3" = "dunnock",
    "4" = "robin",
    "5" = "wagtail",
    "6" = "wren"
  ))

4 Data exploration

How many birds do we have for each type?

Cuckoo %>%
  count(type)

Visualize the data

Cuckoo %>%
  ggplot(aes(x = type, y = length, fill = type)) +
  theme_bw() +
  scale_fill_brewer(palette = "RdGy") +
  geom_boxplot() +
  geom_jitter(width = 0.2) +
  ggtitle("Boxplot of the length of eggs per type") +
  ylab("length (mm)") +
  stat_summary(
    fun = mean, geom = "point",
    shape = 5, size = 3, color = "black"
  )

5 ANOVA

To study if the observed differences in average egg length between the different foster bird types are significant, we can perform an ANOVA.

5.1 The model

We will fit the following linear model:

\[ E(Y_i) = \beta_0 + \beta_1 X_{i1} + \beta_2 X_{i2} + \beta_3 X_{i3} + \beta_4 X_{i4} + \beta_5 X_{i5} \]

where \(Y_i\) is the length of egg \(i\) and the coefficients \(beta_j\) corresond to the additional expected length of a cuckoo egg fostered by bird type \(j + 1\). By convention, the intercept is called \(\beta_0\) and it corresponds to the reference bird type, in this case bird type 1 (the Meadow pipit). The variables \(X_ij\) are dummy variables which take on the value 1 if egg \(i\) was fostered by bird type \(j + 1\) and are 0 otherwise. Note that in this case, eggs are always fostered by a single bird type, so only one of the X’s will be equal to 1.

For example, if egg \(i\) was fostered by the meadow pipit (type 1), all the \(X_{i1}, \dots, X_{i5}\) would be zero and we are left with:

\[E(Y_i | X_{i1} = \dots = X_{i5} = 0) = \beta_0\]

i.e. the intercept. If egg \(i\) was fostered by the European robin (type 4), we would have:

\[E(Y_i | X_{i3} = 1) = \beta_0 + \beta_3\]

So \(\beta_3\) can be interpreted as the change in average length of cuckoo eggs between the reference bird type (the meadow pipit) and the European robin. The coefficients can be negative or positive, so the change can be an increase or a decrease.

To further aid with intepretation, we can visualize the model design using the ExploreModelMatrix package:

ExploreModelMatrix::VisualizeDesign(Cuckoo, ~type)$plotlist[[1]]

5.2 Formulate null and alternative hypothesis

The null hypothesis of ANOVA states that:

\(H0\): The mean egg length is equal between the different bird types.

In terms of the linear model:

\[ H_0:\ \beta_1 = \beta_2 = \beta_3 = \beta_4 = \beta_5 = 0 \]

The alternative hypothesis of ANOVA states that: \(HA\): The mean egg length for at least one bird type is different from the mean egg length in at least one other bird type.

\[ H_A:\ \beta_i \neq \beta_j \text{ for at least one } i \neq j \]

5.3 Parameter estimation

mod <- lm(length ~ type, Cuckoo)
summary(mod)
## 
## Call:
## lm(formula = length ~ type, data = Cuckoo)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.8100 -0.7212  0.1333  0.7775  3.3800 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  22.5000     0.1963 114.611  < 2e-16 ***
## typetree      0.5900     0.3926   1.503 0.135687    
## typedunnock   0.6214     0.4030   1.542 0.125854    
## typerobin     0.0750     0.3833   0.196 0.845225    
## typewagtail   0.4033     0.3926   1.027 0.306475    
## typewren     -1.3700     0.3926  -3.489 0.000689 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.317 on 114 degrees of freedom
## Multiple R-squared:  0.1723, Adjusted R-squared:  0.136 
## F-statistic: 4.747 on 5 and 114 DF,  p-value: 0.0005621

The output of the model suggests that there are indeed differences in the average length of cuckoo eggs between different foster parents. Note, however, that in the standard output of lm(), the p-values are not adjusted for multiple testing (a topic which we will touch upon later). In addition, this model only shows the differences between foster types 2-6 and the reference type (1), represented by the intercept.

The p-value of the F-test, given at the bottom of the summary, corresponds to a one-way ANOVA where the full model is compared to a reduced model containing only the intercept. Thus, it is testing the omnibus null hypothesis that all slope coefficients (\(\beta_1\) - \(\beta_5\)) are equal to 0.

5.4 Check assumptions

Before we may proceed with the analysis, we must make sure that all assumptions for ANOVA are met. ANOVA has three assumptions:

  1. The observations are independent of each other (in all groups)
  2. The data (length) must be normally distributed (in all groups)
  3. The variability within all groups is similar

The first assumption is met, as we may assume that there are no specific patterns of correlation between the randomly selected nests.

To check the normality assumption, we will use QQ plots.

plot(mod, which = 2)

Cuckoo %>%
  ggplot(aes(sample = length)) +
  geom_qq() +
  geom_qq_line() +
  facet_grid(~type)

There seem to be no clear deviations from normality.

The third assumption of equal variances seems to be met based on the visualization with the boxplots (see above).

As such, we may proceed with the ANOVA analysis.

5.4.1 Simulate to train your skills in assessing assumptions

set.seed(1031)
sigma <- mod %>% sigma()
dataHlp <- Cuckoo

simModels <- list()
plotList <- list()
plotListQQ1 <- list()

par(mfrow = c(3, 3))
for (i in 1:9)
{
  nobs <- Cuckoo %>% nrow()
  dataHlp$ySim <- mod$fit + rnorm(nobs, sd = sigma)
  simModels[[i]] <- lm(ySim ~ type, dataHlp)
  plot(simModels[[i]], which = 2)
  plotList[[i]] <- dataHlp %>%
    ggplot(aes(type, ySim)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter()
  plotListQQ1[[i]] <- dataHlp %>%
    filter(type == "meadow") %>%
    ggplot(aes(sample = ySim)) +
    geom_qq() +
    geom_qq_line() +
    xlab("QQ for meadow")
}

do.call(gridExtra::grid.arrange, plotList)

do.call(gridExtra::grid.arrange, plotListQQ1)

The most deviating QQ-plot of the residuals in the nine simulation runs:

par(mfrow = c(1, 1))
plot(simModels[[8]], which = 2)

5.5 ANOVA model

We perform the ANOVA test using the results of the linear regression model. Essentially, we test the following null hypothesis:

\[ H_0:\ \beta_1 = \beta_2 = \beta_3 = \beta_4 = \beta_5 = 0 \]

with the alternative being that at least one of the parameters is different from 0.

anova(mod)

The p-value of the ANOVA analysis is extremely significant (p-value < 0.001), so we reject the null hypothesis that the mean egg length is equal between the different bird types. We can say that the mean egg length is significantly different between at least two bird types on the 5% significance level.

Based on this analysis, we do not yet know between which particular bird types there is a significant difference. To study this, we will perform a Tukey post-hoc analysis.

5.6 Post-hoc analysis

We will perform a post-hoc analysis, to look at the difference in egg length between each pairwise comparison of bird types. Importantly, with this strategy, the p-values will be correctly adjusted for multiple testing.

The null hypothesis for each pairwise test is that there is no difference in the mean egg length between both bird types.

The alternative hypothesis for each pairwise test states that there is indeed a difference in the mean egg length between both bird types.

We will also calculate the confidence interval on the mean differences.

The post-hoc analysis is carried out using the glht() (“General Linear Hypotheses”) function from the multcomp package. We apply this to our linear model object mod and specify in the linfct= argument that we want to perform multiple comparisons (mcp), using Tukey’s method. We store the output of glht() and then display the results using the summary() function and calculating confidence intervals.

mcp <- glht(mod, linfct = mcp(type = "Tukey"))
summary(mcp)
## 
##   Simultaneous Tests for General Linear Hypotheses
## 
## Multiple Comparisons of Means: Tukey Contrasts
## 
## 
## Fit: lm(formula = length ~ type, data = Cuckoo)
## 
## Linear Hypotheses:
##                        Estimate Std. Error t value Pr(>|t|)   
## tree - meadow == 0      0.59000    0.39263   1.503  0.65686   
## dunnock - meadow == 0   0.62143    0.40301   1.542  0.63147   
## robin - meadow == 0     0.07500    0.38332   0.196  0.99996   
## wagtail - meadow == 0   0.40333    0.39263   1.027  0.90518   
## wren - meadow == 0     -1.37000    0.39263  -3.489  0.00847 **
## dunnock - tree == 0     0.03143    0.48939   0.064  1.00000   
## robin - tree == 0      -0.51500    0.47330  -1.088  0.88202   
## wagtail - tree == 0    -0.18667    0.48087  -0.388  0.99878   
## wren - tree == 0       -1.96000    0.48087  -4.076  0.00114 **
## robin - dunnock == 0   -0.54643    0.48195  -1.134  0.86268   
## wagtail - dunnock == 0 -0.21810    0.48939  -0.446  0.99764   
## wren - dunnock == 0    -1.99143    0.48939  -4.069  0.00115 **
## wagtail - robin == 0    0.32833    0.47330   0.694  0.98170   
## wren - robin == 0      -1.44500    0.47330  -3.053  0.03198 * 
## wren - wagtail == 0    -1.77333    0.48087  -3.688  0.00433 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## (Adjusted p values reported -- single-step method)
confint(mcp)
## 
##   Simultaneous Confidence Intervals
## 
## Multiple Comparisons of Means: Tukey Contrasts
## 
## 
## Fit: lm(formula = length ~ type, data = Cuckoo)
## 
## Quantile = 2.8889
## 95% family-wise confidence level
##  
## 
## Linear Hypotheses:
##                        Estimate lwr      upr     
## tree - meadow == 0      0.59000 -0.54429  1.72429
## dunnock - meadow == 0   0.62143 -0.54285  1.78571
## robin - meadow == 0     0.07500 -1.03239  1.18239
## wagtail - meadow == 0   0.40333 -0.73096  1.53763
## wren - meadow == 0     -1.37000 -2.50429 -0.23571
## dunnock - tree == 0     0.03143 -1.38238  1.44524
## robin - tree == 0      -0.51500 -1.88234  0.85234
## wagtail - tree == 0    -0.18667 -1.57589  1.20255
## wren - tree == 0       -1.96000 -3.34922 -0.57078
## robin - dunnock == 0   -0.54643 -1.93875  0.84589
## wagtail - dunnock == 0 -0.21810 -1.63190  1.19571
## wren - dunnock == 0    -1.99143 -3.40524 -0.57762
## wagtail - robin == 0    0.32833 -1.03901  1.69567
## wren - robin == 0      -1.44500 -2.81234 -0.07766
## wren - wagtail == 0    -1.77333 -3.16255 -0.38411

We can also visualize the confidence interval by calling plot() on the mcp object:

plot(mcp)

5.7 Conclusion

The association between the mean length of a cuckoo’s egg and the foster bird species is extremely significant (p << 0.001).

The mean length of cuckoo’s eggs in nests of the Eurasian wren are smaller as compared to those from all other bird species in the study:

  • the meadow pipit (adjusted p-value = 0.009, mean difference = -1.4mm, 95% CI [-2.5, -0.2])
  • the tree pipit (adjusted p-value = 0.001, mean difference = -2mm, 95% CI [-3.3, -0.6])
  • the dunnock (adjusted p-value = 0.001, mean difference = -2mm, 95% CI [-3.4, -0.6])
  • the European robin (adjusted p-value = 0.03, mean difference = -1.4mm, 95% CI [-2.8, -0.1])
  • the white wagtail (adjusted p-value = 0.004, mean difference = -1.8mm, 95% CI [-3.2, -0.4])

There is no evidence taht the mean length of the cuckoo bird’s eggs for all other pairwise comparisons between foster bird species are significantly different at the 5% level.

LS0tCnRpdGxlOiAiRXhlcmNpc2UgNy4yOiBBTk9WQSBvbiB0aGUgY3Vja29vIGRhdGFzZXQgLSBzb2x1dGlvbiIKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQsIEplcm9lbiBHaWxpcyBhbmQgTWlsYW4gTWFsZmFpdCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKLS0tCgojIEN1Y2tvbyBkYXRhc2V0CgpUaGUgY29tbW9uIGN1Y2tvbyBkb2VzIG5vdCBidWlsZCBpdHMgb3duIG5lc3Q6IGl0IHByZWZlcnMKdG8gbGF5IGl0cyBlZ2dzIGluIGFub3RoZXIgYmlyZHMnIG5lc3QuIEl0IGlzIGtub3duLCBzaW5jZSAxODkyLAp0aGF0IHRoZSB0eXBlIG9mIGN1Y2tvbyBiaXJkIGVnZ3MgYXJlIGRpZmZlcmVudCBiZXR3ZWVuIGRpZmZlcmVudApsb2NhdGlvbnMuIEluIGEgc3R1ZHkgZnJvbSAxOTQwLCBpdCB3YXMgc2hvd24gdGhhdCBjdWNrb29zIHJldHVybgp0byB0aGUgc2FtZSBuZXN0aW5nIGFyZWEgZWFjaCB5ZWFyLCBhbmQgdGhhdCB0aGV5IGFsd2F5cyBwaWNrCnRoZSBzYW1lIGJpcmQgc3BlY2llcyB0byBiZSBhICJmb3N0ZXIgcGFyZW50IiBmb3IgdGhlaXIgZWdncy4KCk92ZXIgdGhlIHllYXJzLCB0aGlzIGhhcyBsZWFkIHRvIHRoZSBkZXZlbG9wbWVudCBvZiBnZW9ncmFwaGljYWxseQpkZXRlcm1pbmVkIHN1YnNwZWNpZXMgb2YgY3Vja29vcy4gVGhlc2Ugc3Vic3BlY2llcyBoYXZlIGV2b2x2ZWQgaW4Kc3VjaCBhIHdheSB0aGF0IHRoZWlyIGVnZ3MgbG9vayBhcyBzaW1pbGFyIGFzIHBvc3NpYmxlIGFzIHRob3NlCm9mIHRoZWlyIGZvc3RlciBwYXJlbnRzLgoKVGhlIGN1Y2tvbyBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIDEyMCBDdWNrb28gZWdncywKb2J0YWluZWQgZnJvbSByYW5kb21seSBzZWxlY3RlZCAiZm9zdGVyIiBuZXN0cy4KRm9yIHRoZXNlIGVnZ3MsIHJlc2VhcmNoZXJzIGhhdmUgbWVhc3VyZWQgdGhlIGBsZW5ndGhgIChpbiBtbSkKYW5kIGVzdGFibGlzaGVkIHRoZSBgdHlwZWAgKHNwZWNpZXMpIG9mIGZvc3RlciBwYXJlbnQuClRoZSB0eXBlIGNvbHVtbiBpcyBjb2RlZCBhcyBmb2xsb3dzOgoKLSBgdHlwZT0xYDogTWVhZG93IHBpcGl0Ci0gYHR5cGU9MmA6IFRyZWUgcGlwaXQKLSBgdHlwZT0zYDogRHVubm9jawotIGB0eXBlPTRgOiBFdXJvcGVhbiByb2JpbgotIGB0eXBlPTVgOiBXaGl0ZSB3YWd0YWlsCi0gYHR5cGU9NmA6IEV1cmFzaWFuIHdyZW4KCiMgR29hbAoKVGhlIHJlc2VhcmNoZXJzIHdhbnQgdG90ZXN0IGlmIHRoZSB0eXBlIG9mIGZvc3RlciBwYXJlbnQKaGFzIGFuIGVmZmVjdCBvbiB0aGUgYXZlcmFnZSBsZW5ndGggb2YgdGhlIGN1Y2tvbyBlZ2dzLgoKSW4gdGhlb3J5LCB0aGV5IHdhbnQgdG8gc3R1ZHkgdGhpcyBmb3IgYWxsIHNpeCBzcGVjaWVzLgpQcmV2aW91c2x5LCB3ZSBsb29rZWQgYXQgYSBzaW5nbGUgcGFpcndpc2UgY29tcGFyaXNvbgpiZXR3ZWVuIHRoZSBFdXJvcGVhbiByb2JpbiBhbmQgdGhlIEV1cmFzaWFuIHdyZW4gd2l0aCBhCnQtdGVzdC4gSGVyZSwgd2Ugd2lsbCBhbmFseXNlIGFsbCB0eXBlcyBzaW11bHRhbmVvdXNseQp3aXRoIEFOT1ZBLgoKTG9hZCB0aGUgcmVxdWlyZWQgbGlicmFyaWVzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobXVsdGNvbXApCmBgYAoKIyMgSW1wb3J0IHRoZSBkYXRhCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KQ3Vja29vIDwtIHJlYWRfdHN2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1BTTFNEYXRhL21haW4vQ3Vja29vLnR4dCIpCmhlYWQoQ3Vja29vKQpgYGAKCiMgRGF0YSB0aWR5aW5nCgpJdCBzZWVtcyB0aGF0IHRoZSBgdHB5ZWAgY29sdW1uIGlzIGEgYGRvdWJsZWAgcmF0aGVyIHRoYW4gYSBgZmFjdG9yYC4KTGV0J3MgZml4IHRoaXM6CgpgYGB7cn0KQ3Vja29vIDwtIEN1Y2tvbyAlPiUKICBtdXRhdGUodHlwZSA9IGFzLmZhY3Rvcih0eXBlKSkgJT4lCiAgbXV0YXRlKHR5cGUgPSByZWNvZGUodHlwZSwKICAgICIxIiA9ICJtZWFkb3ciLAogICAgIjIiID0gInRyZWUiLAogICAgIjMiID0gImR1bm5vY2siLAogICAgIjQiID0gInJvYmluIiwKICAgICI1IiA9ICJ3YWd0YWlsIiwKICAgICI2IiA9ICJ3cmVuIgogICkpCmBgYAoKCiMgRGF0YSBleHBsb3JhdGlvbgoKSG93IG1hbnkgYmlyZHMgZG8gd2UgaGF2ZSBmb3IgZWFjaCB0eXBlPwoKYGBge3J9CkN1Y2tvbyAlPiUKICBjb3VudCh0eXBlKQpgYGAKClZpc3VhbGl6ZSB0aGUgZGF0YQoKYGBge3J9CkN1Y2tvbyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0eXBlLCB5ID0gbGVuZ3RoLCBmaWxsID0gdHlwZSkpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkR3kiKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiB0aGUgbGVuZ3RoIG9mIGVnZ3MgcGVyIHR5cGUiKSArCiAgeWxhYigibGVuZ3RoIChtbSkiKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsCiAgICBzaGFwZSA9IDUsIHNpemUgPSAzLCBjb2xvciA9ICJibGFjayIKICApCmBgYAoKIyBBTk9WQQoKVG8gc3R1ZHkgaWYgdGhlIG9ic2VydmVkIGRpZmZlcmVuY2VzIGluIGF2ZXJhZ2UgZWdnIGxlbmd0aApiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgZm9zdGVyIGJpcmQgdHlwZXMgYXJlIHNpZ25pZmljYW50LCB3ZSBjYW4gcGVyZm9ybQphbiBBTk9WQS4KCiMjIFRoZSBtb2RlbAoKV2Ugd2lsbCBmaXQgdGhlIGZvbGxvd2luZyBsaW5lYXIgbW9kZWw6CgokJApFKFlfaSkgPSBcYmV0YV8wICsgXGJldGFfMSBYX3tpMX0gKyBcYmV0YV8yIFhfe2kyfSArCiAgXGJldGFfMyBYX3tpM30gKyBcYmV0YV80IFhfe2k0fSArIFxiZXRhXzUgWF97aTV9CiQkCgp3aGVyZSAkWV9pJCBpcyB0aGUgbGVuZ3RoIG9mIGVnZyAkaSQgYW5kIHRoZSBjb2VmZmljaWVudHMgJGJldGFfaiQgY29ycmVzb25kIHRvCnRoZSAqKmFkZGl0aW9uYWwgZXhwZWN0ZWQqKiBsZW5ndGggb2YgYSBjdWNrb28gZWdnIGZvc3RlcmVkIGJ5IGJpcmQgdHlwZSAkaiArIDEkLiBCeQpjb252ZW50aW9uLCB0aGUgaW50ZXJjZXB0IGlzIGNhbGxlZCAkXGJldGFfMCQgYW5kIGl0IGNvcnJlc3BvbmRzIHRvIHRoZQpyZWZlcmVuY2UgYmlyZCB0eXBlLCBpbiB0aGlzIGNhc2UgYmlyZCB0eXBlIDEgKHRoZSBNZWFkb3cgcGlwaXQpLiBUaGUgdmFyaWFibGVzCiRYX2lqJCBhcmUgKipkdW1teSB2YXJpYWJsZXMqKiB3aGljaCB0YWtlIG9uIHRoZSB2YWx1ZSAxIGlmIGVnZyAkaSQgd2FzIGZvc3RlcmVkCmJ5IGJpcmQgdHlwZSAkaiArIDEkIGFuZCBhcmUgMCBvdGhlcndpc2UuIE5vdGUgdGhhdCBpbiB0aGlzIGNhc2UsIGVnZ3MgYXJlCmFsd2F5cyBmb3N0ZXJlZCBieSBhIHNpbmdsZSBiaXJkIHR5cGUsIHNvIG9ubHkgb25lIG9mIHRoZSBYJ3Mgd2lsbCBiZSBlcXVhbCB0bwoxLgoKRm9yIGV4YW1wbGUsIGlmIGVnZyAkaSQgd2FzIGZvc3RlcmVkIGJ5IHRoZSBtZWFkb3cgcGlwaXQgKHR5cGUgMSksIGFsbCB0aGUgJFhfe2kxfSwgXGRvdHMsIFhfe2k1fSQgd291bGQgYmUgemVybyBhbmQgd2UgYXJlIGxlZnQgd2l0aDoKCiQkRShZX2kgfCBYX3tpMX0gPSBcZG90cyA9IFhfe2k1fSA9IDApID0gXGJldGFfMCQkCgppLmUuIHRoZSBpbnRlcmNlcHQuIElmIGVnZyAkaSQgd2FzIGZvc3RlcmVkIGJ5IHRoZSBFdXJvcGVhbiByb2JpbiAodHlwZSA0KSwgd2Ugd291bGQgaGF2ZToKCiQkRShZX2kgfCBYX3tpM30gPSAxKSA9IFxiZXRhXzAgKyBcYmV0YV8zJCQKClNvICRcYmV0YV8zJCBjYW4gYmUgaW50ZXJwcmV0ZWQgYXMgdGhlICpjaGFuZ2UqIGluIGF2ZXJhZ2UgbGVuZ3RoIG9mIGN1Y2tvbyBlZ2dzCmJldHdlZW4gdGhlIHJlZmVyZW5jZSBiaXJkIHR5cGUgKHRoZSBtZWFkb3cgcGlwaXQpIGFuZCB0aGUgRXVyb3BlYW4gcm9iaW4uIFRoZQpjb2VmZmljaWVudHMgY2FuIGJlIG5lZ2F0aXZlIG9yIHBvc2l0aXZlLCBzbyB0aGUgY2hhbmdlIGNhbiBiZSBhbiBpbmNyZWFzZSBvciBhCmRlY3JlYXNlLgoKVG8gZnVydGhlciBhaWQgd2l0aCBpbnRlcHJldGF0aW9uLCB3ZSBjYW4gdmlzdWFsaXplIHRoZSBtb2RlbCBkZXNpZ24gdXNpbmcgdGhlICoqRXhwbG9yZU1vZGVsTWF0cml4KiogcGFja2FnZToKCmBgYHtyfQpFeHBsb3JlTW9kZWxNYXRyaXg6OlZpc3VhbGl6ZURlc2lnbihDdWNrb28sIH50eXBlKSRwbG90bGlzdFtbMV1dCmBgYAoKCiMjIEZvcm11bGF0ZSBudWxsIGFuZCBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzCgpUaGUgbnVsbCBoeXBvdGhlc2lzIG9mIEFOT1ZBIHN0YXRlcyB0aGF0OgoKJEgwJDogVGhlIG1lYW4gZWdnIGxlbmd0aCBpcyBlcXVhbCBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgYmlyZCB0eXBlcy4KCkluIHRlcm1zIG9mIHRoZSBsaW5lYXIgbW9kZWw6CgokJApIXzA6XCBcYmV0YV8xID0gXGJldGFfMiA9IFxiZXRhXzMgPSBcYmV0YV80ID0gXGJldGFfNSA9IDAKJCQKClRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIG9mIEFOT1ZBIHN0YXRlcyB0aGF0OgokSEEkOiBUaGUgbWVhbiBlZ2cgbGVuZ3RoIGZvciBhdCBsZWFzdCBvbmUgYmlyZCB0eXBlIGlzIGRpZmZlcmVudApmcm9tIHRoZSBtZWFuIGVnZyBsZW5ndGggaW4gYXQgbGVhc3Qgb25lIG90aGVyIGJpcmQgdHlwZS4KCiQkCkhfQTpcIFxiZXRhX2kgXG5lcSBcYmV0YV9qIFx0ZXh0eyBmb3IgYXQgbGVhc3Qgb25lIH0gaSBcbmVxIGoKJCQKCiMjIFBhcmFtZXRlciBlc3RpbWF0aW9uCgpgYGB7cn0KbW9kIDwtIGxtKGxlbmd0aCB+IHR5cGUsIEN1Y2tvbykKc3VtbWFyeShtb2QpCmBgYAoKVGhlIG91dHB1dCBvZiB0aGUgbW9kZWwgc3VnZ2VzdHMgdGhhdCB0aGVyZSBhcmUgaW5kZWVkIGRpZmZlcmVuY2VzIGluIHRoZQoqYXZlcmFnZSogbGVuZ3RoIG9mIGN1Y2tvbyBlZ2dzIGJldHdlZW4gZGlmZmVyZW50IGZvc3RlciBwYXJlbnRzLiBOb3RlLCBob3dldmVyLAp0aGF0IGluIHRoZSBzdGFuZGFyZCBvdXRwdXQgb2YgYGxtKClgLCB0aGUgcC12YWx1ZXMgYXJlIG5vdCBhZGp1c3RlZCBmb3IKbXVsdGlwbGUgdGVzdGluZyAoYSB0b3BpYyB3aGljaCB3ZSB3aWxsIHRvdWNoIHVwb24gbGF0ZXIpLiBJbiBhZGRpdGlvbiwgdGhpcwptb2RlbCBvbmx5IHNob3dzIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGZvc3RlciB0eXBlcyAyLTYgYW5kIHRoZSAqKnJlZmVyZW5jZQp0eXBlKiogKDEpLCByZXByZXNlbnRlZCBieSB0aGUgaW50ZXJjZXB0LgoKVGhlIHAtdmFsdWUgb2YgdGhlIEYtdGVzdCwgZ2l2ZW4gYXQgdGhlIGJvdHRvbSBvZiB0aGUgc3VtbWFyeSwgY29ycmVzcG9uZHMgdG8gYQoqKm9uZS13YXkgQU5PVkEqKiB3aGVyZSB0aGUgZnVsbCBtb2RlbCBpcyBjb21wYXJlZCB0byBhIHJlZHVjZWQgbW9kZWwgY29udGFpbmluZwpvbmx5IHRoZSBpbnRlcmNlcHQuIFRodXMsIGl0IGlzIHRlc3RpbmcgdGhlICpvbW5pYnVzKiBudWxsIGh5cG90aGVzaXMgdGhhdCBhbGwKc2xvcGUgY29lZmZpY2llbnRzICgkXGJldGFfMSQgLSAkXGJldGFfNSQpIGFyZSBlcXVhbCB0byAwLgoKIyMgQ2hlY2sgYXNzdW1wdGlvbnMKCkJlZm9yZSB3ZSBtYXkgcHJvY2VlZCB3aXRoIHRoZSBhbmFseXNpcywgd2UgbXVzdCBtYWtlIHN1cmUgdGhhdCBhbGwKYXNzdW1wdGlvbnMgZm9yIEFOT1ZBIGFyZSBtZXQuIEFOT1ZBIGhhcyB0aHJlZSBhc3N1bXB0aW9uczoKCjEuIFRoZSBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIgKGluIGFsbCBncm91cHMpCjIuIFRoZSBkYXRhIChsZW5ndGgpIG11c3QgYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgKGluIGFsbCBncm91cHMpCjMuIFRoZSB2YXJpYWJpbGl0eSB3aXRoaW4gYWxsIGdyb3VwcyBpcyBzaW1pbGFyCgpUaGUgZmlyc3QgYXNzdW1wdGlvbiBpcyBtZXQsIGFzIHdlIG1heSBhc3N1bWUgdGhhdCB0aGVyZSBhcmUgbm8Kc3BlY2lmaWMgcGF0dGVybnMgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmFuZG9tbHkgc2VsZWN0ZWQgbmVzdHMuCgpUbyBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24sIHdlIHdpbGwgdXNlIFFRIHBsb3RzLgoKYGBge3J9CnBsb3QobW9kLCB3aGljaCA9IDIpCmBgYAoKYGBge3J9CkN1Y2tvbyAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IGxlbmd0aCkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpICsKICBmYWNldF9ncmlkKH50eXBlKQpgYGAKClRoZXJlIHNlZW0gdG8gYmUgbm8gY2xlYXIgZGV2aWF0aW9ucyBmcm9tIG5vcm1hbGl0eS4KClRoZSB0aGlyZCBhc3N1bXB0aW9uIG9mIGVxdWFsIHZhcmlhbmNlcyBzZWVtcyB0byBiZSBtZXQgYmFzZWQgb24gdGhlCnZpc3VhbGl6YXRpb24gd2l0aCB0aGUgYm94cGxvdHMgKHNlZSBhYm92ZSkuCgpBcyBzdWNoLCB3ZSBtYXkgcHJvY2VlZCB3aXRoIHRoZSBBTk9WQSBhbmFseXNpcy4KCgojIyMgU2ltdWxhdGUgdG8gdHJhaW4geW91ciBza2lsbHMgaW4gYXNzZXNzaW5nIGFzc3VtcHRpb25zCgpgYGB7cn0Kc2V0LnNlZWQoMTAzMSkKc2lnbWEgPC0gbW9kICU+JSBzaWdtYSgpCmRhdGFIbHAgPC0gQ3Vja29vCgpzaW1Nb2RlbHMgPC0gbGlzdCgpCnBsb3RMaXN0IDwtIGxpc3QoKQpwbG90TGlzdFFRMSA8LSBsaXN0KCkKCnBhcihtZnJvdyA9IGMoMywgMykpCmZvciAoaSBpbiAxOjkpCnsKICBub2JzIDwtIEN1Y2tvbyAlPiUgbnJvdygpCiAgZGF0YUhscCR5U2ltIDwtIG1vZCRmaXQgKyBybm9ybShub2JzLCBzZCA9IHNpZ21hKQogIHNpbU1vZGVsc1tbaV1dIDwtIGxtKHlTaW0gfiB0eXBlLCBkYXRhSGxwKQogIHBsb3Qoc2ltTW9kZWxzW1tpXV0sIHdoaWNoID0gMikKICBwbG90TGlzdFtbaV1dIDwtIGRhdGFIbHAgJT4lCiAgICBnZ3Bsb3QoYWVzKHR5cGUsIHlTaW0pKSArCiAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBnZW9tX2ppdHRlcigpCiAgcGxvdExpc3RRUTFbW2ldXSA8LSBkYXRhSGxwICU+JQogICAgZmlsdGVyKHR5cGUgPT0gIm1lYWRvdyIpICU+JQogICAgZ2dwbG90KGFlcyhzYW1wbGUgPSB5U2ltKSkgKwogICAgZ2VvbV9xcSgpICsKICAgIGdlb21fcXFfbGluZSgpICsKICAgIHhsYWIoIlFRIGZvciBtZWFkb3ciKQp9Cgpkby5jYWxsKGdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlLCBwbG90TGlzdCkKZG8uY2FsbChncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSwgcGxvdExpc3RRUTEpCmBgYAoKVGhlIG1vc3QgZGV2aWF0aW5nIFFRLXBsb3Qgb2YgdGhlIHJlc2lkdWFscyBpbiB0aGUgbmluZSBzaW11bGF0aW9uIHJ1bnM6CgpgYGB7cn0KcGFyKG1mcm93ID0gYygxLCAxKSkKcGxvdChzaW1Nb2RlbHNbWzhdXSwgd2hpY2ggPSAyKQpgYGAKCgojIyBBTk9WQSBtb2RlbAoKV2UgcGVyZm9ybSB0aGUgQU5PVkEgdGVzdCB1c2luZyB0aGUgcmVzdWx0cyBvZiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwuCkVzc2VudGlhbGx5LCB3ZSB0ZXN0IHRoZSBmb2xsb3dpbmcgbnVsbCBoeXBvdGhlc2lzOgoKJCQKSF8wOlwgXGJldGFfMSA9IFxiZXRhXzIgPSBcYmV0YV8zID0gXGJldGFfNCA9IFxiZXRhXzUgPSAwCiQkCgp3aXRoIHRoZSBhbHRlcm5hdGl2ZSBiZWluZyB0aGF0IGF0IGxlYXN0IG9uZSBvZiB0aGUgcGFyYW1ldGVycyBpcyBkaWZmZXJlbnQgZnJvbQowLgoKYGBge3J9CmFub3ZhKG1vZCkKYGBgCgpUaGUgcC12YWx1ZSBvZiB0aGUgQU5PVkEgYW5hbHlzaXMgaXMgZXh0cmVtZWx5IHNpZ25pZmljYW50CihwLXZhbHVlIDwgMC4wMDEpLApzbyB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSBtZWFuCmVnZyBsZW5ndGggaXMgZXF1YWwgYmV0d2VlbiB0aGUgZGlmZmVyZW50IGJpcmQgdHlwZXMuCldlIGNhbiBzYXkgdGhhdCB0aGUgbWVhbiBlZ2cgbGVuZ3RoIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50CmJldHdlZW4gYXQgbGVhc3QgdHdvIGJpcmQgdHlwZXMgb24gdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbC4KCkJhc2VkIG9uIHRoaXMgYW5hbHlzaXMsIHdlIGRvIG5vdCB5ZXQga25vdyBiZXR3ZWVuIHdoaWNoIHBhcnRpY3VsYXIKYmlyZCB0eXBlcyB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UuIFRvIHN0dWR5IHRoaXMsIHdlIHdpbGwKcGVyZm9ybSBhICoqVHVrZXkgcG9zdC1ob2MgYW5hbHlzaXMqKi4KCiMjIFBvc3QtaG9jIGFuYWx5c2lzCgpXZSB3aWxsIHBlcmZvcm0gYSBwb3N0LWhvYyBhbmFseXNpcywgdG8gbG9vayBhdCB0aGUgZGlmZmVyZW5jZQppbiBlZ2cgbGVuZ3RoIGJldHdlZW4gZWFjaCBwYWlyd2lzZSBjb21wYXJpc29uIG9mIGJpcmQgdHlwZXMuCkltcG9ydGFudGx5LCB3aXRoIHRoaXMgc3RyYXRlZ3ksIHRoZSBwLXZhbHVlcyB3aWxsIGJlIGNvcnJlY3RseQphZGp1c3RlZCBmb3IgbXVsdGlwbGUgdGVzdGluZy4KClRoZSBudWxsIGh5cG90aGVzaXMgZm9yIGVhY2ggcGFpcndpc2UgdGVzdCBpcyB0aGF0IHRoZXJlIGlzIG5vCmRpZmZlcmVuY2UgaW4gdGhlIG1lYW4gZWdnIGxlbmd0aCBiZXR3ZWVuIGJvdGggYmlyZCB0eXBlcy4KClRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIGZvciBlYWNoIHBhaXJ3aXNlIHRlc3Qgc3RhdGVzIHRoYXQgdGhlcmUKaXMgaW5kZWVkIGEgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbiBlZ2cgbGVuZ3RoIGJldHdlZW4gYm90aCBiaXJkIHR5cGVzLgoKV2Ugd2lsbCBhbHNvIGNhbGN1bGF0ZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBvbiB0aGUgbWVhbiBkaWZmZXJlbmNlcy4KClRoZSBwb3N0LWhvYyBhbmFseXNpcyBpcyBjYXJyaWVkIG91dCB1c2luZyB0aGUgYGdsaHQoKWAgKCJHZW5lcmFsIExpbmVhcgpIeXBvdGhlc2VzIikgZnVuY3Rpb24gZnJvbSB0aGUgKm11bHRjb21wKiBwYWNrYWdlLiBXZSBhcHBseSB0aGlzIHRvIG91ciBsaW5lYXIKbW9kZWwgb2JqZWN0IGBtb2RgIGFuZCBzcGVjaWZ5IGluIHRoZSBgbGluZmN0PWAgYXJndW1lbnQgdGhhdCB3ZSB3YW50IHRvIHBlcmZvcm0KKm11bHRpcGxlIGNvbXBhcmlzb25zKiAoYG1jcGApLCB1c2luZyBUdWtleSdzIG1ldGhvZC4gV2Ugc3RvcmUgdGhlIG91dHB1dCBvZgpgZ2xodCgpYCBhbmQgdGhlbiBkaXNwbGF5IHRoZSByZXN1bHRzIHVzaW5nIHRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbiBhbmQKY2FsY3VsYXRpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMuCgpgYGB7cn0KbWNwIDwtIGdsaHQobW9kLCBsaW5mY3QgPSBtY3AodHlwZSA9ICJUdWtleSIpKQpzdW1tYXJ5KG1jcCkKY29uZmludChtY3ApCmBgYAoKV2UgY2FuIGFsc28gdmlzdWFsaXplIHRoZSBjb25maWRlbmNlIGludGVydmFsIGJ5IGNhbGxpbmcgYHBsb3QoKWAgb24gdGhlIGBtY3BgIG9iamVjdDoKCmBgYHtyfQpwbG90KG1jcCkKYGBgCgojIyBDb25jbHVzaW9uCgpUaGUgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgbWVhbiBsZW5ndGggb2YgYSBjdWNrb28ncyBlZ2cgYW5kIHRoZSBmb3N0ZXIgYmlyZCBzcGVjaWVzIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAocCA8PCAwLjAwMSkuCgpUaGUgbWVhbiBsZW5ndGggb2YgY3Vja29vJ3MgZWdncyBpbiBuZXN0cyBvZiB0aGUgRXVyYXNpYW4Kd3JlbiBhcmUgc21hbGxlciBhcyBjb21wYXJlZCB0byB0aG9zZSBmcm9tIGFsbCBvdGhlciBiaXJkCnNwZWNpZXMgaW4gdGhlIHN0dWR5OgoKLSB0aGUgbWVhZG93IHBpcGl0IChhZGp1c3RlZCBwLXZhbHVlID0gYHIgc3VtbWFyeShtY3ApJHRlc3QkcHZhbHVlc1tuYW1lcyhzdW1tYXJ5KG1jcCkkdGVzdCR0c3RhdCkgPT0gIndyZW4gLSBtZWFkb3ciXSAlPiUgZm9ybWF0KGRpZ2l0cz0xKWAsIG1lYW4gZGlmZmVyZW5jZSA9IGByIHJvdW5kKGNvbmZpbnQobWNwKSRjb25maW50WyJ3cmVuIC0gbWVhZG93IiwxXSwxKWBtbSwgOTUlIENJIFtgciByb3VuZChjb25maW50KG1jcCkkY29uZmludFsid3JlbiAtIG1lYWRvdyIsLTFdLDEpYF0pCi0gdGhlIHRyZWUgcGlwaXQgKGFkanVzdGVkIHAtdmFsdWUgPSBgciBzdW1tYXJ5KG1jcCkkdGVzdCRwdmFsdWVzW25hbWVzKHN1bW1hcnkobWNwKSR0ZXN0JHRzdGF0KSA9PSAid3JlbiAtIHRyZWUiXSAlPiUgZm9ybWF0KGRpZ2l0cz0xKWAsIG1lYW4gZGlmZmVyZW5jZSA9IGByIHJvdW5kKGNvbmZpbnQobWNwKSRjb25maW50WyJ3cmVuIC0gdHJlZSIsMV0sMSlgbW0sIDk1JSBDSSBbYHIgcm91bmQoY29uZmludChtY3ApJGNvbmZpbnRbIndyZW4gLSB0cmVlIiwtMV0sMSlgXSkKLSB0aGUgZHVubm9jayAoYWRqdXN0ZWQgcC12YWx1ZSA9IGByIHN1bW1hcnkobWNwKSR0ZXN0JHB2YWx1ZXNbbmFtZXMoc3VtbWFyeShtY3ApJHRlc3QkdHN0YXQpID09ICJ3cmVuIC0gZHVubm9jayJdICU+JSBmb3JtYXQoZGlnaXRzPTEpYCwgbWVhbiBkaWZmZXJlbmNlID0gYHIgcm91bmQoY29uZmludChtY3ApJGNvbmZpbnRbIndyZW4gLSBkdW5ub2NrIiwxXSwxKWBtbSwgOTUlIENJIFtgciByb3VuZChjb25maW50KG1jcCkkY29uZmludFsid3JlbiAtIGR1bm5vY2siLC0xXSwxKWBdKQotIHRoZSBFdXJvcGVhbiByb2JpbiAoYWRqdXN0ZWQgcC12YWx1ZSA9IGByIHN1bW1hcnkobWNwKSR0ZXN0JHB2YWx1ZXNbbmFtZXMoc3VtbWFyeShtY3ApJHRlc3QkdHN0YXQpID09ICJ3cmVuIC0gcm9iaW4iXSAlPiUgZm9ybWF0KGRpZ2l0cz0xKWAsIG1lYW4gZGlmZmVyZW5jZSA9IGByIHJvdW5kKGNvbmZpbnQobWNwKSRjb25maW50WyJ3cmVuIC0gcm9iaW4iLDFdLDEpYG1tLCA5NSUgQ0kgW2ByIHJvdW5kKGNvbmZpbnQobWNwKSRjb25maW50WyJ3cmVuIC0gcm9iaW4iLC0xXSwxKWBdKQotIHRoZSB3aGl0ZSB3YWd0YWlsIChhZGp1c3RlZCBwLXZhbHVlID0gYHIgc3VtbWFyeShtY3ApJHRlc3QkcHZhbHVlc1tuYW1lcyhzdW1tYXJ5KG1jcCkkdGVzdCR0c3RhdCkgPT0gIndyZW4gLSB3YWd0YWlsIl0gJT4lIGZvcm1hdChkaWdpdHM9MSlgLCBtZWFuIGRpZmZlcmVuY2UgPSBgciByb3VuZChjb25maW50KG1jcCkkY29uZmludFsid3JlbiAtIHdhZ3RhaWwiLDFdLDEpYG1tLCA5NSUgQ0kgW2ByIHJvdW5kKGNvbmZpbnQobWNwKSRjb25maW50WyJ3cmVuIC0gd2FndGFpbCIsLTFdLDEpYF0pCgpUaGVyZSBpcyBubyBldmlkZW5jZSB0YWh0IHRoZSBtZWFuIGxlbmd0aCBvZiB0aGUgY3Vja29vIGJpcmQncyBlZ2dzIGZvciBhbGwKb3RoZXIgcGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiBmb3N0ZXIgYmlyZCBzcGVjaWVzIGFyZSBzaWduaWZpY2FudGx5CmRpZmZlcmVudCBhdCB0aGUgNSUgbGV2ZWwuCg==