This RNotebook contains the full analysis of the study examining CFF, RSVP (attentional blink) and RDM tasks.

First, we’ll load the data set and all required packages

library(readxl)
library(tidyr)
library(car)
library(ggplot2)
library(ggnewscale)
library(dplyr)
library(biotools)
library(svglite)
library(lme4)
library(lmerTest)
library(emmeans)

Dataset <- read_excel("Dataset.xlsx")

** Part 1: RSVP analysis**

This data file contains all the raw recordings that were made during the study. We have 3 different tasks: CFF, RSVP and RDM. We want to compare CFF with performance on both other tasks, but not all participants have both RSVP data and RDM data (due to inadequate performance or technical issues etc). So we’ll split up the RSVP and RDM data and remove missing rows first:


# First take the columns we need for our RSVP analysis
RSVP<-Dataset[c("CFF", "Age", "Sex", "RSVP_T1", "AB_Magnitude", "AB_Intercept", "AB_Slope")]

#Then remove the rows with missing values from the dataset
RSVP<-na.omit(RSVP)

We have 84 data points for this analysis.

Let’s have a quick look at the CFF distribution first

hist(RSVP$CFF, breaks = 30, probability = TRUE) 
lines(density(RSVP$CFF), col = "blue", lwd = 2)


qqnorm(RSVP$CFF) 
qqline(RSVP$CFF, col = "red", lwd = 2)

Looks mostly normally distributed, save for a couple of potential high outliers. We’ll keep that in mind.

Our main question is for the RSVP analysis is if CFF can predict the overall profile of the attentional blink (AB) effect. We have 3 measures for the AB: magnitude (severity of the AB), baseline performance on T2 (listed as AB_Intercept) and rate of recovery from AB (listed as AB_Slope). Since we have 3 response variables, that are all correlated, we’ll do a multivariate regression. Before we make the model, we have to check if the response variables are not overly correlated with each other.

cor.test(RSVP$AB_Magnitude, RSVP$AB_Intercept, method = "pearson")

    Pearson's product-moment correlation

data:  RSVP$AB_Magnitude and RSVP$AB_Intercept
t = -5.5566, df = 82, p-value = 3.328e-07
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.6630544 -0.3475876
sample estimates:
       cor 
-0.5230077 
cor.test(RSVP$AB_Magnitude, RSVP$AB_Slope, method = "pearson")

    Pearson's product-moment correlation

data:  RSVP$AB_Magnitude and RSVP$AB_Slope
t = 4.2674, df = 82, p-value = 5.273e-05
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.2332113 0.5870353
sample estimates:
      cor 
0.4262921 
cor.test(RSVP$AB_Intercept, RSVP$AB_Slope, method = "pearson")

    Pearson's product-moment correlation

data:  RSVP$AB_Intercept and RSVP$AB_Slope
t = -5.7623, df = 82, p-value = 1.406e-07
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.6737106 -0.3644078
sample estimates:
       cor 
-0.5368596 

Good, correlations aren’t extremely high. Now for the multivariate model. We’ll include age and gender (actually listed as Sex in this data set) in the model as covariates.


# First, create the model
mod1 <- manova(cbind(AB_Magnitude, AB_Intercept, AB_Slope) ~ CFF + Age + Sex, data = RSVP)

# Now get the test statistics
summary(mod1, test = "Pillai") # The test statistic here is "Pillai", which is the most robust but also the most conservative
          Df   Pillai approx F num Df den Df  Pr(>F)  
CFF        1 0.109835   3.1669      3     77 0.02908 *
Age        1 0.042214   1.1312      3     77 0.34178  
Sex        2 0.165360   2.3434      6    156 0.03401 *
Residuals 79                                          
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Both CFF and Sex have significant effects in our model. Age does not (which is exactly what we expect because we intentionally left the age range small during participant recruitment).

Let’s check the model assumptions:

# Check the residuals
plot(residuals(mod1) ~ fitted(mod1))

qqPlot(mod1$residuals)
[1] 157 141

The heavy tails on the QQ plot indicate we may have some extreme values in the data. Let’s examine the residuals of each response variable when modeled separately:

m1<-lm(AB_Magnitude ~ CFF + Sex + Age, data = RSVP)
qqPlot(m1$residuals)
[1] 78  1

ncvTest(m1)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 0.07343905, Df = 1, p = 0.78639
influenceIndexPlot(m1, vars="Cook")

influenceIndexPlot(m1, vars="hat")

influenceIndexPlot(m1, vars="Bonf")

outlierTest(m1)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
plot(m1)

18 and 43 are highly influential (Cook’s distance) and have high leverage (hat). 73 is an extreme value (Bonferroni). Residuals look good.

m2<-lm(AB_Intercept ~ CFF + Sex + Age, data = RSVP)
qqPlot(m2$residuals)
[1] 73 57

ncvTest(m2)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 1.010188, Df = 1, p = 0.31486
influenceIndexPlot(m2, vars="Cook")

influenceIndexPlot(m2, vars="hat")

influenceIndexPlot(m2, vars="Bonf")

plot(m2)

18 and 43 have high leverage again. 18 and 3 may be influential points and no extreme values. Residuals good.

m3<-lm(AB_Slope ~ CFF + Sex + Age, data = RSVP)
qqPlot(m3$residuals)
[1] 73 74

ncvTest(m3)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 1.05463, Df = 1, p = 0.30444
influenceIndexPlot(m3, vars="Cook")

influenceIndexPlot(m3, vars="hat")

influenceIndexPlot(m3, vars="Bonf")

plot(m3)

18 and 43 come up again as influential and high leverage. 73 is indicated to be extreme. Inspection of the data shows that 73 does have some high values, but it is a valid data point. 18 and 43 are data points belonging to the only 2 participants who indicated to be neither male nor female. Thus, this would cause them to be highly influential for the Sex variable. Since Sex had a significant effect in the model, let’s see if anything changes if these points are not included:


# Remove the 2 data points
RSVP2<-RSVP[RSVP$Sex != "O", ]

# And do the same model again
mod2 <- manova(cbind(AB_Magnitude, AB_Intercept, AB_Slope) ~ CFF + Sex + Age, data = RSVP2)

summary(mod2, test = "Pillai")
          Df   Pillai approx F num Df den Df  Pr(>F)  
CFF        1 0.123085   3.5558      3     76 0.01817 *
Sex        1 0.118591   3.4085      3     76 0.02173 *
Age        1 0.075017   2.0546      3     76 0.11333  
Residuals 78                                          
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Removal of those 2 points did not change the significance of the variables. However, it does change the effect size. Now, it is not Sex, but rather CFF that has the largest effect on the AB-profile. We report on this in the main manuscript.

Now, next issue: the model diagnostics for our multivariate model did not look great. Most of the residuals were clustered right in th middle. However, the residuals for the univariate models looked much better. So it is likely the combined effect of the 3 response variables together that does something weird with the data. The clustering in the residual plot of the manova model shows that the variance may not be equally distributed across the 3 responses. We can scale the response data to see if that fixes our issue.

(The scale function subtracts the column mean and divides by the column SD for each value in that column. This way each column has a mean of 0 and an SD of 1, thus standardizing the data. Handy for when different variables have different magnitudes or a big difference in variance)

y_scaled<- scale(cbind(RSVP$AB_Magnitude, RSVP$AB_Intercept, RSVP$AB_Slope))

# Now try the model again
mod3 <- manova(y_scaled ~ RSVP$CFF + RSVP$Sex + RSVP$Age)

summary(mod3, test = "Pillai")
          Df   Pillai approx F num Df den Df  Pr(>F)  
RSVP$CFF   1 0.109835   3.1669      3     77 0.02908 *
RSVP$Sex   2 0.155408   2.1905      6    156 0.04669 *
RSVP$Age   1 0.052977   1.4358      3     77 0.23885  
Residuals 79                                          
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Now let’s check the assumptions again:

qqPlot(mod3$residuals)
[1] 241 242

plot(residuals(mod3) ~ fitted(mod3))

Much better! Let’s also check for linearity between our predictor and response variables

crPlots(lm(RSVP$AB_Magnitude ~ RSVP$CFF))

crPlots(lm(RSVP$AB_Intercept ~ RSVP$CFF))

crPlots(lm(RSVP$AB_Slope ~ RSVP$CFF))

Pretty good too. Now just to be complete, let’s do the same thing for the model with the two influential points removed and compare the results

# Make the model without the "O" group again, with our response variables scaled
y_scaled2<- scale(cbind(RSVP2$AB_Magnitude, RSVP2$AB_Intercept, RSVP2$AB_Slope))
mod4 <- manova(y_scaled2 ~ RSVP2$CFF + RSVP2$Sex + RSVP2$Age)
summary(mod4, test = "Pillai")
          Df   Pillai approx F num Df den Df  Pr(>F)  
RSVP2$CFF  1 0.123085   3.5558      3     76 0.01817 *
RSVP2$Sex  1 0.118591   3.4085      3     76 0.02173 *
RSVP2$Age  1 0.075017   2.0546      3     76 0.11333  
Residuals 78                                          
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# And compare against our main model (with "O" group)
summary(mod3, test = "Pillai")
          Df   Pillai approx F num Df den Df  Pr(>F)  
RSVP$CFF   1 0.109835   3.1669      3     77 0.02908 *
RSVP$Sex   2 0.155408   2.1905      6    156 0.04669 *
RSVP$Age   1 0.052977   1.4358      3     77 0.23885  
Residuals 79                                          
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Very similar results. We just need to keep in mind that the effect sizes for the two predictors are slightly different depending on whether or not the influential points are kept in the data set.

One last check: since Sex is a categorical variable, we need to check that the assumption for MANOVA is met that the different groups have equal covariance matrices. We’ll do this for the data set that has the two “O” datapoints removed, since we already know these two points made the data set very uneven.

boxM(RSVP2[, c("AB_Magnitude", "AB_Intercept", "AB_Slope")], RSVP2$Sex)

    Box's M-test for Homogeneity of Covariance Matrices

data:  RSVP2[, c("AB_Magnitude", "AB_Intercept", "AB_Slope")]
Chi-Sq (approx.) = 7.2359, df = 6, p-value = 0.2996

The result is not significant, so the covariance matrices can be considered equal for males and females.

Next part:

Now that we know CFF has an effect on the attentional blink effect, we need to examine which of our 3 AB measures is most affected by it. We’ll do this with the Roy-Bargmann stepdown procedure: we do univariate models in stepwise fashion, starting with our most important response variable, the AB magnitude. Since we have 3 response variables, we need to do Bonferroni correction to account for the repeated testing: our result will be significant if P < 0.05/3 = 0.0167.

RB1<- lm(AB_Magnitude ~ CFF + Sex + Age, data = RSVP)
summary(RB1)

Call:
lm(formula = AB_Magnitude ~ CFF + Sex + Age, data = RSVP)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.38758 -0.13847 -0.00396  0.12086  0.41143 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)  0.187486   0.229042   0.819   0.4155  
CFF         -0.006040   0.002409  -2.508   0.0142 *
SexM        -0.020898   0.044025  -0.475   0.6363  
SexO        -0.139994   0.124695  -1.123   0.2650  
Age          0.016777   0.009013   1.861   0.0664 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1723 on 79 degrees of freedom
Multiple R-squared:  0.1237,    Adjusted R-squared:  0.07938 
F-statistic: 2.789 on 4 and 79 DF,  p-value: 0.03191

The P value is smaller than 0.0167, so CFF has a significant effect on the AB magnitude.None of the other variables remain significant.

Now we test the second most important response variable (AB intercept) and add AB Magnitude as a covariate in the model.

RB2<-lm(AB_Intercept ~ CFF + Sex + Age + AB_Magnitude, data = RSVP)
summary(RB2)

Call:
lm(formula = AB_Intercept ~ CFF + Sex + Age + AB_Magnitude, data = RSVP)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.76025 -0.62310 -0.01276  0.62178  2.92148 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   0.754448   1.330924   0.567  0.57244    
CFF           0.009748   0.014482   0.673  0.50286    
SexM          0.828921   0.255106   3.249  0.00171 ** 
SexO          0.243783   0.727261   0.335  0.73837    
Age          -0.049682   0.053283  -0.932  0.35399    
AB_Magnitude -3.125443   0.651014  -4.801 7.48e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.997 on 78 degrees of freedom
Multiple R-squared:  0.3775,    Adjusted R-squared:  0.3376 
F-statistic:  9.46 on 5 and 78 DF,  p-value: 4.434e-07

CFF does not have a significant effect on baseline performance on T2 when the AB magnitude is accounted for. thus, we stop our stepdown process here. Intercept does not explain any additional amount of variance in the data (and since we determined our third predictor, Slope, to be a lower priority, we have to assume this one does not offer any additional explanatory power either).

However, for AB intercept, there is a significant effect of gender: Males have higher overall accuracy.

T1 Accuracy analysis

Now let’s move on to the other part of the RSVP task: accuracy on T1. This is pretty straight forward, we can do a simple regression.

# Regression with T1 accuracy as the response, and the same predictors we had for the AB analysis
T1mod<-lm(RSVP_T1 ~ CFF + Age + Sex + Age, data = RSVP)
summary(T1mod)

Call:
lm(formula = RSVP_T1 ~ CFF + Age + Sex + Age, data = RSVP)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.22843 -0.02908  0.01075  0.04061  0.07404 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.9141430  0.0741934  12.321   <2e-16 ***
CFF         -0.0003172  0.0007803  -0.406   0.6855    
Age          0.0002237  0.0029195   0.077   0.9391    
SexM         0.0300828  0.0142609   2.109   0.0381 *  
SexO         0.0266894  0.0403923   0.661   0.5107    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.05582 on 79 degrees of freedom
Multiple R-squared:  0.05702,   Adjusted R-squared:  0.009271 
F-statistic: 1.194 on 4 and 79 DF,  p-value: 0.3199

