In this dataset, participants are assigned to 1 of 3 conditions:

  1. Control condition (recalled a neutral event)
  2. Sad actor (recalled a sad event)
  3. Sad partner (recalled a neutral event but was paired with the sad actor)

These data are dyadic, but for the sake of this tutorial, we’re going to ignore that and treat participants as independent.

Load the data & libraries

pkgs <- c("tidyverse", "dplyr", "haven", "foreign", "lme4", "plyr", "nlme", "lsr", "emmeans", "afex", "knitr", "kableExtra", "car")

packages <- rownames(installed.packages())
p_to_install <- pkgs[!(pkgs %in% packages)]

if(length(p_to_install) > 0){
  install.packages(p_to_install)
}

lapply(pkgs, library, character.only = TRUE)

getwd()
# Load data
df<- read_sav("lab5_anova_contrasts.sav")

Study Design: - Participants completed an emotion induction (recall either a sad or neutral event) and then interacted with a stranger where they asked each other questions to get acquainted.

Testable research question: - I want to know: Do people feel more (or less) sad after interacting with a sad person? Are there changes in how sad that sad individual feels after the interaction? Does this vary by gender?

Predictors: - Condition (control x sad actor x sad partner) - Gender (female x male)

Outcome: - Post-interaction sadness (1- not at all to 7- a great deal)


ANOVA with no data prep or pre-analyses

First off, I don’t like aov(). The summary function with aov() gives us the omnibus results with type = 1, so we’d have to use Anova from the car package anyway. That said, we’re going to use lm(). I promise, they are doing the same thing, they just present different output when you use summary().

fit <- lm(avg_sad_int ~ genderR*condition_3Level, data = df)
car::Anova(fit, type = "III")
## Anova Table (Type III tests)
## 
## Response: avg_sad_int
##                          Sum Sq  Df  F value Pr(>F)    
## (Intercept)              62.792   1 345.8616 <2e-16 ***
## genderR                   0.140   1   0.7686 0.3816    
## condition_3Level          0.086   1   0.4735 0.4921    
## genderR:condition_3Level  0.001   1   0.0032 0.9550    
## Residuals                40.668 224                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Why don’t these match?

Why are the degrees of freedom different? What does this tell us?


Let’s first check that the variables are in the correct class.

We’re looking at condition_3Level, genderR, and avg_sad_int.

glimpse(df)
## Rows: 230
## Columns: 6
## $ Dyad             <dbl> 100, 100, 101, 101, 102, 102, 103, 103, 105, 105, 106…
## $ ID               <dbl> 1001, 1002, 1011, 1012, 1021, 1022, 1031, 1032, 1051,…
## $ partner          <dbl> 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,…
## $ genderR          <dbl+lbl> -1, -1, -1, -1,  1,  1, -1, -1,  1,  1,  1,  1, -…
## $ condition_3Level <dbl+lbl> 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 1, 1, 2, 3, 1…
## $ avg_sad_int      <dbl> 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.0…

Predictors:

  • condition_3Level: 1, 2, 3
  • genderR: -1, 1

Change variable class

df.f <- df %>% 
  mutate(condition_3Level = as.factor(condition_3Level),
         genderR = as.factor(genderR))

# check class
class(df.f$condition_3Level)
## [1] "factor"
class(df.f$genderR)
## [1] "factor"

Now, let’s rerun the model with categorical predictors

fit2 <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.f)
car::Anova(fit2, type = "III")
## Anova Table (Type III tests)
## 
## Response: avg_sad_int
##                          Sum Sq  Df  F value Pr(>F)    
## (Intercept)              73.699   1 402.5289 <2e-16 ***
## genderR                   0.375   1   2.0475 0.1539    
## condition_3Level          0.060   2   0.1629 0.8498    
## genderR:condition_3Level  0.001   2   0.0032 0.9968    
## Residuals                40.646 222                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

It still doesn’t match. What else could be going on?

What does the omnibus test tell us?


What is ANOVA?

The F-ratio represents how good the model is relative to how bad it is. In other words, it is the ratio of explained variance to unexplained variance.

In ANOVA, we’re asking: is predicting scores from the group means better than predicting scores from the grand mean? Are the groups’ outcomes significantly different from each other?

The equations will be variations of one basic equation:

\[deviation = \sum(observed-model)^2\]

Total Sum of Squares (SST)

This is the total amount of variation in our data. It’s the difference between the observed data point and the grand mean. Then we square these differences and add them together.

It’s the “grand variance” or the variance in responses regardless of group.

\[SST = \sum^N_{i=1}(Y_i-\overline{Y})^2\]

\[Y_i\ represents\ each \ individual\ observation. \] \[\overline{Y} \ is \ the\ grand\ mean. \] \[N\ is\ the\ total \ number\ of\ observations. \]

Between-Group Sum of Squares (SSB)

(aka model sum of squares)

How much of the variation can the model explain? In simple terms, it’s the differences between the predicted values and the grand mean.

\[SSB = \sum^k_{j=1}n_j(\overline{Y}_j-\overline{Y})^2\]

\[\overline{Y}_j\ is\ the \ mean\ of\ group\ j. \]

\[n_j \ is \ the\ number\ mean\ of\ observations\ in\ group\ j. \]

\[k\ is\ the\ total \ number\ of\ groups. \]

Within-Group Sum of Squares (SSW)

(aka residual sum of squares)

This is the variance within each group. So how much of the variance is not due to group differences, but instead due to extraneous factors like individual differences? In other words, this is the variance that cannot be explained by the model.

\[SSW =\sum^{n}_{i=1}({Y}_{ij}-\overline{Y}_j)^2\]

\[{Y}_{ij}\ represents\ each \ observation\ in\ group\ j. \]

In short, SSB tells us how much variation is due to the model and SSW tells us how much variation cannot be explained by the model (error)

Mean Squares

One issue with that formula is because the values are summed values, they will be influenced by the total number of scores summed. To get rid of this bias, we calculate the mean squares, which is the average sum of squares (SS divided by df).

Mean Squares Between

This is the average amount of variance explained by the model.

\[MSB = \frac{SSB}{df_B} \]

Mean Squares Within

This is the average amount of variance not explained by the model.

\[MSW = \frac{SSW}{df_W} \]

F-statistic

This is the ratio of variance explained by the model (systematic variance) to the variance not explained by the model (unsystematic variance)

If the F is above 1, that tells us that there was some effect of the predictor above and beyond the individual differences that could explain the outcome (but, this doesn’t tell us if it’s significant. Just the direction).

If the F is below 1, you know that there’s more error in the model than systematic variance.

\[F = \frac{MSB}{MSW} \]

tldr; the F-statistic tells us whether our model fitted to the data accounts for more variation (good) than extraneous factors (bad), but it doesn’t tell us where these differences between groups are.

For example, if we’re looking at differences in sleep quality by race and we get a significant effect, that tells us that different races do report differences in sleep quality (relative to the grand mean). However, it does not tell us which races sleep better or worse than each other.

SS Types

Imagine we’re testing the effect of various health behaviors (diet, sleep) on mood.

Type I Sums of Squares

This approach is useful if we think the sequence matters, like if we believe sleep needs to be considered before diet. Tells us the story in sequence (first sleep, then diet) and how each step adds to mood.

Type II Sum of Squares

Now, let’s say we want to understand the unique impact of diet on mood, ignoring whether or not they’re sleeping well, and vice versa. Type II sums of squares focus on the individual contribution of each factor without mixing them up. It’s like evaluating the influence of diet and sleep separately, assuming they don’t interact.

Type III Sum of Squares

Lastly, we consider the scenario where we want to understand the influence of diet and sleep on mood, including how they might interact (e.g., does the impact of diet depend on whether they slept well?). Type III sums of squares let us see the full picture, considering all possible interactions. This is best when our experiment is complex (e.g., group sizes vary, or we expect that the factors might affect each other).

I only ever use Type III.


Detour into contrast coding

Our main takeaway from ANOVA is that the omnibus looks at the effect of the predictor(s) relative to the grand mean (or the DV when the predictors are at their average level). With that in mind, we need to make sure our variables are actually coded in that way.

Contrast coding is a way to compare different levels/groups of a categorical variable. The most common contrasts are dummy coding and effects coding.

Dummy coding

This is the most common form of contrast coding. In dummy coding, one level of the categorical variable is chosen as a reference group. For example, if you have a variable “Race” with three levels (White, Black, Asian), you can create two dummy variables: the effect of being Black and the effect of being Asian. The reference group (White) gets coded as 0 in both new variables. The intercept represents the mean outcome for the reference group.

White = 1 Black = 2 Asian = 3

Race Dummy1 Dummy2
White 0 0
Black 1 0
Asian 0 1
Dummy 1: outcome for Black participants vs reference (White)
Dummy 2: outcome for Asian participants vs reference (White)
Intercept = average sleep quality when predictor is zero (sleep for White participants)

Effects coding

Unlike dummy coding, where the reference category is represented by all 0’s, effects coding doesn’t leave out one category as the reference. Instead, categories are coded with numbers that balance out, such that the sum of codes for each categorical level across all coded variables equals zero. This balance allows the model’s intercept to represent the grand mean. You would use this coding scheme if you wanted to compare the mean of each group to the grand mean. The reference group gets -1 for both effects.

The sum of your contrasts should = 0.

Race Effect1 Effect2
White 1 0
Black 0 1
Asian -1 -1
Effect 1: compares the effect of White to the overall mean
Effect 2: compares the effect of Black to the overall mean
Intercept = grand mean across all categories of race

tldr; Dummy coding gives us the “simple effects,” comparing different levels to a reference group while effects coding gives us the “main effects,” comparing different levels to the group mean




Challenge!

Name the comparisons below.

1. Testing the effect of a new medication using treatment and control groups. How would you interpret the intercept? How would you interpret the effect of group?

Group Column1
Control 0
Treatment 1

2. Now we’re testing the effect of different dosages of the same medication to the control group. How would you interpret the intercept? What does level 1 (column 1) look at? How about level 2 (column 2)?

Group Column1 Column 2
Control 0 0
Low Dose 1 0
High Dose 0 1

3. We recoded the groups. How would you interpret the intercept? What does level 1 (column 1) look at? How about level 2 (column 2)?

Group Column1 Column 2
Control 1 0
Low Dose 0 1
High Dose -1 -1

4. One more…we’ve recoded the groups again. How would you interpret the intercept? What does level 1 (column 1) look at? How about level 2 (column 2)?

Group Column1 Column 2
Control 0 2
Low Dose 1 -1
High Dose -1 -1

How are our variables coded?

contrasts(df.f$genderR)
##    1
## -1 0
## 1  1

Identifiers:

  • -1 = Female

  • 1 = Male


Contrasts:

  • 0 = Female

  • 1 = Male

How does this impact our interpretation of the intercept?

  • Average sadness after the interaction for women (when genderR = 0)
contrasts(df.f$condition_3Level)
##   2 3
## 1 0 0
## 2 1 0
## 3 0 1

Identifiers:

  • 1 = Control dyad

  • 2 = Sad actor

  • 3 = Sad partner


Contrasts:

FIRST EFFECT: what is the effect of sad actor vs control condition?


SECOND EFFECT: what is the effect of sad partner vs control condition?



How does SPSS set up the contrasts?

Intercept

Intercept = average all levels

Gender

  • female -1, but coded as 1
  • male 1, but coded as -1
  • when condition = 0 (average collapsing across condition)

Condition

  • when gender = 0 (average collapsing across gender)
  • CONTRAST 1 = control (1) vs sad partner (3)
  • CONTRAST 2 = sad actor (2) vs sad partner(3)

Change reference groups

Gender contrasts

genderContrasts <- matrix(c(1,-1),
                          nrow = 2, ncol = 1, byrow = FALSE)

contrasts(df.f$genderR) = genderContrasts

print(contrasts(df.f$genderR))
##    [,1]
## -1    1
## 1    -1

Condition contrasts

effectContrasts <- matrix(c(1, 0,
                            -1, 1, 
                            -1, 0 ),
                          nrow = 3, ncol = 2, byrow = FALSE)

contrasts(df.f$condition_3Level) = effectContrasts

print(contrasts(df.f$condition_3Level))
##   [,1] [,2]
## 1    1    1
## 2    0   -1
## 3   -1    0

Rerun the omnibus test

fit3 <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.f)
car::Anova(fit3, type = "III")
## Anova Table (Type III tests)
## 
## Response: avg_sad_int
##                           Sum Sq  Df   F value  Pr(>F)    
## (Intercept)              274.506   1 1499.2937 < 2e-16 ***
## genderR                    0.581   1    3.1746 0.07616 .  
## condition_3Level           0.103   2    0.2817 0.75478    
## genderR:condition_3Level   0.001   2    0.0032 0.99678    
## Residuals                 40.646 222                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Yay! It matches.

Note: technically, contrast coding shouldn't influence the omnibus test. By definition, the omnibus test is supposed to compare the group means to the grand mean. SPSS and SAS take care of this by contrast coding in the background. As you can see from the omnibus and summary statistics in R, R expects you to understand what's going on 'under the hood'

Now let’s break down these effects

summary(fit3)
## 
## Call:
## lm(formula = avg_sad_int ~ genderR * condition_3Level, data = df.f)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.2738 -0.2167 -0.1576 -0.1111  2.0595 
## 
## Coefficients:
##                              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 1.1972874  0.0309211  38.721   <2e-16 ***
## genderR1                   -0.0550935  0.0309211  -1.782   0.0762 .  
## condition_3Level1           0.0333985  0.0459370   0.727   0.4680    
## condition_3Level2          -0.0149933  0.0460489  -0.326   0.7450    
## genderR1:condition_3Level1 -0.0023158  0.0459370  -0.050   0.9598    
## genderR1:condition_3Level2 -0.0007076  0.0460489  -0.015   0.9878    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4279 on 222 degrees of freedom
##   (2 observations deleted due to missingness)
## Multiple R-squared:  0.02079,    Adjusted R-squared:  -0.001268 
## F-statistic: 0.9425 on 5 and 222 DF,  p-value: 0.4543

Does it match SPSS output?

No it does not. Why might that be?

How is gender coded?

How is condition coded?

Recode variables to match SPSS

Gender

genderContrasts2 <- matrix(c(1, 0), 
                           nrow = 2, ncol = 1, byrow = FALSE)
contrasts(df.f$genderR) = genderContrasts2

print(contrasts(df.f$genderR))
##    [,1]
## -1    1
## 1     0

Condition

conditionContrasts2 <- matrix(c(1, 0, 0,
                             0, 1, 0), 
                           nrow = 3, ncol = 2, byrow = FALSE)

contrasts(df.f$condition_3Level) = conditionContrasts2

print(contrasts(df.f$condition_3Level))
##   [,1] [,2]
## 1    1    0
## 2    0    1
## 3    0    0
fit4 <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.f)
summary(fit4)
## 
## Call:
## lm(formula = avg_sad_int ~ genderR * condition_3Level, data = df.f)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.2738 -0.2167 -0.1576 -0.1111  2.0595 
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 1.216667   0.095679  12.716   <2e-16 ***
## genderR1                   -0.105556   0.117682  -0.897    0.371    
## condition_3Level1           0.057143   0.111463   0.513    0.609    
## condition_3Level2           0.050000   0.135311   0.370    0.712    
## genderR1:condition_3Level1 -0.010678   0.142995  -0.075    0.941    
## genderR1:condition_3Level2 -0.003216   0.166799  -0.019    0.985    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4279 on 222 degrees of freedom
##   (2 observations deleted due to missingness)
## Multiple R-squared:  0.02079,    Adjusted R-squared:  -0.001268 
## F-statistic: 0.9425 on 5 and 222 DF,  p-value: 0.4543

Woohoo! It matches.


Do I have to go through this process any time I want to run an ANOVA in R?

It’s important that you understand what’s going on “under the hood,” but we can shorten this process.

Let’s demonstrate the steps using our original dataframe

Step 1: Convert numeric predictors to factor variables

df.short <- df %>% 
  mutate(condition_3Level = as.factor(condition_3Level),
         genderR = as.factor(genderR))

Step 2: Contrast code for the omnibus test

We actually don’t have to create our contrasts from scratch. We can use these R functions to automatically contrast code our variables.

# effect-code
contr.sum(3)
##   [,1] [,2]
## 1    1    0
## 2    0    1
## 3   -1   -1
# dummy code
contr.treatment(3)
##   2 3
## 1 0 0
## 2 1 0
## 3 0 1

Apply contrasts (effect code)

contrasts(df.short$genderR) <- contr.sum(2)
contrasts(df.short$condition_3Level) <- contr.sum(3)

Step 3a: Run omnibus test

model_shortcut <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.short)

car::Anova(model_shortcut, type = "III")
## Anova Table (Type III tests)
## 
## Response: avg_sad_int
##                           Sum Sq  Df   F value  Pr(>F)    
## (Intercept)              274.506   1 1499.2937 < 2e-16 ***
## genderR                    0.581   1    3.1746 0.07616 .  
## condition_3Level           0.103   2    0.2817 0.75478    
## genderR:condition_3Level   0.001   2    0.0032 0.99678    
## Residuals                 40.646 222                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Apply contrasts (dummy code)

contrasts(df.short$genderR) <- contr.treatment(2)
contrasts(df.short$condition_3Level) <- contr.treatment(3)

Step 4a: Run regression to get simple effects

Be mindful that this approach defaults to a different reference group than SPSS (notice Condition =1 is missing from the R output and Condition =3 is missing from the SPSS output). It’s not wrong, but good to know that their default settings are different.

model_shortcut2 <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.short)

summary(model_shortcut2)
## 
## Call:
## lm(formula = avg_sad_int ~ genderR * condition_3Level, data = df.short)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.2738 -0.2167 -0.1576 -0.1111  2.0595 
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 1.157576   0.057697  20.063   <2e-16 ***
## genderR2                    0.116234   0.081230   1.431    0.154    
## condition_3Level2           0.000319   0.090261   0.004    0.997    
## condition_3Level3          -0.046465   0.089574  -0.519    0.604    
## genderR2:condition_3Level2 -0.007462   0.143426  -0.052    0.959    
## genderR2:condition_3Level3 -0.010678   0.142995  -0.075    0.941    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4279 on 222 degrees of freedom
##   (2 observations deleted due to missingness)
## Multiple R-squared:  0.02079,    Adjusted R-squared:  -0.001268 
## F-statistic: 0.9425 on 5 and 222 DF,  p-value: 0.4543

Step 3b: Change reference group to match SPSS

# base is reference (it doesn't take negative numbers, but we're telling it we want the reference to be the higher number of the two)
contrasts(df.short$genderR) <- contr.treatment(2, base = 2)