CFF and Age have no effect on people’s ability to predict the first target. Just like with AB, sex is a significant factor though. Check means per gender:

mean(RSVP$RSVP_T1[RSVP$Sex == "F"])
[1] 0.9008136
sd(RSVP$RSVP_T1[RSVP$Sex == "F"])
[1] 0.06021584
mean(RSVP$RSVP_T1[RSVP$Sex == "M"])
[1] 0.9294783
sd(RSVP$RSVP_T1[RSVP$Sex == "M"])
[1] 0.0392056
mean(RSVP$RSVP_T1[RSVP$Sex == "O"])
[1] 0.9285
sd(RSVP$RSVP_T1[RSVP$Sex == "O"])
[1] 0.05020458

Check linear model assumptions

qqPlot(T1mod$residuals)
[1] 45 44

ncvTest(T1mod)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 5.661238, Df = 1, p = 0.017344
residualPlots(T1mod)
           Test stat Pr(>|Test stat|)
CFF           0.3759           0.7080
Age          -0.6132           0.5416
Sex                                  
Tukey test   -1.0642           0.2872

influenceIndexPlot(T1mod, vars = "Cook")

influenceIndexPlot(T1mod, vars = "hat")

outlierTest(T1mod)

The variance isn’t heterogeneous, and there is one significant outlier detected. The two “O” data points in the sex variable of course also still have extreme leverage. Let’s take these points out and see if that improves the model fit.

T1df<- RSVP[-c(18, 43, 45),]
T1mod2<-lm(RSVP_T1 ~ CFF + Sex + Age, data = T1df)
summary(T1mod2)

Call:
lm(formula = RSVP_T1 ~ CFF + Sex + Age, data = T1df)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.161825 -0.029045  0.007473  0.038886  0.067953 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.8931665  0.0664516  13.441   <2e-16 ***
CFF         -0.0001270  0.0006963  -0.182    0.856    
SexM         0.0249317  0.0127398   1.957    0.054 .  
Age          0.0009144  0.0026283   0.348    0.729    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.04968 on 77 degrees of freedom
Multiple R-squared:  0.05201,   Adjusted R-squared:  0.01507 
F-statistic: 1.408 on 3 and 77 DF,  p-value: 0.2469
qqPlot(T1mod2$residuals)
[1] 42 47

ncvTest(T1mod2)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 2.82287, Df = 1, p = 0.09293
residualPlots(T1mod2)
           Test stat Pr(>|Test stat|)
CFF           0.0254           0.9798
Sex                                  
Age          -1.0734           0.2865
Tukey test   -1.5581           0.1192

influenceIndexPlot(T1mod2, vars = "Cook")

influenceIndexPlot(T1mod2, vars = "hat")

outlierTest(T1mod2)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

Ok, the model meets all the assumptions, and sex is still a significant factor.

Plots

Now let’s make some nice plots of our results:

# First CFF vs the AB magnitude
plot1<-ggplot(data = RSVP, aes(x = CFF, y = AB_Magnitude))
plot1+geom_point(size = 4, colour = "#4C72B0", alpha = 0.7)+geom_smooth(method = "lm", colour = "#F6BD60", se = FALSE, alpha = 0.15)+theme_classic()+theme(axis.title = element_text(size = 35, face = "bold"), axis.text = element_text(size = 30), plot.margin = margin(40, 40, 40, 40))+labs(x= "CFF in Hz", y = expression(bold("AB magnitude (" * lag[7]-lag[4] * ")")))
ggsave("ABMag4.svg", width = 8, height = 8, device = svglite)
ggsave("ABMag4.png", width = 8, height = 8, dpi = 300)


# Then CFF vs the AB Intercept
plot1<-ggplot(data = RSVP, aes(x = CFF, y = AB_Intercept))
plot1+geom_point(size = 4, colour = "#4C72B0", alpha = 0.7)+geom_smooth(method = "lm", colour = "#F6BD60", se = FALSE, alpha = 0.15)+theme_classic()+theme(axis.title = element_text(size = 35, face = "bold"), axis.text = element_text(size = 30), plot.margin = margin(40, 40, 40, 40))+labs(x= "CFF in Hz", y = expression(bold("Overall T2 accuracy (β"[0]*")")))
ggsave("ABInt4.svg", width = 8, height = 8, device = svglite)
ggsave("ABInt4.png", width = 8, height = 8, dpi = 300)


# And then CFF vs the AB Slope
plot1<-ggplot(data = RSVP, aes(x = CFF, y = AB_Slope))
plot1+geom_point(size = 4, colour = "#4C72B0", alpha = 0.7)+geom_smooth(method = "lm", colour = "#F6BD60", se = FALSE, alpha = 0.15)+theme_classic()+theme(axis.title = element_text(size = 35, face = "bold"), axis.text = element_text(size = 30), plot.margin = margin(40, 40, 40, 40))+labs(x= "CFF in Hz", y = expression(bold("T2 recovery rate (β"[1]*")")))
ggsave("ABSlope4.svg", width = 8, height = 8, device = svglite)
ggsave("ABSlope4.png", width = 8, height = 8, dpi = 300)

Next, a bar plot showing the attentional blink effect

# First take the columns we need
T1Plot<-Dataset[c("RSVP_T1L1", "RSVP_T1L2", "RSVP_T1L3", "RSVP_T1L4", "RSVP_T1L5", "RSVP_T1L6", "RSVP_T1L7")]

T2Plot<-Dataset[c("RSVP_T2L1", "RSVP_T2L2", "RSVP_T2L3", "RSVP_T2L4", "RSVP_T2L5", "RSVP_T2L6", "RSVP_T2L7")]

#Then remove the rows with missing values from the dataset
T1Plot<-na.omit(T1Plot)
T2Plot<-na.omit(T2Plot)

# Now pivot the data into long form 
T1_long <- T1Plot %>%
  dplyr::select(1:7) %>%
  pivot_longer(everything(), names_to = "variable", values_to = "value")

T2_long <- T2Plot %>%
  dplyr::select(1:7) %>%
  pivot_longer(everything(), names_to = "variable", values_to = "value")

# Now get the T1 means for each lag value, plus SE and confidence intervals for error bars
T1dat <- T1_long %>%
  group_by(variable) %>%
  summarise(
    T1mean = mean(value, na.rm = TRUE),
    T1se = sd(value, na.rm = TRUE)/sqrt(n()),
    ci_low = T1mean - qt(0.975, df = n() - 1) * T1se,
    ci_hi = T1mean + qt(0.975, df = n() - 1) * T1se
    )

# and also for T2. We'll also calculate SE and confidence intervals here so we can add error bars
T2dat <- T2_long %>%
  group_by(variable) %>%
  summarise(
    T2mean = mean(value, na.rm = TRUE), 
    T2se = sd(value, na.rm = TRUE)/sqrt(n()),
    ci_low = T2mean - qt(0.975, df = n() - 1) * T2se,
    ci_hi = T2mean + qt(0.975, df = n() - 1) * T2se
    )

# Then merge the T1 means and T2 means into one dataframe
ABPlot<-data.frame(Lag = c("1","2","3","4","5","6","7"), T1mean = T1dat$T1mean, T1se = T1dat$T1se, T1ci_low = T1dat$ci_low, T1ci_hi = T1dat$ci_hi, T2mean = T2dat$T2mean, T2se = T2dat$T2se, T2ci_low = T2dat$ci_low, T2ci_hi = T2dat$ci_hi)

Now plot

ggplot(ABPlot, aes(x = Lag)) +
  geom_col(aes(y = T2mean), fill = "#F6BD60", colour = "black", linewidth = 0.5) + 
  geom_errorbar(aes(ymin = T2ci_low, ymax = T2ci_hi), width = 0.2) +
  geom_line(aes(y = T1mean, group = 1), linewidth = 0.8, colour = "#4C72B0") +
  geom_point(aes(y = T1mean), size = 2, colour = "#4C72B0") +
  geom_errorbar(aes(ymin = T1ci_low, ymax = T1ci_hi), width = 0.2, colour = "#4C72B0") +
  theme_classic() +
  labs(y = "Mean accuracy", x = "Lag level") +
  theme(axis.title = element_text(size = 18, face = "bold"), axis.text = element_text(size = 18), plot.title =   
  element_text(hjust = 0.5, size = 16, face = "bold")) +
  scale_x_discrete(labels = c(
    RSVP_L1 = "lag 1",
    RSVP_L2 = "lag 2",
    RSVP_L3 = "lag 3",
    RSVP_L4 = "lag 4",
    RSVP_L5 = "lag 5",
    RSVP_L6 = "lag 6",
    RSVP_L7 = "lag 7"
  ))
ggsave("ABPlot.svg", device = svglite)
ggsave("ABPlot.png", width = 8, height = 6, dpi = 300)

Let’s also get the mean and sd for T1 accuracy, both across all lags and just for Lag1 trials (because it is much lower there compared to other lags)

# mean across all lags
mean(RSVP$RSVP_T1)
[1] 0.9093214
sd(RSVP$RSVP_T1)
[1] 0.05607571
# mean of just Lag 1 trials
T1L1<- subset(T1_long, variable == "RSVP_T1L1")$value
mean(T1L1)
[1] 0.6089286
sd(T1L1)
[1] 0.1741002

Now we know AB magnitude is predicted by CFF, but we don’t know exactly how performance across lags may vary depending on someone’s CFF. We can look into this if we divide the data into two groups and plot them: We’ll sort the data by CFF, and the lower half will be a “Low CFF” group and the upper half will be a “High CFF” group.

# First take all the columns we need
RSVP3<-Dataset[c("Participant", "CFF", "AB_Magnitude", "AB_Intercept", "AB_Slope", "RSVP_T1L1", "RSVP_T1L2","RSVP_T1L3","RSVP_T1L4","RSVP_T1L5","RSVP_T1L6","RSVP_T1L7","RSVP_T2L1", "RSVP_T2L2", "RSVP_T2L3", "RSVP_T2L4", "RSVP_T2L5", "RSVP_T2L6", "RSVP_T2L7")]

# Then remove the rows with missing values from the dataset
RSVP3<-na.omit(RSVP3)

# Then add a new column categorizing the data by CFF group
RSVP3 <- RSVP3 %>%
  mutate(
    CFFGroup = ntile(CFF, 2),   # split into two quantiles
    CFFGroup = factor(CFFGroup,
                      labels = c("LowCFF", "HighCFF"))
  )

# Sanity check: how many participants are in each group?
table(RSVP3$CFFGroup)

 LowCFF HighCFF 
     42      42 

Now prepare data for plotting:

# First make the dataframe in long format (T1 accuracy first)
RSVPT1_long <- RSVP3 %>%
  pivot_longer(
    cols = 6:12, 
    names_to = "T1Lag",
    values_to = "T1Accuracy",
  )

# Then a dataframe in long format for T2 accuracy
RSVPT2_long <- RSVP3 %>%
  pivot_longer(
    cols = 13:19, 
    names_to = "T2Lag",
    values_to = "T2Accuracy",
  )

# Now calculate T1 means and standard errors for bar plot
T1Lag_means <- RSVPT1_long %>%
  group_by(T1Lag, CFFGroup) %>%
  summarise(
    T1Mean = mean(T1Accuracy, na.rm = TRUE),
    T1SE   = sd(T1Accuracy, na.rm = TRUE) / sqrt(n()),
    .groups = "drop"
  )

# And the same for T2 means and standard errors
T2Lag_means <- RSVPT2_long %>%
  group_by(T2Lag, CFFGroup) %>%
  summarise(
    T2Mean = mean(T2Accuracy, na.rm = TRUE),
    T2SE   = sd(T2Accuracy, na.rm = TRUE) / sqrt(n()),
    .groups = "drop"
  )

# Get the desired columns from those dataframes and combine them into a new dataframe
groupdiffs<-data.frame(T2Lag_means$T2Lag, T2Lag_means$CFFGroup, T2Lag_means$T2Mean, T2Lag_means$T2SE, T1Lag_means$T1Mean, T1Lag_means$T1SE)

# The combined columns will have weird names. Fix it
names(groupdiffs)[names(groupdiffs) == "T2Lag_means.T2Lag"] <- "T2Lag"
names(groupdiffs)[names(groupdiffs) == "T2Lag_means.CFFGroup"] <- "CFFGroup"
names(groupdiffs)[names(groupdiffs) == "T2Lag_means.T2Mean"] <- "T2Mean"
names(groupdiffs)[names(groupdiffs) == "T2Lag_means.T2SE"] <- "T2SE"
names(groupdiffs)[names(groupdiffs) == "T1Lag_means.T1Mean"] <- "T1Mean"
names(groupdiffs)[names(groupdiffs) == "T1Lag_means.T1SE"] <- "T1SE"

Now we’re ready to plot:

# Make the ggplot object
Groupdiff<-ggplot(groupdiffs, aes(x = T2Lag, group = CFFGroup))

# And add all the visuals we want 
Groupdiff + 
  geom_line(linewidth = 1.2, aes(y = T2Mean, color = CFFGroup, linetype = "T2")) + 
  geom_point(size = 3, aes(y = T2Mean, color = CFFGroup)) + 
  geom_errorbar(aes(ymin = T2Mean - T2SE, ymax = T2Mean + T2SE, color = CFFGroup), width = 0.2)+
  geom_line(linewidth = 0.8, aes(y = T1Mean, color = CFFGroup, linetype = "T1"), alpha = 0.5) + 
  geom_point(size = 2, aes(y = T1Mean, color = CFFGroup), alpha = 0.5) + 
  geom_errorbar(aes(ymin = T1Mean - T1SE, ymax = T1Mean + T1SE, color = CFFGroup), width = 0.2, alpha = 0.7)+
    theme(panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.y = element_line(colour = "grey85", linewidth = 0.3),
    panel.grid.minor.y = element_line(colour = "grey85", linewidth = 0.3),
    axis.line.x = element_line(color = "black", linewidth = 0.5),
    axis.line.y = element_line(color = "black", linewidth = 0.5),
    panel.background = element_rect(fill = "white", colour = NA),
    axis.title = element_text(size = 18, face = "bold"), 
    axis.text = element_text(size = 18, colour = "black"),
    legend.text = element_text(size = 14),
    legend.title = element_text(size = 16, face = "bold"),
    plot.margin = margin(t = 20, r = 10, b = 10, l = 10)
    ) +
  labs(x = "Lag level", y = "Accuracy", color = "CFF Group") + 
  scale_x_discrete(labels = c("RSVP_T2L1" = "1", "RSVP_T2L2" = "2", "RSVP_T2L3" = "3", "RSVP_T2L4" = "4", "RSVP_T2L5" = "5", "RSVP_T2L6" = "6", "RSVP_T2L7" = "7")) +
  scale_color_manual(values = c("darkorchid", "green3"), labels = c("Low CFF", "High CFF")) +   scale_linetype_manual(name = "Target" , values = c("T2" = "solid", "T1" = "dashed"))  
ggsave("2groupdiffLag.svg", device = svglite)
ggsave("2groupdiffLag.png", width = 8, height = 6, dpi = 300)

We can also check if there is a statistically significant difference between the groups, either in the shape of the overall curve, or on any particular lag level.

We’ll do a mixed effects model that has Lag and CFFGroup as predictors, plus their interaction term. If the term is significant, we’ll know if the groups differ in their performance across lags. Participant will be included as random term, since we have multiple measures

lmemod<-lmer(T2Accuracy ~ CFFGroup * T2Lag + (1|Participant), data = RSVPT2_long)
anova(lmemod)
Type III Analysis of Variance Table with Satterthwaite's method
               Sum Sq Mean Sq NumDF DenDF F value Pr(>F)    
CFFGroup       0.0296 0.02962     1    82  1.6673 0.2003    
T2Lag          5.9375 0.98958     6   492 55.6931 <2e-16 ***
CFFGroup:T2Lag 0.1137 0.01894     6   492  1.0661 0.3819    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Lag is significant, but the interaction term is not. So the overall shape of the two performance plots is not significantly different between the groups. This tells us enough, but we’ll also look at how different performance is on a lag-by-lag level, using the Estimated Marginal Means from the model. We’ll use the emmeans package for this.

T2emm<-emmeans(lmemod, pairwise ~ CFFGroup | T2Lag)
summary(T2emm)
$emmeans
T2Lag = RSVP_T2L1:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.876 0.0318 190    0.813    0.939
 HighCFF   0.908 0.0318 190    0.846    0.971

T2Lag = RSVP_T2L2:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.586 0.0318 190    0.523    0.649
 HighCFF   0.662 0.0318 190    0.600    0.725

T2Lag = RSVP_T2L3:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.571 0.0318 190    0.508    0.633
 HighCFF   0.639 0.0318 190    0.577    0.702

T2Lag = RSVP_T2L4:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.542 0.0318 190    0.480    0.605
 HighCFF   0.617 0.0318 190    0.554    0.680

T2Lag = RSVP_T2L5:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.653 0.0318 190    0.590    0.716
 HighCFF   0.704 0.0318 190    0.642    0.767

T2Lag = RSVP_T2L6:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.719 0.0318 190    0.657    0.782
 HighCFF   0.746 0.0318 190    0.683    0.808

T2Lag = RSVP_T2L7:
 CFFGroup emmean     SE  df lower.CL upper.CL
 LowCFF    0.758 0.0318 190    0.696    0.821
 HighCFF   0.754 0.0318 190    0.691    0.817

Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$contrasts
T2Lag = RSVP_T2L1:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0324 0.0449 190  -0.720  0.4724

T2Lag = RSVP_T2L2:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0766 0.0449 190  -1.706  0.0897

T2Lag = RSVP_T2L3:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0687 0.0449 190  -1.528  0.1282

T2Lag = RSVP_T2L4:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0745 0.0449 190  -1.658  0.0990

T2Lag = RSVP_T2L5:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0512 0.0449 190  -1.140  0.2556

T2Lag = RSVP_T2L6:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF  -0.0261 0.0449 190  -0.582  0.5614

T2Lag = RSVP_T2L7:
 contrast         estimate     SE  df t.ratio p.value
 LowCFF - HighCFF   0.0044 0.0449 190   0.098  0.9220

Degrees-of-freedom method: kenward-roger 

Performance is not significantly difference at any lag level, but it approaches significance on Lag 2 and Lag 4.

That’s it for our RSVP analysis.

Part 2: RDM analysis

Now let’s move on to the RDM analysis. Firstly, our experimenters who collected the data used slightly different methodologies to assess the coherence with which a participant could perform with ~70% accuracy. These results for these two methods were kept separate, so we can check if there are no statistically relevant differences between the two sets. Let’s have a look at the means, min/max values and standard deviations:

mean(na.omit(Dataset$RDM_coh_Quest))
[1] 27.52348
mean(na.omit(Dataset$RDM_coh_Verify))
[1] 26.57692
min(na.omit(Dataset$RDM_coh_Quest))
[1] 7.222
min(na.omit(Dataset$RDM_coh_Verify))
[1] 9
max(na.omit(Dataset$RDM_coh_Quest))
[1] 73.764
max(na.omit(Dataset$RDM_coh_Verify))
[1] 50
sd(na.omit(Dataset$RDM_coh_Quest))
[1] 18.32858
sd(na.omit(Dataset$RDM_coh_Verify))
[1] 11.26827

The means are pretty similar. The max values and SD’s are slightly different though. Let’s do a quick t-test

t.test(Dataset$RDM_coh_Quest, Dataset$RDM_coh_Verify, var.equal = FALSE)

    Welch Two Sample t-test

data:  Dataset$RDM_coh_Quest and Dataset$RDM_coh_Verify
t = 0.28256, df = 72.938, p-value = 0.7783
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5.729947  7.623052
sample estimates:
mean of x mean of y 
 27.52348  26.57692 

The two sets are not significantly different from each other, so let’s analyse them together. They’re grouped together in the column “Coherence” in the raw dataset, so we’ll just use that

Let’s make a data frame from the raw data:

# First get only the columns we need for our analysis
RDM<-Dataset[c("CFF", "Age", "Sex", "Coherence", "RDM_RT_verify")]

#Then remove the rows with missing values from the dataset
RDM<-na.omit(RDM)

We have 79 observations for this part.

First we’ll see if the coherence at which participants perform with roughly 70% accuracy can be predicted by CFF. Again, we will also put Age and Sex in the model as predictors

RDMmod1<- lm(Coherence ~ CFF + Age + Sex, data = RDM)
summary(RDMmod1)

Call:
lm(formula = Coherence ~ CFF + Age + Sex, data = RDM)

Residuals:
    Min      1Q  Median      3Q     Max 
-22.755 -11.855  -3.999   6.974  51.474 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  59.3019    22.3618   2.652  0.00979 **
CFF          -0.1879     0.2309  -0.813  0.41856   
Age          -1.0877     0.8909  -1.221  0.22597   
SexM          5.0131     4.3526   1.152  0.25314   
SexO          0.9346    16.5276   0.057  0.95506   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 16.38 on 74 degrees of freedom
Multiple R-squared:  0.03926,   Adjusted R-squared:  -0.01267 
F-statistic: 0.7559 on 4 and 74 DF,  p-value: 0.5573

Check the model assumptions

qqPlot(RDMmod1$residuals)
[1] 57 52

shapiro.test(RDMmod1$residuals)

    Shapiro-Wilk normality test

data:  RDMmod1$residuals
W = 0.90118, p-value = 1.529e-05
vif(RDMmod1)
        GVIF Df GVIF^(1/(2*Df))
CFF 1.045104  1        1.022303
Age 1.010321  1        1.005147
Sex 1.052731  2        1.012930
residualPlots(RDMmod1)
           Test stat Pr(>|Test stat|)
CFF          -0.7880           0.4333
Age           0.3861           0.7005
Sex                                  
Tukey test    1.5312           0.1257

ncvTest(RDMmod1)
Non-constant Variance Score Test 
Variance formula: ~ fitted.values 
Chisquare = 0.3625736, Df = 1, p = 0.54708
influenceIndexPlot(RDMmod1, vars = "Cook")

influenceIndexPlot(RDMmod1, vars = "hat")

outlierTest(RDMmod1)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

The residuals aren’t entirely normally distributed, but overall the model looks good. The Cook’s distance plot shows some influential points, but they are not significant outliers in the outlier test. There’s no relationship at all between RDM coherence and any of the predictors. Just to check, we can drop the other predictors and only include the one we’re interested in the most (CFF)

RDMmod2<- lm(Coherence ~ CFF, data = RDM)
summary(RDMmod2)

Call:
lm(formula = Coherence ~ CFF, data = RDM)

Residuals:
    Min      1Q  Median      3Q     Max 
-19.778 -10.040  -5.410   7.067  47.335 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  35.6956    13.1861   2.707  0.00836 **
CFF          -0.1464     0.2253  -0.650  0.51781   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 16.33 on 77 degrees of freedom
Multiple R-squared:  0.005452,  Adjusted R-squared:  -0.007464 
F-statistic: 0.4221 on 1 and 77 DF,  p-value: 0.5178

Makes no difference for the result. Just to be extra sure, let’s separate the data by the slight difference in methodology used by our two experimenters.

# Version 1 of our separated data set
RDMv1<-Dataset[c("CFF", "Age", "Sex", "RDM_coh_Quest")]
RDMv1<-na.omit(RDMv1)

# Version 2 of our separated data set
RDMv2<-Dataset[c("CFF", "Age", "Sex", "RDM_coh_Verify")]
RDMv2<-na.omit(RDMv2)

# Now for the linear models
Questmod<-lm(RDM_coh_Quest ~ CFF + Age + Sex, data = RDMv1)
summary(Questmod)

Call:
lm(formula = RDM_coh_Quest ~ CFF + Age + Sex, data = RDMv1)

Residuals:
    Min      1Q  Median      3Q     Max 
-19.804 -13.221  -6.114   9.099  50.669 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  57.5581    28.6633   2.008   0.0502 .
CFF          -0.1125     0.3549  -0.317   0.7526  
Age          -1.1924     1.1099  -1.074   0.2879  
SexM          6.3253     6.2075   1.019   0.3132  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 18.5 on 49 degrees of freedom
Multiple R-squared:  0.03962,   Adjusted R-squared:  -0.01918 
F-statistic: 0.6738 on 3 and 49 DF,  p-value: 0.5722
Verifymod<-lm(RDM_coh_Verify ~ CFF + Age + Sex, data = RDMv2)
summary(Verifymod)

Call:
lm(formula = RDM_coh_Verify ~ CFF + Age + Sex, data = RDMv2)

Residuals:
     Min       1Q   Median       3Q      Max 
-20.4675  -6.5446  -0.9614   6.1976  24.8644 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  79.3400    45.8460   1.731   0.0982 .
CFF          -0.2237     0.2582  -0.866   0.3961  
Age          -2.0233     2.1249  -0.952   0.3518  
SexM          3.2735     5.2366   0.625   0.5386  
SexO          1.6115    12.1579   0.133   0.8958  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.79 on 21 degrees of freedom
Multiple R-squared:  0.07969,   Adjusted R-squared:  -0.09561 
F-statistic: 0.4546 on 4 and 21 DF,  p-value: 0.768

Similar results: no relationship between CFF and RDM coherence

RDMplot<-ggplot(data = RDM, aes(x = Coherence, y = CFF))
RDMplot + 
  geom_point(size = 3, colour = "#4C72B0", alpha = 0.7) + 
  geom_smooth(method = "lm", colour = "#F6BD60", se = FALSE, alpha =  0.15) + 
  theme_classic() + 
  theme(axis.title = element_text(size = 18, face = "bold"), axis.text = element_text(size =     18)) + 
  labs(x= "RDM Coherence", y = "CFF")
ggsave("RDMPlot.svg", device = svglite)
ggsave("RDMPlot.png", width = 8, height = 6, dpi = 300)

End