contrasts(df.short$condition_3Level) <- contr.treatment(3, base = 3)

Step 4b: Run regression to get simple effects to match SPSS

model_shortcut3 <- lm(avg_sad_int ~ genderR*condition_3Level, data = df.short)

summary(model_shortcut3)
## 
## Call:
## lm(formula = avg_sad_int ~ genderR * condition_3Level, data = df.short)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.2738 -0.2167 -0.1576 -0.1111  2.0595 
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 1.216667   0.095679  12.716   <2e-16 ***
## genderR1                   -0.105556   0.117682  -0.897    0.371    
## condition_3Level1           0.057143   0.111463   0.513    0.609    
## condition_3Level2           0.050000   0.135311   0.370    0.712    
## genderR1:condition_3Level1 -0.010678   0.142995  -0.075    0.941    
## genderR1:condition_3Level2 -0.003216   0.166799  -0.019    0.985    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4279 on 222 degrees of freedom
##   (2 observations deleted due to missingness)
## Multiple R-squared:  0.02079,    Adjusted R-squared:  -0.001268 
## F-statistic: 0.9425 on 5 and 222 DF,  p-value: 0.4543

Do I really have to do all that just for ANOVA?

No, but it’s important that you understand how ANOVA works. Here’s an actual shortcut that defaults to SS type 3 and does not require you to contrast code. You can run the pairwise comparisons as you normally would.

Omnibus shortcut

# we don't even need to convert numeric predictors to factor. It does that for us.

# omnibus test
shortcut_model <- afex::aov_car(avg_sad_int ~ genderR*condition_3Level + 
                Error(ID), # must add the error term (i.e. ID)
              data = df) # original dataframe
## Converting to factor: genderR, condition_3Level
## Contrasts set to contr.sum for the following variables: genderR, condition_3Level
print(shortcut_model)
## Anova Table (Type 3 tests)
## 
## Response: avg_sad_int
##                     Effect     df  MSE      F   ges p.value
## 1                  genderR 1, 222 0.18 3.17 +  .014    .076
## 2         condition_3Level 2, 222 0.18   0.28  .003    .755
## 3 genderR:condition_3Level 2, 222 0.18   0.00 <.001    .997
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1

Pairwise comparisons to breakdown interactions

emm <- emmeans(model_shortcut3, specs = c("genderR", "condition_3Level"))

pairs(emm, simple = "each")
## $`simple contrasts for genderR`
## condition_3Level = 1:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.116 0.0812 222  -1.431  0.1539
## 
## condition_3Level = 2:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.109 0.1182 222  -0.920  0.3585
## 
## condition_3Level = 3:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.106 0.1177 222  -0.897  0.3707
## 
## 
## $`simple contrasts for condition_3Level`
## genderR = -1:
##  contrast                               estimate     SE  df t.ratio p.value
##  condition_3Level1 - condition_3Level2 -0.000319 0.0903 222  -0.004  1.0000
##  condition_3Level1 - condition_3Level3  0.046465 0.0896 222   0.519  0.8623
##  condition_3Level2 - condition_3Level3  0.046784 0.0975 222   0.480  0.8810
## 
## genderR = 1:
##  contrast                               estimate     SE  df t.ratio p.value
##  condition_3Level1 - condition_3Level2  0.007143 0.1115 222   0.064  0.9977
##  condition_3Level1 - condition_3Level3  0.057143 0.1115 222   0.513  0.8653
##  condition_3Level2 - condition_3Level3  0.050000 0.1353 222   0.370  0.9275
## 
## P value adjustment: tukey method for comparing a family of 3 estimates
pairs(emm, adjust = "tukey")
##  contrast                                                       estimate     SE
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level1    -0.116234 0.0812
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) -0.000319 0.0903
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level2    -0.109091 0.1117
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level3)  0.046465 0.0896
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level3    -0.059091 0.1117
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level2)     0.115915 0.0899
##  genderR1 condition_3Level1 - genderR1 condition_3Level2        0.007143 0.1115
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level3)     0.162698 0.0892
##  genderR1 condition_3Level1 - genderR1 condition_3Level3        0.057143 0.1115
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level2    -0.108772 0.1182
##  (genderR-1 condition_3Level2) - (genderR-1 condition_3Level3)  0.046784 0.0975
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level3    -0.058772 0.1182
##  genderR1 condition_3Level2 - (genderR-1 condition_3Level3)     0.155556 0.1177
##  genderR1 condition_3Level2 - genderR1 condition_3Level3        0.050000 0.1353
##  (genderR-1 condition_3Level3) - genderR1 condition_3Level3    -0.105556 0.1177
##   df t.ratio p.value
##  222  -1.431  0.7082
##  222  -0.004  1.0000
##  222  -0.976  0.9250
##  222   0.519  0.9954
##  222  -0.529  0.9950
##  222   1.289  0.7909
##  222   0.064  1.0000
##  222   1.823  0.4530
##  222   0.513  0.9957
##  222  -0.920  0.9410
##  222   0.480  0.9968
##  222  -0.497  0.9962
##  222   1.322  0.7727
##  222   0.370  0.9991
##  222  -0.897  0.9469
## 
## P value adjustment: tukey method for comparing a family of 6 estimates

Alternative formatting

kable(pairs(emm, adjust = "tukey"), "simple", digits = 3) 
contrast estimate SE df t.ratio p.value
(genderR-1 condition_3Level1) - genderR1 condition_3Level1 -0.116 0.081 222 -1.431 0.708
(genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) 0.000 0.090 222 -0.004 1.000
(genderR-1 condition_3Level1) - genderR1 condition_3Level2 -0.109 0.112 222 -0.976 0.925
(genderR-1 condition_3Level1) - (genderR-1 condition_3Level3) 0.046 0.090 222 0.519 0.995
(genderR-1 condition_3Level1) - genderR1 condition_3Level3 -0.059 0.112 222 -0.529 0.995
genderR1 condition_3Level1 - (genderR-1 condition_3Level2) 0.116 0.090 222 1.289 0.791
genderR1 condition_3Level1 - genderR1 condition_3Level2 0.007 0.111 222 0.064 1.000
genderR1 condition_3Level1 - (genderR-1 condition_3Level3) 0.163 0.089 222 1.823 0.453
genderR1 condition_3Level1 - genderR1 condition_3Level3 0.057 0.111 222 0.513 0.996
(genderR-1 condition_3Level2) - genderR1 condition_3Level2 -0.109 0.118 222 -0.920 0.941
(genderR-1 condition_3Level2) - (genderR-1 condition_3Level3) 0.047 0.098 222 0.480 0.997
(genderR-1 condition_3Level2) - genderR1 condition_3Level3 -0.059 0.118 222 -0.497 0.996
genderR1 condition_3Level2 - (genderR-1 condition_3Level3) 0.156 0.118 222 1.322 0.773
genderR1 condition_3Level2 - genderR1 condition_3Level3 0.050 0.135 222 0.370 0.999
(genderR-1 condition_3Level3) - genderR1 condition_3Level3 -0.106 0.118 222 -0.897 0.947
kable(pairs(emm, adjust = "bonferroni"), "simple", digits = 3) 
contrast estimate SE df t.ratio p.value
(genderR-1 condition_3Level1) - genderR1 condition_3Level1 -0.116 0.081 222 -1.431 1
(genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) 0.000 0.090 222 -0.004 1
(genderR-1 condition_3Level1) - genderR1 condition_3Level2 -0.109 0.112 222 -0.976 1
(genderR-1 condition_3Level1) - (genderR-1 condition_3Level3) 0.046 0.090 222 0.519 1
(genderR-1 condition_3Level1) - genderR1 condition_3Level3 -0.059 0.112 222 -0.529 1
genderR1 condition_3Level1 - (genderR-1 condition_3Level2) 0.116 0.090 222 1.289 1
genderR1 condition_3Level1 - genderR1 condition_3Level2 0.007 0.111 222 0.064 1
genderR1 condition_3Level1 - (genderR-1 condition_3Level3) 0.163 0.089 222 1.823 1
genderR1 condition_3Level1 - genderR1 condition_3Level3 0.057 0.111 222 0.513 1
(genderR-1 condition_3Level2) - genderR1 condition_3Level2 -0.109 0.118 222 -0.920 1
(genderR-1 condition_3Level2) - (genderR-1 condition_3Level3) 0.047 0.098 222 0.480 1
(genderR-1 condition_3Level2) - genderR1 condition_3Level3 -0.059 0.118 222 -0.497 1
genderR1 condition_3Level2 - (genderR-1 condition_3Level3) 0.156 0.118 222 1.322 1
genderR1 condition_3Level2 - genderR1 condition_3Level3 0.050 0.135 222 0.370 1
(genderR-1 condition_3Level3) - genderR1 condition_3Level3 -0.106 0.118 222 -0.897 1

What else can we do with emmeans()?

Estimated marginal means

emm2 <- emmeans(model_shortcut3, specs = pairwise ~ genderR:condition_3Level)

emm2$emmeans
##  genderR condition_3Level emmean     SE  df lower.CL upper.CL
##  -1      1                  1.16 0.0577 222    1.044     1.27
##  1       1                  1.27 0.0572 222    1.161     1.39
##  -1      2                  1.16 0.0694 222    1.021     1.29
##  1       2                  1.27 0.0957 222    1.078     1.46
##  -1      3                  1.11 0.0685 222    0.976     1.25
##  1       3                  1.22 0.0957 222    1.028     1.41
## 
## Confidence level used: 0.95

Contrasts

emm2$contrasts
##  contrast                                                       estimate     SE
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level1    -0.116234 0.0812
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) -0.000319 0.0903
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level2    -0.109091 0.1117
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level3)  0.046465 0.0896
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level3    -0.059091 0.1117
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level2)     0.115915 0.0899
##  genderR1 condition_3Level1 - genderR1 condition_3Level2        0.007143 0.1115
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level3)     0.162698 0.0892
##  genderR1 condition_3Level1 - genderR1 condition_3Level3        0.057143 0.1115
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level2    -0.108772 0.1182
##  (genderR-1 condition_3Level2) - (genderR-1 condition_3Level3)  0.046784 0.0975
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level3    -0.058772 0.1182
##  genderR1 condition_3Level2 - (genderR-1 condition_3Level3)     0.155556 0.1177
##  genderR1 condition_3Level2 - genderR1 condition_3Level3        0.050000 0.1353
##  (genderR-1 condition_3Level3) - genderR1 condition_3Level3    -0.105556 0.1177
##   df t.ratio p.value
##  222  -1.431  0.7082
##  222  -0.004  1.0000
##  222  -0.976  0.9250
##  222   0.519  0.9954
##  222  -0.529  0.9950
##  222   1.289  0.7909
##  222   0.064  1.0000
##  222   1.823  0.4530
##  222   0.513  0.9957
##  222  -0.920  0.9410
##  222   0.480  0.9968
##  222  -0.497  0.9962
##  222   1.322  0.7727
##  222   0.370  0.9991
##  222  -0.897  0.9469
## 
## P value adjustment: tukey method for comparing a family of 6 estimates

Confidence intervals

emm2$contrasts %>% confint()
##  contrast                                                       estimate     SE
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level1    -0.116234 0.0812
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) -0.000319 0.0903
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level2    -0.109091 0.1117
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level3)  0.046465 0.0896
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level3    -0.059091 0.1117
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level2)     0.115915 0.0899
##  genderR1 condition_3Level1 - genderR1 condition_3Level2        0.007143 0.1115
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level3)     0.162698 0.0892
##  genderR1 condition_3Level1 - genderR1 condition_3Level3        0.057143 0.1115
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level2    -0.108772 0.1182
##  (genderR-1 condition_3Level2) - (genderR-1 condition_3Level3)  0.046784 0.0975
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level3    -0.058772 0.1182
##  genderR1 condition_3Level2 - (genderR-1 condition_3Level3)     0.155556 0.1177
##  genderR1 condition_3Level2 - genderR1 condition_3Level3        0.050000 0.1353
##  (genderR-1 condition_3Level3) - genderR1 condition_3Level3    -0.105556 0.1177
##   df lower.CL upper.CL
##  222  -0.3498    0.117
##  222  -0.2598    0.259
##  222  -0.4303    0.212
##  222  -0.2110    0.304
##  222  -0.3803    0.262
##  222  -0.1426    0.374
##  222  -0.3133    0.328
##  222  -0.0939    0.419
##  222  -0.2633    0.378
##  222  -0.4486    0.231
##  222  -0.2336    0.327
##  222  -0.3986    0.281
##  222  -0.1828    0.494
##  222  -0.3390    0.439
##  222  -0.4439    0.233
## 
## Confidence level used: 0.95 
## Conf-level adjustment: tukey method for comparing a family of 6 estimates

Within-group comparisons with |

emm3 <- emmeans(model_shortcut3, specs = pairwise ~ genderR|condition_3Level)

emm3 
## $emmeans
## condition_3Level = 1:
##  genderR emmean     SE  df lower.CL upper.CL
##  -1        1.16 0.0577 222    1.044     1.27
##  1         1.27 0.0572 222    1.161     1.39
## 
## condition_3Level = 2:
##  genderR emmean     SE  df lower.CL upper.CL
##  -1        1.16 0.0694 222    1.021     1.29
##  1         1.27 0.0957 222    1.078     1.46
## 
## condition_3Level = 3:
##  genderR emmean     SE  df lower.CL upper.CL
##  -1        1.11 0.0685 222    0.976     1.25
##  1         1.22 0.0957 222    1.028     1.41
## 
## Confidence level used: 0.95 
## 
## $contrasts
## condition_3Level = 1:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.116 0.0812 222  -1.431  0.1539
## 
## condition_3Level = 2:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.109 0.1182 222  -0.920  0.3585
## 
## condition_3Level = 3:
##  contrast               estimate     SE  df t.ratio p.value
##  (genderR-1) - genderR1   -0.106 0.1177 222  -0.897  0.3707

Pass these contrasts through rbind() to correct for multiple comparisons (defaults to Bonferroni, which can be a bit too conservative and too statistically underpowered for so many comparisons; see Lee & Lee, 2018; Lieberman & Cunningham, 2009)

emm2$contrasts %>% 
  rbind()
##  contrast                                                       estimate     SE
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level1    -0.116234 0.0812
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level2) -0.000319 0.0903
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level2    -0.109091 0.1117
##  (genderR-1 condition_3Level1) - (genderR-1 condition_3Level3)  0.046465 0.0896
##  (genderR-1 condition_3Level1) - genderR1 condition_3Level3    -0.059091 0.1117
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level2)     0.115915 0.0899
##  genderR1 condition_3Level1 - genderR1 condition_3Level2        0.007143 0.1115
##  genderR1 condition_3Level1 - (genderR-1 condition_3Level3)     0.162698 0.0892
##  genderR1 condition_3Level1 - genderR1 condition_3Level3        0.057143 0.1115
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level2    -0.108772 0.1182
##  (genderR-1 condition_3Level2) - (genderR-1 condition_3Level3)  0.046784 0.0975
##  (genderR-1 condition_3Level2) - genderR1 condition_3Level3    -0.058772 0.1182
##  genderR1 condition_3Level2 - (genderR-1 condition_3Level3)     0.155556 0.1177
##  genderR1 condition_3Level2 - genderR1 condition_3Level3        0.050000 0.1353
##  (genderR-1 condition_3Level3) - genderR1 condition_3Level3    -0.105556 0.1177
##   df t.ratio p.value
##  222  -1.431  1.0000
##  222  -0.004  1.0000
##  222  -0.976  1.0000
##  222   0.519  1.0000
##  222  -0.529  1.0000
##  222   1.289  1.0000
##  222   0.064  1.0000
##  222   1.823  1.0000
##  222   0.513  1.0000
##  222  -0.920  1.0000
##  222   0.480  1.0000
##  222  -0.497  1.0000
##  222   1.322  1.0000
##  222   0.370  1.0000
##  222  -0.897  1.0000
## 
## P value adjustment: bonferroni method for 15 tests

Mini Check-in

  1. What is a one-way ANOVA? How is it different from a factorial or two-way ANOVA?
  2. What is an interaction? How would you interpret an interaction?
  3. What kind of graph could I use to plot a one-way ANOVA?

Replicate Madalina’s Python code

m_df_og <- readxl::read_xlsx("data_ANOVA.xlsx")
m_df <- m_df_og %>% 
  group_by(partnum) %>% 
  dplyr::summarise(across(everything(), ~ mean(., na.rm = TRUE)) )%>% 
  ungroup()

head(m_df)
## # A tibble: 6 × 11
##   partnum RdeltaB pop_unpop sci_anec convincing  cond itemnum   age party
##     <dbl>   <dbl>     <dbl>    <dbl>      <dbl> <dbl>   <dbl> <dbl> <dbl>
## 1       0    1.91     0.5      0.531       46.1  1.56    15.5    18     1
## 2       1    2.09     0.469    0.375       53.4  1.22    15.5    19     2
## 3       2    5.34     0.656    0.469       48.0  1.59    15.5    18     1
## 4       3   -7.78     0.469    0.344        6    1.16    15.5    22     1
## 5       4    6.09     0.594    0.375       48.4  1.34    15.5    19     3
## 6       5   -1.34     0.469    0.469       46.1  1.41    15.5    20     3
## # ℹ 2 more variables: twitter <dbl>, trust <dbl>

One-way ANOVA

oneway_model <- afex::aov_car(RdeltaB ~ party + Error(partnum), 
              data = m_df) # original dataframe
## Converting to factor: party
## Contrasts set to contr.sum for the following variables: party
print(oneway_model)
## Anova Table (Type 3 tests)
## 
## Response: RdeltaB
##   Effect     df   MSE    F  ges p.value
## 1  party 2, 197 18.07 1.60 .016    .204
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1

Two-way ANOVA

# change to type = 2 to match python
twoway_model <- afex::aov_car(RdeltaB ~ party*twitter + Error(partnum),
                              type = "II",
                              data = m_df) 
## Converting to factor: party, twitter
## Contrasts set to contr.sum for the following variables: party, twitter
print(twoway_model)
## Anova Table (Type II tests)
## 
## Response: RdeltaB
##          Effect     df   MSE    F  ges p.value
## 1         party 2, 194 18.16 1.62 .016    .200
## 2       twitter 1, 194 18.16 0.49 .003    .486
## 3 party:twitter 2, 194 18.16 0.77 .008    .465
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1

Repeated Measures ANOVA

Here, I’m showing you two different ways to run a repeated measures ANOVA with the afex package. The first is the aov_car function, which takes a lm-style formula.

# within the Error statement, we're saying that within each partnum (ID), sci_anec and pop_unpop are repeated.

# remember this 'nesting' format. It will come up again when we run mixed models.