LS0tDQp0aXRsZTogIkZ1bGwgYW5hbHlzaXMgd29ya2Zsb3cgZm9yIHRoZSBtYW51c2NyaXB0IENyaXRpY2FsIGZsaWNrZXIgZnVzaW9uIHRocmVzaG9sZHMgcHJlZGljdCBhdHRlbnRpb25hbCBibGluayBtYWduaXR1ZGUiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIFJOb3RlYm9vayBjb250YWlucyB0aGUgZnVsbCBhbmFseXNpcyBvZiB0aGUgc3R1ZHkgZXhhbWluaW5nIENGRiwgUlNWUCAoYXR0ZW50aW9uYWwgYmxpbmspIGFuZCBSRE0gdGFza3MuDQoNCg0KDQpGaXJzdCwgd2UnbGwgbG9hZCB0aGUgZGF0YSBzZXQgYW5kIGFsbCByZXF1aXJlZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ25ld3NjYWxlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoYmlvdG9vbHMpDQpsaWJyYXJ5KHN2Z2xpdGUpDQpsaWJyYXJ5KGxtZTQpDQpsaWJyYXJ5KGxtZXJUZXN0KQ0KbGlicmFyeShlbW1lYW5zKQ0KDQpEYXRhc2V0IDwtIHJlYWRfZXhjZWwoIkRhdGFzZXQueGxzeCIpDQpgYGANCg0KKiogUGFydCAxOiBSU1ZQIGFuYWx5c2lzKioNCg0KVGhpcyBkYXRhIGZpbGUgY29udGFpbnMgYWxsIHRoZSByYXcgcmVjb3JkaW5ncyB0aGF0IHdlcmUgbWFkZSBkdXJpbmcgdGhlIHN0dWR5LiBXZSBoYXZlIDMgZGlmZmVyZW50IHRhc2tzOiBDRkYsIFJTVlAgYW5kIFJETS4gV2Ugd2FudCB0byBjb21wYXJlIENGRiB3aXRoIHBlcmZvcm1hbmNlIG9uIGJvdGggb3RoZXIgdGFza3MsIGJ1dCBub3QgYWxsIHBhcnRpY2lwYW50cyBoYXZlIGJvdGggUlNWUCBkYXRhIGFuZCBSRE0gZGF0YSAoZHVlIHRvIGluYWRlcXVhdGUgcGVyZm9ybWFuY2Ugb3IgdGVjaG5pY2FsIGlzc3VlcyBldGMpLiBTbyB3ZSdsbCBzcGxpdCB1cCB0aGUgUlNWUCBhbmQgUkRNIGRhdGEgYW5kIHJlbW92ZSBtaXNzaW5nIHJvd3MgZmlyc3Q6DQoNCmBgYHtyfQ0KDQojIEZpcnN0IHRha2UgdGhlIGNvbHVtbnMgd2UgbmVlZCBmb3Igb3VyIFJTVlAgYW5hbHlzaXMNClJTVlA8LURhdGFzZXRbYygiQ0ZGIiwgIkFnZSIsICJTZXgiLCAiUlNWUF9UMSIsICJBQl9NYWduaXR1ZGUiLCAiQUJfSW50ZXJjZXB0IiwgIkFCX1Nsb3BlIildDQoNCiNUaGVuIHJlbW92ZSB0aGUgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIGZyb20gdGhlIGRhdGFzZXQNClJTVlA8LW5hLm9taXQoUlNWUCkNCg0KYGBgDQoNCldlIGhhdmUgODQgZGF0YSBwb2ludHMgZm9yIHRoaXMgYW5hbHlzaXMuDQoNCkxldCdzIGhhdmUgYSBxdWljayBsb29rIGF0IHRoZSBDRkYgZGlzdHJpYnV0aW9uIGZpcnN0DQoNCmBgYHtyfQ0KaGlzdChSU1ZQJENGRiwgYnJlYWtzID0gMzAsIHByb2JhYmlsaXR5ID0gVFJVRSkgDQpsaW5lcyhkZW5zaXR5KFJTVlAkQ0ZGKSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KDQpxcW5vcm0oUlNWUCRDRkYpIA0KcXFsaW5lKFJTVlAkQ0ZGLCBjb2wgPSAicmVkIiwgbHdkID0gMikNCmBgYA0KDQpMb29rcyBtb3N0bHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHNhdmUgZm9yIGEgY291cGxlIG9mIHBvdGVudGlhbCBoaWdoIG91dGxpZXJzLiBXZSdsbCBrZWVwIHRoYXQgaW4gbWluZC4NCg0KT3VyIG1haW4gcXVlc3Rpb24gaXMgZm9yIHRoZSBSU1ZQIGFuYWx5c2lzIGlzIGlmIENGRiBjYW4gcHJlZGljdCB0aGUgb3ZlcmFsbCBwcm9maWxlIG9mIHRoZSBhdHRlbnRpb25hbCBibGluayAoQUIpIGVmZmVjdC4gV2UgaGF2ZSAzIG1lYXN1cmVzIGZvciB0aGUgQUI6IG1hZ25pdHVkZSAoc2V2ZXJpdHkgb2YgdGhlIEFCKSwgYmFzZWxpbmUgcGVyZm9ybWFuY2Ugb24gVDIgKGxpc3RlZCBhcyBBQl9JbnRlcmNlcHQpIGFuZCByYXRlIG9mIHJlY292ZXJ5IGZyb20gQUIgKGxpc3RlZCBhcyBBQl9TbG9wZSkuIFNpbmNlIHdlIGhhdmUgMyByZXNwb25zZSB2YXJpYWJsZXMsIHRoYXQgYXJlIGFsbCBjb3JyZWxhdGVkLCB3ZSdsbCBkbyBhIG11bHRpdmFyaWF0ZSByZWdyZXNzaW9uLiBCZWZvcmUgd2UgbWFrZSB0aGUgbW9kZWwsIHdlIGhhdmUgdG8gY2hlY2sgaWYgdGhlIHJlc3BvbnNlIHZhcmlhYmxlcyBhcmUgbm90IG92ZXJseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4NCg0KYGBge3J9DQpjb3IudGVzdChSU1ZQJEFCX01hZ25pdHVkZSwgUlNWUCRBQl9JbnRlcmNlcHQsIG1ldGhvZCA9ICJwZWFyc29uIikNCmNvci50ZXN0KFJTVlAkQUJfTWFnbml0dWRlLCBSU1ZQJEFCX1Nsb3BlLCBtZXRob2QgPSAicGVhcnNvbiIpDQpjb3IudGVzdChSU1ZQJEFCX0ludGVyY2VwdCwgUlNWUCRBQl9TbG9wZSwgbWV0aG9kID0gInBlYXJzb24iKQ0KYGBgDQpHb29kLCBjb3JyZWxhdGlvbnMgYXJlbid0IGV4dHJlbWVseSBoaWdoLiBOb3cgZm9yIHRoZSBtdWx0aXZhcmlhdGUgbW9kZWwuIFdlJ2xsIGluY2x1ZGUgYWdlIGFuZCBnZW5kZXIgKGFjdHVhbGx5IGxpc3RlZCBhcyBTZXggaW4gdGhpcyBkYXRhIHNldCkgaW4gdGhlIG1vZGVsIGFzIGNvdmFyaWF0ZXMuDQoNCmBgYHtyfQ0KDQojIEZpcnN0LCBjcmVhdGUgdGhlIG1vZGVsDQptb2QxIDwtIG1hbm92YShjYmluZChBQl9NYWduaXR1ZGUsIEFCX0ludGVyY2VwdCwgQUJfU2xvcGUpIH4gQ0ZGICsgQWdlICsgU2V4LCBkYXRhID0gUlNWUCkNCg0KIyBOb3cgZ2V0IHRoZSB0ZXN0IHN0YXRpc3RpY3MNCnN1bW1hcnkobW9kMSwgdGVzdCA9ICJQaWxsYWkiKSAjIFRoZSB0ZXN0IHN0YXRpc3RpYyBoZXJlIGlzICJQaWxsYWkiLCB3aGljaCBpcyB0aGUgbW9zdCByb2J1c3QgYnV0IGFsc28gdGhlIG1vc3QgY29uc2VydmF0aXZlDQoNCmBgYA0KDQpCb3RoIENGRiBhbmQgU2V4IGhhdmUgc2lnbmlmaWNhbnQgZWZmZWN0cyBpbiBvdXIgbW9kZWwuIEFnZSBkb2VzIG5vdCAgKHdoaWNoIGlzIGV4YWN0bHkgd2hhdCB3ZSBleHBlY3QgYmVjYXVzZSB3ZSBpbnRlbnRpb25hbGx5IGxlZnQgdGhlIGFnZSByYW5nZSBzbWFsbCBkdXJpbmcgcGFydGljaXBhbnQgcmVjcnVpdG1lbnQpLg0KDQpMZXQncyBjaGVjayB0aGUgbW9kZWwgYXNzdW1wdGlvbnM6DQoNCmBgYHtyfQ0KIyBDaGVjayB0aGUgcmVzaWR1YWxzDQpwbG90KHJlc2lkdWFscyhtb2QxKSB+IGZpdHRlZChtb2QxKSkNCnFxUGxvdChtb2QxJHJlc2lkdWFscykNCmBgYA0KVGhlIGhlYXZ5IHRhaWxzIG9uIHRoZSBRUSBwbG90IGluZGljYXRlIHdlIG1heSBoYXZlIHNvbWUgZXh0cmVtZSB2YWx1ZXMgaW4gdGhlIGRhdGEuIExldCdzIGV4YW1pbmUgdGhlIHJlc2lkdWFscyBvZiBlYWNoIHJlc3BvbnNlIHZhcmlhYmxlIHdoZW4gbW9kZWxlZCBzZXBhcmF0ZWx5Og0KDQpgYGB7cn0NCm0xPC1sbShBQl9NYWduaXR1ZGUgfiBDRkYgKyBTZXggKyBBZ2UsIGRhdGEgPSBSU1ZQKQ0KcXFQbG90KG0xJHJlc2lkdWFscykNCm5jdlRlc3QobTEpDQppbmZsdWVuY2VJbmRleFBsb3QobTEsIHZhcnM9IkNvb2siKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG0xLCB2YXJzPSJoYXQiKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG0xLCB2YXJzPSJCb25mIikNCm91dGxpZXJUZXN0KG0xKQ0KcGxvdChtMSkNCmBgYA0KDQoxOCBhbmQgNDMgYXJlIGhpZ2hseSBpbmZsdWVudGlhbCAoQ29vaydzIGRpc3RhbmNlKSBhbmQgaGF2ZSBoaWdoIGxldmVyYWdlIChoYXQpLiA3MyBpcyBhbiBleHRyZW1lIHZhbHVlIChCb25mZXJyb25pKS4gUmVzaWR1YWxzIGxvb2sgZ29vZC4NCg0KYGBge3J9DQptMjwtbG0oQUJfSW50ZXJjZXB0IH4gQ0ZGICsgU2V4ICsgQWdlLCBkYXRhID0gUlNWUCkNCnFxUGxvdChtMiRyZXNpZHVhbHMpDQpuY3ZUZXN0KG0yKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG0yLCB2YXJzPSJDb29rIikNCmluZmx1ZW5jZUluZGV4UGxvdChtMiwgdmFycz0iaGF0IikNCmluZmx1ZW5jZUluZGV4UGxvdChtMiwgdmFycz0iQm9uZiIpDQpwbG90KG0yKQ0KYGBgDQoxOCBhbmQgNDMgaGF2ZSBoaWdoIGxldmVyYWdlIGFnYWluLiAxOCBhbmQgMyBtYXkgYmUgaW5mbHVlbnRpYWwgcG9pbnRzIGFuZCBubyBleHRyZW1lIHZhbHVlcy4gUmVzaWR1YWxzIGdvb2QuIA0KYGBge3J9DQptMzwtbG0oQUJfU2xvcGUgfiBDRkYgKyBTZXggKyBBZ2UsIGRhdGEgPSBSU1ZQKQ0KcXFQbG90KG0zJHJlc2lkdWFscykNCm5jdlRlc3QobTMpDQppbmZsdWVuY2VJbmRleFBsb3QobTMsIHZhcnM9IkNvb2siKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG0zLCB2YXJzPSJoYXQiKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG0zLCB2YXJzPSJCb25mIikNCnBsb3QobTMpDQpgYGANCg0KMTggYW5kIDQzIGNvbWUgdXAgYWdhaW4gYXMgaW5mbHVlbnRpYWwgYW5kIGhpZ2ggbGV2ZXJhZ2UuIDczIGlzIGluZGljYXRlZCB0byBiZSBleHRyZW1lLiBJbnNwZWN0aW9uIG9mIHRoZSBkYXRhIHNob3dzIHRoYXQgNzMgZG9lcyBoYXZlIHNvbWUgaGlnaCB2YWx1ZXMsIGJ1dCBpdCBpcyBhIHZhbGlkIGRhdGEgcG9pbnQuIDE4IGFuZCA0MyBhcmUgZGF0YSBwb2ludHMgYmVsb25naW5nIHRvIHRoZSBvbmx5IDIgcGFydGljaXBhbnRzIHdobyBpbmRpY2F0ZWQgdG8gYmUgbmVpdGhlciBtYWxlIG5vciBmZW1hbGUuIFRodXMsIHRoaXMgd291bGQgY2F1c2UgdGhlbSB0byBiZSBoaWdobHkgaW5mbHVlbnRpYWwgZm9yIHRoZSBTZXggdmFyaWFibGUuIFNpbmNlIFNleCBoYWQgYSBzaWduaWZpY2FudCBlZmZlY3QgaW4gdGhlIG1vZGVsLCBsZXQncyBzZWUgaWYgYW55dGhpbmcgY2hhbmdlcyBpZiB0aGVzZSBwb2ludHMgYXJlIG5vdCBpbmNsdWRlZDoNCg0KDQpgYGB7cn0NCg0KIyBSZW1vdmUgdGhlIDIgZGF0YSBwb2ludHMNClJTVlAyPC1SU1ZQW1JTVlAkU2V4ICE9ICJPIiwgXQ0KDQojIEFuZCBkbyB0aGUgc2FtZSBtb2RlbCBhZ2Fpbg0KbW9kMiA8LSBtYW5vdmEoY2JpbmQoQUJfTWFnbml0dWRlLCBBQl9JbnRlcmNlcHQsIEFCX1Nsb3BlKSB+IENGRiArIFNleCArIEFnZSwgZGF0YSA9IFJTVlAyKQ0KDQpzdW1tYXJ5KG1vZDIsIHRlc3QgPSAiUGlsbGFpIikNCmBgYA0KDQpSZW1vdmFsIG9mIHRob3NlIDIgcG9pbnRzIGRpZCBub3QgY2hhbmdlIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhlIHZhcmlhYmxlcy4gSG93ZXZlciwgaXQgZG9lcyBjaGFuZ2UgdGhlIGVmZmVjdCBzaXplLiBOb3csIGl0IGlzIG5vdCBTZXgsIGJ1dCByYXRoZXIgQ0ZGIHRoYXQgaGFzIHRoZSBsYXJnZXN0IGVmZmVjdCBvbiB0aGUgQUItcHJvZmlsZS4gV2UgcmVwb3J0IG9uIHRoaXMgaW4gdGhlIG1haW4gbWFudXNjcmlwdC4NCg0KDQpOb3csIG5leHQgaXNzdWU6IHRoZSBtb2RlbCBkaWFnbm9zdGljcyBmb3Igb3VyIG11bHRpdmFyaWF0ZSBtb2RlbCBkaWQgbm90IGxvb2sgZ3JlYXQuIE1vc3Qgb2YgdGhlIHJlc2lkdWFscyB3ZXJlIGNsdXN0ZXJlZCByaWdodCBpbiB0aCBtaWRkbGUuIEhvd2V2ZXIsIHRoZSByZXNpZHVhbHMgZm9yIHRoZSB1bml2YXJpYXRlIG1vZGVscyBsb29rZWQgbXVjaCBiZXR0ZXIuIFNvIGl0IGlzIGxpa2VseSB0aGUgY29tYmluZWQgZWZmZWN0IG9mIHRoZSAzIHJlc3BvbnNlIHZhcmlhYmxlcyB0b2dldGhlciB0aGF0IGRvZXMgc29tZXRoaW5nIHdlaXJkIHdpdGggdGhlIGRhdGEuIFRoZSBjbHVzdGVyaW5nIGluIHRoZSByZXNpZHVhbCBwbG90IG9mIHRoZSBtYW5vdmEgbW9kZWwgc2hvd3MgdGhhdCB0aGUgdmFyaWFuY2UgbWF5IG5vdCBiZSBlcXVhbGx5IGRpc3RyaWJ1dGVkIGFjcm9zcyB0aGUgMyByZXNwb25zZXMuIFdlIGNhbiBzY2FsZSB0aGUgcmVzcG9uc2UgZGF0YSB0byBzZWUgaWYgdGhhdCBmaXhlcyBvdXIgaXNzdWUuDQoNCihUaGUgc2NhbGUgZnVuY3Rpb24gc3VidHJhY3RzIHRoZSBjb2x1bW4gbWVhbiBhbmQgZGl2aWRlcyBieSB0aGUgY29sdW1uIFNEIGZvciBlYWNoIHZhbHVlIGluIHRoYXQgY29sdW1uLiBUaGlzIHdheSBlYWNoIGNvbHVtbiBoYXMgYSBtZWFuIG9mIDAgYW5kIGFuIFNEIG9mIDEsIHRodXMgc3RhbmRhcmRpemluZyB0aGUgZGF0YS4gSGFuZHkgZm9yIHdoZW4gZGlmZmVyZW50IHZhcmlhYmxlcyBoYXZlIGRpZmZlcmVudCBtYWduaXR1ZGVzIG9yIGEgYmlnIGRpZmZlcmVuY2UgaW4gdmFyaWFuY2UpDQoNCmBgYHtyfQ0KeV9zY2FsZWQ8LSBzY2FsZShjYmluZChSU1ZQJEFCX01hZ25pdHVkZSwgUlNWUCRBQl9JbnRlcmNlcHQsIFJTVlAkQUJfU2xvcGUpKQ0KDQojIE5vdyB0cnkgdGhlIG1vZGVsIGFnYWluDQptb2QzIDwtIG1hbm92YSh5X3NjYWxlZCB+IFJTVlAkQ0ZGICsgUlNWUCRTZXggKyBSU1ZQJEFnZSkNCg0Kc3VtbWFyeShtb2QzLCB0ZXN0ID0gIlBpbGxhaSIpDQpgYGANCg0KTm93IGxldCdzIGNoZWNrIHRoZSBhc3N1bXB0aW9ucyBhZ2FpbjoNCg0KYGBge3J9DQpxcVBsb3QobW9kMyRyZXNpZHVhbHMpDQpwbG90KHJlc2lkdWFscyhtb2QzKSB+IGZpdHRlZChtb2QzKSkNCmBgYA0KDQpNdWNoIGJldHRlciEgTGV0J3MgYWxzbyBjaGVjayBmb3IgbGluZWFyaXR5IGJldHdlZW4gb3VyIHByZWRpY3RvciBhbmQgcmVzcG9uc2UgdmFyaWFibGVzDQoNCmBgYHtyfQ0KY3JQbG90cyhsbShSU1ZQJEFCX01hZ25pdHVkZSB+IFJTVlAkQ0ZGKSkNCmNyUGxvdHMobG0oUlNWUCRBQl9JbnRlcmNlcHQgfiBSU1ZQJENGRikpDQpjclBsb3RzKGxtKFJTVlAkQUJfU2xvcGUgfiBSU1ZQJENGRikpDQpgYGANCg0KUHJldHR5IGdvb2QgdG9vLiBOb3cganVzdCB0byBiZSBjb21wbGV0ZSwgbGV0J3MgZG8gdGhlIHNhbWUgdGhpbmcgZm9yIHRoZSBtb2RlbCB3aXRoIHRoZSB0d28gaW5mbHVlbnRpYWwgcG9pbnRzIHJlbW92ZWQgYW5kIGNvbXBhcmUgdGhlIHJlc3VsdHMNCg0KDQpgYGB7cn0NCiMgTWFrZSB0aGUgbW9kZWwgd2l0aG91dCB0aGUgIk8iIGdyb3VwIGFnYWluLCB3aXRoIG91ciByZXNwb25zZSB2YXJpYWJsZXMgc2NhbGVkDQp5X3NjYWxlZDI8LSBzY2FsZShjYmluZChSU1ZQMiRBQl9NYWduaXR1ZGUsIFJTVlAyJEFCX0ludGVyY2VwdCwgUlNWUDIkQUJfU2xvcGUpKQ0KbW9kNCA8LSBtYW5vdmEoeV9zY2FsZWQyIH4gUlNWUDIkQ0ZGICsgUlNWUDIkU2V4ICsgUlNWUDIkQWdlKQ0Kc3VtbWFyeShtb2Q0LCB0ZXN0ID0gIlBpbGxhaSIpDQoNCiMgQW5kIGNvbXBhcmUgYWdhaW5zdCBvdXIgbWFpbiBtb2RlbCAod2l0aCAiTyIgZ3JvdXApDQpzdW1tYXJ5KG1vZDMsIHRlc3QgPSAiUGlsbGFpIikNCmBgYA0KVmVyeSBzaW1pbGFyIHJlc3VsdHMuIFdlIGp1c3QgbmVlZCB0byBrZWVwIGluIG1pbmQgdGhhdCB0aGUgZWZmZWN0IHNpemVzIGZvciB0aGUgdHdvIHByZWRpY3RvcnMgYXJlIHNsaWdodGx5IGRpZmZlcmVudCBkZXBlbmRpbmcgb24gd2hldGhlciBvciBub3QgdGhlIGluZmx1ZW50aWFsIHBvaW50cyBhcmUga2VwdCBpbiB0aGUgZGF0YSBzZXQuDQoNCk9uZSBsYXN0IGNoZWNrOiBzaW5jZSBTZXggaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgd2UgbmVlZCB0byBjaGVjayB0aGF0IHRoZSBhc3N1bXB0aW9uIGZvciBNQU5PVkEgaXMgbWV0IHRoYXQgdGhlIGRpZmZlcmVudCBncm91cHMgaGF2ZSBlcXVhbCBjb3ZhcmlhbmNlIG1hdHJpY2VzLiBXZSdsbCBkbyB0aGlzIGZvciB0aGUgZGF0YSBzZXQgdGhhdCBoYXMgdGhlIHR3byAiTyIgZGF0YXBvaW50cyByZW1vdmVkLCBzaW5jZSB3ZSBhbHJlYWR5IGtub3cgdGhlc2UgdHdvIHBvaW50cyBtYWRlIHRoZSBkYXRhIHNldCB2ZXJ5IHVuZXZlbi4NCg0KYGBge3J9DQpib3hNKFJTVlAyWywgYygiQUJfTWFnbml0dWRlIiwgIkFCX0ludGVyY2VwdCIsICJBQl9TbG9wZSIpXSwgUlNWUDIkU2V4KQ0KYGBgDQpUaGUgcmVzdWx0IGlzIG5vdCBzaWduaWZpY2FudCwgc28gdGhlIGNvdmFyaWFuY2UgbWF0cmljZXMgY2FuIGJlIGNvbnNpZGVyZWQgZXF1YWwgZm9yIG1hbGVzIGFuZCBmZW1hbGVzLg0KDQoNCk5leHQgcGFydDoNCg0KDQpOb3cgdGhhdCB3ZSBrbm93IENGRiBoYXMgYW4gZWZmZWN0IG9uIHRoZSBhdHRlbnRpb25hbCBibGluayBlZmZlY3QsIHdlIG5lZWQgdG8gZXhhbWluZSB3aGljaCBvZiBvdXIgMyBBQiBtZWFzdXJlcyBpcyBtb3N0IGFmZmVjdGVkIGJ5IGl0LiBXZSdsbCBkbyB0aGlzIHdpdGggdGhlIFJveS1CYXJnbWFubiBzdGVwZG93biBwcm9jZWR1cmU6IHdlIGRvIHVuaXZhcmlhdGUgbW9kZWxzIGluIHN0ZXB3aXNlIGZhc2hpb24sIHN0YXJ0aW5nIHdpdGggb3VyIG1vc3QgaW1wb3J0YW50IHJlc3BvbnNlIHZhcmlhYmxlLCB0aGUgQUIgbWFnbml0dWRlLiBTaW5jZSB3ZSBoYXZlIDMgcmVzcG9uc2UgdmFyaWFibGVzLCB3ZSBuZWVkIHRvIGRvIEJvbmZlcnJvbmkgY29ycmVjdGlvbiB0byBhY2NvdW50IGZvciB0aGUgcmVwZWF0ZWQgdGVzdGluZzogb3VyIHJlc3VsdCB3aWxsIGJlIHNpZ25pZmljYW50IGlmIFAgPCAwLjA1LzMgPSAgMC4wMTY3Lg0KDQoNCmBgYHtyfQ0KUkIxPC0gbG0oQUJfTWFnbml0dWRlIH4gQ0ZGICsgU2V4ICsgQWdlLCBkYXRhID0gUlNWUCkNCnN1bW1hcnkoUkIxKQ0KYGBgDQoNClRoZSBQIHZhbHVlIGlzIHNtYWxsZXIgdGhhbiAwLjAxNjcsIHNvIENGRiBoYXMgYSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIEFCIG1hZ25pdHVkZS5Ob25lIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgcmVtYWluIHNpZ25pZmljYW50Lg0KDQpOb3cgd2UgdGVzdCB0aGUgc2Vjb25kIG1vc3QgaW1wb3J0YW50IHJlc3BvbnNlIHZhcmlhYmxlIChBQiBpbnRlcmNlcHQpIGFuZCBhZGQgQUIgTWFnbml0dWRlIGFzIGEgY292YXJpYXRlIGluIHRoZSBtb2RlbC4NCg0KYGBge3J9DQpSQjI8LWxtKEFCX0ludGVyY2VwdCB+IENGRiArIFNleCArIEFnZSArIEFCX01hZ25pdHVkZSwgZGF0YSA9IFJTVlApDQpzdW1tYXJ5KFJCMikNCmBgYA0KDQpDRkYgZG9lcyBub3QgaGF2ZSBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiBiYXNlbGluZSBwZXJmb3JtYW5jZSBvbiBUMiB3aGVuIHRoZSBBQiBtYWduaXR1ZGUgaXMgYWNjb3VudGVkIGZvci4gdGh1cywgd2Ugc3RvcCBvdXIgc3RlcGRvd24gcHJvY2VzcyBoZXJlLiBJbnRlcmNlcHQgZG9lcyBub3QgZXhwbGFpbiBhbnkgYWRkaXRpb25hbCBhbW91bnQgb2YgdmFyaWFuY2UgaW4gdGhlIGRhdGEgKGFuZCBzaW5jZSB3ZSBkZXRlcm1pbmVkIG91ciB0aGlyZCBwcmVkaWN0b3IsIFNsb3BlLCB0byBiZSBhIGxvd2VyIHByaW9yaXR5LCB3ZSBoYXZlIHRvIGFzc3VtZSB0aGlzIG9uZSBkb2VzIG5vdCBvZmZlciBhbnkgYWRkaXRpb25hbCBleHBsYW5hdG9yeSBwb3dlciBlaXRoZXIpLiANCg0KSG93ZXZlciwgZm9yIEFCIGludGVyY2VwdCwgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBlZmZlY3Qgb2YgZ2VuZGVyOiBNYWxlcyBoYXZlIGhpZ2hlciBvdmVyYWxsIGFjY3VyYWN5Lg0KDQoNCipUMSBBY2N1cmFjeSBhbmFseXNpcyoNCg0KTm93IGxldCdzIG1vdmUgb24gdG8gdGhlIG90aGVyIHBhcnQgb2YgdGhlIFJTVlAgdGFzazogYWNjdXJhY3kgb24gVDEuIFRoaXMgaXMgcHJldHR5IHN0cmFpZ2h0IGZvcndhcmQsIHdlIGNhbiBkbyBhIHNpbXBsZSByZWdyZXNzaW9uLiANCmBgYHtyfQ0KIyBSZWdyZXNzaW9uIHdpdGggVDEgYWNjdXJhY3kgYXMgdGhlIHJlc3BvbnNlLCBhbmQgdGhlIHNhbWUgcHJlZGljdG9ycyB3ZSBoYWQgZm9yIHRoZSBBQiBhbmFseXNpcw0KVDFtb2Q8LWxtKFJTVlBfVDEgfiBDRkYgKyBBZ2UgKyBTZXggKyBBZ2UsIGRhdGEgPSBSU1ZQKQ0Kc3VtbWFyeShUMW1vZCkNCmBgYA0KDQpDRkYgYW5kIEFnZSBoYXZlIG5vIGVmZmVjdCBvbiBwZW9wbGUncyBhYmlsaXR5IHRvIHByZWRpY3QgdGhlIGZpcnN0IHRhcmdldC4gSnVzdCBsaWtlIHdpdGggQUIsIHNleCBpcyBhIHNpZ25pZmljYW50IGZhY3RvciB0aG91Z2guIENoZWNrIG1lYW5zIHBlciBnZW5kZXI6DQoNCmBgYHtyfQ0KbWVhbihSU1ZQJFJTVlBfVDFbUlNWUCRTZXggPT0gIkYiXSkNCnNkKFJTVlAkUlNWUF9UMVtSU1ZQJFNleCA9PSAiRiJdKQ0KbWVhbihSU1ZQJFJTVlBfVDFbUlNWUCRTZXggPT0gIk0iXSkNCnNkKFJTVlAkUlNWUF9UMVtSU1ZQJFNleCA9PSAiTSJdKQ0KbWVhbihSU1ZQJFJTVlBfVDFbUlNWUCRTZXggPT0gIk8iXSkNCnNkKFJTVlAkUlNWUF9UMVtSU1ZQJFNleCA9PSAiTyJdKQ0KYGBgDQoNCkNoZWNrIGxpbmVhciBtb2RlbCBhc3N1bXB0aW9ucw0KDQpgYGB7cn0NCnFxUGxvdChUMW1vZCRyZXNpZHVhbHMpDQpuY3ZUZXN0KFQxbW9kKQ0KcmVzaWR1YWxQbG90cyhUMW1vZCkNCmluZmx1ZW5jZUluZGV4UGxvdChUMW1vZCwgdmFycyA9ICJDb29rIikNCmluZmx1ZW5jZUluZGV4UGxvdChUMW1vZCwgdmFycyA9ICJoYXQiKQ0Kb3V0bGllclRlc3QoVDFtb2QpDQpgYGANCg0KVGhlIHZhcmlhbmNlIGlzbid0IGhldGVyb2dlbmVvdXMsIGFuZCB0aGVyZSBpcyBvbmUgc2lnbmlmaWNhbnQgb3V0bGllciBkZXRlY3RlZC4gVGhlIHR3byAiTyIgZGF0YSBwb2ludHMgaW4gdGhlIHNleCB2YXJpYWJsZSBvZiBjb3Vyc2UgYWxzbyBzdGlsbCBoYXZlIGV4dHJlbWUgbGV2ZXJhZ2UuIExldCdzIHRha2UgdGhlc2UgcG9pbnRzIG91dCBhbmQgc2VlIGlmIHRoYXQgaW1wcm92ZXMgdGhlIG1vZGVsIGZpdC4gDQoNCmBgYHtyfQ0KVDFkZjwtIFJTVlBbLWMoMTgsIDQzLCA0NSksXQ0KVDFtb2QyPC1sbShSU1ZQX1QxIH4gQ0ZGICsgU2V4ICsgQWdlLCBkYXRhID0gVDFkZikNCnN1bW1hcnkoVDFtb2QyKQ0KDQpxcVBsb3QoVDFtb2QyJHJlc2lkdWFscykNCm5jdlRlc3QoVDFtb2QyKQ0KcmVzaWR1YWxQbG90cyhUMW1vZDIpDQppbmZsdWVuY2VJbmRleFBsb3QoVDFtb2QyLCB2YXJzID0gIkNvb2siKQ0KaW5mbHVlbmNlSW5kZXhQbG90KFQxbW9kMiwgdmFycyA9ICJoYXQiKQ0Kb3V0bGllclRlc3QoVDFtb2QyKQ0KYGBgDQoNCk9rLCB0aGUgbW9kZWwgbWVldHMgYWxsIHRoZSBhc3N1bXB0aW9ucywgYW5kIHNleCBpcyBzdGlsbCBhIHNpZ25pZmljYW50IGZhY3Rvci4NCg0KDQoqUGxvdHMqDQoNCk5vdyBsZXQncyBtYWtlIHNvbWUgbmljZSBwbG90cyBvZiBvdXIgcmVzdWx0czoNCg0KYGBge3J9DQojIEZpcnN0IENGRiB2cyB0aGUgQUIgbWFnbml0dWRlDQpwbG90MTwtZ2dwbG90KGRhdGEgPSBSU1ZQLCBhZXMoeCA9IENGRiwgeSA9IEFCX01hZ25pdHVkZSkpDQpwbG90MStnZW9tX3BvaW50KHNpemUgPSA0LCBjb2xvdXIgPSAiIzRDNzJCMCIsIGFscGhhID0gMC43KStnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvdXIgPSAiI0Y2QkQ2MCIsIHNlID0gRkFMU0UsIGFscGhhID0gMC4xNSkrdGhlbWVfY2xhc3NpYygpK3RoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1LCBmYWNlID0gImJvbGQiKSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksIHBsb3QubWFyZ2luID0gbWFyZ2luKDQwLCA0MCwgNDAsIDQwKSkrbGFicyh4PSAiQ0ZGIGluIEh6IiwgeSA9IGV4cHJlc3Npb24oYm9sZCgiQUIgbWFnbml0dWRlICgiICogbGFnWzddLWxhZ1s0XSAqICIpIikpKQ0KZ2dzYXZlKCJBQk1hZzQuc3ZnIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCBkZXZpY2UgPSBzdmdsaXRlKQ0KZ2dzYXZlKCJBQk1hZzQucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCBkcGkgPSAzMDApDQoNCiMgVGhlbiBDRkYgdnMgdGhlIEFCIEludGVyY2VwdA0KcGxvdDE8LWdncGxvdChkYXRhID0gUlNWUCwgYWVzKHggPSBDRkYsIHkgPSBBQl9JbnRlcmNlcHQpKQ0KcGxvdDErZ2VvbV9wb2ludChzaXplID0gNCwgY29sb3VyID0gIiM0QzcyQjAiLCBhbHBoYSA9IDAuNykrZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3VyID0gIiNGNkJENjAiLCBzZSA9IEZBTFNFLCBhbHBoYSA9IDAuMTUpK3RoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLCBwbG90Lm1hcmdpbiA9IG1hcmdpbig0MCwgNDAsIDQwLCA0MCkpK2xhYnMoeD0gIkNGRiBpbiBIeiIsIHkgPSBleHByZXNzaW9uKGJvbGQoIk92ZXJhbGwgVDIgYWNjdXJhY3kgKM6yIlswXSoiKSIpKSkNCmdnc2F2ZSgiQUJJbnQ0LnN2ZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCwgZGV2aWNlID0gc3ZnbGl0ZSkNCmdnc2F2ZSgiQUJJbnQ0LnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCwgZHBpID0gMzAwKQ0KDQojIEFuZCB0aGVuIENGRiB2cyB0aGUgQUIgU2xvcGUNCnBsb3QxPC1nZ3Bsb3QoZGF0YSA9IFJTVlAsIGFlcyh4ID0gQ0ZGLCB5ID0gQUJfU2xvcGUpKQ0KcGxvdDErZ2VvbV9wb2ludChzaXplID0gNCwgY29sb3VyID0gIiM0QzcyQjAiLCBhbHBoYSA9IDAuNykrZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3VyID0gIiNGNkJENjAiLCBzZSA9IEZBTFNFLCBhbHBoYSA9IDAuMTUpK3RoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLCBwbG90Lm1hcmdpbiA9IG1hcmdpbig0MCwgNDAsIDQwLCA0MCkpK2xhYnMoeD0gIkNGRiBpbiBIeiIsIHkgPSBleHByZXNzaW9uKGJvbGQoIlQyIHJlY292ZXJ5IHJhdGUgKM6yIlsxXSoiKSIpKSkNCmdnc2F2ZSgiQUJTbG9wZTQuc3ZnIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCBkZXZpY2UgPSBzdmdsaXRlKQ0KZ2dzYXZlKCJBQlNsb3BlNC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCkNCmBgYA0KDQpOZXh0LCBhIGJhciBwbG90IHNob3dpbmcgdGhlIGF0dGVudGlvbmFsIGJsaW5rIGVmZmVjdA0KDQpgYGB7cn0NCiMgRmlyc3QgdGFrZSB0aGUgY29sdW1ucyB3ZSBuZWVkDQpUMVBsb3Q8LURhdGFzZXRbYygiUlNWUF9UMUwxIiwgIlJTVlBfVDFMMiIsICJSU1ZQX1QxTDMiLCAiUlNWUF9UMUw0IiwgIlJTVlBfVDFMNSIsICJSU1ZQX1QxTDYiLCAiUlNWUF9UMUw3IildDQoNClQyUGxvdDwtRGF0YXNldFtjKCJSU1ZQX1QyTDEiLCAiUlNWUF9UMkwyIiwgIlJTVlBfVDJMMyIsICJSU1ZQX1QyTDQiLCAiUlNWUF9UMkw1IiwgIlJTVlBfVDJMNiIsICJSU1ZQX1QyTDciKV0NCg0KI1RoZW4gcmVtb3ZlIHRoZSByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMgZnJvbSB0aGUgZGF0YXNldA0KVDFQbG90PC1uYS5vbWl0KFQxUGxvdCkNClQyUGxvdDwtbmEub21pdChUMlBsb3QpDQoNCiMgTm93IHBpdm90IHRoZSBkYXRhIGludG8gbG9uZyBmb3JtIA0KVDFfbG9uZyA8LSBUMVBsb3QgJT4lDQogIGRwbHlyOjpzZWxlY3QoMTo3KSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQpUMl9sb25nIDwtIFQyUGxvdCAlPiUNCiAgZHBseXI6OnNlbGVjdCgxOjcpICU+JQ0KICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpDQoNCiMgTm93IGdldCB0aGUgVDEgbWVhbnMgZm9yIGVhY2ggbGFnIHZhbHVlLCBwbHVzIFNFIGFuZCBjb25maWRlbmNlIGludGVydmFscyBmb3IgZXJyb3IgYmFycw0KVDFkYXQgPC0gVDFfbG9uZyAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgVDFtZWFuID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBUMXNlID0gc2QodmFsdWUsIG5hLnJtID0gVFJVRSkvc3FydChuKCkpLA0KICAgIGNpX2xvdyA9IFQxbWVhbiAtIHF0KDAuOTc1LCBkZiA9IG4oKSAtIDEpICogVDFzZSwNCiAgICBjaV9oaSA9IFQxbWVhbiArIHF0KDAuOTc1LCBkZiA9IG4oKSAtIDEpICogVDFzZQ0KICAgICkNCg0KIyBhbmQgYWxzbyBmb3IgVDIuIFdlJ2xsIGFsc28gY2FsY3VsYXRlIFNFIGFuZCBjb25maWRlbmNlIGludGVydmFscyBoZXJlIHNvIHdlIGNhbiBhZGQgZXJyb3IgYmFycw0KVDJkYXQgPC0gVDJfbG9uZyAlPiUNCiAgZ3JvdXBfYnkodmFyaWFibGUpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgVDJtZWFuID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKSwgDQogICAgVDJzZSA9IHNkKHZhbHVlLCBuYS5ybSA9IFRSVUUpL3NxcnQobigpKSwNCiAgICBjaV9sb3cgPSBUMm1lYW4gLSBxdCgwLjk3NSwgZGYgPSBuKCkgLSAxKSAqIFQyc2UsDQogICAgY2lfaGkgPSBUMm1lYW4gKyBxdCgwLjk3NSwgZGYgPSBuKCkgLSAxKSAqIFQyc2UNCiAgICApDQoNCiMgVGhlbiBtZXJnZSB0aGUgVDEgbWVhbnMgYW5kIFQyIG1lYW5zIGludG8gb25lIGRhdGFmcmFtZQ0KQUJQbG90PC1kYXRhLmZyYW1lKExhZyA9IGMoIjEiLCIyIiwiMyIsIjQiLCI1IiwiNiIsIjciKSwgVDFtZWFuID0gVDFkYXQkVDFtZWFuLCBUMXNlID0gVDFkYXQkVDFzZSwgVDFjaV9sb3cgPSBUMWRhdCRjaV9sb3csIFQxY2lfaGkgPSBUMWRhdCRjaV9oaSwgVDJtZWFuID0gVDJkYXQkVDJtZWFuLCBUMnNlID0gVDJkYXQkVDJzZSwgVDJjaV9sb3cgPSBUMmRhdCRjaV9sb3csIFQyY2lfaGkgPSBUMmRhdCRjaV9oaSkNCmBgYA0KDQpOb3cgcGxvdA0KDQpgYGB7cn0NCmdncGxvdChBQlBsb3QsIGFlcyh4ID0gTGFnKSkgKw0KICBnZW9tX2NvbChhZXMoeSA9IFQybWVhbiksIGZpbGwgPSAiI0Y2QkQ2MCIsIGNvbG91ciA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuNSkgKyANCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IFQyY2lfbG93LCB5bWF4ID0gVDJjaV9oaSksIHdpZHRoID0gMC4yKSArDQogIGdlb21fbGluZShhZXMoeSA9IFQxbWVhbiwgZ3JvdXAgPSAxKSwgbGluZXdpZHRoID0gMC44LCBjb2xvdXIgPSAiIzRDNzJCMCIpICsNCiAgZ2VvbV9wb2ludChhZXMoeSA9IFQxbWVhbiksIHNpemUgPSAyLCBjb2xvdXIgPSAiIzRDNzJCMCIpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IFQxY2lfbG93LCB5bWF4ID0gVDFjaV9oaSksIHdpZHRoID0gMC4yLCBjb2xvdXIgPSAiIzRDNzJCMCIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgbGFicyh5ID0gIk1lYW4gYWNjdXJhY3kiLCB4ID0gIkxhZyBsZXZlbCIpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIpLCBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgcGxvdC50aXRsZSA9ICAgDQogIGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoDQogICAgUlNWUF9MMSA9ICJsYWcgMSIsDQogICAgUlNWUF9MMiA9ICJsYWcgMiIsDQogICAgUlNWUF9MMyA9ICJsYWcgMyIsDQogICAgUlNWUF9MNCA9ICJsYWcgNCIsDQogICAgUlNWUF9MNSA9ICJsYWcgNSIsDQogICAgUlNWUF9MNiA9ICJsYWcgNiIsDQogICAgUlNWUF9MNyA9ICJsYWcgNyINCiAgKSkNCmdnc2F2ZSgiQUJQbG90LnN2ZyIsIGRldmljZSA9IHN2Z2xpdGUpDQpnZ3NhdmUoIkFCUGxvdC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KYGBgDQoNCkxldCdzIGFsc28gZ2V0IHRoZSBtZWFuIGFuZCBzZCBmb3IgVDEgYWNjdXJhY3ksIGJvdGggYWNyb3NzIGFsbCBsYWdzIGFuZCBqdXN0IGZvciBMYWcxIHRyaWFscyAoYmVjYXVzZSBpdCBpcyBtdWNoIGxvd2VyIHRoZXJlIGNvbXBhcmVkIHRvIG90aGVyIGxhZ3MpDQpgYGB7cn0NCiMgbWVhbiBhY3Jvc3MgYWxsIGxhZ3MNCm1lYW4oUlNWUCRSU1ZQX1QxKQ0Kc2QoUlNWUCRSU1ZQX1QxKQ0KDQojIG1lYW4gb2YganVzdCBMYWcgMSB0cmlhbHMNClQxTDE8LSBzdWJzZXQoVDFfbG9uZywgdmFyaWFibGUgPT0gIlJTVlBfVDFMMSIpJHZhbHVlDQptZWFuKFQxTDEpDQpzZChUMUwxKQ0KYGBgDQoNCk5vdyB3ZSBrbm93IEFCIG1hZ25pdHVkZSBpcyBwcmVkaWN0ZWQgYnkgQ0ZGLCBidXQgd2UgZG9uJ3Qga25vdyBleGFjdGx5IGhvdyBwZXJmb3JtYW5jZSBhY3Jvc3MgbGFncyBtYXkgdmFyeSBkZXBlbmRpbmcgb24gc29tZW9uZSdzIENGRi4gV2UgY2FuIGxvb2sgaW50byB0aGlzIGlmIHdlIGRpdmlkZSB0aGUgZGF0YSBpbnRvIHR3byBncm91cHMgYW5kIHBsb3QgdGhlbTogV2UnbGwgc29ydCB0aGUgZGF0YSBieSBDRkYsIGFuZCB0aGUgbG93ZXIgaGFsZiB3aWxsIGJlIGEgIkxvdyBDRkYiIGdyb3VwIGFuZCB0aGUgdXBwZXIgaGFsZiB3aWxsIGJlIGEgIkhpZ2ggQ0ZGIiBncm91cC4NCg0KYGBge3J9DQojIEZpcnN0IHRha2UgYWxsIHRoZSBjb2x1bW5zIHdlIG5lZWQNClJTVlAzPC1EYXRhc2V0W2MoIlBhcnRpY2lwYW50IiwgIkNGRiIsICJBQl9NYWduaXR1ZGUiLCAiQUJfSW50ZXJjZXB0IiwgIkFCX1Nsb3BlIiwgIlJTVlBfVDFMMSIsICJSU1ZQX1QxTDIiLCJSU1ZQX1QxTDMiLCJSU1ZQX1QxTDQiLCJSU1ZQX1QxTDUiLCJSU1ZQX1QxTDYiLCJSU1ZQX1QxTDciLCJSU1ZQX1QyTDEiLCAiUlNWUF9UMkwyIiwgIlJTVlBfVDJMMyIsICJSU1ZQX1QyTDQiLCAiUlNWUF9UMkw1IiwgIlJTVlBfVDJMNiIsICJSU1ZQX1QyTDciKV0NCg0KIyBUaGVuIHJlbW92ZSB0aGUgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIGZyb20gdGhlIGRhdGFzZXQNClJTVlAzPC1uYS5vbWl0KFJTVlAzKQ0KDQojIFRoZW4gYWRkIGEgbmV3IGNvbHVtbiBjYXRlZ29yaXppbmcgdGhlIGRhdGEgYnkgQ0ZGIGdyb3VwDQpSU1ZQMyA8LSBSU1ZQMyAlPiUNCiAgbXV0YXRlKA0KICAgIENGRkdyb3VwID0gbnRpbGUoQ0ZGLCAyKSwgICAjIHNwbGl0IGludG8gdHdvIHF1YW50aWxlcw0KICAgIENGRkdyb3VwID0gZmFjdG9yKENGRkdyb3VwLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkxvd0NGRiIsICJIaWdoQ0ZGIikpDQogICkNCg0KIyBTYW5pdHkgY2hlY2s6IGhvdyBtYW55IHBhcnRpY2lwYW50cyBhcmUgaW4gZWFjaCBncm91cD8NCnRhYmxlKFJTVlAzJENGRkdyb3VwKQ0KYGBgDQoNCk5vdyBwcmVwYXJlIGRhdGEgZm9yIHBsb3R0aW5nOg0KDQpgYGB7cn0NCiMgRmlyc3QgbWFrZSB0aGUgZGF0YWZyYW1lIGluIGxvbmcgZm9ybWF0IChUMSBhY2N1cmFjeSBmaXJzdCkNClJTVlBUMV9sb25nIDwtIFJTVlAzICU+JQ0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IDY6MTIsIA0KICAgIG5hbWVzX3RvID0gIlQxTGFnIiwNCiAgICB2YWx1ZXNfdG8gPSAiVDFBY2N1cmFjeSIsDQogICkNCg0KIyBUaGVuIGEgZGF0YWZyYW1lIGluIGxvbmcgZm9ybWF0IGZvciBUMiBhY2N1cmFjeQ0KUlNWUFQyX2xvbmcgPC0gUlNWUDMgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gMTM6MTksIA0KICAgIG5hbWVzX3RvID0gIlQyTGFnIiwNCiAgICB2YWx1ZXNfdG8gPSAiVDJBY2N1cmFjeSIsDQogICkNCg0KIyBOb3cgY2FsY3VsYXRlIFQxIG1lYW5zIGFuZCBzdGFuZGFyZCBlcnJvcnMgZm9yIGJhciBwbG90DQpUMUxhZ19tZWFucyA8LSBSU1ZQVDFfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoVDFMYWcsIENGRkdyb3VwKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIFQxTWVhbiA9IG1lYW4oVDFBY2N1cmFjeSwgbmEucm0gPSBUUlVFKSwNCiAgICBUMVNFICAgPSBzZChUMUFjY3VyYWN5LCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIEFuZCB0aGUgc2FtZSBmb3IgVDIgbWVhbnMgYW5kIHN0YW5kYXJkIGVycm9ycw0KVDJMYWdfbWVhbnMgPC0gUlNWUFQyX2xvbmcgJT4lDQogIGdyb3VwX2J5KFQyTGFnLCBDRkZHcm91cCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBUMk1lYW4gPSBtZWFuKFQyQWNjdXJhY3ksIG5hLnJtID0gVFJVRSksDQogICAgVDJTRSAgID0gc2QoVDJBY2N1cmFjeSwgbmEucm0gPSBUUlVFKSAvIHNxcnQobigpKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KIyBHZXQgdGhlIGRlc2lyZWQgY29sdW1ucyBmcm9tIHRob3NlIGRhdGFmcmFtZXMgYW5kIGNvbWJpbmUgdGhlbSBpbnRvIGEgbmV3IGRhdGFmcmFtZQ0KZ3JvdXBkaWZmczwtZGF0YS5mcmFtZShUMkxhZ19tZWFucyRUMkxhZywgVDJMYWdfbWVhbnMkQ0ZGR3JvdXAsIFQyTGFnX21lYW5zJFQyTWVhbiwgVDJMYWdfbWVhbnMkVDJTRSwgVDFMYWdfbWVhbnMkVDFNZWFuLCBUMUxhZ19tZWFucyRUMVNFKQ0KDQojIFRoZSBjb21iaW5lZCBjb2x1bW5zIHdpbGwgaGF2ZSB3ZWlyZCBuYW1lcy4gRml4IGl0DQpuYW1lcyhncm91cGRpZmZzKVtuYW1lcyhncm91cGRpZmZzKSA9PSAiVDJMYWdfbWVhbnMuVDJMYWciXSA8LSAiVDJMYWciDQpuYW1lcyhncm91cGRpZmZzKVtuYW1lcyhncm91cGRpZmZzKSA9PSAiVDJMYWdfbWVhbnMuQ0ZGR3JvdXAiXSA8LSAiQ0ZGR3JvdXAiDQpuYW1lcyhncm91cGRpZmZzKVtuYW1lcyhncm91cGRpZmZzKSA9PSAiVDJMYWdfbWVhbnMuVDJNZWFuIl0gPC0gIlQyTWVhbiINCm5hbWVzKGdyb3VwZGlmZnMpW25hbWVzKGdyb3VwZGlmZnMpID09ICJUMkxhZ19tZWFucy5UMlNFIl0gPC0gIlQyU0UiDQpuYW1lcyhncm91cGRpZmZzKVtuYW1lcyhncm91cGRpZmZzKSA9PSAiVDFMYWdfbWVhbnMuVDFNZWFuIl0gPC0gIlQxTWVhbiINCm5hbWVzKGdyb3VwZGlmZnMpW25hbWVzKGdyb3VwZGlmZnMpID09ICJUMUxhZ19tZWFucy5UMVNFIl0gPC0gIlQxU0UiDQpgYGANCg0KTm93IHdlJ3JlIHJlYWR5IHRvIHBsb3Q6DQoNCmBgYHtyfQ0KIyBNYWtlIHRoZSBnZ3Bsb3Qgb2JqZWN0DQpHcm91cGRpZmY8LWdncGxvdChncm91cGRpZmZzLCBhZXMoeCA9IFQyTGFnLCBncm91cCA9IENGRkdyb3VwKSkNCg0KIyBBbmQgYWRkIGFsbCB0aGUgdmlzdWFscyB3ZSB3YW50IA0KR3JvdXBkaWZmICsgDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxLjIsIGFlcyh5ID0gVDJNZWFuLCBjb2xvciA9IENGRkdyb3VwLCBsaW5ldHlwZSA9ICJUMiIpKSArIA0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBhZXMoeSA9IFQyTWVhbiwgY29sb3IgPSBDRkZHcm91cCkpICsgDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBUMk1lYW4gLSBUMlNFLCB5bWF4ID0gVDJNZWFuICsgVDJTRSwgY29sb3IgPSBDRkZHcm91cCksIHdpZHRoID0gMC4yKSsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuOCwgYWVzKHkgPSBUMU1lYW4sIGNvbG9yID0gQ0ZGR3JvdXAsIGxpbmV0eXBlID0gIlQxIiksIGFscGhhID0gMC41KSArIA0KICBnZW9tX3BvaW50KHNpemUgPSAyLCBhZXMoeSA9IFQxTWVhbiwgY29sb3IgPSBDRkZHcm91cCksIGFscGhhID0gMC41KSArIA0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gVDFNZWFuIC0gVDFTRSwgeW1heCA9IFQxTWVhbiArIFQxU0UsIGNvbG9yID0gQ0ZGR3JvdXApLCB3aWR0aCA9IDAuMiwgYWxwaGEgPSAwLjcpKw0KICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODUiLCBsaW5ld2lkdGggPSAwLjMpLA0KICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTg1IiwgbGluZXdpZHRoID0gMC4zKSwNCiAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuNSksDQogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjUpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9IE5BKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiksIA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG91ciA9ICJibGFjayIpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDIwLCByID0gMTAsIGIgPSAxMCwgbCA9IDEwKQ0KICAgICkgKw0KICBsYWJzKHggPSAiTGFnIGxldmVsIiwgeSA9ICJBY2N1cmFjeSIsIGNvbG9yID0gIkNGRiBHcm91cCIpICsgDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiUlNWUF9UMkwxIiA9ICIxIiwgIlJTVlBfVDJMMiIgPSAiMiIsICJSU1ZQX1QyTDMiID0gIjMiLCAiUlNWUF9UMkw0IiA9ICI0IiwgIlJTVlBfVDJMNSIgPSAiNSIsICJSU1ZQX1QyTDYiID0gIjYiLCAiUlNWUF9UMkw3IiA9ICI3IikpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmNoaWQiLCAiZ3JlZW4zIiksIGxhYmVscyA9IGMoIkxvdyBDRkYiLCAiSGlnaCBDRkYiKSkgKyAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIlRhcmdldCIgLCB2YWx1ZXMgPSBjKCJUMiIgPSAic29saWQiLCAiVDEiID0gImRhc2hlZCIpKSAgDQpnZ3NhdmUoIjJncm91cGRpZmZMYWcuc3ZnIiwgZGV2aWNlID0gc3ZnbGl0ZSkNCmdnc2F2ZSgiMmdyb3VwZGlmZkxhZy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCmBgYA0KDQpXZSBjYW4gYWxzbyBjaGVjayBpZiB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBncm91cHMsIGVpdGhlciBpbiB0aGUgc2hhcGUgb2YgdGhlIG92ZXJhbGwgY3VydmUsIG9yIG9uIGFueSBwYXJ0aWN1bGFyIGxhZyBsZXZlbC4NCg0KV2UnbGwgZG8gYSBtaXhlZCBlZmZlY3RzIG1vZGVsIHRoYXQgaGFzIExhZyBhbmQgQ0ZGR3JvdXAgYXMgcHJlZGljdG9ycywgcGx1cyB0aGVpciBpbnRlcmFjdGlvbiB0ZXJtLiBJZiB0aGUgdGVybSBpcyBzaWduaWZpY2FudCwgd2UnbGwga25vdyBpZiB0aGUgZ3JvdXBzIGRpZmZlciBpbiB0aGVpciBwZXJmb3JtYW5jZSBhY3Jvc3MgbGFncy4gUGFydGljaXBhbnQgd2lsbCBiZSBpbmNsdWRlZCBhcyByYW5kb20gdGVybSwgc2luY2Ugd2UgaGF2ZSBtdWx0aXBsZSBtZWFzdXJlcw0KDQpgYGB7cn0NCmxtZW1vZDwtbG1lcihUMkFjY3VyYWN5IH4gQ0ZGR3JvdXAgKiBUMkxhZyArICgxfFBhcnRpY2lwYW50KSwgZGF0YSA9IFJTVlBUMl9sb25nKQ0KYW5vdmEobG1lbW9kKQ0KYGBgDQoNCkxhZyBpcyBzaWduaWZpY2FudCwgYnV0IHRoZSBpbnRlcmFjdGlvbiB0ZXJtIGlzIG5vdC4gU28gdGhlIG92ZXJhbGwgc2hhcGUgb2YgdGhlIHR3byBwZXJmb3JtYW5jZSBwbG90cyBpcyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgZ3JvdXBzLiBUaGlzIHRlbGxzIHVzIGVub3VnaCwgYnV0IHdlJ2xsIGFsc28gbG9vayBhdCBob3cgZGlmZmVyZW50IHBlcmZvcm1hbmNlIGlzIG9uIGEgbGFnLWJ5LWxhZyBsZXZlbCwgdXNpbmcgdGhlIEVzdGltYXRlZCBNYXJnaW5hbCBNZWFucyBmcm9tIHRoZSBtb2RlbC4gV2UnbGwgdXNlIHRoZSBlbW1lYW5zIHBhY2thZ2UgZm9yIHRoaXMuDQoNCmBgYHtyfQ0KVDJlbW08LWVtbWVhbnMobG1lbW9kLCBwYWlyd2lzZSB+IENGRkdyb3VwIHwgVDJMYWcpDQpzdW1tYXJ5KFQyZW1tKQ0KYGBgDQoNClBlcmZvcm1hbmNlIGlzIG5vdCBzaWduaWZpY2FudGx5IGRpZmZlcmVuY2UgYXQgYW55IGxhZyBsZXZlbCwgYnV0IGl0IGFwcHJvYWNoZXMgc2lnbmlmaWNhbmNlIG9uIExhZyAyIGFuZCBMYWcgNC4NCg0KVGhhdCdzIGl0IGZvciBvdXIgUlNWUCBhbmFseXNpcy4NCg0KDQoNCg0KDQoqKlBhcnQgMjogUkRNIGFuYWx5c2lzKioNCg0KTm93IGxldCdzIG1vdmUgb24gdG8gdGhlIFJETSBhbmFseXNpcy4gRmlyc3RseSwgb3VyIGV4cGVyaW1lbnRlcnMgd2hvIGNvbGxlY3RlZCB0aGUgZGF0YSB1c2VkIHNsaWdodGx5IGRpZmZlcmVudCBtZXRob2RvbG9naWVzIHRvIGFzc2VzcyB0aGUgY29oZXJlbmNlIHdpdGggd2hpY2ggYSBwYXJ0aWNpcGFudCBjb3VsZCBwZXJmb3JtIHdpdGggfjcwJSBhY2N1cmFjeS4gVGhlc2UgcmVzdWx0cyBmb3IgdGhlc2UgdHdvIG1ldGhvZHMgd2VyZSBrZXB0IHNlcGFyYXRlLCBzbyB3ZSBjYW4gY2hlY2sgaWYgdGhlcmUgYXJlIG5vIHN0YXRpc3RpY2FsbHkgcmVsZXZhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvIHNldHMuIExldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBtZWFucywgbWluL21heCB2YWx1ZXMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnM6DQoNCmBgYHtyfQ0KbWVhbihuYS5vbWl0KERhdGFzZXQkUkRNX2NvaF9RdWVzdCkpDQptZWFuKG5hLm9taXQoRGF0YXNldCRSRE1fY29oX1ZlcmlmeSkpDQoNCm1pbihuYS5vbWl0KERhdGFzZXQkUkRNX2NvaF9RdWVzdCkpDQptaW4obmEub21pdChEYXRhc2V0JFJETV9jb2hfVmVyaWZ5KSkNCg0KbWF4KG5hLm9taXQoRGF0YXNldCRSRE1fY29oX1F1ZXN0KSkNCm1heChuYS5vbWl0KERhdGFzZXQkUkRNX2NvaF9WZXJpZnkpKQ0KDQpzZChuYS5vbWl0KERhdGFzZXQkUkRNX2NvaF9RdWVzdCkpDQpzZChuYS5vbWl0KERhdGFzZXQkUkRNX2NvaF9WZXJpZnkpKQ0KYGBgDQoNClRoZSBtZWFucyBhcmUgcHJldHR5IHNpbWlsYXIuIFRoZSBtYXggdmFsdWVzIGFuZCBTRCdzIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQgdGhvdWdoLiBMZXQncyBkbyBhIHF1aWNrIHQtdGVzdA0KDQpgYGB7cn0NCnQudGVzdChEYXRhc2V0JFJETV9jb2hfUXVlc3QsIERhdGFzZXQkUkRNX2NvaF9WZXJpZnksIHZhci5lcXVhbCA9IEZBTFNFKQ0KYGBgDQoNClRoZSB0d28gc2V0cyBhcmUgbm90IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciwgc28gbGV0J3MgYW5hbHlzZSB0aGVtIHRvZ2V0aGVyLiBUaGV5J3JlIGdyb3VwZWQgdG9nZXRoZXIgaW4gdGhlIGNvbHVtbiAiQ29oZXJlbmNlIiBpbiB0aGUgcmF3IGRhdGFzZXQsIHNvIHdlJ2xsIGp1c3QgdXNlIHRoYXQNCg0KDQpMZXQncyBtYWtlIGEgZGF0YSBmcmFtZSBmcm9tIHRoZSByYXcgZGF0YToNCg0KYGBge3J9DQojIEZpcnN0IGdldCBvbmx5IHRoZSBjb2x1bW5zIHdlIG5lZWQgZm9yIG91ciBhbmFseXNpcw0KUkRNPC1EYXRhc2V0W2MoIkNGRiIsICJBZ2UiLCAiU2V4IiwgIkNvaGVyZW5jZSIsICJSRE1fUlRfdmVyaWZ5IildDQoNCiNUaGVuIHJlbW92ZSB0aGUgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIGZyb20gdGhlIGRhdGFzZXQNClJETTwtbmEub21pdChSRE0pDQpgYGANCg0KV2UgaGF2ZSA3OSBvYnNlcnZhdGlvbnMgZm9yIHRoaXMgcGFydC4NCg0KRmlyc3Qgd2XigJlsbCBzZWUgaWYgdGhlIGNvaGVyZW5jZSBhdCB3aGljaCBwYXJ0aWNpcGFudHMgcGVyZm9ybSB3aXRoIHJvdWdobHkgNzAlIGFjY3VyYWN5IGNhbiBiZSBwcmVkaWN0ZWQgYnkgQ0ZGLiBBZ2Fpbiwgd2Ugd2lsbCBhbHNvIHB1dCBBZ2UgYW5kIFNleCBpbiB0aGUgbW9kZWwgYXMgcHJlZGljdG9ycw0KDQpgYGB7cn0NClJETW1vZDE8LSBsbShDb2hlcmVuY2UgfiBDRkYgKyBBZ2UgKyBTZXgsIGRhdGEgPSBSRE0pDQpzdW1tYXJ5KFJETW1vZDEpDQpgYGANCg0KQ2hlY2sgdGhlIG1vZGVsIGFzc3VtcHRpb25zDQoNCmBgYHtyfQ0KcXFQbG90KFJETW1vZDEkcmVzaWR1YWxzKQ0Kc2hhcGlyby50ZXN0KFJETW1vZDEkcmVzaWR1YWxzKQ0KdmlmKFJETW1vZDEpDQpyZXNpZHVhbFBsb3RzKFJETW1vZDEpDQpuY3ZUZXN0KFJETW1vZDEpDQppbmZsdWVuY2VJbmRleFBsb3QoUkRNbW9kMSwgdmFycyA9ICJDb29rIikNCmluZmx1ZW5jZUluZGV4UGxvdChSRE1tb2QxLCB2YXJzID0gImhhdCIpDQpvdXRsaWVyVGVzdChSRE1tb2QxKQ0KYGBgDQoNClRoZSByZXNpZHVhbHMgYXJlbuKAmXQgZW50aXJlbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIGJ1dCBvdmVyYWxsIHRoZSBtb2RlbCBsb29rcyBnb29kLiBUaGUgQ29vaydzIGRpc3RhbmNlIHBsb3Qgc2hvd3Mgc29tZSBpbmZsdWVudGlhbCBwb2ludHMsIGJ1dCB0aGV5IGFyZSBub3Qgc2lnbmlmaWNhbnQgb3V0bGllcnMgaW4gdGhlIG91dGxpZXIgdGVzdC4gVGhlcmXigJlzIG5vIHJlbGF0aW9uc2hpcCBhdCBhbGwgYmV0d2VlbiBSRE0gY29oZXJlbmNlIGFuZCBhbnkgb2YgdGhlIHByZWRpY3RvcnMuIEp1c3QgdG8gY2hlY2ssIHdlIGNhbiBkcm9wIHRoZSBvdGhlciBwcmVkaWN0b3JzDQphbmQgb25seSBpbmNsdWRlIHRoZSBvbmUgd2XigJlyZSBpbnRlcmVzdGVkIGluIHRoZSBtb3N0IChDRkYpDQoNCmBgYHtyfQ0KUkRNbW9kMjwtIGxtKENvaGVyZW5jZSB+IENGRiwgZGF0YSA9IFJETSkNCnN1bW1hcnkoUkRNbW9kMikNCmBgYA0KDQpNYWtlcyBubyBkaWZmZXJlbmNlIGZvciB0aGUgcmVzdWx0LiBKdXN0IHRvIGJlIGV4dHJhIHN1cmUsIGxldOKAmXMgc2VwYXJhdGUgdGhlIGRhdGEgYnkgdGhlIHNsaWdodCBkaWZmZXJlbmNlIGluIG1ldGhvZG9sb2d5IHVzZWQgYnkgb3VyIHR3byBleHBlcmltZW50ZXJzLg0KDQpgYGB7cn0NCiMgVmVyc2lvbiAxIG9mIG91ciBzZXBhcmF0ZWQgZGF0YSBzZXQNClJETXYxPC1EYXRhc2V0W2MoIkNGRiIsICJBZ2UiLCAiU2V4IiwgIlJETV9jb2hfUXVlc3QiKV0NClJETXYxPC1uYS5vbWl0KFJETXYxKQ0KDQojIFZlcnNpb24gMiBvZiBvdXIgc2VwYXJhdGVkIGRhdGEgc2V0DQpSRE12MjwtRGF0YXNldFtjKCJDRkYiLCAiQWdlIiwgIlNleCIsICJSRE1fY29oX1ZlcmlmeSIpXQ0KUkRNdjI8LW5hLm9taXQoUkRNdjIpDQoNCiMgTm93IGZvciB0aGUgbGluZWFyIG1vZGVscw0KUXVlc3Rtb2Q8LWxtKFJETV9jb2hfUXVlc3QgfiBDRkYgKyBBZ2UgKyBTZXgsIGRhdGEgPSBSRE12MSkNCnN1bW1hcnkoUXVlc3Rtb2QpDQoNClZlcmlmeW1vZDwtbG0oUkRNX2NvaF9WZXJpZnkgfiBDRkYgKyBBZ2UgKyBTZXgsIGRhdGEgPSBSRE12MikNCnN1bW1hcnkoVmVyaWZ5bW9kKQ0KDQpgYGANCg0KU2ltaWxhciByZXN1bHRzOiBubyByZWxhdGlvbnNoaXAgYmV0d2VlbiBDRkYgYW5kIFJETSBjb2hlcmVuY2UNCg0KYGBge3J9DQpSRE1wbG90PC1nZ3Bsb3QoZGF0YSA9IFJETSwgYWVzKHggPSBDb2hlcmVuY2UsIHkgPSBDRkYpKQ0KUkRNcGxvdCArIA0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2xvdXIgPSAiIzRDNzJCMCIsIGFscGhhID0gMC43KSArIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvdXIgPSAiI0Y2QkQ2MCIsIHNlID0gRkFMU0UsIGFscGhhID0gIDAuMTUpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gICAgIDE4KSkgKyANCiAgbGFicyh4PSAiUkRNIENvaGVyZW5jZSIsIHkgPSAiQ0ZGIikNCmdnc2F2ZSgiUkRNUGxvdC5zdmciLCBkZXZpY2UgPSBzdmdsaXRlKQ0KZ2dzYXZlKCJSRE1QbG90LnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KYGBgDQoqKkVuZCoqDQoNCg==