repeated_model1 <- afex::aov_car(RdeltaB ~ 1 + Error(partnum/(sci_anec*pop_unpop)),
                             data = m_df_og)

knitr::kable(nice(repeated_model1))
Effect df MSE F ges p.value
sci_anec 1, 199 48.66 6.82 ** .008 .010
pop_unpop 1, 199 43.98 10.27 ** .011 .002
sci_anec:pop_unpop 1, 199 31.68 0.93 <.001 .336



Now, we’re going to use a different function from the afex package called aov_ez. The only difference is that aov_ez takes character arguments (like you literally enter what your between and within variables are) instead of a formula.

repeated_model2 <- afex::aov_ez(id = "partnum", 
                             dv = "RdeltaB", 
                             within = c('sci_anec', 'pop_unpop'),
                             data = m_df_og) 

knitr::kable(nice(repeated_model2))
Effect df MSE F ges p.value
sci_anec 1, 199 48.66 6.82 ** .008 .010
pop_unpop 1, 199 43.98 10.27 ** .011 .002
sci_anec:pop_unpop 1, 199 31.68 0.93 <.001 .336
summary(repeated_model2)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                    Sum Sq num Df Error SS den Df F value    Pr(>F)    
## (Intercept)        4580.5      1  15779.3    199 57.7665 1.136e-12 ***
## sci_anec            331.7      1   9683.2    199  6.8166  0.009719 ** 
## pop_unpop           451.8      1   8751.2    199 10.2742  0.001572 ** 
## sci_anec:pop_unpop   29.5      1   6304.4    199  0.9309  0.335806    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

What about Mauchly’s test of sphericity?

Mauchly’s test of sphericity is only applicable when you have more than two levels in at least one of your within-participant (repeated measures) factors. This is because sphericity is a concept that applies to the variances of the differences between all combinations of levels within a factor. If a factor only has two levels, the assumption of sphericity is inherently met because there’s only one possible difference to consider, thus no variability in these differences across levels to test against.

library(ez)

mod<- ezANOVA(data = m_df_og, dv = .(RdeltaB), wid = .(partnum),
              within = .(sci_anec,pop_unpop),
              detailed = TRUE,
              type = 3)

mod
## $ANOVA
##               Effect DFn DFd       SSn      SSd          F           p p<.05
## 1           sci_anec   1 199 331.69405 9683.242  6.8166339 0.009718873     *
## 2          pop_unpop   1 199 451.81686 8751.161 10.2742429 0.001571558     *
## 3 sci_anec:pop_unpop   1 199  29.49055 6304.404  0.9308761 0.335806365      
##           ges
## 1 0.013230452
## 2 0.017935914
## 3 0.001190657

ANCOVA

ANOVA can be extended to include one or more continuous variables that predict the outcome. Continuous variables such as these, that are not part of the main experimental manipulation but have an influence on the dependent variable, are known as covariates and they can be included in an ANOVA analysis.

Why use ANCOVA?

To reduce within-group error variance: In the discussion of ANOVA and t-tests we got used to the idea that we assess the effect of an experiment by comparing the amount of variability in the data that the experiment can explain against the variability that it cannot explain. If we can explain some of this ‘unexplained’ variance (SSW) in terms of other variables (covariates), then we reduce the error variance, allowing us to more accurately assess the effect of the independent variable (SSB).

Elimination of confounds: In any experiment, there may be unmeasured variables that confound the results (i.e., variables other than the experimental manipulation that affect the outcome variable). If any variables are known to influence the dependent variable being measured, then ANCOVA is ideally suited to remove the bias of these variables. Once a possible confounding variable has been identified, it can be measured and entered into the analysis as a covariate.

Assumptions of the ANCOVA: (1) independence of the covariate and treatment effect and (2) homogeneity of regression slopes.

  1. Basically, we want to make sure that the covariate and the predictor are not related. In other words, you should have three variances: the variance that is explained by your predictor, the variance explained by the covariate, and unexplained variance. The variance explained by the covariate should not overlap with the variance explained by the predictor. When your groups differ on the covariate, putting it into the analysis will not ‘balance out the differences.’ (e.g., anxious vs non-anxious will likely differ in depression, so controlling for depression isn’t going to give you a ‘pure’ effect of anxiety).

  2. We assume that the relationship between the covariate and the outcome is the same across all groups because the slope is supposed to represent the average across groups. It assumes a linear slope. If the relationship is non-linear, you would need a different model.

Example with Viagra data

credit: Andy Field’s Discovering Statistics

Here, we want to know the effect of Viagra (none, low-dose, high-dose) on libido. However, we know that partner’s libido might impact our own libido. Therefore, we’ll need to adjust for partner’s libido.

v_df <- read.delim("ViagraCovariate.dat")

v_df$dose <- as.factor(v_df$dose)

Inspect the data

Test the independence of the covariate and predictor

contrasts(v_df$dose) <- contr.sum(3)

# is there a relationship between dose and partner libido?
test1 <- lm(partnerLibido ~ dose, data = v_df)

car::Anova(test1, type = "III")
## Anova Table (Type III tests)
## 
## Response: partnerLibido
##              Sum Sq Df F value    Pr(>F)    
## (Intercept) 234.592  1 72.7232 3.846e-09 ***
## dose         12.769  2  1.9793    0.1577    
## Residuals    87.097 27                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Check the slopes

v_df %>% 
  ggplot(aes(x=partnerLibido, y=libido, color=dose)) + # Map partnerLibido to x, libido to y, and dose to color
  geom_point() +  # Use geom_point for a scatter plot
  geom_smooth(method = "lm")

Homogeneity of variances

car::leveneTest(v_df$libido, v_df$dose)
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  2  0.3256 0.7249
##       27

Run the ANCOVA

v_model <- lm(libido ~ dose + partnerLibido, data = v_df)

car::Anova(v_model, type = "III")
## Anova Table (Type III tests)
## 
## Response: libido
##               Sum Sq Df F value    Pr(>F)    
## (Intercept)   76.069  1 25.0205 3.342e-05 ***
## dose          25.185  2  4.1419   0.02745 *  
## partnerLibido 15.076  1  4.9587   0.03483 *  
## Residuals     79.047 26                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
v_emm <- emmeans(v_model, specs = ~ dose)

print(v_emm)
##  dose emmean    SE df lower.CL upper.CL
##  1      2.93 0.596 26     1.70     4.15
##  2      4.71 0.621 26     3.44     5.99
##  3      5.15 0.503 26     4.12     6.18
## 
## Confidence level used: 0.95
contrasts(v_df$dose) <- contr.treatment(3)

# rerunning the model as dummy coded
v_model <- lm(libido ~ dose + partnerLibido, data = v_df)
summary(v_model)
## 
## Call:
## lm(formula = libido ~ dose + partnerLibido, data = v_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.2622 -0.7899 -0.3230  0.8811  4.5699 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)  
## (Intercept)     1.7892     0.8671   2.063   0.0492 *
## dose2           1.7857     0.8494   2.102   0.0454 *
## dose3           2.2249     0.8028   2.771   0.0102 *
## partnerLibido   0.4160     0.1868   2.227   0.0348 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.744 on 26 degrees of freedom
## Multiple R-squared:  0.2876, Adjusted R-squared:  0.2055 
## F-statistic:   3.5 on 3 and 26 DF,  p-value: 0.02954

What if I want to compare placebo vs low + high dose and low vs high?

contrasts(v_df$dose) <- cbind(c(-2,1,1), c(0,-1,1))

print(contrasts(v_df$dose)) #placebo, low dose, then high dose
##   [,1] [,2]
## 1   -2    0
## 2    1   -1
## 3    1    1

dose1: placebo vs treatment (low + high dose)
dose2: low vs high
How would you interpret partnerLibido?

v_model2 <- lm(libido ~ dose + partnerLibido, data = v_df)

summary(v_model2)
## 
## Call:
## lm(formula = libido ~ dose + partnerLibido, data = v_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.2622 -0.7899 -0.3230  0.8811  4.5699 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     3.1260     0.6250   5.002 3.34e-05 ***
## dose1           0.6684     0.2400   2.785  0.00985 ** 
## dose2           0.2196     0.4056   0.541  0.59284    
## partnerLibido   0.4160     0.1868   2.227  0.03483 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.744 on 26 degrees of freedom
## Multiple R-squared:  0.2876, Adjusted R-squared:  0.2055 
## F-statistic:   3.5 on 3 and 26 DF,  p-value: 0.02954

Post hoc tests

emm_v <- emmeans(v_model2, specs = pairwise ~ dose + partnerLibido, adjust = "Tukey")

emm_v$contrasts
##  contrast                                                                 
##  dose1 partnerLibido2.73333333333333 - dose2 partnerLibido2.73333333333333
##  dose1 partnerLibido2.73333333333333 - dose3 partnerLibido2.73333333333333
##  dose2 partnerLibido2.73333333333333 - dose3 partnerLibido2.73333333333333
##  estimate    SE df t.ratio p.value
##    -1.786 0.849 26  -2.102  0.1089
##    -2.225 0.803 26  -2.771  0.0266
##    -0.439 0.811 26  -0.541  0.8517
## 
## P value adjustment: tukey method for comparing a family of 3 estimates

Effect size

What’s the difference between eta squared and partial eta squared?

\[\eta^2 = \frac{SS_{effect}}{SS_{total}}\] Eta-squared represents the total variance explained by the effect, considering both that effect and any of its interactions.

\[ partial \ \eta^2 = \frac{SS_{effect}}{SS_{effect}+SS_{residual}}\] Partial eta-squared is the total variance explained by the effect that is not explained by other variables in the model

lsr::etaSquared(v_model2)
##                  eta.sq eta.sq.part
## dose          0.2269618   0.2416256
## partnerLibido 0.1358583   0.1601709

Contrasts effect sizes

\[ r_{contrast} = \sqrt \frac{t^2}{t^2 +df}\]

rcontrast <- function(t, df) {
  r <- sqrt(t^2/(t^2 + df))
  print(paste("r = ", r))
}

t <- c(2.785, 0.541, 2.227)
df <- 26

rcontrast(t, df)
## [1] "r =  0.47934506773475"  "r =  0.105506648839546" "r =  0.400242354364157"

The output shows that the effect of the covariate (.400) and the difference between the combined dose groups and the placebo (.479) both represent medium to large effect sizes (they’re both between .4 and .5). The difference between the high- and low-dose groups (.106) was a fairly small effect.


Testing the homogeneity of regression slopes

v_model_int <- lm(libido ~ dose + partnerLibido + dose:partnerLibido, #interaction term
                  data = v_df)

car::Anova(v_model_int, type = "3")
## Anova Table (Type III tests)
## 
## Response: libido
##                    Sum Sq Df F value    Pr(>F)    
## (Intercept)        53.542  1 21.9207 9.323e-05 ***
## dose               36.558  2  7.4836   0.00298 ** 
## partnerLibido      17.182  1  7.0346   0.01395 *  
## dose:partnerLibido 20.427  2  4.1815   0.02767 *  
## Residuals          58.621 24                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Uh oh… we violated that assumption. What now?


Your turn!

Make sure to inspect the data first for any assumption violations!

Q1: injury by superhero costume

  1. Superhero.dat : Children reporting to the emergency room had the severity of their injury (injury) assessed (on a scale from 0, no injury, to 100, death). In addition, a note was taken of which superhero costume they were wearing (hero): Spiderman, Superman, the Hulk or a Teenage Mutant Ninja Turtle. Test the hypotheses that different costumes are associated with more severe injuries. Make sure to run the levene’s test and compare the different costumes!

load data

sh_df <- read.delim("/Users/kareenadelrosario/Downloads/Superhero.dat")

glimpse(sh_df)
## Rows: 30
## Columns: 2
## $ hero   <int> 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, …
## $ injury <int> 51, 31, 58, 20, 47, 37, 49, 40, 69, 32, 85, 66, 58, 52, 26, 43,…

test for homogeneity of variance

# Run a levene's test
leveneTest(sh_df$injury, sh_df$hero)
## Warning in leveneTest.default(sh_df$injury, sh_df$hero): sh_df$hero coerced to
## factor.
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  3   0.827  0.491
##       26

run one-way ANOVA

Note that here, I’m taking the manual approach, but you can also run the afex code.

# make sure the predictor is coded correctly
sh_df$hero <- as.factor(sh_df$hero)
contrasts(sh_df$hero) <- contr.sum(4)

superModel <- lm(injury~hero, data = sh_df)
Anova(superModel, type = "3")
## Anova Table (Type III tests)
## 
## Response: injury
##             Sum Sq Df  F value    Pr(>F)    
## (Intercept)  49402  1 294.8311 1.048e-15 ***
## hero          4181  3   8.3166 0.0004828 ***
## Residuals     4357 26                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

afex option

if you decide to use aov_car, note that you’ll need an ID variable

# create id variable for error term
sh_df_afex <- sh_df %>% 
  dplyr::mutate(id = row_number())

# make sure the predictor is coded correctly
afex::aov_car(injury~hero + Error(id), data = sh_df_afex)
## Contrasts set to contr.sum for the following variables: hero
## Anova Table (Type 3 tests)
## 
## Response: injury
##   Effect    df    MSE        F  ges p.value
## 1   hero 3, 26 167.56 8.32 *** .490   <.001
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1

Compare injury by costume

sh_emm <- emmeans(superModel, specs = ~ hero)

print(sh_emm)
##  hero emmean   SE df lower.CL upper.CL
##  1      41.6 4.58 26     32.2     51.0
##  2      60.3 5.28 26     49.5     71.2
##  3      35.4 4.58 26     26.0     44.8
##  4      26.2 4.58 26     16.8     35.7
## 
## Confidence level used: 0.95

Bonferroni pairwise comparisons

pairs(sh_emm) %>% rbind()
##  contrast      estimate   SE df t.ratio p.value
##  hero1 - hero2   -18.71 6.99 26  -2.676  0.0763
##  hero1 - hero3     6.25 6.47 26   0.966  1.0000
##  hero1 - hero4    15.38 6.47 26   2.376  0.1511
##  hero2 - hero3    24.96 6.99 26   3.570  0.0085
##  hero2 - hero4    34.08 6.99 26   4.875  0.0003
##  hero3 - hero4     9.12 6.47 26   1.410  1.0000
## 
## P value adjustment: bonferroni method for 6 tests

Q2: Hangover cure?

  1. HangoverCure.dat : A marketing manager for a certain well-known drinks manufacturer was interested in the therapeutic benefit of certain soft drinks for curing hangovers. He took 15 people out on the town one night and got them drunk. The next morning as they awoke, dehydrated and feeling as though they’d licked a camel’s sandy feet clean with their tongue, he gave five of them water to drink, five of them Lucozade (in case this isn’t sold outside the UK, it’s a very nice glucose-based drink) and the remaining five a leading brand of cola (this variable is called drink). He then measured how well they felt (on a scale from 0 = I feel like death to 10 = I feel really full of beans and healthy) two hours later (this variable is called well). He wanted to know which drink produced the greatest level of wellness. However, he realized it was important to control for how drunk the person got the night before, and so he measured this on a scale from 0 = as sober as a nun to 10 = flapping about like a haddock out of water on the floor in a puddle of their own vomit. The data are in the file HangoverCure. dat. Test whether people felt better after different drinks when controlling for how drunk they were the night before.

read data

hc_df <- read.delim("/Users/kareenadelrosario/Downloads/HangoverCure.dat", header = T)

glimpse(hc_df)
## Rows: 15
## Columns: 3
## $ drink <int> 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3
## $ well  <int> 5, 5, 6, 6, 3, 5, 4, 6, 8, 6, 5, 6, 6, 6, 6
## $ drunk <int> 5, 3, 2, 1, 7, 6, 6, 4, 2, 3, 2, 3, 2, 3, 2
hc_df$drink <- factor(hc_df$drink, levels = c(1:3), labels = c("Water",
"Lucozade", "Cola"))

Does the type of drink you have the next day predict how well you feel?

oneway_hc <- lm(well ~ drink, data = hc_df)
Anova(oneway_hc, type = "3")
## Anova Table (Type III tests)
## 
## Response: well
##              Sum Sq Df F value    Pr(>F)    
## (Intercept) 125.000  1 96.1538 4.425e-07 ***
## drink         2.133  2  0.8205    0.4635    
## Residuals    15.600 12                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

homogeneity of variance

we want to do a Levene’s test to see whether the variance in well (how well the person feels) varies across the interaction of different types of drinks (drink) and how drunk the person was the night before (drunk). To do this we can execute:

leveneTest(hc_df$well, interaction(hc_df$drink, hc_df$drunk))
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group 10    0.34 0.9242
##        4

assumption: independence of covariate vs predictor

checkIND <- aov(drunk ~ drink, data = hc_df)

Anova(checkIND, type = "3")
## Anova Table (Type III tests)
## 
## Response: drunk
##             Sum Sq Df F value    Pr(>F)    
## (Intercept)   64.8  1 20.9032 0.0006412 ***
## drink          8.4  2  1.3548 0.2947600    
## Residuals     37.2 12                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

If we control for how drunk you got, does the type of drink you have the next day predict how well you feel?

contrasts(hc_df$drink) <- contr.sum(3)

ancova_hc <- lm(well ~ drink + drunk, data = hc_df)
Anova(ancova_hc, type = "3")
## Anova Table (Type III tests)
## 
## Response: well
##              Sum Sq Df  F value    Pr(>F)    
## (Intercept) 145.006  1 361.4557 9.197e-10 ***
## drink         3.464  2   4.3177   0.04130 *  
## drunk        11.187  1  27.8860   0.00026 ***
## Residuals     4.413 11                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Regression output

contrasts(hc_df$drink) <- contr.treatment(3)

ancova_hc2 <- lm(well ~ drink + drunk, data = hc_df)
summary(ancova_hc2)
## 
## Call:
## lm(formula = well ~ drink + drunk, data = hc_df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.01935 -0.37742 -0.01935  0.35806  0.99355 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   6.9742     0.4690  14.869 1.25e-08 ***
## drink2        1.1290     0.4054   2.785  0.01775 *  
## drink3        0.1419     0.4195   0.338  0.74149    
## drunk        -0.5484     0.1038  -5.281  0.00026 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6334 on 11 degrees of freedom
## Multiple R-squared:  0.7512, Adjusted R-squared:  0.6833 
## F-statistic: 11.07 on 3 and 11 DF,  p-value: 0.001193

Testing homogeneity of regression slopes

If the interaction is significant, we need to run a two-way ANOVA (this) and not ANCOVA.

ancova_hc3 <- update(ancova_hc, .~. + drink:drunk)
Anova(ancova_hc3, type = "III")
## Anova Table (Type III tests)
## 
## Response: well
##             Sum Sq Df  F value    Pr(>F)    
## (Intercept) 59.295  1 194.1961 2.134e-07 ***
## drink        3.376  2   5.5278  0.027166 *  
## drunk        5.216  1  17.0812  0.002548 ** 
## drink:drunk  1.665  2   2.7263  0.118668    
## Residuals    2.748  9                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
LS0tCnRpdGxlOiAiVXNpbmcgY29udHJhc3QgY29kaW5nIHRvIHVuZGVyc3RhbmQgQU5PVkEgaW4gUiIKYXV0aG9yOiAiS2FyZWVuYSBkZWwgUm9zYXJpbyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogcmVhZGFibGUKICAgIGhpZ2hsaWdodDogYXJyb3cKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCmBgYAoKCkluIHRoaXMgZGF0YXNldCwgcGFydGljaXBhbnRzIGFyZSBhc3NpZ25lZCB0byAxIG9mIDMgY29uZGl0aW9uczoKCjEuIENvbnRyb2wgY29uZGl0aW9uIChyZWNhbGxlZCBhIG5ldXRyYWwgZXZlbnQpCjIuIFNhZCBhY3RvciAocmVjYWxsZWQgYSBzYWQgZXZlbnQpCjMuIFNhZCBwYXJ0bmVyIChyZWNhbGxlZCBhIG5ldXRyYWwgZXZlbnQgYnV0IHdhcyBwYWlyZWQgd2l0aCB0aGUgc2FkIGFjdG9yKQoKVGhlc2UgZGF0YSBhcmUgZHlhZGljLCBidXQgZm9yIHRoZSBzYWtlIG9mIHRoaXMgdHV0b3JpYWwsIHdlJ3JlIGdvaW5nIHRvIGlnbm9yZSB0aGF0IGFuZCB0cmVhdCBwYXJ0aWNpcGFudHMgYXMgaW5kZXBlbmRlbnQuCgojIyMjIExvYWQgdGhlIGRhdGEgJiBsaWJyYXJpZXMKCmBgYHtyLCBsb2FkIGRhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpwa2dzIDwtIGMoInRpZHl2ZXJzZSIsICJkcGx5ciIsICJoYXZlbiIsICJmb3JlaWduIiwgImxtZTQiLCAicGx5ciIsICJubG1lIiwgImxzciIsICJlbW1lYW5zIiwgImFmZXgiLCAia25pdHIiLCAia2FibGVFeHRyYSIsICJjYXIiKQoKcGFja2FnZXMgPC0gcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpCnBfdG9faW5zdGFsbCA8LSBwa2dzWyEocGtncyAlaW4lIHBhY2thZ2VzKV0KCmlmKGxlbmd0aChwX3RvX2luc3RhbGwpID4gMCl7CiAgaW5zdGFsbC5wYWNrYWdlcyhwX3RvX2luc3RhbGwpCn0KCmxhcHBseShwa2dzLCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCgpnZXR3ZCgpCiMgTG9hZCBkYXRhCmRmPC0gcmVhZF9zYXYoImxhYjVfYW5vdmFfY29udHJhc3RzLnNhdiIpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoqKlN0dWR5IERlc2lnbjoqKgotIFBhcnRpY2lwYW50cyBjb21wbGV0ZWQgYW4gZW1vdGlvbiBpbmR1Y3Rpb24gKHJlY2FsbCBlaXRoZXIgYSBzYWQgb3IgbmV1dHJhbCBldmVudCkgYW5kIHRoZW4gaW50ZXJhY3RlZCB3aXRoIGEgc3RyYW5nZXIgd2hlcmUgdGhleSBhc2tlZCBlYWNoIG90aGVyIHF1ZXN0aW9ucyB0byBnZXQgYWNxdWFpbnRlZC4gCgoqKlRlc3RhYmxlIHJlc2VhcmNoIHF1ZXN0aW9uOioqCi0gSSB3YW50IHRvIGtub3c6IERvIHBlb3BsZSBmZWVsIG1vcmUgKG9yIGxlc3MpIHNhZCBhZnRlciBpbnRlcmFjdGluZyB3aXRoIGEgc2FkIHBlcnNvbj8gQXJlIHRoZXJlIGNoYW5nZXMgaW4gaG93IHNhZCB0aGF0IHNhZCBpbmRpdmlkdWFsIGZlZWxzIGFmdGVyIHRoZSBpbnRlcmFjdGlvbj8gRG9lcyB0aGlzIHZhcnkgYnkgZ2VuZGVyPwoKKipQcmVkaWN0b3JzOioqCi0gQ29uZGl0aW9uIChjb250cm9sIHggc2FkIGFjdG9yIHggc2FkIHBhcnRuZXIpCi0gR2VuZGVyIChmZW1hbGUgeCBtYWxlKQoKKipPdXRjb21lOioqCi0gUG9zdC1pbnRlcmFjdGlvbiBzYWRuZXNzICgxLSBub3QgYXQgYWxsIHRvIDctIGEgZ3JlYXQgZGVhbCkKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBBTk9WQSB3aXRoIG5vIGRhdGEgcHJlcCBvciBwcmUtYW5hbHlzZXMKCkZpcnN0IG9mZiwgSSBkb24ndCBsaWtlIGFvdigpLiBUaGUgc3VtbWFyeSBmdW5jdGlvbiB3aXRoIGFvdigpIGdpdmVzIHVzIHRoZSBvbW5pYnVzIHJlc3VsdHMgd2l0aCB0eXBlID0gMSwgc28gd2UnZCBoYXZlIHRvIHVzZSBBbm92YSBmcm9tIHRoZSBjYXIgcGFja2FnZSBhbnl3YXkuIFRoYXQgc2FpZCwgd2UncmUgZ29pbmcgdG8gdXNlIGxtKCkuIEkgcHJvbWlzZSwgdGhleSBhcmUgZG9pbmcgdGhlIHNhbWUgdGhpbmcsIHRoZXkganVzdCBwcmVzZW50IGRpZmZlcmVudCBvdXRwdXQgd2hlbiB5b3UgdXNlIHN1bW1hcnkoKS4KCmBgYHtyLCBhbm92YSBubyBwcmVwfQpmaXQgPC0gbG0oYXZnX3NhZF9pbnQgfiBnZW5kZXJSKmNvbmRpdGlvbl8zTGV2ZWwsIGRhdGEgPSBkZikKY2FyOjpBbm92YShmaXQsIHR5cGUgPSAiSUlJIikKYGBgCgpgYGB7ciwgc3BzcyBvbW5pYnVzMSwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSc4MCUnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnc3Bzc19vbW5pYnVzLnBuZycpCmBgYAoKIyMgV2h5IGRvbid0IHRoZXNlIG1hdGNoPwoKCgpXaHkgYXJlIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gZGlmZmVyZW50PyBXaGF0IGRvZXMgdGhpcyB0ZWxsIHVzPwoKCl9fX19fX19fX18KCiMjIyBMZXQncyBmaXJzdCBjaGVjayB0aGF0IHRoZSB2YXJpYWJsZXMgYXJlIGluIHRoZSBjb3JyZWN0IGNsYXNzLiAKCldlJ3JlIGxvb2tpbmcgYXQgY29uZGl0aW9uXzNMZXZlbCwgZ2VuZGVyUiwgYW5kIGF2Z19zYWRfaW50LgoKCmBgYHtyfQpnbGltcHNlKGRmKQpgYGAKUHJlZGljdG9yczoKCi0gY29uZGl0aW9uXzNMZXZlbDogMSwgMiwgMwotIGdlbmRlclI6IC0xLCAxCgojIyMgQ2hhbmdlIHZhcmlhYmxlIGNsYXNzCmBgYHtyfQpkZi5mIDwtIGRmICU+JSAKICBtdXRhdGUoY29uZGl0aW9uXzNMZXZlbCA9IGFzLmZhY3Rvcihjb25kaXRpb25fM0xldmVsKSwKICAgICAgICAgZ2VuZGVyUiA9IGFzLmZhY3RvcihnZW5kZXJSKSkKCiMgY2hlY2sgY2xhc3MKY2xhc3MoZGYuZiRjb25kaXRpb25fM0xldmVsKQpjbGFzcyhkZi5mJGdlbmRlclIpCmBgYAoKIyMgTm93LCBsZXQncyByZXJ1biB0aGUgbW9kZWwgd2l0aCBjYXRlZ29yaWNhbCBwcmVkaWN0b3JzCgpgYGB7ciwgYW5vdmEgMiB3aXRoIGNhdGVnb3JpY2FsfQpmaXQyIDwtIGxtKGF2Z19zYWRfaW50IH4gZ2VuZGVyUipjb25kaXRpb25fM0xldmVsLCBkYXRhID0gZGYuZikKY2FyOjpBbm92YShmaXQyLCB0eXBlID0gIklJSSIpCmBgYApgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzgwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdzcHNzX29tbmlidXMucG5nJykKYGBgCgoKSXQgc3RpbGwgZG9lc24ndCBtYXRjaC4gV2hhdCBlbHNlIGNvdWxkIGJlIGdvaW5nIG9uPwoKCldoYXQgZG9lcyB0aGUgb21uaWJ1cyB0ZXN0IHRlbGwgdXM/CgoKLS0tLS0tLS0tLS0tCgojIFdoYXQgaXMgQU5PVkE/CgpUaGUgRi1yYXRpbyByZXByZXNlbnRzIGhvdyBnb29kIHRoZSBtb2RlbCBpcyByZWxhdGl2ZSB0byBob3cgYmFkIGl0IGlzLiBJbiBvdGhlciB3b3JkcywgaXQgaXMgdGhlIHJhdGlvIG9mIGV4cGxhaW5lZCB2YXJpYW5jZSB0byB1bmV4cGxhaW5lZCB2YXJpYW5jZS4KCkluIEFOT1ZBLCB3ZSdyZSBhc2tpbmc6IGlzIHByZWRpY3Rpbmcgc2NvcmVzIGZyb20gdGhlIGdyb3VwIG1lYW5zIGJldHRlciB0aGFuIHByZWRpY3Rpbmcgc2NvcmVzIGZyb20gdGhlIGdyYW5kIG1lYW4/IEFyZSB0aGUgZ3JvdXBzJyBvdXRjb21lcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXI/CgpUaGUgZXF1YXRpb25zIHdpbGwgYmUgdmFyaWF0aW9ucyBvZiBvbmUgYmFzaWMgZXF1YXRpb246CgokJGRldmlhdGlvbiA9IFxzdW0ob2JzZXJ2ZWQtbW9kZWwpXjIkJAoKIyMjIFRvdGFsIFN1bSBvZiBTcXVhcmVzIChTU1QpCgpUaGlzIGlzIHRoZSB0b3RhbCBhbW91bnQgb2YgdmFyaWF0aW9uIGluIG91ciBkYXRhLiBJdCdzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG9ic2VydmVkIGRhdGEgcG9pbnQgYW5kIHRoZSBncmFuZCBtZWFuLiBUaGVuIHdlIHNxdWFyZSB0aGVzZSBkaWZmZXJlbmNlcyBhbmQgYWRkIHRoZW0gdG9nZXRoZXIuCgpJdCdzIHRoZSAiZ3JhbmQgdmFyaWFuY2UiIG9yIHRoZSB2YXJpYW5jZSBpbiByZXNwb25zZXMgcmVnYXJkbGVzcyBvZiBncm91cC4KCiQkU1NUID0gXHN1bV5OX3tpPTF9KFlfaS1cb3ZlcmxpbmV7WX0pXjIkJAoKJCRZX2lcIHJlcHJlc2VudHNcIGVhY2ggXCBpbmRpdmlkdWFsXCAgb2JzZXJ2YXRpb24uICQkCiQkXG92ZXJsaW5le1l9IFwgaXMgXCB0aGVcIGdyYW5kXCBtZWFuLiAkJAokJE5cIGlzXCB0aGVcIHRvdGFsIFwgbnVtYmVyXCBvZlwgb2JzZXJ2YXRpb25zLiAkJAoKIyMjIEJldHdlZW4tR3JvdXAgU3VtIG9mIFNxdWFyZXMgKFNTQikKKGFrYSBtb2RlbCBzdW0gb2Ygc3F1YXJlcykKCkhvdyBtdWNoIG9mIHRoZSB2YXJpYXRpb24gY2FuIHRoZSBtb2RlbCBleHBsYWluPyBJbiBzaW1wbGUgdGVybXMsIGl0J3MgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHByZWRpY3RlZCB2YWx1ZXMgYW5kIHRoZSBncmFuZCBtZWFuLgoKJCRTU0IgPSBcc3VtXmtfe2o9MX1uX2ooXG92ZXJsaW5le1l9X2otXG92ZXJsaW5le1l9KV4yJCQKCiQkXG92ZXJsaW5le1l9X2pcIGlzXCB0aGUgXCBtZWFuXCBvZlwgZ3JvdXBcIGouICQkCgoKJCRuX2ogXCBpcyBcIHRoZVwgbnVtYmVyXCBtZWFuXCBvZlwgb2JzZXJ2YXRpb25zXCBpblwgZ3JvdXBcIGouICQkCgoKJCRrXCBpc1wgdGhlXCB0b3RhbCBcIG51bWJlclwgb2ZcIGdyb3Vwcy4gJCQKCiMjIyBXaXRoaW4tR3JvdXAgU3VtIG9mIFNxdWFyZXMgKFNTVykKKGFrYSByZXNpZHVhbCBzdW0gb2Ygc3F1YXJlcykKClRoaXMgaXMgdGhlIHZhcmlhbmNlIHdpdGhpbiBlYWNoIGdyb3VwLiBTbyBob3cgbXVjaCBvZiB0aGUgdmFyaWFuY2UgaXMgbm90IGR1ZSB0byBncm91cCBkaWZmZXJlbmNlcywgYnV0IGluc3RlYWQgZHVlIHRvIGV4dHJhbmVvdXMgZmFjdG9ycyBsaWtlIGluZGl2aWR1YWwgZGlmZmVyZW5jZXM/IEluIG90aGVyIHdvcmRzLCB0aGlzIGlzIHRoZSB2YXJpYW5jZSB0aGF0ICpjYW5ub3QqIGJlIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwuCgokJFNTVyA9XHN1bV57bn1fe2k9MX0oe1l9X3tpan0tXG92ZXJsaW5le1l9X2opXjIkJAoKJCR7WX1fe2lqfVwgcmVwcmVzZW50c1wgZWFjaCBcIG9ic2VydmF0aW9uXCBpblwgZ3JvdXBcIGouICQkCgoqKkluIHNob3J0LCBTU0IgdGVsbHMgdXMgaG93IG11Y2ggdmFyaWF0aW9uIGlzIGR1ZSB0byB0aGUgbW9kZWwgYW5kIFNTVyB0ZWxscyB1cyBob3cgbXVjaCB2YXJpYXRpb24gY2Fubm90IGJlIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwgKGVycm9yKSoqCgoKIyMjIE1lYW4gU3F1YXJlcwoKT25lIGlzc3VlIHdpdGggdGhhdCBmb3JtdWxhIGlzIGJlY2F1c2UgdGhlIHZhbHVlcyBhcmUgc3VtbWVkIHZhbHVlcywgdGhleSB3aWxsIGJlIGluZmx1ZW5jZWQgYnkgdGhlIHRvdGFsIG51bWJlciBvZiBzY29yZXMgc3VtbWVkLiBUbyBnZXQgcmlkIG9mIHRoaXMgYmlhcywgd2UgY2FsY3VsYXRlIHRoZSBtZWFuIHNxdWFyZXMsIHdoaWNoIGlzIHRoZSBhdmVyYWdlIHN1bSBvZiBzcXVhcmVzIChTUyBkaXZpZGVkIGJ5IGRmKS4KCgojIyMjIE1lYW4gU3F1YXJlcyBCZXR3ZWVuCgpUaGlzIGlzIHRoZSBhdmVyYWdlIGFtb3VudCBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsLgoKJCRNU0IgPSBcZnJhY3tTU0J9e2RmX0J9ICQkCgoKIyMjIyBNZWFuIFNxdWFyZXMgV2l0aGluCgpUaGlzIGlzIHRoZSBhdmVyYWdlIGFtb3VudCBvZiB2YXJpYW5jZSAqKm5vdCoqIGV4cGxhaW5lZCBieSB0aGUgbW9kZWwuCgokJE1TVyA9IFxmcmFje1NTV317ZGZfV30gJCQKCiMjIyBGLXN0YXRpc3RpYwoKVGhpcyBpcyB0aGUgcmF0aW8gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IHRoZSBtb2RlbCAoc3lzdGVtYXRpYyB2YXJpYW5jZSkgdG8gdGhlIHZhcmlhbmNlIG5vdCBleHBsYWluZWQgYnkgdGhlIG1vZGVsICh1bnN5c3RlbWF0aWMgdmFyaWFuY2UpCgpJZiB0aGUgRiBpcyBhYm92ZSAxLCB0aGF0IHRlbGxzIHVzIHRoYXQgdGhlcmUgd2FzIHNvbWUgZWZmZWN0IG9mIHRoZSBwcmVkaWN0b3IgYWJvdmUgYW5kIGJleW9uZCB0aGUgaW5kaXZpZHVhbCBkaWZmZXJlbmNlcyB0aGF0IGNvdWxkIGV4cGxhaW4gdGhlIG91dGNvbWUgKGJ1dCwgdGhpcyBkb2Vzbid0IHRlbGwgdXMgaWYgaXQncyBzaWduaWZpY2FudC4gSnVzdCB0aGUgZGlyZWN0aW9uKS4KCklmIHRoZSBGIGlzIGJlbG93IDEsIHlvdSBrbm93IHRoYXQgdGhlcmUncyBtb3JlIGVycm9yIGluIHRoZSBtb2RlbCB0aGFuIHN5c3RlbWF0aWMgdmFyaWFuY2UuCgokJEYgPSBcZnJhY3tNU0J9e01TV30gJCQKCioqdGxkcjsgdGhlIEYtc3RhdGlzdGljIHRlbGxzIHVzIHdoZXRoZXIgb3VyIG1vZGVsIGZpdHRlZCB0byB0aGUgZGF0YSBhY2NvdW50cyBmb3IgbW9yZSB2YXJpYXRpb24gKGdvb2QpIHRoYW4gZXh0cmFuZW91cyBmYWN0b3JzIChiYWQpLCBidXQgaXQgZG9lc24ndCB0ZWxsIHVzIHdoZXJlIHRoZXNlIGRpZmZlcmVuY2VzIGJldHdlZW4gZ3JvdXBzIGFyZS4qKiAKCkZvciBleGFtcGxlLCBpZiB3ZSdyZSBsb29raW5nIGF0IGRpZmZlcmVuY2VzIGluIHNsZWVwIHF1YWxpdHkgYnkgcmFjZSBhbmQgd2UgZ2V0IGEgc2lnbmlmaWNhbnQgZWZmZWN0LCB0aGF0IHRlbGxzIHVzIHRoYXQgZGlmZmVyZW50IHJhY2VzIGRvIHJlcG9ydCBkaWZmZXJlbmNlcyBpbiBzbGVlcCBxdWFsaXR5IChyZWxhdGl2ZSB0byB0aGUgZ3JhbmQgbWVhbikuIEhvd2V2ZXIsIGl0IGRvZXMgbm90IHRlbGwgdXMgd2hpY2ggcmFjZXMgc2xlZXAgYmV0dGVyIG9yIHdvcnNlIHRoYW4gZWFjaCBvdGhlci4KCgojIyBTUyBUeXBlcwoKSW1hZ2luZSB3ZSdyZSB0ZXN0aW5nIHRoZSBlZmZlY3Qgb2YgdmFyaW91cyBoZWFsdGggYmVoYXZpb3JzIChkaWV0LCBzbGVlcCkgb24gbW9vZC4gCgojIyMjIFR5cGUgSSBTdW1zIG9mIFNxdWFyZXMKClRoaXMgYXBwcm9hY2ggaXMgdXNlZnVsIGlmIHdlIHRoaW5rIHRoZSBzZXF1ZW5jZSBtYXR0ZXJzLCBsaWtlIGlmIHdlIGJlbGlldmUgc2xlZXAgbmVlZHMgdG8gYmUgY29uc2lkZXJlZCBiZWZvcmUgZGlldC4gVGVsbHMgdXMgdGhlIHN0b3J5IGluIHNlcXVlbmNlIChmaXJzdCBzbGVlcCwgdGhlbiBkaWV0KSBhbmQgaG93IGVhY2ggc3RlcCBhZGRzIHRvIG1vb2QuCgojIyMjIFR5cGUgSUkgU3VtIG9mIFNxdWFyZXMKCk5vdywgbGV0J3Mgc2F5IHdlIHdhbnQgdG8gdW5kZXJzdGFuZCB0aGUgdW5pcXVlIGltcGFjdCBvZiBkaWV0IG9uIG1vb2QsIGlnbm9yaW5nIHdoZXRoZXIgb3Igbm90IHRoZXkncmUgc2xlZXBpbmcgd2VsbCwgYW5kIHZpY2UgdmVyc2EuIFR5cGUgSUkgc3VtcyBvZiBzcXVhcmVzIGZvY3VzIG9uIHRoZSBpbmRpdmlkdWFsIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIGZhY3RvciB3aXRob3V0IG1peGluZyB0aGVtIHVwLiBJdCdzIGxpa2UgZXZhbHVhdGluZyB0aGUgaW5mbHVlbmNlIG9mIGRpZXQgYW5kIHNsZWVwIHNlcGFyYXRlbHksIGFzc3VtaW5nIHRoZXkgZG9uJ3QgaW50ZXJhY3QuCgojIyMjIFR5cGUgSUlJIFN1bSBvZiBTcXVhcmVzCgpMYXN0bHksIHdlIGNvbnNpZGVyIHRoZSBzY2VuYXJpbyB3aGVyZSB3ZSB3YW50IHRvIHVuZGVyc3RhbmQgdGhlIGluZmx1ZW5jZSBvZiBkaWV0IGFuZCBzbGVlcCBvbiBtb29kLCBpbmNsdWRpbmcgaG93IHRoZXkgbWlnaHQgaW50ZXJhY3QgKGUuZy4sIGRvZXMgdGhlIGltcGFjdCBvZiBkaWV0IGRlcGVuZCBvbiB3aGV0aGVyIHRoZXkgc2xlcHQgd2VsbD8pLiBUeXBlIElJSSBzdW1zIG9mIHNxdWFyZXMgbGV0IHVzIHNlZSB0aGUgZnVsbCBwaWN0dXJlLCBjb25zaWRlcmluZyBhbGwgcG9zc2libGUgaW50ZXJhY3Rpb25zLiBUaGlzIGlzIGJlc3Qgd2hlbiBvdXIgZXhwZXJpbWVudCBpcyBjb21wbGV4IChlLmcuLCBncm91cCBzaXplcyB2YXJ5LCBvciB3ZSBleHBlY3QgdGhhdCB0aGUgZmFjdG9ycyBtaWdodCBhZmZlY3QgZWFjaCBvdGhlcikuIAoKSSBvbmx5IGV2ZXIgdXNlIFR5cGUgSUlJLgoKLS0tLS0tCgojIERldG91ciBpbnRvIGNvbnRyYXN0IGNvZGluZwoKT3VyIG1haW4gdGFrZWF3YXkgZnJvbSBBTk9WQSBpcyB0aGF0IHRoZSBvbW5pYnVzIGxvb2tzIGF0IHRoZSBlZmZlY3Qgb2YgdGhlIHByZWRpY3RvcihzKSByZWxhdGl2ZSB0byB0aGUgZ3JhbmQgbWVhbiAob3IgdGhlIERWIHdoZW4gdGhlIHByZWRpY3RvcnMgYXJlIGF0IHRoZWlyIGF2ZXJhZ2UgbGV2ZWwpLiBXaXRoIHRoYXQgaW4gbWluZCwgd2UgbmVlZCB0byBtYWtlIHN1cmUgb3VyIHZhcmlhYmxlcyBhcmUgYWN0dWFsbHkgY29kZWQgaW4gdGhhdCB3YXkuCgpDb250cmFzdCBjb2RpbmcgaXMgYSB3YXkgdG8gY29tcGFyZSBkaWZmZXJlbnQgbGV2ZWxzL2dyb3VwcyBvZiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBUaGUgbW9zdCBjb21tb24gY29udHJhc3RzIGFyZSBkdW1teSBjb2RpbmcgYW5kIGVmZmVjdHMgY29kaW5nLgoKIyMjIER1bW15IGNvZGluZwoKVGhpcyBpcyB0aGUgbW9zdCBjb21tb24gZm9ybSBvZiBjb250cmFzdCBjb2RpbmcuIEluIGR1bW15IGNvZGluZywgb25lIGxldmVsIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpcyBjaG9zZW4gYXMgYSByZWZlcmVuY2UgZ3JvdXAuIEZvciBleGFtcGxlLCBpZiB5b3UgaGF2ZSBhIHZhcmlhYmxlICJSYWNlIiB3aXRoIHRocmVlIGxldmVscyAoV2hpdGUsIEJsYWNrLCBBc2lhbiksIHlvdSBjYW4gY3JlYXRlIHR3byBkdW1teSB2YXJpYWJsZXM6IHRoZSBlZmZlY3Qgb2YgYmVpbmcgQmxhY2sgYW5kIHRoZSBlZmZlY3Qgb2YgYmVpbmcgQXNpYW4uIFRoZSByZWZlcmVuY2UgZ3JvdXAgKFdoaXRlKSBnZXRzIGNvZGVkIGFzIDAgaW4gYm90aCBuZXcgdmFyaWFibGVzLiBUaGUgaW50ZXJjZXB0IHJlcHJlc2VudHMgdGhlIG1lYW4gb3V0Y29tZSBmb3IgdGhlIHJlZmVyZW5jZSBncm91cC4gCgpXaGl0ZSA9IDEKQmxhY2sgPSAyCkFzaWFuID0gMwoKCnwgUmFjZSAgfCBEdW1teTEgfCBEdW1teTIgfAp8LS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0tLXwKfCBXaGl0ZSB8IDAgICAgICB8IDAgICAgICB8CnwgQmxhY2sgfCAxICAgICAgfCAwICAgICAgfAp8IEFzaWFuIHwgMCAgICAgIHwgMSAgICAgIHwKCnwgRHVtbXkgMTogb3V0Y29tZSBmb3IgQmxhY2sgcGFydGljaXBhbnRzIHZzIHJlZmVyZW5jZSAoV2hpdGUpCnwgRHVtbXkgMjogb3V0Y29tZSBmb3IgQXNpYW4gcGFydGljaXBhbnRzIHZzIHJlZmVyZW5jZSAoV2hpdGUpCnwgSW50ZXJjZXB0ID0gYXZlcmFnZSBzbGVlcCBxdWFsaXR5IHdoZW4gcHJlZGljdG9yIGlzIHplcm8gKHNsZWVwIGZvciBXaGl0ZSBwYXJ0aWNpcGFudHMpCgojIyMgRWZmZWN0cyBjb2RpbmcKClVubGlrZSBkdW1teSBjb2RpbmcsIHdoZXJlIHRoZSByZWZlcmVuY2UgY2F0ZWdvcnkgaXMgcmVwcmVzZW50ZWQgYnkgYWxsIDAncywgZWZmZWN0cyBjb2RpbmcgZG9lc24ndCBsZWF2ZSBvdXQgb25lIGNhdGVnb3J5IGFzIHRoZSByZWZlcmVuY2UuIEluc3RlYWQsIGNhdGVnb3JpZXMgYXJlIGNvZGVkIHdpdGggbnVtYmVycyB0aGF0IGJhbGFuY2Ugb3V0LCBzdWNoIHRoYXQgdGhlIHN1bSBvZiBjb2RlcyBmb3IgZWFjaCBjYXRlZ29yaWNhbCBsZXZlbCBhY3Jvc3MgYWxsIGNvZGVkIHZhcmlhYmxlcyBlcXVhbHMgemVyby4gVGhpcyBiYWxhbmNlIGFsbG93cyB0aGUgbW9kZWwncyBpbnRlcmNlcHQgdG8gcmVwcmVzZW50IHRoZSBncmFuZCBtZWFuLiBZb3Ugd291bGQgdXNlIHRoaXMgY29kaW5nIHNjaGVtZSBpZiB5b3Ugd2FudGVkIHRvIGNvbXBhcmUgdGhlIG1lYW4gb2YgZWFjaCBncm91cCB0byB0aGUgZ3JhbmQgbWVhbi4gVGhlIHJlZmVyZW5jZSBncm91cCBnZXRzIC0xIGZvciBib3RoIGVmZmVjdHMuCgpUaGUgc3VtIG9mIHlvdXIgY29udHJhc3RzIHNob3VsZCA9IDAuCgp8IFJhY2UgIHxFZmZlY3QxIHxFZmZlY3QyIHwKfDotLS0tLS18Oi0tLS0tLS18Oi0tLS0tLS18CnwgV2hpdGUgfCAxICAgICAgfCAwICAgICAgfAp8IEJsYWNrIHwgMCAgICAgIHwgMSAgICAgIHwKfCBBc2lhbiB8IC0xICAgICB8IC0xICAgICB8CgoKfCBFZmZlY3QgMTogY29tcGFyZXMgdGhlIGVmZmVjdCBvZiBXaGl0ZSB0byB0aGUgb3ZlcmFsbCBtZWFuCnwgRWZmZWN0IDI6IGNvbXBhcmVzIHRoZSBlZmZlY3Qgb2YgQmxhY2sgdG8gdGhlIG92ZXJhbGwgbWVhbgp8IEludGVyY2VwdCA9IGdyYW5kIG1lYW4gYWNyb3NzIGFsbCBjYXRlZ29yaWVzIG9mIHJhY2UgCgoKKip0bGRyOyBEdW1teSBjb2RpbmcgZ2l2ZXMgdXMgdGhlICJzaW1wbGUgZWZmZWN0cywiIGNvbXBhcmluZyBkaWZmZXJlbnQgbGV2ZWxzIHRvIGEgKnJlZmVyZW5jZSBncm91cCogd2hpbGUgZWZmZWN0cyBjb2RpbmcgZ2l2ZXMgdXMgdGhlICJtYWluIGVmZmVjdHMsIiBjb21wYXJpbmcgZGlmZmVyZW50IGxldmVscyB0byB0aGUgKmdyb3VwIG1lYW4qICoqCgo8YnI+PGJyPgoKLS0tLS0tLS0KCiMjIyMgQ2hhbGxlbmdlISAKCk5hbWUgdGhlIGNvbXBhcmlzb25zIGJlbG93LgoKKioxLiBUZXN0aW5nIHRoZSBlZmZlY3Qgb2YgYSBuZXcgbWVkaWNhdGlvbiB1c2luZyB0cmVhdG1lbnQgYW5kIGNvbnRyb2wgZ3JvdXBzLiBIb3cgd291bGQgeW91IGludGVycHJldCB0aGUgaW50ZXJjZXB0PyBIb3cgd291bGQgeW91IGludGVycHJldCB0aGUgZWZmZWN0IG9mIGdyb3VwPyoqCgp8IEdyb3VwICAgICB8IENvbHVtbjF8Cnw6LS0tLS0tLS0tLXw6LS0tLS0tLXwKfCBDb250cm9sICAgfCAwICAgICAgfCAKfCBUcmVhdG1lbnQgfCAxICAgICAgfAoKCgoKKioyLiBOb3cgd2UncmUgdGVzdGluZyB0aGUgZWZmZWN0IG9mIGRpZmZlcmVudCBkb3NhZ2VzIG9mIHRoZSBzYW1lIG1lZGljYXRpb24gdG8gdGhlIGNvbnRyb2wgZ3JvdXAuIEhvdyB3b3VsZCB5b3UgaW50ZXJwcmV0IHRoZSBpbnRlcmNlcHQ/IFdoYXQgZG9lcyBsZXZlbCAxIChjb2x1bW4gMSkgbG9vayBhdD8gSG93IGFib3V0IGxldmVsIDIgKGNvbHVtbiAyKT8qKgoKCnwgR3JvdXAgICAgICB8IENvbHVtbjEgfCBDb2x1bW4gMnwKfDotLS0tLS0tLS0tLXw6LS0tLS0tLS18Oi0tLS0tLS0tfAp8IENvbnRyb2wgICAgfCAwICAgICAgIHwgMCAgICAgICB8CnwgTG93IERvc2UgICB8IDEgICAgICAgfCAwICAgICAgIHwKfCBIaWdoIERvc2UgIHwgMCAgICAgICB8IDEgICAgICAgfAoKCgoqKjMuIFdlIHJlY29kZWQgdGhlIGdyb3Vwcy4gSG93IHdvdWxkIHlvdSBpbnRlcnByZXQgdGhlIGludGVyY2VwdD8gV2hhdCBkb2VzIGxldmVsIDEgKGNvbHVtbiAxKSBsb29rIGF0PyBIb3cgYWJvdXQgbGV2ZWwgMiAoY29sdW1uIDIpPyoqCgoKfCBHcm91cCAgICAgIHwgQ29sdW1uMSB8IENvbHVtbiAyIHwKfDotLS0tLS0tLS0tLXw6LS0tLS0tLS18Oi0tLS0tLS0tLXwKfCBDb250cm9sICAgIHwgMSAgICAgICB8IDAgICAgICAgIHwKfCBMb3cgRG9zZSAgIHwgMCAgICAgICB8IDEgICAgICAgIHwKfCBIaWdoIERvc2UgIHwgLTEgICAgICB8IC0xICAgICAgIHwKCgoKKio0LiBPbmUgbW9yZS4uLndlJ3ZlIHJlY29kZWQgdGhlIGdyb3VwcyBhZ2Fpbi4gSG93IHdvdWxkIHlvdSBpbnRlcnByZXQgdGhlIGludGVyY2VwdD8gV2hhdCBkb2VzIGxldmVsIDEgKGNvbHVtbiAxKSBsb29rIGF0PyBIb3cgYWJvdXQgbGV2ZWwgMiAoY29sdW1uIDIpPyoqCgoKfCBHcm91cCAgICAgIHwgQ29sdW1uMSB8IENvbHVtbiAyIHwKfDotLS0tLS0tLS0tLXw6LS0tLS0tLS18Oi0tLS0tLS0tLXwKfCBDb250cm9sICAgIHwgMCAgICAgICB8IDIgICAgICAgIHwKfCBMb3cgRG9zZSAgIHwgMSAgICAgICB8IC0xICAgICAgIHwKfCBIaWdoIERvc2UgIHwgLTEgICAgICB8IC0xICAgICAgIHwKCgoKLS0tLS0tLS0tLS0tCgojIyBIb3cgYXJlIG91ciB2YXJpYWJsZXMgY29kZWQ/CgpgYGB7cn0KY29udHJhc3RzKGRmLmYkZ2VuZGVyUikKCmBgYAoKKipJZGVudGlmaWVyczoqKgoKKiAtMSA9IEZlbWFsZQoKKiAxID0gTWFsZQoKPGJyPgoKKipDb250cmFzdHM6KioKCiogMCA9IEZlbWFsZQoKKiAxID0gTWFsZQoKKipIb3cgZG9lcyB0aGlzIGltcGFjdCBvdXIgaW50ZXJwcmV0YXRpb24gb2YgdGhlIGludGVyY2VwdD8qKgoKKiBBdmVyYWdlIHNhZG5lc3MgYWZ0ZXIgdGhlIGludGVyYWN0aW9uIGZvciB3b21lbiAod2hlbiBnZW5kZXJSID0gMCkKCgpgYGB7cn0KY29udHJhc3RzKGRmLmYkY29uZGl0aW9uXzNMZXZlbCkKYGBgCgoqKklkZW50aWZpZXJzOioqCgoqIDEgPSBDb250cm9sIGR5YWQKCiogMiA9IFNhZCBhY3RvcgoKKiAzID0gU2FkIHBhcnRuZXIKCjxicj4KCioqQ29udHJhc3RzOioqCgpGSVJTVCBFRkZFQ1Q6IHdoYXQgaXMgdGhlIGVmZmVjdCBvZiBzYWQgYWN0b3IgdnMgY29udHJvbCBjb25kaXRpb24/Cgo8YnI+CgpTRUNPTkQgRUZGRUNUOiB3aGF0IGlzIHRoZSBlZmZlY3Qgb2Ygc2FkIHBhcnRuZXIgdnMgY29udHJvbCBjb25kaXRpb24/Cgo8YnI+CgotLS0tLS0tLS0tLS0KCiMgSG93IGRvZXMgU1BTUyBzZXQgdXAgdGhlIGNvbnRyYXN0cz8KCiMjIyMgSW50ZXJjZXB0CgpJbnRlcmNlcHQgPSBhdmVyYWdlIGFsbCBsZXZlbHMgCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzMwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdzcHNzX2ludGVyY2VwdF9jb250cmFzdHMucG5nJykKYGBgCgoKIyMjIyBHZW5kZXIKCgoqIGZlbWFsZSAtMSwgYnV0IGNvZGVkIGFzIDEKKiBtYWxlIDEsIGJ1dCBjb2RlZCBhcyAtMQoqIHdoZW4gY29uZGl0aW9uID0gMCAoYXZlcmFnZSBjb2xsYXBzaW5nIGFjcm9zcyBjb25kaXRpb24pCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzQ1JSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdzcHNzX2dlbmRlcl9jb250cmFzdHMucG5nJykKYGBgCgoKIyMjIyBDb25kaXRpb24KCgoqIHdoZW4gZ2VuZGVyID0gMCAoYXZlcmFnZSBjb2xsYXBzaW5nIGFjcm9zcyBnZW5kZXIpCiogQ09OVFJBU1QgMSA9IGNvbnRyb2wgKDEpIHZzIHNhZCBwYXJ0bmVyICgzKQoqIENPTlRSQVNUIDIgPSBzYWQgYWN0b3IgKDIpIHZzIHNhZCBwYXJ0bmVyKDMpCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzUwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdzcHNzX2NvbmRpdGlvbl9jb250cmFzdHMucG5nJykKYGBgCgojIyMgQ2hhbmdlIHJlZmVyZW5jZSBncm91cHMKCgojIyMjIEdlbmRlciBjb250cmFzdHMKCgpgYGB7cn0KZ2VuZGVyQ29udHJhc3RzIDwtIG1hdHJpeChjKDEsLTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLCBuY29sID0gMSwgYnlyb3cgPSBGQUxTRSkKCmNvbnRyYXN0cyhkZi5mJGdlbmRlclIpID0gZ2VuZGVyQ29udHJhc3RzCgpwcmludChjb250cmFzdHMoZGYuZiRnZW5kZXJSKSkKYGBgCgoKCiMjIyMgQ29uZGl0aW9uIGNvbnRyYXN0cwoKCmBgYHtyfQplZmZlY3RDb250cmFzdHMgPC0gbWF0cml4KGMoMSwgMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0xLCAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0xLCAwICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDMsIG5jb2wgPSAyLCBieXJvdyA9IEZBTFNFKQoKY29udHJhc3RzKGRmLmYkY29uZGl0aW9uXzNMZXZlbCkgPSBlZmZlY3RDb250cmFzdHMKCnByaW50KGNvbnRyYXN0cyhkZi5mJGNvbmRpdGlvbl8zTGV2ZWwpKQpgYGAKCgojIyMgUmVydW4gdGhlIG9tbmlidXMgdGVzdAoKCmBgYHtyfQpmaXQzIDwtIGxtKGF2Z19zYWRfaW50IH4gZ2VuZGVyUipjb25kaXRpb25fM0xldmVsLCBkYXRhID0gZGYuZikKY2FyOjpBbm92YShmaXQzLCB0eXBlID0gIklJSSIpCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSc4MCUnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnc3Bzc19vbW5pYnVzLnBuZycpCmBgYAoKCllheSEgSXQgbWF0Y2hlcy4KCiAgICBOb3RlOiB0ZWNobmljYWxseSwgY29udHJhc3QgY29kaW5nIHNob3VsZG4ndCBpbmZsdWVuY2UgdGhlIG9tbmlidXMgdGVzdC4gQnkgZGVmaW5pdGlvbiwgdGhlIG9tbmlidXMgdGVzdCBpcyBzdXBwb3NlZCB0byBjb21wYXJlIHRoZSBncm91cCBtZWFucyB0byB0aGUgZ3JhbmQgbWVhbi4gU1BTUyBhbmQgU0FTIHRha2UgY2FyZSBvZiB0aGlzIGJ5IGNvbnRyYXN0IGNvZGluZyBpbiB0aGUgYmFja2dyb3VuZC4gQXMgeW91IGNhbiBzZWUgZnJvbSB0aGUgb21uaWJ1cyBhbmQgc3VtbWFyeSBzdGF0aXN0aWNzIGluIFIsIFIgZXhwZWN0cyB5b3UgdG8gdW5kZXJzdGFuZCB3aGF0J3MgZ29pbmcgb24gJ3VuZGVyIHRoZSBob29kJwoKCgojIyMjIE5vdyBsZXQncyBicmVhayBkb3duIHRoZXNlIGVmZmVjdHMKCmBgYHtyfQpzdW1tYXJ5KGZpdDMpCmBgYAoKCiMjIyMgRG9lcyBpdCBtYXRjaCBTUFNTIG91dHB1dD8KCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzgwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdzcHNzX3BhcmFtZXRlcnMucG5nJykKYGBgCgpObyBpdCBkb2VzIG5vdC4gV2h5IG1pZ2h0IHRoYXQgYmU/CgoKIyMjIyBIb3cgaXMgZ2VuZGVyIGNvZGVkPwoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nNTAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ3Nwc3NfZ2VuZGVyX2NvbnRyYXN0czIucG5nJykKYGBgCgoKIyMjIyBIb3cgaXMgY29uZGl0aW9uIGNvZGVkPwoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nNTAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ3Nwc3NfY29uZGl0aW9uX2NvbnRyYXN0czIucG5nJykKYGBgCgoKIyMjIFJlY29kZSB2YXJpYWJsZXMgdG8gbWF0Y2ggU1BTUwoKCgojIyMjIEdlbmRlcgoKYGBge3J9CmdlbmRlckNvbnRyYXN0czIgPC0gbWF0cml4KGMoMSwgMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwgbmNvbCA9IDEsIGJ5cm93ID0gRkFMU0UpCmNvbnRyYXN0cyhkZi5mJGdlbmRlclIpID0gZ2VuZGVyQ29udHJhc3RzMgoKcHJpbnQoY29udHJhc3RzKGRmLmYkZ2VuZGVyUikpCmBgYAoKCgojIyMjIENvbmRpdGlvbgoKYGBge3J9CmNvbmRpdGlvbkNvbnRyYXN0czIgPC0gbWF0cml4KGMoMSwgMCwgMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAxLCAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAzLCBuY29sID0gMiwgYnlyb3cgPSBGQUxTRSkKCmNvbnRyYXN0cyhkZi5mJGNvbmRpdGlvbl8zTGV2ZWwpID0gY29uZGl0aW9uQ29udHJhc3RzMgoKcHJpbnQoY29udHJhc3RzKGRmLmYkY29uZGl0aW9uXzNMZXZlbCkpCmBgYApgYGB7cn0KZml0NCA8LSBsbShhdmdfc2FkX2ludCB+IGdlbmRlclIqY29uZGl0aW9uXzNMZXZlbCwgZGF0YSA9IGRmLmYpCnN1bW1hcnkoZml0NCkKYGBgCgpXb29ob28hIEl0IG1hdGNoZXMuCgotLS0tLS0tLS0tLS0tLS0KCiMgRG8gSSBoYXZlIHRvIGdvIHRocm91Z2ggdGhpcyBwcm9jZXNzIGFueSB0aW1lIEkgd2FudCB0byBydW4gYW4gQU5PVkEgaW4gUj8KCkl0J3MgaW1wb3J0YW50IHRoYXQgeW91IHVuZGVyc3RhbmQgd2hhdCdzIGdvaW5nIG9uICJ1bmRlciB0aGUgaG9vZCwiIGJ1dCB3ZSBjYW4gc2hvcnRlbiB0aGlzIHByb2Nlc3MuCgpMZXQncyBkZW1vbnN0cmF0ZSB0aGUgc3RlcHMgdXNpbmcgb3VyIG9yaWdpbmFsIGRhdGFmcmFtZQoKIyMgU3RlcCAxOiBDb252ZXJ0IG51bWVyaWMgcHJlZGljdG9ycyB0byBmYWN0b3IgdmFyaWFibGVzCgpgYGB7cn0KZGYuc2hvcnQgPC0gZGYgJT4lIAogIG11dGF0ZShjb25kaXRpb25fM0xldmVsID0gYXMuZmFjdG9yKGNvbmRpdGlvbl8zTGV2ZWwpLAogICAgICAgICBnZW5kZXJSID0gYXMuZmFjdG9yKGdlbmRlclIpKQpgYGAKCgojIyBTdGVwIDI6IENvbnRyYXN0IGNvZGUgZm9yIHRoZSBvbW5pYnVzIHRlc3QKCldlIGFjdHVhbGx5IGRvbid0IGhhdmUgdG8gY3JlYXRlIG91ciBjb250cmFzdHMgZnJvbSBzY3JhdGNoLiBXZSBjYW4gdXNlIHRoZXNlIFIgZnVuY3Rpb25zIHRvIGF1dG9tYXRpY2FsbHkgY29udHJhc3QgY29kZSBvdXIgdmFyaWFibGVzLgpgYGB7cn0KIyBlZmZlY3QtY29kZQpjb250ci5zdW0oMykKYGBgCgpgYGB7cn0KIyBkdW1teSBjb2RlCmNvbnRyLnRyZWF0bWVudCgzKQpgYGAKCgpBcHBseSBjb250cmFzdHMgKGVmZmVjdCBjb2RlKQoKYGBge3J9CmNvbnRyYXN0cyhkZi5zaG9ydCRnZW5kZXJSKSA8LSBjb250ci5zdW0oMikKY29udHJhc3RzKGRmLnNob3J0JGNvbmRpdGlvbl8zTGV2ZWwpIDwtIGNvbnRyLnN1bSgzKQpgYGAKCgojIyBTdGVwIDNhOiBSdW4gb21uaWJ1cyB0ZXN0CgpgYGB7cn0KbW9kZWxfc2hvcnRjdXQgPC0gbG0oYXZnX3NhZF9pbnQgfiBnZW5kZXJSKmNvbmRpdGlvbl8zTGV2ZWwsIGRhdGEgPSBkZi5zaG9ydCkKCmNhcjo6QW5vdmEobW9kZWxfc2hvcnRjdXQsIHR5cGUgPSAiSUlJIikKYGBgCgoKQXBwbHkgY29udHJhc3RzIChkdW1teSBjb2RlKQoKYGBge3J9CmNvbnRyYXN0cyhkZi5zaG9ydCRnZW5kZXJSKSA8LSBjb250ci50cmVhdG1lbnQoMikKY29udHJhc3RzKGRmLnNob3J0JGNvbmRpdGlvbl8zTGV2ZWwpIDwtIGNvbnRyLnRyZWF0bWVudCgzKQpgYGAKCgojIyBTdGVwIDRhOiBSdW4gcmVncmVzc2lvbiB0byBnZXQgc2ltcGxlIGVmZmVjdHMKCkJlIG1pbmRmdWwgdGhhdCB0aGlzIGFwcHJvYWNoIGRlZmF1bHRzIHRvIGEgZGlmZmVyZW50IHJlZmVyZW5jZSBncm91cCB0aGFuIFNQU1MgKG5vdGljZSBDb25kaXRpb24gPTEgaXMgbWlzc2luZyBmcm9tIHRoZSBSIG91dHB1dCBhbmQgQ29uZGl0aW9uID0zIGlzIG1pc3NpbmcgZnJvbSB0aGUgU1BTUyBvdXRwdXQpLiBJdCdzIG5vdCB3cm9uZywgYnV0IGdvb2QgdG8ga25vdyB0aGF0IHRoZWlyIGRlZmF1bHQgc2V0dGluZ3MgYXJlIGRpZmZlcmVudC4KCmBgYHtyfQptb2RlbF9zaG9ydGN1dDIgPC0gbG0oYXZnX3NhZF9pbnQgfiBnZW5kZXJSKmNvbmRpdGlvbl8zTGV2ZWwsIGRhdGEgPSBkZi5zaG9ydCkKCnN1bW1hcnkobW9kZWxfc2hvcnRjdXQyKQpgYGAKCgojIyBTdGVwIDNiOiBDaGFuZ2UgcmVmZXJlbmNlIGdyb3VwIHRvIG1hdGNoIFNQU1MKCmBgYHtyfQojIGJhc2UgaXMgcmVmZXJlbmNlIChpdCBkb2Vzbid0IHRha2UgbmVnYXRpdmUgbnVtYmVycywgYnV0IHdlJ3JlIHRlbGxpbmcgaXQgd2Ugd2FudCB0aGUgcmVmZXJlbmNlIHRvIGJlIHRoZSBoaWdoZXIgbnVtYmVyIG9mIHRoZSB0d28pCmNvbnRyYXN0cyhkZi5zaG9ydCRnZW5kZXJSKSA8LSBjb250ci50cmVhdG1lbnQoMiwgYmFzZSA9IDIpCgpjb250cmFzdHMoZGYuc2hvcnQkY29uZGl0aW9uXzNMZXZlbCkgPC0gY29udHIudHJlYXRtZW50KDMsIGJhc2UgPSAzKQoKYGBgCgoKIyMgU3RlcCA0YjogUnVuIHJlZ3Jlc3Npb24gdG8gZ2V0IHNpbXBsZSBlZmZlY3RzIHRvIG1hdGNoIFNQU1MKCmBgYHtyfQptb2RlbF9zaG9ydGN1dDMgPC0gbG0oYXZnX3NhZF9pbnQgfiBnZW5kZXJSKmNvbmRpdGlvbl8zTGV2ZWwsIGRhdGEgPSBkZi5zaG9ydCkKCnN1bW1hcnkobW9kZWxfc2hvcnRjdXQzKQpgYGAKCgojIERvIEkgcmVhbGx5IGhhdmUgdG8gZG8gYWxsIHRoYXQganVzdCBmb3IgQU5PVkE/CgpObywgYnV0IGl0J3MgaW1wb3J0YW50IHRoYXQgeW91IHVuZGVyc3RhbmQgaG93IEFOT1ZBIHdvcmtzLiBIZXJlJ3MgYW4gYWN0dWFsIHNob3J0Y3V0IHRoYXQgZGVmYXVsdHMgdG8gU1MgdHlwZSAzIGFuZCBkb2VzIG5vdCByZXF1aXJlIHlvdSB0byBjb250cmFzdCBjb2RlLiBZb3UgY2FuIHJ1biB0aGUgcGFpcndpc2UgY29tcGFyaXNvbnMgYXMgeW91IG5vcm1hbGx5IHdvdWxkLgoKIyMjIE9tbmlidXMgc2hvcnRjdXQKCmBgYHtyLCBtZXNzYWdlcz0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgd2UgZG9uJ3QgZXZlbiBuZWVkIHRvIGNvbnZlcnQgbnVtZXJpYyBwcmVkaWN0b3JzIHRvIGZhY3Rvci4gSXQgZG9lcyB0aGF0IGZvciB1cy4KCiMgb21uaWJ1cyB0ZXN0CnNob3J0Y3V0X21vZGVsIDwtIGFmZXg6OmFvdl9jYXIoYXZnX3NhZF9pbnQgfiBnZW5kZXJSKmNvbmRpdGlvbl8zTGV2ZWwgKyAKICAgICAgICAgICAgICAgIEVycm9yKElEKSwgIyBtdXN0IGFkZCB0aGUgZXJyb3IgdGVybSAoaS5lLiBJRCkKICAgICAgICAgICAgICBkYXRhID0gZGYpICMgb3JpZ2luYWwgZGF0YWZyYW1lCgpwcmludChzaG9ydGN1dF9tb2RlbCkKYGBgCgotLS0tLS0tLS0tCgojIFBhaXJ3aXNlIGNvbXBhcmlzb25zIHRvIGJyZWFrZG93biBpbnRlcmFjdGlvbnMKCmBgYHtyfQplbW0gPC0gZW1tZWFucyhtb2RlbF9zaG9ydGN1dDMsIHNwZWNzID0gYygiZ2VuZGVyUiIsICJjb25kaXRpb25fM0xldmVsIikpCgpwYWlycyhlbW0sIHNpbXBsZSA9ICJlYWNoIikKYGBgCmBgYHtyfQpwYWlycyhlbW0sIGFkanVzdCA9ICJ0dWtleSIpCmBgYAoKCiMjIyMgQWx0ZXJuYXRpdmUgZm9ybWF0dGluZwoKCmBgYHtyfQprYWJsZShwYWlycyhlbW0sIGFkanVzdCA9ICJ0dWtleSIpLCAic2ltcGxlIiwgZGlnaXRzID0gMykgCmBgYAoKYGBge3J9CmthYmxlKHBhaXJzKGVtbSwgYWRqdXN0ID0gImJvbmZlcnJvbmkiKSwgInNpbXBsZSIsIGRpZ2l0cyA9IDMpIApgYGAKCgojIyMgV2hhdCBlbHNlIGNhbiB3ZSBkbyB3aXRoIGVtbWVhbnMoKT8KCiMjIyMgRXN0aW1hdGVkIG1hcmdpbmFsIG1lYW5zCgpgYGB7cn0KZW1tMiA8LSBlbW1lYW5zKG1vZGVsX3Nob3J0Y3V0Mywgc3BlY3MgPSBwYWlyd2lzZSB+IGdlbmRlclI6Y29uZGl0aW9uXzNMZXZlbCkKCmVtbTIkZW1tZWFucwpgYGAKCiMjIyMgQ29udHJhc3RzCgpgYGB7cn0KZW1tMiRjb250cmFzdHMKYGBgCgojIyMjIENvbmZpZGVuY2UgaW50ZXJ2YWxzCgpgYGB7cn0KZW1tMiRjb250cmFzdHMgJT4lIGNvbmZpbnQoKQpgYGAKCiMjIyMgV2l0aGluLWdyb3VwIGNvbXBhcmlzb25zIHdpdGggfAoKYGBge3J9CmVtbTMgPC0gZW1tZWFucyhtb2RlbF9zaG9ydGN1dDMsIHNwZWNzID0gcGFpcndpc2UgfiBnZW5kZXJSfGNvbmRpdGlvbl8zTGV2ZWwpCgplbW0zIApgYGAKClBhc3MgdGhlc2UgY29udHJhc3RzIHRocm91Z2ggcmJpbmQoKSB0byBjb3JyZWN0IGZvciBtdWx0aXBsZSBjb21wYXJpc29ucyAoZGVmYXVsdHMgdG8gQm9uZmVycm9uaSwgd2hpY2ggY2FuIGJlIGEgYml0IHRvbyBjb25zZXJ2YXRpdmUgYW5kIHRvbyBzdGF0aXN0aWNhbGx5IHVuZGVycG93ZXJlZCBmb3Igc28gbWFueSBjb21wYXJpc29uczsgc2VlIFtMZWUgJiBMZWUsIDIwMThdKGh0dHBzOi8vZWtqYS5vcmcvam91cm5hbC92aWV3LnBocD9kb2k9MTAuNDA5Ny9ramEuZC4xOC4wMDI0Mik7IFtMaWViZXJtYW4gJiBDdW5uaW5naGFtLCAyMDA5XShodHRwczovL2FjYWRlbWljLm91cC5jb20vc2Nhbi9hcnRpY2xlLzQvNC80MjMvMTY3MDgwMikpCgoKYGBge3J9CmVtbTIkY29udHJhc3RzICU+JSAKICByYmluZCgpCmBgYAoKLS0tLS0tLS0KCiMgTWluaSBDaGVjay1pbgoKMS4gV2hhdCBpcyBhIG9uZS13YXkgQU5PVkE/IEhvdyBpcyBpdCBkaWZmZXJlbnQgZnJvbSBhIGZhY3RvcmlhbCBvciB0d28td2F5IEFOT1ZBPwoyLiBXaGF0IGlzIGFuIGludGVyYWN0aW9uPyBIb3cgd291bGQgeW91IGludGVycHJldCBhbiBpbnRlcmFjdGlvbj8KMy4gV2hhdCBraW5kIG9mIGdyYXBoIGNvdWxkIEkgdXNlIHRvIHBsb3QgYSBvbmUtd2F5IEFOT1ZBPwoKLS0tLS0tLS0KCiMgUmVwbGljYXRlIE1hZGFsaW5hJ3MgUHl0aG9uIGNvZGUKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQptX2RmX29nIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJkYXRhX0FOT1ZBLnhsc3giKQpgYGAKCmBgYHtyfQptX2RmIDwtIG1fZGZfb2cgJT4lIAogIGdyb3VwX2J5KHBhcnRudW0pICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gbWVhbiguLCBuYS5ybSA9IFRSVUUpKSApJT4lIAogIHVuZ3JvdXAoKQoKaGVhZChtX2RmKQpgYGAKCgoKIyMjIE9uZS13YXkgQU5PVkEKCmBgYHtyfQpvbmV3YXlfbW9kZWwgPC0gYWZleDo6YW92X2NhcihSZGVsdGFCIH4gcGFydHkgKyBFcnJvcihwYXJ0bnVtKSwgCiAgICAgICAgICAgICAgZGF0YSA9IG1fZGYpICMgb3JpZ2luYWwgZGF0YWZyYW1lCgpwcmludChvbmV3YXlfbW9kZWwpCmBgYAoKIyMjIFR3by13YXkgQU5PVkEKCmBgYHtyfQojIGNoYW5nZSB0byB0eXBlID0gMiB0byBtYXRjaCBweXRob24KdHdvd2F5X21vZGVsIDwtIGFmZXg6OmFvdl9jYXIoUmRlbHRhQiB+IHBhcnR5KnR3aXR0ZXIgKyBFcnJvcihwYXJ0bnVtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJJSSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBtX2RmKSAKcHJpbnQodHdvd2F5X21vZGVsKQpgYGAKIyMjIFJlcGVhdGVkIE1lYXN1cmVzIEFOT1ZBCgpIZXJlLCBJJ20gc2hvd2luZyB5b3UgdHdvIGRpZmZlcmVudCB3YXlzIHRvIHJ1biBhIHJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIHdpdGggdGhlIGFmZXggcGFja2FnZS4gVGhlIGZpcnN0IGlzIHRoZSBhb3ZfY2FyIGZ1bmN0aW9uLCB3aGljaCB0YWtlcyBhIGxtLXN0eWxlIGZvcm11bGEuIAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgd2l0aGluIHRoZSBFcnJvciBzdGF0ZW1lbnQsIHdlJ3JlIHNheWluZyB0aGF0IHdpdGhpbiBlYWNoIHBhcnRudW0gKElEKSwgc2NpX2FuZWMgYW5kIHBvcF91bnBvcCBhcmUgcmVwZWF0ZWQuCgojIHJlbWVtYmVyIHRoaXMgJ25lc3RpbmcnIGZvcm1hdC4gSXQgd2lsbCBjb21lIHVwIGFnYWluIHdoZW4gd2UgcnVuIG1peGVkIG1vZGVscy4KCnJlcGVhdGVkX21vZGVsMSA8LSBhZmV4Ojphb3ZfY2FyKFJkZWx0YUIgfiAxICsgRXJyb3IocGFydG51bS8oc2NpX2FuZWMqcG9wX3VucG9wKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1fZGZfb2cpCgprbml0cjo6a2FibGUobmljZShyZXBlYXRlZF9tb2RlbDEpKQpgYGAKCjxicj48YnI+CgpOb3csIHdlJ3JlIGdvaW5nIHRvIHVzZSBhIGRpZmZlcmVudCBmdW5jdGlvbiBmcm9tIHRoZSBhZmV4IHBhY2thZ2UgY2FsbGVkIGFvdl9lei4gVGhlIG9ubHkgZGlmZmVyZW5jZSBpcyB0aGF0IGFvdl9leiB0YWtlcyBjaGFyYWN0ZXIgYXJndW1lbnRzIChsaWtlIHlvdSBsaXRlcmFsbHkgZW50ZXIgd2hhdCB5b3VyIGJldHdlZW4gYW5kIHdpdGhpbiB2YXJpYWJsZXMgYXJlKSBpbnN0ZWFkIG9mIGEgZm9ybXVsYS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpyZXBlYXRlZF9tb2RlbDIgPC0gYWZleDo6YW92X2V6KGlkID0gInBhcnRudW0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdiA9ICJSZGVsdGFCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aGluID0gYygnc2NpX2FuZWMnLCAncG9wX3VucG9wJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1fZGZfb2cpIAoKa25pdHI6OmthYmxlKG5pY2UocmVwZWF0ZWRfbW9kZWwyKSkKCnN1bW1hcnkocmVwZWF0ZWRfbW9kZWwyKQpgYGAKCiMjIyMgV2hhdCBhYm91dCBNYXVjaGx5J3MgdGVzdCBvZiBzcGhlcmljaXR5PwoKTWF1Y2hseSdzIHRlc3Qgb2Ygc3BoZXJpY2l0eSBpcyBvbmx5IGFwcGxpY2FibGUgd2hlbiB5b3UgaGF2ZSBtb3JlIHRoYW4gdHdvIGxldmVscyBpbiBhdCBsZWFzdCBvbmUgb2YgeW91ciB3aXRoaW4tcGFydGljaXBhbnQgKHJlcGVhdGVkIG1lYXN1cmVzKSBmYWN0b3JzLiBUaGlzIGlzIGJlY2F1c2Ugc3BoZXJpY2l0eSBpcyBhIGNvbmNlcHQgdGhhdCBhcHBsaWVzIHRvIHRoZSB2YXJpYW5jZXMgb2YgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gYWxsIGNvbWJpbmF0aW9ucyBvZiBsZXZlbHMgd2l0aGluIGEgZmFjdG9yLiBJZiBhIGZhY3RvciBvbmx5IGhhcyB0d28gbGV2ZWxzLCB0aGUgYXNzdW1wdGlvbiBvZiBzcGhlcmljaXR5IGlzIGluaGVyZW50bHkgbWV0IGJlY2F1c2UgdGhlcmUncyBvbmx5IG9uZSBwb3NzaWJsZSBkaWZmZXJlbmNlIHRvIGNvbnNpZGVyLCB0aHVzIG5vIHZhcmlhYmlsaXR5IGluIHRoZXNlIGRpZmZlcmVuY2VzIGFjcm9zcyBsZXZlbHMgdG8gdGVzdCBhZ2FpbnN0LgoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0KbGlicmFyeShleikKCm1vZDwtIGV6QU5PVkEoZGF0YSA9IG1fZGZfb2csIGR2ID0gLihSZGVsdGFCKSwgd2lkID0gLihwYXJ0bnVtKSwKICAgICAgICAgICAgICB3aXRoaW4gPSAuKHNjaV9hbmVjLHBvcF91bnBvcCksCiAgICAgICAgICAgICAgZGV0YWlsZWQgPSBUUlVFLAogICAgICAgICAgICAgIHR5cGUgPSAzKQoKbW9kCmBgYAoKCgotLS0tLS0tLQoKCiMgQU5DT1ZBCgpBTk9WQSBjYW4gYmUgZXh0ZW5kZWQgdG8gaW5jbHVkZSBvbmUgb3IgbW9yZSBjb250aW51b3VzIHZhcmlhYmxlcyB0aGF0IHByZWRpY3QgdGhlIG91dGNvbWUuIENvbnRpbnVvdXMgdmFyaWFibGVzIHN1Y2ggYXMgdGhlc2UsIHRoYXQgYXJlIG5vdCBwYXJ0IG9mIHRoZSBtYWluIGV4cGVyaW1lbnRhbCBtYW5pcHVsYXRpb24gYnV0IGhhdmUgYW4gaW5mbHVlbmNlIG9uIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIGFyZSBrbm93biBhcyBjb3ZhcmlhdGVzIGFuZCB0aGV5IGNhbiBiZSBpbmNsdWRlZCBpbiBhbiBBTk9WQSBhbmFseXNpcy4KCldoeSB1c2UgQU5DT1ZBPwoKKlRvIHJlZHVjZSB3aXRoaW4tZ3JvdXAgZXJyb3IgdmFyaWFuY2U6KiBJbiB0aGUgZGlzY3Vzc2lvbiBvZiBBTk9WQSBhbmQgdC10ZXN0cyB3ZSBnb3QgdXNlZCB0byB0aGUgaWRlYSB0aGF0IHdlIGFzc2VzcyB0aGUgZWZmZWN0IG9mIGFuIGV4cGVyaW1lbnQgYnkgY29tcGFyaW5nIHRoZSBhbW91bnQgb2YgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEgdGhhdCB0aGUgZXhwZXJpbWVudCBjYW4gZXhwbGFpbiBhZ2FpbnN0IHRoZSB2YXJpYWJpbGl0eSB0aGF0IGl0IGNhbm5vdCBleHBsYWluLiBJZiB3ZSBjYW4gZXhwbGFpbiBzb21lIG9mIHRoaXMg4oCYdW5leHBsYWluZWTigJkgdmFyaWFuY2UgKFNTVykgaW4gdGVybXMgb2Ygb3RoZXIgdmFyaWFibGVzIChjb3ZhcmlhdGVzKSwgdGhlbiB3ZSByZWR1Y2UgdGhlIGVycm9yIHZhcmlhbmNlLCBhbGxvd2luZyB1cyB0byBtb3JlIGFjY3VyYXRlbHkgYXNzZXNzIHRoZSBlZmZlY3Qgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlIChTU0IpLiAKCipFbGltaW5hdGlvbiBvZiBjb25mb3VuZHM6KiBJbiBhbnkgZXhwZXJpbWVudCwgdGhlcmUgbWF5IGJlIHVubWVhc3VyZWQgdmFyaWFibGVzIHRoYXQgY29uZm91bmQgdGhlIHJlc3VsdHMgKGkuZS4sIHZhcmlhYmxlcyBvdGhlciB0aGFuIHRoZSBleHBlcmltZW50YWwgbWFuaXB1bGF0aW9uIHRoYXQgYWZmZWN0IHRoZSBvdXRjb21lIHZhcmlhYmxlKS4gSWYgYW55IHZhcmlhYmxlcyBhcmUga25vd24gdG8gaW5mbHVlbmNlIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYmVpbmcgbWVhc3VyZWQsIHRoZW4gQU5DT1ZBIGlzIGlkZWFsbHkgc3VpdGVkIHRvIHJlbW92ZSB0aGUgYmlhcyBvZiB0aGVzZSB2YXJpYWJsZXMuIE9uY2UgYSBwb3NzaWJsZSBjb25mb3VuZGluZyB2YXJpYWJsZSBoYXMgYmVlbiBpZGVudGlmaWVkLCBpdCBjYW4gYmUgbWVhc3VyZWQgYW5kIGVudGVyZWQgaW50byB0aGUgYW5hbHlzaXMgYXMgYSBjb3ZhcmlhdGUuCgoqKkFzc3VtcHRpb25zIG9mIHRoZSBBTkNPVkE6ICgxKSBpbmRlcGVuZGVuY2Ugb2YgdGhlIGNvdmFyaWF0ZSBhbmQgdHJlYXRtZW50IGVmZmVjdCBhbmQgKDIpIGhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzLioqCgoxLiBCYXNpY2FsbHksIHdlIHdhbnQgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGNvdmFyaWF0ZSBhbmQgdGhlIHByZWRpY3RvciBhcmUgbm90IHJlbGF0ZWQuIEluIG90aGVyIHdvcmRzLCB5b3Ugc2hvdWxkIGhhdmUgdGhyZWUgdmFyaWFuY2VzOiB0aGUgdmFyaWFuY2UgdGhhdCBpcyBleHBsYWluZWQgYnkgeW91ciBwcmVkaWN0b3IsIHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIGNvdmFyaWF0ZSwgYW5kIHVuZXhwbGFpbmVkIHZhcmlhbmNlLiBUaGUgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IHRoZSBjb3ZhcmlhdGUgc2hvdWxkIG5vdCBvdmVybGFwIHdpdGggdGhlIHZhcmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgcHJlZGljdG9yLiBXaGVuIHlvdXIgZ3JvdXBzIGRpZmZlciBvbiB0aGUgY292YXJpYXRlLCBwdXR0aW5nIGl0IGludG8gdGhlIGFuYWx5c2lzIHdpbGwgbm90ICdiYWxhbmNlIG91dCB0aGUgZGlmZmVyZW5jZXMuJyAoZS5nLiwgYW54aW91cyB2cyBub24tYW54aW91cyB3aWxsIGxpa2VseSBkaWZmZXIgaW4gZGVwcmVzc2lvbiwgc28gY29udHJvbGxpbmcgZm9yIGRlcHJlc3Npb24gaXNuJ3QgZ29pbmcgdG8gZ2l2ZSB5b3UgYSAncHVyZScgZWZmZWN0IG9mIGFueGlldHkpLiAKCjIuIFdlIGFzc3VtZSB0aGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgY292YXJpYXRlIGFuZCB0aGUgb3V0Y29tZSBpcyB0aGUgc2FtZSBhY3Jvc3MgYWxsIGdyb3VwcyBiZWNhdXNlIHRoZSBzbG9wZSBpcyBzdXBwb3NlZCB0byByZXByZXNlbnQgdGhlIGF2ZXJhZ2UgYWNyb3NzIGdyb3Vwcy4gSXQgYXNzdW1lcyBhIGxpbmVhciBzbG9wZS4gSWYgdGhlIHJlbGF0aW9uc2hpcCBpcyBub24tbGluZWFyLCB5b3Ugd291bGQgbmVlZCBhIGRpZmZlcmVudCBtb2RlbC4KCiMjIyBFeGFtcGxlIHdpdGggVmlhZ3JhIGRhdGEKCioqY3JlZGl0OiBBbmR5IEZpZWxkJ3MgRGlzY292ZXJpbmcgU3RhdGlzdGljcyoqCgpIZXJlLCB3ZSB3YW50IHRvIGtub3cgdGhlIGVmZmVjdCBvZiBWaWFncmEgKG5vbmUsIGxvdy1kb3NlLCBoaWdoLWRvc2UpIG9uIGxpYmlkby4gSG93ZXZlciwgd2Uga25vdyB0aGF0IHBhcnRuZXIncyBsaWJpZG8gbWlnaHQgaW1wYWN0IG91ciBvd24gbGliaWRvLiBUaGVyZWZvcmUsIHdlJ2xsIG5lZWQgdG8gYWRqdXN0IGZvciBwYXJ0bmVyJ3MgbGliaWRvLgoKYGBge3J9CnZfZGYgPC0gcmVhZC5kZWxpbSgiVmlhZ3JhQ292YXJpYXRlLmRhdCIpCgp2X2RmJGRvc2UgPC0gYXMuZmFjdG9yKHZfZGYkZG9zZSkKYGBgCgojIyMjIEluc3BlY3QgdGhlIGRhdGEKClRlc3QgdGhlIGluZGVwZW5kZW5jZSBvZiB0aGUgY292YXJpYXRlIGFuZCBwcmVkaWN0b3IKCmBgYHtyfQpjb250cmFzdHModl9kZiRkb3NlKSA8LSBjb250ci5zdW0oMykKCiMgaXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBkb3NlIGFuZCBwYXJ0bmVyIGxpYmlkbz8KdGVzdDEgPC0gbG0ocGFydG5lckxpYmlkbyB+IGRvc2UsIGRhdGEgPSB2X2RmKQoKY2FyOjpBbm92YSh0ZXN0MSwgdHlwZSA9ICJJSUkiKQpgYGAKCkNoZWNrIHRoZSBzbG9wZXMKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CnZfZGYgJT4lIAogIGdncGxvdChhZXMoeD1wYXJ0bmVyTGliaWRvLCB5PWxpYmlkbywgY29sb3I9ZG9zZSkpICsgIyBNYXAgcGFydG5lckxpYmlkbyB0byB4LCBsaWJpZG8gdG8geSwgYW5kIGRvc2UgdG8gY29sb3IKICBnZW9tX3BvaW50KCkgKyAgIyBVc2UgZ2VvbV9wb2ludCBmb3IgYSBzY2F0dGVyIHBsb3QKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQpgYGAKCkhvbW9nZW5laXR5IG9mIHZhcmlhbmNlcwoKYGBge3J9CmNhcjo6bGV2ZW5lVGVzdCh2X2RmJGxpYmlkbywgdl9kZiRkb3NlKQpgYGAKCiMjIyBSdW4gdGhlIEFOQ09WQQoKYGBge3J9CnZfbW9kZWwgPC0gbG0obGliaWRvIH4gZG9zZSArIHBhcnRuZXJMaWJpZG8sIGRhdGEgPSB2X2RmKQoKY2FyOjpBbm92YSh2X21vZGVsLCB0eXBlID0gIklJSSIpCmBgYApgYGB7cn0Kdl9lbW0gPC0gZW1tZWFucyh2X21vZGVsLCBzcGVjcyA9IH4gZG9zZSkKCnByaW50KHZfZW1tKQpgYGAKYGBge3J9CmNvbnRyYXN0cyh2X2RmJGRvc2UpIDwtIGNvbnRyLnRyZWF0bWVudCgzKQoKIyByZXJ1bm5pbmcgdGhlIG1vZGVsIGFzIGR1bW15IGNvZGVkCnZfbW9kZWwgPC0gbG0obGliaWRvIH4gZG9zZSArIHBhcnRuZXJMaWJpZG8sIGRhdGEgPSB2X2RmKQpzdW1tYXJ5KHZfbW9kZWwpCmBgYAoKIyMjIyBXaGF0IGlmIEkgd2FudCB0byBjb21wYXJlICpwbGFjZWJvIHZzIGxvdyArIGhpZ2ggZG9zZSogYW5kICpsb3cgdnMgaGlnaCo/CgpgYGB7cn0KY29udHJhc3RzKHZfZGYkZG9zZSkgPC0gY2JpbmQoYygtMiwxLDEpLCBjKDAsLTEsMSkpCgpwcmludChjb250cmFzdHModl9kZiRkb3NlKSkgI3BsYWNlYm8sIGxvdyBkb3NlLCB0aGVuIGhpZ2ggZG9zZQpgYGAKCipkb3NlMToqIHBsYWNlYm8gdnMgdHJlYXRtZW50IChsb3cgKyBoaWdoIGRvc2UpIDxicj4KKmRvc2UyOiogbG93IHZzIGhpZ2ggPGJyPgpIb3cgd291bGQgeW91IGludGVycHJldCAqcGFydG5lckxpYmlkbyo/CgpgYGB7cn0Kdl9tb2RlbDIgPC0gbG0obGliaWRvIH4gZG9zZSArIHBhcnRuZXJMaWJpZG8sIGRhdGEgPSB2X2RmKQoKc3VtbWFyeSh2X21vZGVsMikKYGBgCgpQb3N0IGhvYyB0ZXN0cwoKYGBge3J9CmVtbV92IDwtIGVtbWVhbnModl9tb2RlbDIsIHNwZWNzID0gcGFpcndpc2UgfiBkb3NlICsgcGFydG5lckxpYmlkbywgYWRqdXN0ID0gIlR1a2V5IikKCmVtbV92JGNvbnRyYXN0cwpgYGAKCiMjIyBFZmZlY3Qgc2l6ZQoKV2hhdCdzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gZXRhIHNxdWFyZWQgYW5kIHBhcnRpYWwgZXRhIHNxdWFyZWQ/IAoKJCRcZXRhXjIgPSBcZnJhY3tTU197ZWZmZWN0fX17U1Nfe3RvdGFsfX0kJApFdGEtc3F1YXJlZCByZXByZXNlbnRzIHRoZSB0b3RhbCB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIGVmZmVjdCwgY29uc2lkZXJpbmcgYm90aCB0aGF0IGVmZmVjdCBhbmQgYW55IG9mIGl0cyBpbnRlcmFjdGlvbnMuCgoKJCQgcGFydGlhbCBcIFxldGFeMiA9IFxmcmFje1NTX3tlZmZlY3R9fXtTU197ZWZmZWN0fStTU197cmVzaWR1YWx9fSQkClBhcnRpYWwgZXRhLXNxdWFyZWQgaXMgdGhlIHRvdGFsIHZhcmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgZWZmZWN0ICoqdGhhdCBpcyBub3QgZXhwbGFpbmVkIGJ5IG90aGVyIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwqKgoKCmBgYHtyfQpsc3I6OmV0YVNxdWFyZWQodl9tb2RlbDIpCmBgYAoKCiMjIyMgQ29udHJhc3RzIGVmZmVjdCBzaXplcwoKJCQgcl97Y29udHJhc3R9ID0gXHNxcnQgXGZyYWN7dF4yfXt0XjIgK2RmfSQkCgoKYGBge3J9CnJjb250cmFzdCA8LSBmdW5jdGlvbih0LCBkZikgewogIHIgPC0gc3FydCh0XjIvKHReMiArIGRmKSkKICBwcmludChwYXN0ZSgiciA9ICIsIHIpKQp9Cgp0IDwtIGMoMi43ODUsIDAuNTQxLCAyLjIyNykKZGYgPC0gMjYKCnJjb250cmFzdCh0LCBkZikKYGBgCgpUaGUgb3V0cHV0IHNob3dzIHRoYXQgdGhlIGVmZmVjdCBvZiB0aGUgY292YXJpYXRlICguNDAwKSBhbmQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgY29tYmluZWQgZG9zZSBncm91cHMgYW5kIHRoZSBwbGFjZWJvICguNDc5KSBib3RoIHJlcHJlc2VudCBtZWRpdW0gdG8gbGFyZ2UgZWZmZWN0IHNpemVzICh0aGV54oCZcmUgYm90aCBiZXR3ZWVuIC40IGFuZCAuNSkuIFRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGhpZ2gtIGFuZCBsb3ctZG9zZSBncm91cHMgKC4xMDYpIHdhcyBhIGZhaXJseSBzbWFsbCBlZmZlY3QuCgotLS0tLS0tLS0tLQoKCiMjIyBUZXN0aW5nIHRoZSBob21vZ2VuZWl0eSBvZiByZWdyZXNzaW9uIHNsb3BlcwoKYGBge3J9CnZfbW9kZWxfaW50IDwtIGxtKGxpYmlkbyB+IGRvc2UgKyBwYXJ0bmVyTGliaWRvICsgZG9zZTpwYXJ0bmVyTGliaWRvLCAjaW50ZXJhY3Rpb24gdGVybQogICAgICAgICAgICAgICAgICBkYXRhID0gdl9kZikKCmNhcjo6QW5vdmEodl9tb2RlbF9pbnQsIHR5cGUgPSAiMyIpCmBgYAoKVWggb2guLi4gd2UgdmlvbGF0ZWQgdGhhdCBhc3N1bXB0aW9uLiBXaGF0IG5vdz8KCi0tLS0tLS0tLQoKCiMjIFlvdXIgdHVybiEKCk1ha2Ugc3VyZSB0byBpbnNwZWN0IHRoZSBkYXRhIGZpcnN0IGZvciBhbnkgYXNzdW1wdGlvbiB2aW9sYXRpb25zIQoKCiMjIyBRMTogaW5qdXJ5IGJ5IHN1cGVyaGVybyBjb3N0dW1lCgoKMS4gU3VwZXJoZXJvLmRhdCA6IENoaWxkcmVuIHJlcG9ydGluZyB0byB0aGUgZW1lcmdlbmN5IHJvb20gaGFkIHRoZSBzZXZlcml0eSBvZiB0aGVpciBpbmp1cnkgKGluanVyeSkgYXNzZXNzZWQgKG9uIGEgc2NhbGUgZnJvbSAwLCBubyBpbmp1cnksIHRvIDEwMCwgZGVhdGgpLiBJbiBhZGRpdGlvbiwgYSBub3RlIHdhcyB0YWtlbiBvZiB3aGljaCBzdXBlcmhlcm8gY29zdHVtZSB0aGV5IHdlcmUgd2VhcmluZyAoaGVybyk6IFNwaWRlcm1hbiwgU3VwZXJtYW4sIHRoZSBIdWxrIG9yIGEgVGVlbmFnZSBNdXRhbnQgTmluamEgVHVydGxlLiBUZXN0IHRoZSBoeXBvdGhlc2VzIHRoYXQgZGlmZmVyZW50IGNvc3R1bWVzIGFyZSBhc3NvY2lhdGVkIHdpdGggbW9yZSBzZXZlcmUgaW5qdXJpZXMuIE1ha2Ugc3VyZSB0byBydW4gdGhlIGxldmVuZSdzIHRlc3QgYW5kIGNvbXBhcmUgdGhlIGRpZmZlcmVudCBjb3N0dW1lcyEKCiMjIyMgbG9hZCBkYXRhCgpgYGB7cn0Kc2hfZGYgPC0gcmVhZC5kZWxpbSgiL1VzZXJzL2thcmVlbmFkZWxyb3NhcmlvL0Rvd25sb2Fkcy9TdXBlcmhlcm8uZGF0IikKCmdsaW1wc2Uoc2hfZGYpCmBgYAojIyMjIHRlc3QgZm9yIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlCgpgYGB7cn0KIyBSdW4gYSBsZXZlbmUncyB0ZXN0CmxldmVuZVRlc3Qoc2hfZGYkaW5qdXJ5LCBzaF9kZiRoZXJvKQpgYGAKIyMjIyBydW4gb25lLXdheSBBTk9WQQoKTm90ZSB0aGF0IGhlcmUsIEknbSB0YWtpbmcgdGhlIG1hbnVhbCBhcHByb2FjaCwgYnV0IHlvdSBjYW4gYWxzbyBydW4gdGhlIGFmZXggY29kZS4KCmBgYHtyfQojIG1ha2Ugc3VyZSB0aGUgcHJlZGljdG9yIGlzIGNvZGVkIGNvcnJlY3RseQpzaF9kZiRoZXJvIDwtIGFzLmZhY3RvcihzaF9kZiRoZXJvKQpjb250cmFzdHMoc2hfZGYkaGVybykgPC0gY29udHIuc3VtKDQpCgpzdXBlck1vZGVsIDwtIGxtKGluanVyeX5oZXJvLCBkYXRhID0gc2hfZGYpCkFub3ZhKHN1cGVyTW9kZWwsIHR5cGUgPSAiMyIpCmBgYAojIyMjIGFmZXggb3B0aW9uCgppZiB5b3UgZGVjaWRlIHRvIHVzZSBhb3ZfY2FyLCBub3RlIHRoYXQgeW91J2xsIG5lZWQgYW4gSUQgdmFyaWFibGUKCmBgYHtyfQojIGNyZWF0ZSBpZCB2YXJpYWJsZSBmb3IgZXJyb3IgdGVybQpzaF9kZl9hZmV4IDwtIHNoX2RmICU+JSAKICBkcGx5cjo6bXV0YXRlKGlkID0gcm93X251bWJlcigpKQoKIyBtYWtlIHN1cmUgdGhlIHByZWRpY3RvciBpcyBjb2RlZCBjb3JyZWN0bHkKYWZleDo6YW92X2Nhcihpbmp1cnl+aGVybyArIEVycm9yKGlkKSwgZGF0YSA9IHNoX2RmX2FmZXgpCmBgYAoKIyMjIyBDb21wYXJlIGluanVyeSBieSBjb3N0dW1lCgpgYGB7cn0Kc2hfZW1tIDwtIGVtbWVhbnMoc3VwZXJNb2RlbCwgc3BlY3MgPSB+IGhlcm8pCgpwcmludChzaF9lbW0pCmBgYAojIyMjIEJvbmZlcnJvbmkgcGFpcndpc2UgY29tcGFyaXNvbnMKCmBgYHtyfQpwYWlycyhzaF9lbW0pICU+JSByYmluZCgpCmBgYAoKLS0tLS0tLQoKIyMjIFEyOiBIYW5nb3ZlciBjdXJlPwoKMi4gSGFuZ292ZXJDdXJlLmRhdCA6IEEgbWFya2V0aW5nIG1hbmFnZXIgZm9yIGEgY2VydGFpbiB3ZWxsLWtub3duIGRyaW5rcyBtYW51ZmFjdHVyZXIgd2FzIGludGVyZXN0ZWQgaW4gdGhlIHRoZXJhcGV1dGljIGJlbmVmaXQgb2YgY2VydGFpbiBzb2Z0IGRyaW5rcyBmb3IgY3VyaW5nIGhhbmdvdmVycy4gSGUgdG9vayAxNSBwZW9wbGUgb3V0IG9uIHRoZSB0b3duIG9uZSBuaWdodCBhbmQgZ290IHRoZW0gZHJ1bmsuIFRoZSBuZXh0IG1vcm5pbmcgYXMgdGhleSBhd29rZSwgZGVoeWRyYXRlZCBhbmQgZmVlbGluZyBhcyB0aG91Z2ggdGhleeKAmWQgbGlja2VkIGEgY2FtZWzigJlzIHNhbmR5IGZlZXQgY2xlYW4gd2l0aCB0aGVpciB0b25ndWUsIGhlIGdhdmUgZml2ZSBvZiB0aGVtIHdhdGVyIHRvIGRyaW5rLCBmaXZlIG9mIHRoZW0gTHVjb3phZGUgKGluIGNhc2UgdGhpcyBpc27igJl0IHNvbGQgb3V0c2lkZSB0aGUgVUssIGl04oCZcyBhIHZlcnkgbmljZSBnbHVjb3NlLWJhc2VkIGRyaW5rKSBhbmQgdGhlIHJlbWFpbmluZyBmaXZlIGEgbGVhZGluZyBicmFuZCBvZiBjb2xhICh0aGlzIHZhcmlhYmxlIGlzIGNhbGxlZCBkcmluaykuIEhlIHRoZW4gbWVhc3VyZWQgaG93IHdlbGwgdGhleSBmZWx0IChvbiBhIHNjYWxlIGZyb20gMCA9IEkgZmVlbCBsaWtlIGRlYXRoIHRvIDEwID0gSSBmZWVsIHJlYWxseSBmdWxsIG9mIGJlYW5zIGFuZCBoZWFsdGh5KSB0d28gaG91cnMgbGF0ZXIgKHRoaXMgdmFyaWFibGUgaXMgY2FsbGVkIHdlbGwpLiBIZSB3YW50ZWQgdG8ga25vdyB3aGljaCBkcmluayBwcm9kdWNlZCB0aGUgZ3JlYXRlc3QgbGV2ZWwgb2Ygd2VsbG5lc3MuIEhvd2V2ZXIsIGhlIHJlYWxpemVkIGl0IHdhcyBpbXBvcnRhbnQgdG8gY29udHJvbCBmb3IgaG93IGRydW5rIHRoZSBwZXJzb24gZ290IHRoZSBuaWdodCBiZWZvcmUsIGFuZCBzbyBoZSBtZWFzdXJlZCB0aGlzIG9uIGEgc2NhbGUgZnJvbSAwID0gYXMgc29iZXIgYXMgYSBudW4gdG8gMTAgPSBmbGFwcGluZyBhYm91dCBsaWtlIGEgaGFkZG9jayBvdXQgb2Ygd2F0ZXIgb24gdGhlIGZsb29yIGluIGEgcHVkZGxlIG9mIHRoZWlyIG93biB2b21pdC4gVGhlIGRhdGEgYXJlIGluIHRoZSBmaWxlIEhhbmdvdmVyQ3VyZS4gZGF0LiBUZXN0IHdoZXRoZXIgcGVvcGxlIGZlbHQgYmV0dGVyIGFmdGVyIGRpZmZlcmVudCBkcmlua3Mgd2hlbiBjb250cm9sbGluZyBmb3IgaG93IGRydW5rIHRoZXkgd2VyZSB0aGUgbmlnaHQgYmVmb3JlLgoKIyMjIyByZWFkIGRhdGEKCmBgYHtyfQpoY19kZiA8LSByZWFkLmRlbGltKCIvVXNlcnMva2FyZWVuYWRlbHJvc2FyaW8vRG93bmxvYWRzL0hhbmdvdmVyQ3VyZS5kYXQiLCBoZWFkZXIgPSBUKQoKZ2xpbXBzZShoY19kZikKYGBgCmBgYHtyfQpoY19kZiRkcmluayA8LSBmYWN0b3IoaGNfZGYkZHJpbmssIGxldmVscyA9IGMoMTozKSwgbGFiZWxzID0gYygiV2F0ZXIiLAoiTHVjb3phZGUiLCAiQ29sYSIpKQpgYGAKCgojIyMjIERvZXMgdGhlIHR5cGUgb2YgZHJpbmsgeW91IGhhdmUgdGhlIG5leHQgZGF5IHByZWRpY3QgaG93IHdlbGwgeW91IGZlZWw/CgpgYGB7cn0Kb25ld2F5X2hjIDwtIGxtKHdlbGwgfiBkcmluaywgZGF0YSA9IGhjX2RmKQpBbm92YShvbmV3YXlfaGMsIHR5cGUgPSAiMyIpCmBgYAoKIyMjIyBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZQoKd2Ugd2FudCB0byBkbyBhIExldmVuZeKAmXMgdGVzdCB0byBzZWUgd2hldGhlciB0aGUgdmFyaWFuY2UgaW4gd2VsbCAoaG93IHdlbGwgdGhlIHBlcnNvbgpmZWVscykgdmFyaWVzIGFjcm9zcyB0aGUgaW50ZXJhY3Rpb24gb2YgZGlmZmVyZW50IHR5cGVzIG9mIGRyaW5rcyAoZHJpbmspIGFuZCBob3cgZHJ1bmsgdGhlCnBlcnNvbiB3YXMgdGhlIG5pZ2h0IGJlZm9yZSAoZHJ1bmspLiBUbyBkbyB0aGlzIHdlIGNhbiBleGVjdXRlOgoKYGBge3J9CmxldmVuZVRlc3QoaGNfZGYkd2VsbCwgaW50ZXJhY3Rpb24oaGNfZGYkZHJpbmssIGhjX2RmJGRydW5rKSkKYGBgCiMjIyMgYXNzdW1wdGlvbjogaW5kZXBlbmRlbmNlIG9mIGNvdmFyaWF0ZSB2cyBwcmVkaWN0b3IKCmBgYHtyfQpjaGVja0lORCA8LSBhb3YoZHJ1bmsgfiBkcmluaywgZGF0YSA9IGhjX2RmKQoKQW5vdmEoY2hlY2tJTkQsIHR5cGUgPSAiMyIpCmBgYAoKIyMjIyBJZiB3ZSBjb250cm9sIGZvciBob3cgZHJ1bmsgeW91IGdvdCwgZG9lcyB0aGUgdHlwZSBvZiBkcmluayB5b3UgaGF2ZSB0aGUgbmV4dCBkYXkgcHJlZGljdCBob3cgd2VsbCB5b3UgZmVlbD8KCmBgYHtyfQpjb250cmFzdHMoaGNfZGYkZHJpbmspIDwtIGNvbnRyLnN1bSgzKQoKYW5jb3ZhX2hjIDwtIGxtKHdlbGwgfiBkcmluayArIGRydW5rLCBkYXRhID0gaGNfZGYpCkFub3ZhKGFuY292YV9oYywgdHlwZSA9ICIzIikKYGBgCgojIyMjIFJlZ3Jlc3Npb24gb3V0cHV0CgpgYGB7cn0KY29udHJhc3RzKGhjX2RmJGRyaW5rKSA8LSBjb250ci50cmVhdG1lbnQoMykKCmFuY292YV9oYzIgPC0gbG0od2VsbCB+IGRyaW5rICsgZHJ1bmssIGRhdGEgPSBoY19kZikKc3VtbWFyeShhbmNvdmFfaGMyKQpgYGAKCiMjIyMgVGVzdGluZyBob21vZ2VuZWl0eSBvZiByZWdyZXNzaW9uIHNsb3BlcwoKSWYgdGhlIGludGVyYWN0aW9uIGlzIHNpZ25pZmljYW50LCB3ZSBuZWVkIHRvIHJ1biBhIHR3by13YXkgQU5PVkEgKHRoaXMpIGFuZCBub3QgQU5DT1ZBLgoKYGBge3J9CmFuY292YV9oYzMgPC0gdXBkYXRlKGFuY292YV9oYywgLn4uICsgZHJpbms6ZHJ1bmspCkFub3ZhKGFuY292YV9oYzMsIHR5cGUgPSAiSUlJIikKYGBgCg==