1 Introduction

This report evaluates the prerequisites for conducting a Multivariate Analysis of Covariance (MANCOVA). We aim to determine if an educational intervention significantly affected Math and Reading scores while controlling for baseline performance.

1.1 Environment Setup & Data Preparation

library(tidyverse)   
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.0     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.2     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(MVN)         
## Warning: package 'MVN' was built under R version 4.5.3
library(biotools)    
## Warning: package 'biotools' was built under R version 4.5.3
## Loading required package: MASS
## 
## Attaching package: 'MASS'
## 
## The following object is masked from 'package:dplyr':
## 
##     select
## 
## ---
## biotools version 4.3
library(ggcorrplot)  
## Warning: package 'ggcorrplot' was built under R version 4.5.3
library(ggplot2)     
library(car)         
## Loading required package: carData
## 
## Attaching package: 'car'
## 
## The following object is masked from 'package:dplyr':
## 
##     recode
## 
## The following object is masked from 'package:purrr':
## 
##     some
library(patchwork)
## 
## Attaching package: 'patchwork'
## 
## The following object is masked from 'package:MASS':
## 
##     area
library(heplots)
## Warning: package 'heplots' was built under R version 4.5.3
## Loading required package: broom
## 
## Attaching package: 'heplots'
## 
## The following object is masked from 'package:biotools':
## 
##     boxM
library(emmeans)
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(patchwork)

education_data <- read.csv("education_intervention_10000.csv")
names(education_data) <- make.names(names(education_data))

dv_cols <- c("post_math", "post_reading")
iv_col <- "intervention"
covariate_cols <- c("baseline_math", "baseline_reading")

data_clean <- education_data |>
  drop_na(all_of(c(dv_cols, iv_col, covariate_cols)))

cont_cols <- c(dv_cols, covariate_cols)
remove_outliers_iqr <- function(df, cols) {
  df_filtered <- df
  for (col in cols) {
    Q1 <- quantile(df_filtered[[col]], 0.25, na.rm = TRUE)
    Q3 <- quantile(df_filtered[[col]], 0.75, na.rm = TRUE)
    IQR_val <- Q3 - Q1
    
    lower_bound <- Q1 - 1.5 * IQR_val
    upper_bound <- Q3 + 1.5 * IQR_val
    
    df_filtered <- df_filtered |> 
      filter(.data[[col]] >= lower_bound & .data[[col]] <= upper_bound)
  }
  return(df_filtered)
}

data_no_outliers <- remove_outliers_iqr(data_clean, cont_cols)
cat("Removed", nrow(data_clean) - nrow(data_no_outliers), "outliers using IQR method.\n\n")
## Removed 79 outliers using IQR method.
set.seed(42)
data_clean <- data_no_outliers |>
  group_by(!!sym(iv_col)) |>
  sample_n(30) |>
  ungroup() |>
  as.data.frame()

print("Education Intervention Dataframe Preview (IQR Outliers Removed & Balanced):")
## [1] "Education Intervention Dataframe Preview (IQR Outliers Removed & Balanced):"
print(head(data_clean[, c(iv_col, dv_cols, covariate_cols)]))
##   intervention post_math post_reading baseline_math baseline_reading
## 1      blended      91.8         83.8          80.2             71.5
## 2      blended      52.2         58.3          41.4             48.2
## 3      blended      99.8        100.0          76.9             88.6
## 4      blended      91.9         93.1          77.9             80.4
## 5      blended      97.7         93.1          86.4             81.9
## 6      blended      85.7         50.9          80.6             44.7

We load the necessary libraries and prepare the data by balancing the groups, ensuring a clean start for the multivariate tests.

desc_stats <- data_clean |>
  group_by(intervention) |>
  summarise(across(all_of(cont_cols), list(mean = mean, sd = sd), .names = "{.col}_{.fn}")) |>
  bind_rows(
    data_clean |>
      summarise(across(all_of(cont_cols), list(mean = mean, sd = sd), .names = "{.col}_{.fn}")) |>
      mutate(intervention = "Total")
  )
 
print(desc_stats)
## # A tibble: 5 × 9
##   intervention post_math_mean post_math_sd post_reading_mean post_reading_sd
##   <chr>                 <dbl>        <dbl>             <dbl>           <dbl>
## 1 blended                83.7         13.8              79.7            13.2
## 2 control                73.8         15.5              78.7            12.5
## 3 flipped                81.3         11.8              81.8            12.8
## 4 tutoring               77.2         12.9              78.4            12.2
## 5 Total                  79.0         13.9              79.6            12.6
## # ℹ 4 more variables: baseline_math_mean <dbl>, baseline_math_sd <dbl>,
## #   baseline_reading_mean <dbl>, baseline_reading_sd <dbl>
plot_post_math <- ggplot(data_clean, aes(x = intervention, y = post_math, fill = intervention)) +
  geom_boxplot(alpha = 0.7, outlier.shape = 16, outlier.size = 1.5) +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none") +
  labs(title = "Post Math Score", x = "Intervention", y = "Score")
 
plot_post_reading <- ggplot(data_clean, aes(x = intervention, y = post_reading, fill = intervention)) +
  geom_boxplot(alpha = 0.7, outlier.shape = 16, outlier.size = 1.5) +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none") +
  labs(title = "Post Reading Score", x = "Intervention", y = "Score")
 
plot_baseline_math <- ggplot(data_clean, aes(x = intervention, y = baseline_math, fill = intervention)) +
  geom_boxplot(alpha = 0.7, outlier.shape = 16, outlier.size = 1.5) +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none") +
  labs(title = "Baseline Math Score", x = "Intervention", y = "Score")
 
plot_baseline_reading <- ggplot(data_clean, aes(x = intervention, y = baseline_reading, fill = intervention)) +
  geom_boxplot(alpha = 0.7, outlier.shape = 16, outlier.size = 1.5) +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none") +
  labs(title = "Baseline Reading Score", x = "Intervention", y = "Score")
 
combined_plot <- (plot_post_math + plot_post_reading) / (plot_baseline_math + plot_baseline_reading) +
  plot_annotation(title = "Score Distribution by Intervention Method")
 
print(combined_plot)

2 Assumption Test

2.1 Step 1: DV Dependency (Bartlett’s Test of Sphericity)

MANCOVA is only appropriate if the Dependent Variables (Post Math and Post Reading) are significantly correlated. If they were independent, the analysis would not provide any multivariate advantage over separate ANOVAs.

In order to simplify, hypothesis of H0 and H1 need to conducted:

  • H0: DV not correlated with each other

  • H1: DV correlated with each other

In order to pass the test, we need to successfully reject H0.

cor_matrix <- cor(data_clean[dv_cols])
n <- nrow(data_clean)
p <- length(dv_cols)
det_R <- det(cor_matrix)
bartlett_chi <- -((n - 1) - (2 * p + 5) / 6) * log(det_R)
p_val_bartlett <- pchisq(bartlett_chi, df = p*(p-1)/2, lower.tail = FALSE)

cat("Bartlett's Sphericity p-value:", p_val_bartlett)
## Bartlett's Sphericity p-value: 0.01371306

We seek a p-value < 0.05. A significant result confirms that: we reject H0; there is indeed correlation between each DV. Math and reading scores share enough variance to be analyzed as a unified educational outcome, satisfying the first core assumption.

2.2 Step 2: Homogeneity of Covariance Matrices (Box’s M Test)

Explanation: This test ensures that the “spread” (variance) and the relationship (covariance) between the test scores are equal across all Intervention groups (e.g., Tutoring, Flipped, Blended).

  • H0: All groups share the same covariance matrix

  • H1: At least one of the group have differ covariance matrix

In order to pass, we need to fail to reject H0. Since we want the data to be have homogeneity accross group

box_m_res <- boxM(data_clean[dv_cols], data_clean[[iv_col]])
print(box_m_res)
## 
##  Box's M-test for Homogeneity of Covariance Matrices 
## 
## data:  data_clean[dv_cols] by data_clean[[iv_col]] 
## Chi-Sq (approx.) = 7.5046, df = 9, p-value = 0.5847

Following the publication’s standards, we look for a p-value > 0.05.

The result confirms that: we successfully fail to reject H0. Because Box’s M is highly sensitive to sample size, a p-value above this strict threshold indicates that the group variances are sufficiently homogenous for a valid MANCOVA.

2.3 Step 3: Multivariate Normality (Henze-Zirkler’s Test)

We check if the combination of Math and Reading scores follows a multivariate normal distribution by looking at Skewness (symmetry) and Kurtosis (peak height).

  • H0: Data follows a multivariate normal distribution

  • H1: Data not follows a multivariate normal distribution

In order to pass the test, we need to fail to reject H0

# Creating distributions for Math and Reading scores
plot_math <- ggplot(data_clean, aes(x = post_math)) +
  geom_histogram(fill = "steelblue", color = "white", bins = 30) +
  theme_minimal() +
  labs(title = "Post Math Distribution")

plot_reading <- ggplot(data_clean, aes(x = post_reading)) +
  geom_histogram(fill = "darkgreen", color = "white", bins = 30) +
  theme_minimal() +
  labs(title = "Post Reading Distribution")

# Displaying them side-by-side
print(plot_math + plot_reading)

mvn_res <- mvn(data_clean[dv_cols], mvn_test = "hz")
print(summary(mvn_res, "mvn"))
## 
## ── Multivariate Normality Test Results ─────────────────────────────────────────
##            Test Statistic p.value     Method      MVN
## 1 Henze-Zirkler     0.907   0.081 asymptotic ✓ Normal
## $multivariate_normality
##            Test Statistic p.value     Method      MVN
## 1 Henze-Zirkler     0.907   0.081 asymptotic ✓ Normal
## 
## $univariate_normality
##               Test     Variable Statistic p.value    Normality
## 1 Anderson-Darling    post_math     0.818   0.033 ✗ Not normal
## 2 Anderson-Darling post_reading     0.626   0.101     ✓ Normal
## 
## $descriptives
##       Variable   n   Mean Std.Dev Median  Min Max  25th   75th   Skew Kurtosis
## 1    post_math 120 78.998  13.932  79.90 46.0 100 68.35 89.600 -0.248    2.182
## 2 post_reading 120 79.629  12.574  79.05 50.9 100 69.95 90.375 -0.168    2.280
## 
## $data
##     post_math post_reading
## 1        91.8         83.8
## 2        52.2         58.3
## 3        99.8        100.0
## 4        91.9         93.1
## 5        97.7         93.1
## 6        85.7         50.9
## 7        68.7         98.2
## 8        59.6         60.1
## 9       100.0         94.0
## 10       73.9         72.4
## 11       90.7         93.2
## 12       79.7         83.7
## 13       85.6         82.8
## 14       77.0         82.4
## 15      100.0         83.4
## 16       86.8         88.3
## 17       94.8         89.8
## 18       83.8         98.8
## 19       62.1         73.0
## 20       72.6         77.1
## 21       71.7         69.3
## 22       65.6         64.8
## 23       92.4         86.0
## 24       82.6         71.3
## 25      100.0         69.2
## 26       89.9         91.5
## 27       99.2         67.1
## 28       67.3         65.7
## 29      100.0         68.7
## 30       88.9         79.8
## 31       57.1         69.3
## 32       57.7         60.5
## 33       80.9        100.0
## 34       69.1         77.9
## 35       72.2        100.0
## 36       83.3         77.9
## 37       49.9         75.3
## 38       70.6         98.2
## 39       59.0         94.3
## 40       79.6         71.2
## 41       64.0         55.5
## 42       95.3         86.1
## 43       91.2         59.9
## 44       71.2         91.9
## 45       66.5         90.3
## 46       84.3         67.9
## 47       89.0         84.4
## 48       57.9         75.0
## 49       81.6         69.2
## 50       96.1         87.7
## 51       94.6         75.2
## 52       88.8         72.9
## 53       65.5         90.8
## 54       48.1         80.6
## 55      100.0         70.1
## 56       87.5         72.1
## 57       67.0         67.4
## 58       46.0         70.8
## 59       58.7         97.3
## 60       80.4         70.6
## 61      100.0         88.8
## 62       83.7        100.0
## 63       83.6         82.7
## 64       89.5        100.0
## 65       59.6         63.2
## 66       70.4         90.7
## 67       85.7         63.8
## 68       68.8         83.5
## 69      100.0         94.3
## 70       82.9         71.2
## 71       67.1         97.3
## 72       63.0         68.1
## 73       96.2         79.0
## 74      100.0         82.1
## 75       87.3         67.8
## 76       88.8         83.7
## 77       74.6         79.1
## 78       93.3         99.9
## 79       77.6         89.1
## 80      100.0         84.6
## 81       79.1         90.6
## 82       69.2         90.9
## 83       61.4         79.0
## 84       71.5         90.9
## 85       76.3         78.3
## 86       76.3         66.7
## 87       79.5         93.2
## 88       84.2         54.1
## 89       84.7         83.4
## 90       84.5         57.7
## 91       81.8         80.3
## 92       92.2         89.4
## 93       73.1         52.2
## 94       75.8         75.4
## 95       65.1         90.6
## 96       76.9         51.7
## 97       98.4         81.7
## 98       57.0         69.5
## 99       66.3         80.5
## 100      66.9         82.8
## 101      80.1         68.6
## 102      63.5         74.7
## 103      97.0         78.2
## 104      85.3         96.6
## 105      52.6         77.0
## 106      67.1         74.8
## 107      85.9         97.7
## 108      73.5         68.6
## 109      86.6         76.1
## 110     100.0        100.0
## 111      93.8         87.4
## 112      93.0         62.2
## 113      70.3         67.1
## 114      75.6         77.6
## 115      86.8        100.0
## 116      61.3         77.7
## 117      57.7         77.5
## 118      78.1         70.1
## 119      77.5         88.0
## 120      76.7         77.7
## 
## $subset
## NULL
## 
## $outlierMethod
## [1] "none"
## 
## attr(,"class")
## [1] "mvn"

The Henze-Zirkler test produced a test statistic of 0.907 with p = 0.081, which is above the 0.05 threshold. We succesfully fail to reject H0, meaning the joint distribution of post_math and post_reading satisfies multivariate normality. At the univariate level, post_reading is normal (p = 0.101), while post_math shows a minor violation (p = 0.033). Given the balanced sample size of n = 120 and the low skewness values for both variables (post_math: -0.248, post_reading: -0.168), this violation is considered negligible. The multivariate normality assumption is met.

2.4 Step 4: Linearity (Covariates vs. DVs)

This ensures a linear relationship between the Covariates (Baseline scores) and the DVs (Post-test scores). It also checks if the relationship is consistent across different intervention groups.

  • H0: There is no linearity between covariate and DV

  • H1: There is linearity between covariates and DV

In order to pass the test we need to reject H0.

for (dv in dv_cols) {
  formula_str <- paste(dv, "~", paste(covariate_cols, collapse = " + "))
  fit <- lm(as.formula(formula_str), data = data_clean)
  
  cat("\nLinearity Analysis for", dv, ":\n")
  print(summary(fit))
  cat("R-squared:", summary(fit)$r.squared, "\n")
  
  # Extract p-values
  coef_table <- coef(summary(fit))
  p_values <- coef_table[, "Pr(>|t|)"]
  
  cat("\nP-values for", dv, ":\n")
  print(p_values)
  
  # Overall model p-value
  overall_p <- pf(summary(fit)$fstatistic[1], 
                  summary(fit)$fstatistic[2], 
                  summary(fit)$fstatistic[3], 
                  lower.tail = FALSE)
  cat("Overall model p-value:", overall_p, "\n")
}
## 
## Linearity Analysis for post_math :
## 
## Call:
## lm(formula = as.formula(formula_str), data = data_clean)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -11.1819  -3.2368  -0.0691   2.6842  12.1383 
## 
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      10.31294    3.13383   3.291  0.00132 ** 
## baseline_math     0.94523    0.03357  28.161  < 2e-16 ***
## baseline_reading  0.06129    0.03622   1.692  0.09330 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.909 on 117 degrees of freedom
## Multiple R-squared:  0.8779, Adjusted R-squared:  0.8758 
## F-statistic: 420.7 on 2 and 117 DF,  p-value: < 2.2e-16
## 
## R-squared: 0.8779264 
## 
## P-values for post_math :
##      (Intercept)    baseline_math baseline_reading 
##     1.320574e-03     6.021460e-54     9.329803e-02 
## Overall model p-value: 3.692913e-54 
## 
## Linearity Analysis for post_reading :
## 
## Call:
## lm(formula = as.formula(formula_str), data = data_clean)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -12.4737  -3.0823   0.8732   3.1575   7.4170 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      13.525692   2.754323   4.911 2.97e-06 ***
## baseline_math     0.001621   0.029500   0.055    0.956    
## baseline_reading  0.935309   0.031835  29.379  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.315 on 117 degrees of freedom
## Multiple R-squared:  0.8842, Adjusted R-squared:  0.8822 
## F-statistic: 446.8 on 2 and 117 DF,  p-value: < 2.2e-16
## 
## R-squared: 0.8842265 
## 
## P-values for post_reading :
##      (Intercept)    baseline_math baseline_reading 
##     2.972857e-06     9.562718e-01     7.801254e-56 
## Overall model p-value: 1.663921e-55

The assumption is met if the regression models are significant (p < 0.05). The results says that we successfully reject H0. This proves that the baseline scores and study hours are valid predictors that can effectively “clean” the post-test data in the MANCOVA model.

2.5 Step 5: Independence of Observations

This assumption requires that each student’s score is independent and not influenced by others. Since there is no specific statistical test for this, we examine the residuals for random distribution.

res_fit <- lm(as.matrix(data_clean[dv_cols]) ~ intervention + baseline_math, data = data_clean)
res_data <- residuals(res_fit)[,1]
plot(res_data, main="Independence Check: Residual Plot", 
     xlab="Student Index", ylab="Residuals", col="darkblue")
abline(h = 0, col = "red", lwd = 2)

A random scatter of points around the zero line indicates that there is no temporal or group-based correlation between student records. This confirms the Independence of Observations, fulfilling the final requirement for the analysis.

3 Initial Exploratory Data Analysis

Before running any formal tests, we must understand the shape and behavior of our data across both outcomes. Exploratory Data Analysis helps us visualize the raw performance differences between the intervention groups and the relationship between the baseline and post-test scores for both math and reading.

3.1 Visualizing the Raw Group Differences

data_clean |>
  pivot_longer(cols = c(post_math, post_reading), names_to = 'outcome', values_to = 'score') |>
  mutate(outcome = case_when(
    outcome == 'post_math'     ~ 'Post Math',
    outcome == 'post_reading'  ~ 'Post Reading'
  )) |>
  ggplot(aes(x = intervention, y = score, fill = intervention)) +
  geom_boxplot(alpha = 0.7) +
  facet_wrap(~ outcome, scales = 'free_y') +
  theme_minimal() +
  labs(
    title = 'Raw Post-Test Scores by Intervention Group',
    x = 'Intervention Type',
    y = 'Score'
  ) +
  theme(legend.position = 'none')

For math, blended and flipped groups show visibly higher medians compared to control, with blended in particular sitting notably above the rest. The control group also displays a wider interquartile range, suggesting more variability in math outcomes among students who received no active intervention. For reading, the picture is strikingly different, as all four groups show heavily overlapping boxes with medians clustered closely together, indicating that intervention type produces little visible separation in raw reading outcomes. Notably, the reading plots also show wider spreads overall compared to math, meaning individual reading scores vary considerably regardless of group. Both observations are based on unadjusted raw scores however, so the apparent math advantage of blended and flipped may simply reflect the fact that those students started with stronger baseline math ability rather than benefiting more from the instruction itself.

3.2 Visualizing the Covariate Effect

data_clean |>
  pivot_longer(
    cols = c(baseline_math, baseline_reading),
    names_to = 'baseline_outcome',
    values_to = 'baseline_score'
  ) |>
  mutate(
    post_score = ifelse(baseline_outcome == 'baseline_math', post_math, post_reading),
    outcome = case_when(
      baseline_outcome == 'baseline_math'     ~ 'Math',
      baseline_outcome == 'baseline_reading'  ~ 'Reading'
    )
  ) |>
  ggplot(aes(x = baseline_score, y = post_score, color = intervention)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = 'lm', se = FALSE) +
  facet_wrap(~ outcome, scales = 'free') +
  theme_minimal() +
  labs(
    title = 'Trajectory: Baseline vs Post-Test Scores',
    x = 'Baseline Score',
    y = 'Post-Test Score'
  )
## `geom_smooth()` using formula = 'y ~ x'

Both plots confirm a strong positive linear relationship between baseline and post-test scores for math and reading alike, meaning students who entered the study with higher prior ability consistently scored higher on the post-test regardless of which intervention they received. The regression lines across all four intervention groups are strikingly parallel and run in the same direction without crossing, which provides early visual evidence that the covariate behaves consistently across groups for both outcomes. For math, the control group line sits visibly lower than the active intervention groups across most of the baseline range, hinting that the intervention effect may be meaningful once baseline is accounted for. For reading, the four lines are even more tightly clustered together, reinforcing the earlier boxplot observation that group separation in reading is minimal. The consistent slopes across both outcomes are an encouraging early sign that the homogeneity of regression slopes assumption, which will be formally tested later, is likely to be satisfied.

3.3 Distribution of Post-Test Scores by Group

data_clean |>
  pivot_longer(cols = c(post_math, post_reading), names_to = 'outcome', values_to = 'score') |>
  mutate(outcome = case_when(
    outcome == 'post_math'     ~ 'Post Math',
    outcome == 'post_reading'  ~ 'Post Reading'
  )) |>
  ggplot(aes(x = score, fill = intervention)) +
  geom_density(alpha = 0.5) +
  facet_wrap(~ outcome, scales = 'free') +
  theme_minimal() +
  labs(
    title = 'Post-Test Score Distribution by Intervention Group',
    x = 'Post-Test Score',
    y = 'Density'
  )

For math, the density curves show meaningful separation between groups, with blended peaking furthest to the right around 90 and control spreading broadly across a lower range, consistent with the boxplot pattern observed earlier. Flipped and tutoring sit in between, with their peaks clustering around 80. The control group notably produces the flattest and widest curve, reflecting greater score variability among students with no active intervention. For reading, the picture is more chaotic, with all four curves overlapping heavily and peaks scattered across a narrow band between 75 and 85. Tutoring produces a sharp narrow peak while control spreads broadly, but no group consistently dominates the higher score range the way blended does in math. The overall reading distributions are largely indistinguishable from one another, further confirming that intervention type carries very little signal for reading outcomes when baseline ability is not controlled for.

3.4 Baseline Scores by Group: Are Groups Starting Equally?

data_clean |>
  pivot_longer(cols = c(baseline_math, baseline_reading), names_to = 'outcome', values_to = 'score') |>
  mutate(outcome = case_when(
    outcome == 'baseline_math'     ~ 'Baseline Math',
    outcome == 'baseline_reading'  ~ 'Baseline Reading'
  )) |>
  ggplot(aes(x = intervention, y = score, fill = intervention)) +
  geom_boxplot(alpha = 0.7) +
  facet_wrap(~ outcome, scales = 'free_y') +
  theme_minimal() +
  labs(
    title = 'Baseline Scores by Intervention Group',
    x = 'Intervention Type',
    y = 'Score'
  ) +
  theme(legend.position = 'none')

For baseline math, the blended group enters the study with a noticeably higher median compared to control, while flipped also sits slightly above control and tutoring. This means the groups were not on equal footing before the intervention even began, so any raw post-test math advantage observed for blended cannot be confidently attributed to the instruction alone. For baseline reading, the four groups are considerably more comparable, with all medians sitting close together around 70 and heavily overlapping interquartile ranges across groups. The one exception is a single outlier visible in the tutoring group reaching near 100. Overall, the baseline math imbalance is the more concerning of the two, as it directly explains why the raw post-math differences we observed earlier need to be treated with caution. This confirms that statistically controlling for baseline scores in ANCOVA and MANCOVA is not just a methodological formality but a necessary correction given the pre-existing differences between groups.

3.5 Summary Statistics by Group

data_clean |>
  group_by(intervention) |>
  summarise(
    n                    = n(),
    mean_post_math       = round(mean(post_math), 2),
    sd_post_math         = round(sd(post_math), 2),
    mean_baseline_math   = round(mean(baseline_math), 2),
    sd_baseline_math     = round(sd(baseline_math), 2),
    mean_post_reading    = round(mean(post_reading), 2),
    sd_post_reading      = round(sd(post_reading), 2),
    mean_baseline_reading = round(mean(baseline_reading), 2),
    sd_baseline_reading  = round(sd(baseline_reading), 2)
  )

4 ANOVA

4.1 Univariate Effect of Intervention

Before controlling for any baseline differences, we first examine whether intervention type alone produces significantly different mean scores across groups. This establishes a raw baseline comparison that will later be contrasted against the covariate-adjusted results from ANCOVA.

  • H0: The mean scores are equal across all intervention groups.
  • H1: At least one group differ
anova_math <- aov(post_math ~ intervention, data = data_clean)
cat('--- One-Way ANOVA: Post Math ---\n')
## --- One-Way ANOVA: Post Math ---
summary(anova_math)
##               Df Sum Sq Mean Sq F value Pr(>F)  
## intervention   3   1748   582.7   3.166 0.0271 *
## Residuals    116  21350   184.1                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova_reading <- aov(post_reading ~ intervention, data = data_clean)
cat('--- One-Way ANOVA: Post Reading ---\n')
## --- One-Way ANOVA: Post Reading ---
summary(anova_reading)
##               Df Sum Sq Mean Sq F value Pr(>F)
## intervention   3    213   71.13   0.444  0.722
## Residuals    116  18600  160.34

For post-math scores, the intervention effect is significant (F(3, 116) = 3.17, p = .027), meaning that intervention group membership is associated with different math outcomes even without baseline adjustment. For post-reading, the effect is non-significant (F(3, 116) = 0.44, p = .722), suggesting that reading outcomes do not differ meaningfully across groups when prior ability is ignored.

We therefore reject H0 for math but fail to reject H0 for reading.

This asymmetry is expected rather than concerning. Math outcomes tend to be more immediately responsive to instructional differences, while reading development is slower and more dependent on accumulated prior ability. Crucially, neither result can be fully trusted at face value.

Students entering different intervention programs likely carried different baseline ability levels into the study, meaning these raw group differences may reflect pre-existing advantages rather than the true effect of the instruction itself. This fundamental limitation of unadjusted ANOVA motivates the transition to ANCOVA, where baseline math and reading scores are statistically controlled to isolate the intervention’s genuine contribution to each outcome independently.

4.2 Effect Size

Partial eta squared quantifies how much of the total variance in each outcome is explained by intervention group membership alone, before any baseline adjustment is applied.

etasq(anova_math,    partial = TRUE)
etasq(anova_reading, partial = TRUE)

The partial eta squared for post-math indicates that intervention group membership explains approximately 7.6% of variance in math scores before any baseline adjustment, a rather small-to-medium effect that aligns with the significant omnibus result. For post-reading, η² = 0.011, a negligible effect consistent with the non-significant ANOVA. These unadjusted effect sizes likely underestimate the true intervention impact, since a substantial portion of outcome variance is driven by students’ pre-existing ability levels rather than the instruction they received. Once baseline scores are controlled in ANCOVA, the proportion of variance uniquely attributable to the intervention is expected to become clearer and more precise.

4.3 Post-Hoc: Which group differs?

Since the omnibus ANOVA was significant for post-math (p = .027), Bonferroni-adjusted pairwise comparisons are conducted to identify which specific intervention pairs are driving the difference. These results serve as confirmatory evidence of group separation in math outcomes.

pairs(emmeans(anova_math,    ~ intervention), adjust = 'bonferroni')
##  contrast           estimate  SE  df t.ratio p.value
##  blended - control      9.96 3.5 116   2.844  0.0316
##  blended - flipped      2.44 3.5 116   0.697  1.0000
##  blended - tutoring     6.54 3.5 116   1.866  0.3873
##  control - flipped     -7.52 3.5 116  -2.148  0.2029
##  control - tutoring    -3.43 3.5 116  -0.978  1.0000
##  flipped - tutoring     4.10 3.5 116   1.170  1.0000
## 
## P value adjustment: bonferroni method for 6 tests
emm_math_anova <- as.data.frame(emmeans(anova_math, ~ intervention))
emm_math_anova$outcome <- 'Post Math'
names(emm_math_anova)[names(emm_math_anova) == 'emmean'] <- 'mean'

ggplot(emm_math_anova, aes(x = intervention, y = mean, fill = intervention)) +
  geom_bar(stat = 'identity', width = 0.6) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.2) +
  labs(
    title = 'Group Means by Intervention (ANOVA)',
    subtitle = 'Post Math',
    x = 'Intervention', y = 'Mean Score'
  ) +
  theme_minimal() +
  theme(legend.position = 'none')

For post-math scores, the only significant pairwise contrast after Bonferroni adjustment was blended vs. control (difference = 9.96, p = .032), where the blended group scored notably higher than the control group. All other pairwise comparisons were non-significant, suggesting that flipped and tutoring groups did not differ meaningfully from either the control or each other after correction.

The bar chart visually confirms this pattern. Blended and flipped sit visibly higher than control, while tutoring falls closer to the middle, yet only the blended-control gap is large enough to survive the Bonferroni correction. These unadjusted group means still reflect whatever baseline ability differences existed between students before the intervention began, which is precisely why ANCOVA is needed to determine whether this blended advantage holds after leveling the playing field.

Although the omnibus ANOVA for post-reading was non-significant (p = .722), we present Bonferroni-adjusted pairwise comparisons as an exploratory exercise to examine the direction of group differences. These results should be interpreted with caution and are not intended as confirmatory evidence.

pairs(emmeans(anova_reading, ~ intervention), adjust = 'bonferroni')
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control     0.983 3.27 116   0.301  1.0000
##  blended - flipped    -2.130 3.27 116  -0.651  1.0000
##  blended - tutoring    1.270 3.27 116   0.388  1.0000
##  control - flipped    -3.113 3.27 116  -0.952  1.0000
##  control - tutoring    0.287 3.27 116   0.088  1.0000
##  flipped - tutoring    3.400 3.27 116   1.040  1.0000
## 
## P value adjustment: bonferroni method for 6 tests
emm_reading_anova <- as.data.frame(emmeans(anova_reading, ~ intervention))
emm_reading_anova$outcome <- 'Post Reading'
names(emm_reading_anova)[names(emm_reading_anova) == 'emmean'] <- 'mean'

ggplot(emm_reading_anova, aes(x = intervention, y = mean, fill = intervention)) +
  geom_bar(stat = 'identity', width = 0.6) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.2) +
  labs(
    title = 'Group Means by Intervention (ANOVA)',
    subtitle = 'Post Reading',
    x = 'Intervention', y = 'Mean Score'
  ) +
  theme_minimal() +
  theme(legend.position = 'none')

As expected from the non-significant omnibus result, no pairwise comparison reached significance for post-reading scores, all p-values were 1.000 after Bonferroni adjustment. The bar chart visually encourages this, showing four nearly identical bar heights with heavily overlapping confidence intervals across all intervention groups. Reading outcomes appear entirely uniform regardless of which intervention a student received, suggesting that intervention type carries no detectable signal for reading performance when baseline ability is not accounted for. This is consistent with the earlier discussion that reading development is slower and more resistant to short-term instructional differences, and further supports the need for ANCOVA to determine whether any reading signal emerges once baseline scores are properly controlled.

5 ANCOVA

Now we move to ANCOVA. The goal of ANCOVA is to answer one critical question: if all students had started with the exact same baseline scores, would the intervention they received still make a significant difference in their final academic performance? By statistically controlling for each student’s prior math and reading ability, ANCOVA isolates the intervention’s true effect on each outcome independently, removing the noise caused by pre-existing differences between students before the instruction even began.

5.1 Covariate-Adjusted Effect of Intervention

ANCOVA extends the earlier ANOVA by statistically removing baseline differences before comparing groups. We run one model per DV, each controlling for its own respective baseline covariate.

  • H0: Controlling for baseline scores, there is no significant difference between intervention groups.
  • H1: Controlling for baseline scores, at least one group differs significantly.
ancova_math <- lm(post_math ~ baseline_math + intervention, data = data_clean) 
cat('--- ANCOVA: Post Math ---\n') 
## --- ANCOVA: Post Math ---
car::Anova(ancova_math, type = 'III')
ancova_reading <- lm(post_reading ~ baseline_reading + intervention, data = data_clean) 
cat('--- ANCOVA: Post Reading ---\n') 
## --- ANCOVA: Post Reading ---
car::Anova(ancova_reading, type = 'III')

After statistically controlling for prior ability, the ANCOVA results reveal a clear and consistent picture across both outcomes.

For post-math scores, baseline math is an overwhelmingly strong predictor (F(1, 115) = 871.31, p < .001), confirming that prior math ability dominates student outcomes. Critically, even after removing this baseline effect, the intervention remains highly significant (F(3, 115) = 6.15, p < .001), meaning the type of instruction a student received had a genuine impact on their final math score independent of where they started.

The same pattern holds for post-reading scores, where baseline reading is again the dominant predictor (F(1, 115) = 969.33, p < .001), yet the intervention effect remains significant (F(3, 115) = 3.99, p = .010).

Therefore we reject H0 for both outcomes.

These results demonstrate that a student’s prior ability is by far the strongest driver of their final score, but the type of instruction they received still contributes a meaningful and statistically significant effect on top of that. This also sets up an important question: do these intervention effects hold when both outcomes are examined simultaneously while controlling for baselines across the board? That is precisely what MANCOVA will address.

5.2 Effect Size

etasq(ancova_math,    partial = TRUE) 
etasq(ancova_reading, partial = TRUE)

The partial eta squared values reinforce the ANCOVA findings. For post-math, baseline math accounts for an overwhelming 88.3% of variance in final math scores (η² = 0.883), while the intervention explains an additional 13.8% after that baseline is controlled (η² = 0.138). For post-reading, the pattern is nearly identical — baseline reading accounts for 89.4% of variance (η² = 0.894), with the intervention explaining a further 9.4% on top (η² = 0.094). While the intervention effect sizes are modest relative to the covariate, a 10-14% explained variance after already accounting for prior ability is considered practically meaningful in an educational context, where baseline performance naturally dominates outcomes.

5.3 Post-Hoc: Which Groups Differ?

Pairwise comparisons using adjusted means. This is the core value of ANCOVA, since it compares groups as if they all started from the same baseline.

pairs(emmeans(ancova_math,    ~ intervention), adjust = 'bonferroni') 
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control     3.867 1.22 115   3.172  0.0116
##  blended - flipped     1.645 1.20 115   1.369  1.0000
##  blended - tutoring   -0.939 1.23 115  -0.765  1.0000
##  control - flipped    -2.221 1.21 115  -1.829  0.4200
##  control - tutoring   -4.806 1.20 115  -3.998  0.0007
##  flipped - tutoring   -2.585 1.22 115  -2.114  0.2198
## 
## P value adjustment: bonferroni method for 6 tests
pairs(emmeans(ancova_reading, ~ intervention), adjust = 'bonferroni')
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control     3.020 1.07 115   2.818  0.0341
##  blended - flipped    -0.266 1.07 115  -0.248  1.0000
##  blended - tutoring    1.426 1.07 115   1.334  1.0000
##  control - flipped    -3.285 1.07 115  -3.072  0.0159
##  control - tutoring   -1.593 1.07 115  -1.487  0.8377
##  flipped - tutoring    1.692 1.07 115   1.580  0.7007
## 
## P value adjustment: bonferroni method for 6 tests
emm_ancova_math    <- as.data.frame(emmeans(ancova_math,    ~ intervention))
emm_ancova_reading <- as.data.frame(emmeans(ancova_reading, ~ intervention))

emm_ancova_math$outcome    <- 'Post Math'
emm_ancova_reading$outcome <- 'Post Reading'

names(emm_ancova_math)[names(emm_ancova_math)       == 'emmean'] <- 'adj_mean'
names(emm_ancova_reading)[names(emm_ancova_reading) == 'emmean'] <- 'adj_mean'

emm_ancova <- rbind(emm_ancova_math, emm_ancova_reading)

ggplot(emm_ancova, aes(x = intervention, y = adj_mean, fill = intervention)) +
  geom_bar(stat = 'identity', width = 0.6) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.2) +
  facet_wrap(~ outcome) +
  labs(
    title = 'Adjusted Means by Intervention (ANCOVA)',
    subtitle = 'Each DV controlled for its own baseline',
    x = 'Intervention', y = 'Adjusted Mean Score'
  ) +
  theme_minimal() +
  theme(legend.position = 'none')

After adjusting for baseline scores, the pairwise comparisons reveal specific group differences that were not visible in the raw data. For post-math, two contrasts reached significance: blended outperformed control (difference = 3.87, p = .012) and tutoring outperformed control (difference = 4.81, p < .001), while all other math pairs were non-significant. For post-reading, blended outperformed control (difference = 3.02, p = .034) and flipped outperformed control (difference = 3.29, p = .016), with remaining pairs non-significant.

The bar chart visually confirms this pattern. The control group consistently sits lower than the active intervention groups across both outcomes, while blended, flipped, and tutoring cluster closely together with heavily overlapping confidence intervals. The tight confidence intervals reflect the reduced error variance achieved by controlling for baseline scores, giving us a more precise estimate of each group’s true performance. Across both subjects, the consistent takeaway is that any form of active intervention outperforms no intervention, but no single intervention method stands out as superior to the others.

5.4 Homogeneity of Regression Slope

Before trusting the ANCOVA results, we must verify a key assumption: homogeneity of regression slopes. This assumption requires that the relationship between the covariate and the dependent variable is consistent across all intervention groups. In other words, the baseline-to-post-test slope should be roughly parallel for every group. If the slopes differ significantly across groups, it means the covariate affects each group differently, and a standard ANCOVA would be inappropriate.

  • H0: The regression slopes are equal across all intervention groups

  • H1: At least one group differ

ancova_slope_math <- lm(post_math ~ baseline_math * intervention, data = data_clean)
cat("--- Homogeneity of Regression Slopes: Post Math ---\n")
## --- Homogeneity of Regression Slopes: Post Math ---
car::Anova(ancova_slope_math, type = "III")
ancova_slope_reading <- lm(post_reading ~ baseline_reading * intervention, data = data_clean)
cat("--- Homogeneity of Regression Slopes: Post Reading ---\n")
## --- Homogeneity of Regression Slopes: Post Reading ---
car::Anova(ancova_slope_reading, type = "III")
p1 <- ggplot(data_clean, aes(x = baseline_math, y = post_math, color = intervention)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
  labs(
    title = "Regression Slopes: Post Math",
    x = "Baseline Math",
    y = "Post Math",
    color = "Intervention"
  ) +
  theme_minimal()

p2 <- ggplot(data_clean, aes(x = baseline_reading, y = post_reading, color = intervention)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
  labs(
    title = "Regression Slopes: Post Reading",
    x = "Baseline Reading",
    y = "Post Reading",
    color = "Intervention"
  ) +
  theme_minimal()

p1 + p2 + plot_layout(guides = "collect")
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'

The interaction term between the covariate and intervention group is non-significant for both post-math (F(3, 112) = 0.97, p = .408) and post-reading (F(3, 112) = 0.69, p = .561), meaning we fail to reject H0. This confirms that the regression slopes are parallel across all four intervention groups for both outcomes: the relationship between baseline and post-test scores behaves consistently regardless of which intervention a student received. The assumption of homogeneity of regression slopes is therefore satisfied, and we can proceed with ANCOVA with confidence that the covariate adjustment is being implemented equally and fairly across all groups.

6 MANOVA

The ANCOVA successfully proved that the intervention works for Mathematics when controlling for prior knowledge. However, education is multidimensional. Did the math tutoring inadvertently hurt their reading scores? Did the flipped classroom boost both equally?

Because we want to know the impact of the intervention on the combined educational profile (Math AND Reading simultaneously) without necessarily controlling for baselines in every single scenario, our next logical step is to perform a Multivariate Analysis of Variance (MANOVA).

6.1 Multivariate Effect of Intervention

The goal here is to test whether intervention type simultaneously affects post_math and post_reading without controlling for any baseline. Unlike ANCOVA, no covariate adjustment is made, we are comparing the raw group differences across both outcomes at once.

  • H0: The mean vector of (post_math, post_reading) is equal across all intervention groups.
  • H1: At least one group has a different mean vector.
manova_model <- manova(
  cbind(post_math, post_reading) ~ intervention,
  data = data_clean
)

cat('--- MANOVA: Pillai\'s Trace ---\n')
## --- MANOVA: Pillai's Trace ---
summary(manova_model, test = 'Pillai')
##               Df  Pillai approx F num Df den Df Pr(>F)
## intervention   3 0.08326   1.6796      6    232 0.1268
## Residuals    116
cat('--- MANOVA: Wilks\' Lambda ---\n')
## --- MANOVA: Wilks' Lambda ---
summary(manova_model, test = 'Wilks')
##               Df   Wilks approx F num Df den Df Pr(>F)
## intervention   3 0.91731   1.6904      6    230 0.1242
## Residuals    116

The MANOVA revealed a non-significant multivariate effect of intervention type on the combined outcome of post-test math and reading scores (Pillai’s Trace = 0.083, F(6, 232) = 1.68, p = .127; Wilks’ Lambda = 0.917, F(6, 230) = 1.69, p = .124). Both test statistics are consistent with each other and both exceed the α = 0.05 threshold. Therefore, we fail to reject H0, meaning that when baseline differences between students are not accounted for, the intervention groups do not appear to differ significantly in their combined academic outcomes.

This result is not surprising, as students entering different intervention programs likely had varying levels of prior knowledge that obscure the true effect of the instruction itself. This limitation motivates the transition to MANCOVA, where baseline math and reading scores are statistically controlled, allowing us to isolate the intervention’s genuine contribution to student outcomes.

6.2 Affected DVs (Univariate Follow-ups)

After confirming a significant multivariate effect, we break it down to see which individual outcome (math or reading) is driving the result.

summary.aov(manova_model)
##  Response post_math :
##               Df  Sum Sq Mean Sq F value  Pr(>F)  
## intervention   3  1748.1  582.69  3.1659 0.02714 *
## Residuals    116 21349.9  184.05                  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##  Response post_reading :
##               Df  Sum Sq Mean Sq F value Pr(>F)
## intervention   3   213.4  71.129  0.4436 0.7223
## Residuals    116 18600.0 160.344

Breaking down the multivariate result into individual outcomes reveals that the two DVs behave differently. For post-math scores, the intervention effect is significant (F(3, 116) = 3.17, p = .027), meaning that even without baseline adjustment, intervention group membership is associated with different math outcomes. For post-reading scores however, the effect is clearly non-significant (F(3, 116) = 0.44, p = .722), suggesting that reading outcomes do not differ meaningfully across groups when baseline is ignored.

This asymmetry explains why the overall MANOVA was non-significant. The reading outcome carries no group signal, diluting the combined multivariate effect. It also reinforces why controlling for baseline matters: the math signal we see here may partly reflect pre-existing differences rather than the true effect of the intervention, which again motivates the use of MANCOVA.

6.3 Effect Size

Partial eta squared tells us how much variance in the combined outcome is explained by intervention group membership alone, before any baseline adjustment.

etasq(manova_model, partial = TRUE)

The partial eta squared value for intervention group membership is η² = 0.042, indicating that approximately 4.2% of the total variance in the combined post-test outcomes is explained by intervention type alone. By conventional benchmarks this is a small effect size, which is consistent with the non-significant overall MANOVA result. Notably, this unadjusted figure likely underestimates the true impact of the intervention, since a substantial portion of the outcome variance is driven by students’ pre-existing ability levels rather than the instruction they received. This further illustrates the value of MANCOVA, by partialling out baseline scores, the proportion of variance uniquely attributable to the intervention becomes much clearer.

6.4 Post-Hoc: Which Groups Differ?

Although the overall MANOVA was non-significant (p = .127), the univariate follow-up revealed a significant effect for post-math scores specifically (p = .027). As an exploratory exercise, we present Bonferroni-adjusted pairwise comparisons per outcome to examine which specific intervention pairs may be driving the math signal. These results should be interpreted with caution given the non-significant omnibus test, and are intended to illustrate the direction of group differences rather than serve as confirmatory evidence.

pairs(emmeans(lm(post_math    ~ intervention, data = data_clean), ~ intervention), adjust = 'bonferroni')
##  contrast           estimate  SE  df t.ratio p.value
##  blended - control      9.96 3.5 116   2.844  0.0316
##  blended - flipped      2.44 3.5 116   0.697  1.0000
##  blended - tutoring     6.54 3.5 116   1.866  0.3873
##  control - flipped     -7.52 3.5 116  -2.148  0.2029
##  control - tutoring    -3.43 3.5 116  -0.978  1.0000
##  flipped - tutoring     4.10 3.5 116   1.170  1.0000
## 
## P value adjustment: bonferroni method for 6 tests
pairs(emmeans(lm(post_reading ~ intervention, data = data_clean), ~ intervention), adjust = 'bonferroni')
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control     0.983 3.27 116   0.301  1.0000
##  blended - flipped    -2.130 3.27 116  -0.651  1.0000
##  blended - tutoring    1.270 3.27 116   0.388  1.0000
##  control - flipped    -3.113 3.27 116  -0.952  1.0000
##  control - tutoring    0.287 3.27 116   0.088  1.0000
##  flipped - tutoring    3.400 3.27 116   1.040  1.0000
## 
## P value adjustment: bonferroni method for 6 tests
emm_math_manova    <- as.data.frame(emmeans(lm(post_math    ~ intervention, data = data_clean), ~ intervention))
emm_reading_manova <- as.data.frame(emmeans(lm(post_reading ~ intervention, data = data_clean), ~ intervention))

emm_math_manova$outcome    <- 'Post Math'
emm_reading_manova$outcome <- 'Post Reading'

names(emm_math_manova)[names(emm_math_manova)       == 'emmean'] <- 'mean'
names(emm_reading_manova)[names(emm_reading_manova) == 'emmean'] <- 'mean'

emm_manova <- rbind(emm_math_manova, emm_reading_manova)

ggplot(emm_manova, aes(x = intervention, y = mean, fill = intervention)) +
  geom_bar(stat = 'identity', width = 0.6) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.2) +
  facet_wrap(~ outcome) +
  labs(
    title = 'Group Means by Intervention (MANOVA)',
    x = 'Intervention', y = 'Mean Score'
  ) +
  theme_minimal() +
  theme(legend.position = 'none')

For post-math scores, the only significant pairwise difference was between blended and control (difference = 9.96, p = .032), where the blended group scored notably higher. All other math comparisons were non-significant after Bonferroni adjustment, suggesting the remaining intervention pairs produce comparable math outcomes. For post-reading scores, no pairwise comparison reached significance (all p-values were 1.000) which is consistent with the non-significant univariate reading result from the follow-up. Visually, the bar chart confirms this pattern: math scores show more visible separation between groups, particularly blended vs. control, while reading scores are strikingly uniform across all four groups with heavily overlapping confidence intervals.

However, these group mean differences are unadjusted. They reflect whatever baseline ability differences already existed between students before the intervention began. It is entirely possible that the blended group simply started with higher math ability rather than benefiting more from the instruction.

This is the fundamental limitation of MANOVA, and precisely why we proceed to MANCOVA. By statistically controlling for each student’s baseline math and reading scores, we can determine whether these group differences hold up after leveling the playing field.

7 MANCOVA

MANCOVA and MANOVA is the same method that answer a question about “how do the groups score differently across multiple outcomes?” The difference is that MANCOVA adjusts for each student started before comparing groups. Without that adjustment, there is risk giving the intervention credit for score differences that already existed before it even began.

7.1 Multivariate Effect of Intervention

dv_matrix <- cbind(data_clean$post_math, data_clean$post_reading)

mancova_model <- manova(
  dv_matrix ~ baseline_math + baseline_reading + intervention,
  data = data_clean
)

# Summary using Pillai's Trace (most robust)
summary(mancova_model, test = "Pillai")
##                   Df  Pillai approx F num Df den Df    Pr(>F)    
## baseline_math      1 0.89620   487.80      2    113 < 2.2e-16 ***
## baseline_reading   1 0.89113   462.45      2    113 < 2.2e-16 ***
## intervention       3 0.23931     5.16      6    228 5.318e-05 ***
## Residuals        114                                             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# check Wilks' Lambda for comparison
summary(mancova_model, test = "Wilks")
##                   Df   Wilks approx F num Df den Df    Pr(>F)    
## baseline_math      1 0.10380   487.80      2    113 < 2.2e-16 ***
## baseline_reading   1 0.10887   462.45      2    113 < 2.2e-16 ***
## intervention       3 0.77138     5.22      6    226 4.708e-05 ***
## Residuals        114                                             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

After controlling for baseline math and reading scores, the MANCOVA revealed a significant multivariate effect of intervention type on the combined outcome of post-test math and reading scores (Pillai’s Trace = 0.239, F(6, 228) = 5.16, p < .001; Wilks’ Lambda = 0.771, F(6, 226) = 5.22, p < .001). Both covariates also showed significant multivariate effects, confirming that prior scores strongly predicted post-test performance.

These results indicate that students in different intervention groups performed differently overall, even after accounting for where they started. The significance of both test statistics adds confidence to this conclusion.

7.2 Affected DVs (Univariate Follow-ups)

summary.aov(mancova_model)
##  Response 1 :
##                   Df  Sum Sq Mean Sq  F value    Pr(>F)    
## baseline_math      1 20209.3 20209.3 963.1185 < 2.2e-16 ***
## baseline_reading   1    69.0    69.0   3.2882 0.0724085 .  
## intervention       3   427.6   142.5   6.7922 0.0002967 ***
## Residuals        114  2392.1    21.0                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##  Response 2 :
##                   Df  Sum Sq Mean Sq  F value    Pr(>F)    
## baseline_math      1   566.7   566.7  32.8887  8.14e-08 ***
## baseline_reading   1 16068.6 16068.6 932.6107 < 2.2e-16 ***
## intervention       3   213.9    71.3   4.1382   0.00797 ** 
## Residuals        114  1964.2    17.2                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Univariate follow-up tests showed that the intervention effect was significant for both post-test math (F(3, 114) = 6.79, p < .001) and post-test reading (F(3, 114) = 4.14, p = .008). Baseline math was the dominant predictor of post-math scores, while baseline reading was the dominant predictor of post-reading scores, each explaining the vast majority of variance in their respective outcomes.

This means the intervention did not just affect one subject area. Both math and reading outcomes differed across groups, suggesting the type of instruction had a broad academic impact rather than a narrow one.

7.3 Effect Size

etasq(mancova_model, partial = TRUE)

Partial eta squared values indicated that the covariates accounted for a large proportion of variance: baseline math explained 88.1% of variance in the outcomes, and baseline reading explained 89.2%. The intervention itself explained a smaller but practically meaningful 11.9% of variance after controlling for baseline scores.

While the intervention effect size is modest compared to the covariates, a roughly 12% explained variance in an educational setting is considered meaningful, particularly given that prior achievement already dominates student outcomes.

7.4 Post-Hoc: Which Groups Differ?

# Adjusted means for post_math
emm_math <- emmeans(
  lm(post_math ~ baseline_math + baseline_reading + intervention, data = data_clean),
  ~ intervention
)
pairs(emm_math, adjust = "bonferroni")
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control     4.110 1.21 114   3.410  0.0054
##  blended - flipped     1.802 1.19 114   1.520  0.7877
##  blended - tutoring   -0.823 1.21 114  -0.680  1.0000
##  control - flipped    -2.309 1.20 114  -1.929  0.3370
##  control - tutoring   -4.933 1.19 114  -4.163  0.0004
##  flipped - tutoring   -2.625 1.20 114  -2.181  0.1876
## 
## P value adjustment: bonferroni method for 6 tests
# Adjusted means for post_reading
emm_reading <- emmeans(
  lm(post_reading ~ baseline_math + baseline_reading + intervention, data = data_clean),
  ~ intervention
)
pairs(emm_reading, adjust = "bonferroni")
##  contrast           estimate   SE  df t.ratio p.value
##  blended - control      3.16 1.09 114   2.893  0.0274
##  blended - flipped     -0.24 1.07 114  -0.224  1.0000
##  blended - tutoring     1.59 1.10 114   1.449  0.9010
##  control - flipped     -3.40 1.08 114  -3.136  0.0131
##  control - tutoring    -1.57 1.07 114  -1.464  0.8764
##  flipped - tutoring     1.83 1.09 114   1.677  0.5781
## 
## P value adjustment: bonferroni method for 6 tests
# Fit univariate models
model_math    <- lm(post_math    ~ baseline_math + baseline_reading + intervention, data = data_clean)
model_reading <- lm(post_reading ~ baseline_math + baseline_reading + intervention, data = data_clean)

# Extract adjusted means
emm_math    <- as.data.frame(emmeans(model_math,    ~ intervention))
emm_reading <- as.data.frame(emmeans(model_reading, ~ intervention))

emm_math$outcome    <- "Post Math"
emm_reading$outcome <- "Post Reading"

# Rename emmean column to 'adjusted_mean'
names(emm_math)[names(emm_math)       == "emmean"] <- "adjusted_mean"
names(emm_reading)[names(emm_reading) == "emmean"] <- "adjusted_mean"

emm_combined <- rbind(emm_math, emm_reading)

# Plot
ggplot(emm_combined, aes(x = intervention, y = adjusted_mean, fill = intervention)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.6) +
  geom_errorbar(
    aes(ymin = lower.CL, ymax = upper.CL),
    width = 0.2
  ) +
  facet_wrap(~ outcome) +
  labs(
    title    = "Adjusted Means by Intervention Group",
    subtitle = "Controlling for baseline math and reading scores",
    x        = "Intervention",
    y        = "Adjusted Mean Score",
    fill     = "Intervention"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

Bonferroni-adjusted pairwise comparisons for post-math scores showed that the blended group scored significantly higher than the control group (difference = 4.11, p = .005), and tutoring scored significantly higher than control (difference = 4.93, p < .001). For post-reading, blended outperformed control (difference = 3.16, p = .027), and flipped outperformed control (difference = 3.40, p = .013).

Across both outcomes, the control group consistently scored lower than the active intervention groups. No significant differences emerged between blended, flipped, and tutoring groups, suggesting these three approaches produced comparable results relative to one another.

7.5 Homogeneity of Regression Slopes

mancova_interaction_test <- manova(
  dv_matrix ~ baseline_math * intervention + baseline_reading * intervention,
  data = data_clean
)
summary(mancova_interaction_test, test = "Pillai")
##                                Df  Pillai approx F num Df den Df    Pr(>F)    
## baseline_math                   1 0.90397   503.61      2    107 < 2.2e-16 ***
## intervention                    3 0.21139     4.25      6    216 0.0004503 ***
## baseline_reading                1 0.89771   469.53      2    107 < 2.2e-16 ***
## baseline_math:intervention      3 0.09457     1.79      6    216 0.1029986    
## intervention:baseline_reading   3 0.03819     0.70      6    216 0.6491808    
## Residuals                     108                                             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Math
p1 <- ggplot(data_clean, aes(x = baseline_math, y = post_math, color = intervention)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
  labs(
    title = "Regression Slopes: Math",
    x = "Baseline Math",
    y = "Post Math",
    color = "Intervention"
  ) +
  theme_minimal()

# Reading
p2 <- ggplot(data_clean, aes(x = baseline_reading, y = post_reading, color = intervention)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
  labs(
    title = "Regression Slopes: Reading",
    x = "Baseline Reading",
    y = "Post Reading",
    color = "Intervention"
  ) +
  theme_minimal()

p1 + p2 + plot_layout(guides = "collect")
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'

The interaction between each covariate and intervention group was non-significant for both baseline math (Pillai = 0.095, F(6, 216) = 1.79, p = .103) and baseline reading (Pillai = 0.038, F(6, 216) = 0.70, p = .649). This confirms that the assumption of homogeneity of regression slopes was met, meaning the relationship between baseline and post-test scores was consistent across all four intervention groups.

The regression slope plots visually support this finding. Lines across all four groups run roughly parallel for both math and reading, with no meaningful crossing or fanning, which validates the use of MANCOVA for this dataset.

8 Grand Conclusion

ANOVA initially suggested that Math scores differed significantly across intervention groups while Reading showed no effect, but this was misleading because groups started with unequal baselines, particularly with the blended group having higher initial Math scores. ANCOVA addressed this by controlling for prior ability, revealing significant intervention effects in both Math (F(3,115)=6.15, p<.001, η²=.138) and Reading (F(3,115)=3.99, p=.010, η²=.094), with blended and tutoring outperforming control in Math, and blended and flipped outperforming control in Reading, though no intervention was superior to another.

In contrast, MANOVA without covariate adjustment found no significant multivariate effect (Pillai=.083, p=.127), highlighting how baseline differences can obscure results. Finally, MANCOVA, which controlled for both baseline Math and Reading, showed a strong multivariate intervention effect (Pillai=.239, F(6,228)=5.16, p<.001), confirming that the intervention significantly improved both outcomes, with assumptions such as homogeneity of regression slopes satisfied.

The final picture is this: prior academic ability is by far the strongest determinant of student outcomes, accounting for roughly 88 to 89 percent of variance in each subject. Yet even after that dominant influence is removed, the type of instruction a student received still explains an additional 12 percent of variance in their combined academic performance. Across both subjects and across every analytic framework that controlled for baseline, the control group consistently finished below every active intervention condition. Blended learning in particular showed statistically significant advantages over control in both Math and Reading, making it the most consistently effective method in this dataset, though tutoring and flipped classroom were competitive across specific outcomes as well.

To conclude, the educational intervention worked. It worked after leveling for prior ability, it worked across multiple outcomes simultaneously, and it worked according to every statistical framework designed to isolate its true contribution from pre-existing student differences. The recommendation that follows from this analysis is straightforward: passive control conditions should be replaced with active instructional methods, and future studies should prioritize baseline-adjusted designs from the outset to avoid systematically underestimating the effect of instruction.

LS0tDQp0aXRsZTogIjxzcGFuIHN0eWxlPSdmb250LXNpemU6IDMycHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogIzRBMEUwRTsnPk1BTk9WQSwgQU5DT1ZBLCBhbmQgTUFOQ09WQSBTdGF0aXN0aWNhbCBBc3N1bXB0aW9ucyBSZXBvcnQ8L3NwYW4+Ig0KYXV0aG9yOiAiRmlvIFVsYWEnIE9jdGlyeWFudGkgKDAzMCksIEFsZmluIEpheWFkaSAoMDgyKSwgS2V0dXQgU3JpZGhhcmEgKDExNSkiDQpkYXRlOiAiVXBkYXRlZCBvbjogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNA0KICAgIHRoZW1lOiBjb3NtbyAgICAgICAgDQogICAgaGlnaGxpZ2h0OiBlc3ByZXNzbyAgDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCjxzdHlsZT4NCmJvZHkgew0KICB0ZXh0LWFsaWduOiBqdXN0aWZ5Ow0KICBmb250LWZhbWlseTogJ09wZW4gU2FucycsIHNhbnMtc2VyaWY7DQp9DQoubGlzdC1ncm91cC1pdGVtLmFjdGl2ZSwgLmxpc3QtZ3JvdXAtaXRlbS5hY3RpdmU6Zm9jdXMsIC5saXN0LWdyb3VwLWl0ZW0uYWN0aXZlOmhvdmVyIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjNEEwRTBFOyANCiAgICBib3JkZXItY29sb3I6ICM0QTBFMEU7DQp9DQpoMSwgaDIsIGgzIHsNCiAgY29sb3I6ICM0QTBFMEU7DQp9DQoubmF2LXBpbGxzID4gbGkuYWN0aXZlID4gYSwgLm5hdi1waWxscyA+IGxpLmFjdGl2ZSA+IGE6Zm9jdXMsIC5uYXYtcGlsbHMgPiBsaS5hY3RpdmUgPiBhOmhvdmVyIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjNEEwRTBFOw0KfQ0KPC9zdHlsZT4NCi0tLQ0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIHJlcG9ydCBldmFsdWF0ZXMgdGhlIHByZXJlcXVpc2l0ZXMgZm9yIGNvbmR1Y3RpbmcgYSBNdWx0aXZhcmlhdGUgQW5hbHlzaXMgb2YgQ292YXJpYW5jZSAoTUFOQ09WQSkuIFdlIGFpbSB0byBkZXRlcm1pbmUgaWYgYW4gZWR1Y2F0aW9uYWwgaW50ZXJ2ZW50aW9uIHNpZ25pZmljYW50bHkgYWZmZWN0ZWQgTWF0aCBhbmQgUmVhZGluZyBzY29yZXMgd2hpbGUgY29udHJvbGxpbmcgZm9yIGJhc2VsaW5lIHBlcmZvcm1hbmNlLg0KDQojIyBFbnZpcm9ubWVudCBTZXR1cCAmIERhdGEgUHJlcGFyYXRpb24NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkgICANCmxpYnJhcnkoTVZOKSAgICAgICAgIA0KbGlicmFyeShiaW90b29scykgICAgDQpsaWJyYXJ5KGdnY29ycnBsb3QpICANCmxpYnJhcnkoZ2dwbG90MikgICAgIA0KbGlicmFyeShjYXIpICAgICAgICAgDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkoaGVwbG90cykNCmxpYnJhcnkoZW1tZWFucykNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQplZHVjYXRpb25fZGF0YSA8LSByZWFkLmNzdigiZWR1Y2F0aW9uX2ludGVydmVudGlvbl8xMDAwMC5jc3YiKQ0KbmFtZXMoZWR1Y2F0aW9uX2RhdGEpIDwtIG1ha2UubmFtZXMobmFtZXMoZWR1Y2F0aW9uX2RhdGEpKQ0KDQpkdl9jb2xzIDwtIGMoInBvc3RfbWF0aCIsICJwb3N0X3JlYWRpbmciKQ0KaXZfY29sIDwtICJpbnRlcnZlbnRpb24iDQpjb3ZhcmlhdGVfY29scyA8LSBjKCJiYXNlbGluZV9tYXRoIiwgImJhc2VsaW5lX3JlYWRpbmciKQ0KDQpkYXRhX2NsZWFuIDwtIGVkdWNhdGlvbl9kYXRhIHw+DQogIGRyb3BfbmEoYWxsX29mKGMoZHZfY29scywgaXZfY29sLCBjb3ZhcmlhdGVfY29scykpKQ0KDQpjb250X2NvbHMgPC0gYyhkdl9jb2xzLCBjb3ZhcmlhdGVfY29scykNCnJlbW92ZV9vdXRsaWVyc19pcXIgPC0gZnVuY3Rpb24oZGYsIGNvbHMpIHsNCiAgZGZfZmlsdGVyZWQgPC0gZGYNCiAgZm9yIChjb2wgaW4gY29scykgew0KICAgIFExIDwtIHF1YW50aWxlKGRmX2ZpbHRlcmVkW1tjb2xdXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KICAgIFEzIDwtIHF1YW50aWxlKGRmX2ZpbHRlcmVkW1tjb2xdXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KICAgIElRUl92YWwgPC0gUTMgLSBRMQ0KICAgIA0KICAgIGxvd2VyX2JvdW5kIDwtIFExIC0gMS41ICogSVFSX3ZhbA0KICAgIHVwcGVyX2JvdW5kIDwtIFEzICsgMS41ICogSVFSX3ZhbA0KICAgIA0KICAgIGRmX2ZpbHRlcmVkIDwtIGRmX2ZpbHRlcmVkIHw+IA0KICAgICAgZmlsdGVyKC5kYXRhW1tjb2xdXSA+PSBsb3dlcl9ib3VuZCAmIC5kYXRhW1tjb2xdXSA8PSB1cHBlcl9ib3VuZCkNCiAgfQ0KICByZXR1cm4oZGZfZmlsdGVyZWQpDQp9DQoNCmRhdGFfbm9fb3V0bGllcnMgPC0gcmVtb3ZlX291dGxpZXJzX2lxcihkYXRhX2NsZWFuLCBjb250X2NvbHMpDQpjYXQoIlJlbW92ZWQiLCBucm93KGRhdGFfY2xlYW4pIC0gbnJvdyhkYXRhX25vX291dGxpZXJzKSwgIm91dGxpZXJzIHVzaW5nIElRUiBtZXRob2QuXG5cbiIpDQoNCnNldC5zZWVkKDQyKQ0KZGF0YV9jbGVhbiA8LSBkYXRhX25vX291dGxpZXJzIHw+DQogIGdyb3VwX2J5KCEhc3ltKGl2X2NvbCkpIHw+DQogIHNhbXBsZV9uKDMwKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgYXMuZGF0YS5mcmFtZSgpDQoNCnByaW50KCJFZHVjYXRpb24gSW50ZXJ2ZW50aW9uIERhdGFmcmFtZSBQcmV2aWV3IChJUVIgT3V0bGllcnMgUmVtb3ZlZCAmIEJhbGFuY2VkKToiKQ0KcHJpbnQoaGVhZChkYXRhX2NsZWFuWywgYyhpdl9jb2wsIGR2X2NvbHMsIGNvdmFyaWF0ZV9jb2xzKV0pKQ0KYGBgDQoNCldlIGxvYWQgdGhlIG5lY2Vzc2FyeSBsaWJyYXJpZXMgYW5kIHByZXBhcmUgdGhlIGRhdGEgYnkgYmFsYW5jaW5nIHRoZSBncm91cHMsIGVuc3VyaW5nIGEgY2xlYW4gc3RhcnQgZm9yIHRoZSBtdWx0aXZhcmlhdGUgdGVzdHMuDQoNCmBgYHtyfQ0KZGVzY19zdGF0cyA8LSBkYXRhX2NsZWFuIHw+DQogIGdyb3VwX2J5KGludGVydmVudGlvbikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhhbGxfb2YoY29udF9jb2xzKSwgbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCksIC5uYW1lcyA9ICJ7LmNvbH1fey5mbn0iKSkgfD4NCiAgYmluZF9yb3dzKA0KICAgIGRhdGFfY2xlYW4gfD4NCiAgICAgIHN1bW1hcmlzZShhY3Jvc3MoYWxsX29mKGNvbnRfY29scyksIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpLCAubmFtZXMgPSAiey5jb2x9X3suZm59IikpIHw+DQogICAgICBtdXRhdGUoaW50ZXJ2ZW50aW9uID0gIlRvdGFsIikNCiAgKQ0KIA0KcHJpbnQoZGVzY19zdGF0cykNCiANCnBsb3RfcG9zdF9tYXRoIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IHBvc3RfbWF0aCwgZmlsbCA9IGludGVydmVudGlvbikpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNoYXBlID0gMTYsIG91dGxpZXIuc2l6ZSA9IDEuNSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjMsIHNpemUgPSAzLCBmaWxsID0gIndoaXRlIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSAiUG9zdCBNYXRoIFNjb3JlIiwgeCA9ICJJbnRlcnZlbnRpb24iLCB5ID0gIlNjb3JlIikNCiANCnBsb3RfcG9zdF9yZWFkaW5nIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IHBvc3RfcmVhZGluZywgZmlsbCA9IGludGVydmVudGlvbikpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNoYXBlID0gMTYsIG91dGxpZXIuc2l6ZSA9IDEuNSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjMsIHNpemUgPSAzLCBmaWxsID0gIndoaXRlIikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSAiUG9zdCBSZWFkaW5nIFNjb3JlIiwgeCA9ICJJbnRlcnZlbnRpb24iLCB5ID0gIlNjb3JlIikNCiANCnBsb3RfYmFzZWxpbmVfbWF0aCA8LSBnZ3Bsb3QoZGF0YV9jbGVhbiwgYWVzKHggPSBpbnRlcnZlbnRpb24sIHkgPSBiYXNlbGluZV9tYXRoLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuc2hhcGUgPSAxNiwgb3V0bGllci5zaXplID0gMS41KSArDQogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMywgc2l6ZSA9IDMsIGZpbGwgPSAid2hpdGUiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgbGFicyh0aXRsZSA9ICJCYXNlbGluZSBNYXRoIFNjb3JlIiwgeCA9ICJJbnRlcnZlbnRpb24iLCB5ID0gIlNjb3JlIikNCiANCnBsb3RfYmFzZWxpbmVfcmVhZGluZyA8LSBnZ3Bsb3QoZGF0YV9jbGVhbiwgYWVzKHggPSBpbnRlcnZlbnRpb24sIHkgPSBiYXNlbGluZV9yZWFkaW5nLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuc2hhcGUgPSAxNiwgb3V0bGllci5zaXplID0gMS41KSArDQogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2hhcGUgPSAyMywgc2l6ZSA9IDMsIGZpbGwgPSAid2hpdGUiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgbGFicyh0aXRsZSA9ICJCYXNlbGluZSBSZWFkaW5nIFNjb3JlIiwgeCA9ICJJbnRlcnZlbnRpb24iLCB5ID0gIlNjb3JlIikNCiANCmNvbWJpbmVkX3Bsb3QgPC0gKHBsb3RfcG9zdF9tYXRoICsgcGxvdF9wb3N0X3JlYWRpbmcpIC8gKHBsb3RfYmFzZWxpbmVfbWF0aCArIHBsb3RfYmFzZWxpbmVfcmVhZGluZykgKw0KICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiU2NvcmUgRGlzdHJpYnV0aW9uIGJ5IEludGVydmVudGlvbiBNZXRob2QiKQ0KIA0KcHJpbnQoY29tYmluZWRfcGxvdCkNCmBgYA0KDQojIEFzc3VtcHRpb24gVGVzdA0KDQojIyBTdGVwIDE6IERWIERlcGVuZGVuY3kgKEJhcnRsZXR0J3MgVGVzdCBvZiBTcGhlcmljaXR5KQ0KDQpNQU5DT1ZBIGlzIG9ubHkgYXBwcm9wcmlhdGUgaWYgdGhlIERlcGVuZGVudCBWYXJpYWJsZXMgKFBvc3QgTWF0aCBhbmQgUG9zdCBSZWFkaW5nKSBhcmUgc2lnbmlmaWNhbnRseSBjb3JyZWxhdGVkLiBJZiB0aGV5IHdlcmUgaW5kZXBlbmRlbnQsIHRoZSBhbmFseXNpcyB3b3VsZCBub3QgcHJvdmlkZSBhbnkgbXVsdGl2YXJpYXRlIGFkdmFudGFnZSBvdmVyIHNlcGFyYXRlIEFOT1ZBcy4NCg0KSW4gb3JkZXIgdG8gc2ltcGxpZnksIGh5cG90aGVzaXMgb2YgSDAgYW5kIEgxIG5lZWQgdG8gY29uZHVjdGVkOg0KDQotICAgSDA6IERWIG5vdCBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlcg0KDQotICAgSDE6IERWIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyDQoNCkluIG9yZGVyIHRvIHBhc3MgdGhlIHRlc3QsIHdlIG5lZWQgdG8gc3VjY2Vzc2Z1bGx5IHJlamVjdCBIMC4NCg0KYGBge3J9DQpjb3JfbWF0cml4IDwtIGNvcihkYXRhX2NsZWFuW2R2X2NvbHNdKQ0KbiA8LSBucm93KGRhdGFfY2xlYW4pDQpwIDwtIGxlbmd0aChkdl9jb2xzKQ0KZGV0X1IgPC0gZGV0KGNvcl9tYXRyaXgpDQpiYXJ0bGV0dF9jaGkgPC0gLSgobiAtIDEpIC0gKDIgKiBwICsgNSkgLyA2KSAqIGxvZyhkZXRfUikNCnBfdmFsX2JhcnRsZXR0IDwtIHBjaGlzcShiYXJ0bGV0dF9jaGksIGRmID0gcCoocC0xKS8yLCBsb3dlci50YWlsID0gRkFMU0UpDQoNCmNhdCgiQmFydGxldHQncyBTcGhlcmljaXR5IHAtdmFsdWU6IiwgcF92YWxfYmFydGxldHQpDQpgYGANCg0KV2Ugc2VlayBhIHAtdmFsdWUgXDwgMC4wNS4gQSBzaWduaWZpY2FudCByZXN1bHQgY29uZmlybXMgdGhhdDogd2UgcmVqZWN0IEgwOyB0aGVyZSBpcyBpbmRlZWQgY29ycmVsYXRpb24gYmV0d2VlbiBlYWNoIERWLiBNYXRoIGFuZCByZWFkaW5nIHNjb3JlcyBzaGFyZSBlbm91Z2ggdmFyaWFuY2UgdG8gYmUgYW5hbHl6ZWQgYXMgYSB1bmlmaWVkIGVkdWNhdGlvbmFsIG91dGNvbWUsIHNhdGlzZnlpbmcgdGhlIGZpcnN0IGNvcmUgYXNzdW1wdGlvbi4NCg0KIyMgU3RlcCAyOiBIb21vZ2VuZWl0eSBvZiBDb3ZhcmlhbmNlIE1hdHJpY2VzIChCb3jigJlzIE0gVGVzdCkNCg0KRXhwbGFuYXRpb246IFRoaXMgdGVzdCBlbnN1cmVzIHRoYXQgdGhlICJzcHJlYWQiICh2YXJpYW5jZSkgYW5kIHRoZSByZWxhdGlvbnNoaXAgKGNvdmFyaWFuY2UpIGJldHdlZW4gdGhlIHRlc3Qgc2NvcmVzIGFyZSBlcXVhbCBhY3Jvc3MgYWxsIEludGVydmVudGlvbiBncm91cHMgKGUuZy4sIFR1dG9yaW5nLCBGbGlwcGVkLCBCbGVuZGVkKS4NCg0KLSAgIEgwOiBBbGwgZ3JvdXBzIHNoYXJlIHRoZSBzYW1lIGNvdmFyaWFuY2UgbWF0cml4DQoNCi0gICBIMTogQXQgbGVhc3Qgb25lIG9mIHRoZSBncm91cCBoYXZlIGRpZmZlciBjb3ZhcmlhbmNlIG1hdHJpeA0KDQpJbiBvcmRlciB0byBwYXNzLCB3ZSBuZWVkIHRvIGZhaWwgdG8gcmVqZWN0IEgwLiBTaW5jZSB3ZSB3YW50IHRoZSBkYXRhIHRvIGJlIGhhdmUgaG9tb2dlbmVpdHkgYWNjcm9zcyBncm91cA0KDQpgYGB7cn0NCmJveF9tX3JlcyA8LSBib3hNKGRhdGFfY2xlYW5bZHZfY29sc10sIGRhdGFfY2xlYW5bW2l2X2NvbF1dKQ0KcHJpbnQoYm94X21fcmVzKQ0KYGBgDQoNCkZvbGxvd2luZyB0aGUgcHVibGljYXRpb24ncyBzdGFuZGFyZHMsIHdlIGxvb2sgZm9yIGEgcC12YWx1ZSBcPiAwLjA1Lg0KDQpUaGUgcmVzdWx0IGNvbmZpcm1zIHRoYXQ6IHdlIHN1Y2Nlc3NmdWxseSBmYWlsIHRvIHJlamVjdCBIMC4gQmVjYXVzZSBCb3gncyBNIGlzIGhpZ2hseSBzZW5zaXRpdmUgdG8gc2FtcGxlIHNpemUsIGEgcC12YWx1ZSBhYm92ZSB0aGlzIHN0cmljdCB0aHJlc2hvbGQgaW5kaWNhdGVzIHRoYXQgdGhlIGdyb3VwIHZhcmlhbmNlcyBhcmUgc3VmZmljaWVudGx5IGhvbW9nZW5vdXMgZm9yIGEgdmFsaWQgTUFOQ09WQS4NCg0KIyMgU3RlcCAzOiBNdWx0aXZhcmlhdGUgTm9ybWFsaXR5IChIZW56ZS1aaXJrbGVyJ3MgVGVzdCkNCg0KV2UgY2hlY2sgaWYgdGhlIGNvbWJpbmF0aW9uIG9mIE1hdGggYW5kIFJlYWRpbmcgc2NvcmVzIGZvbGxvd3MgYSBtdWx0aXZhcmlhdGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBieSBsb29raW5nIGF0IFNrZXduZXNzIChzeW1tZXRyeSkgYW5kIEt1cnRvc2lzIChwZWFrIGhlaWdodCkuDQoNCi0gICBIMDogRGF0YSBmb2xsb3dzIGEgbXVsdGl2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24NCg0KLSAgIEgxOiBEYXRhIG5vdCBmb2xsb3dzIGEgbXVsdGl2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24NCg0KSW4gb3JkZXIgdG8gcGFzcyB0aGUgdGVzdCwgd2UgbmVlZCB0byBmYWlsIHRvIHJlamVjdCBIMA0KDQpgYGB7cn0NCiMgQ3JlYXRpbmcgZGlzdHJpYnV0aW9ucyBmb3IgTWF0aCBhbmQgUmVhZGluZyBzY29yZXMNCnBsb3RfbWF0aCA8LSBnZ3Bsb3QoZGF0YV9jbGVhbiwgYWVzKHggPSBwb3N0X21hdGgpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAic3RlZWxibHVlIiwgY29sb3IgPSAid2hpdGUiLCBiaW5zID0gMzApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJQb3N0IE1hdGggRGlzdHJpYnV0aW9uIikNCg0KcGxvdF9yZWFkaW5nIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IHBvc3RfcmVhZGluZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJkYXJrZ3JlZW4iLCBjb2xvciA9ICJ3aGl0ZSIsIGJpbnMgPSAzMCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlBvc3QgUmVhZGluZyBEaXN0cmlidXRpb24iKQ0KDQojIERpc3BsYXlpbmcgdGhlbSBzaWRlLWJ5LXNpZGUNCnByaW50KHBsb3RfbWF0aCArIHBsb3RfcmVhZGluZykNCmBgYA0KDQpgYGB7cn0NCm12bl9yZXMgPC0gbXZuKGRhdGFfY2xlYW5bZHZfY29sc10sIG12bl90ZXN0ID0gImh6IikNCnByaW50KHN1bW1hcnkobXZuX3JlcywgIm12biIpKQ0KYGBgDQoNClRoZSBIZW56ZS1aaXJrbGVyIHRlc3QgcHJvZHVjZWQgYSB0ZXN0IHN0YXRpc3RpYyBvZiAwLjkwNyB3aXRoIHAgPSAwLjA4MSwgd2hpY2ggaXMgYWJvdmUgdGhlIDAuMDUgdGhyZXNob2xkLiBXZSBzdWNjZXNmdWxseSBmYWlsIHRvIHJlamVjdCBIMCwgbWVhbmluZyB0aGUgam9pbnQgZGlzdHJpYnV0aW9uIG9mIHBvc3RfbWF0aCBhbmQgcG9zdF9yZWFkaW5nIHNhdGlzZmllcyBtdWx0aXZhcmlhdGUgbm9ybWFsaXR5LiBBdCB0aGUgdW5pdmFyaWF0ZSBsZXZlbCwgcG9zdF9yZWFkaW5nIGlzIG5vcm1hbCAocCA9IDAuMTAxKSwgd2hpbGUgcG9zdF9tYXRoIHNob3dzIGEgbWlub3IgdmlvbGF0aW9uIChwID0gMC4wMzMpLiBHaXZlbiB0aGUgYmFsYW5jZWQgc2FtcGxlIHNpemUgb2YgbiA9IDEyMCBhbmQgdGhlIGxvdyBza2V3bmVzcyB2YWx1ZXMgZm9yIGJvdGggdmFyaWFibGVzIChwb3N0X21hdGg6IC0wLjI0OCwgcG9zdF9yZWFkaW5nOiAtMC4xNjgpLCB0aGlzIHZpb2xhdGlvbiBpcyBjb25zaWRlcmVkIG5lZ2xpZ2libGUuIFRoZSBtdWx0aXZhcmlhdGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gaXMgbWV0Lg0KDQojIyBTdGVwIDQ6IExpbmVhcml0eSAoQ292YXJpYXRlcyB2cy4gRFZzKQ0KDQpUaGlzIGVuc3VyZXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIENvdmFyaWF0ZXMgKEJhc2VsaW5lIHNjb3JlcykgYW5kIHRoZSBEVnMgKFBvc3QtdGVzdCBzY29yZXMpLiBJdCBhbHNvIGNoZWNrcyBpZiB0aGUgcmVsYXRpb25zaGlwIGlzIGNvbnNpc3RlbnQgYWNyb3NzIGRpZmZlcmVudCBpbnRlcnZlbnRpb24gZ3JvdXBzLg0KDQotICAgSDA6IFRoZXJlIGlzIG5vIGxpbmVhcml0eSBiZXR3ZWVuIGNvdmFyaWF0ZSBhbmQgRFYNCg0KLSAgIEgxOiBUaGVyZSBpcyBsaW5lYXJpdHkgYmV0d2VlbiBjb3ZhcmlhdGVzIGFuZCBEVg0KDQpJbiBvcmRlciB0byBwYXNzIHRoZSB0ZXN0IHdlIG5lZWQgdG8gcmVqZWN0IEgwLg0KDQpgYGB7cn0NCmZvciAoZHYgaW4gZHZfY29scykgew0KICBmb3JtdWxhX3N0ciA8LSBwYXN0ZShkdiwgIn4iLCBwYXN0ZShjb3ZhcmlhdGVfY29scywgY29sbGFwc2UgPSAiICsgIikpDQogIGZpdCA8LSBsbShhcy5mb3JtdWxhKGZvcm11bGFfc3RyKSwgZGF0YSA9IGRhdGFfY2xlYW4pDQogIA0KICBjYXQoIlxuTGluZWFyaXR5IEFuYWx5c2lzIGZvciIsIGR2LCAiOlxuIikNCiAgcHJpbnQoc3VtbWFyeShmaXQpKQ0KICBjYXQoIlItc3F1YXJlZDoiLCBzdW1tYXJ5KGZpdCkkci5zcXVhcmVkLCAiXG4iKQ0KICANCiAgIyBFeHRyYWN0IHAtdmFsdWVzDQogIGNvZWZfdGFibGUgPC0gY29lZihzdW1tYXJ5KGZpdCkpDQogIHBfdmFsdWVzIDwtIGNvZWZfdGFibGVbLCAiUHIoPnx0fCkiXQ0KICANCiAgY2F0KCJcblAtdmFsdWVzIGZvciIsIGR2LCAiOlxuIikNCiAgcHJpbnQocF92YWx1ZXMpDQogIA0KICAjIE92ZXJhbGwgbW9kZWwgcC12YWx1ZQ0KICBvdmVyYWxsX3AgPC0gcGYoc3VtbWFyeShmaXQpJGZzdGF0aXN0aWNbMV0sIA0KICAgICAgICAgICAgICAgICAgc3VtbWFyeShmaXQpJGZzdGF0aXN0aWNbMl0sIA0KICAgICAgICAgICAgICAgICAgc3VtbWFyeShmaXQpJGZzdGF0aXN0aWNbM10sIA0KICAgICAgICAgICAgICAgICAgbG93ZXIudGFpbCA9IEZBTFNFKQ0KICBjYXQoIk92ZXJhbGwgbW9kZWwgcC12YWx1ZToiLCBvdmVyYWxsX3AsICJcbiIpDQp9DQpgYGANCg0KVGhlIGFzc3VtcHRpb24gaXMgbWV0IGlmIHRoZSByZWdyZXNzaW9uIG1vZGVscyBhcmUgc2lnbmlmaWNhbnQgKHAgXDwgMC4wNSkuIFRoZSByZXN1bHRzIHNheXMgdGhhdCB3ZSBzdWNjZXNzZnVsbHkgcmVqZWN0IEgwLiBUaGlzIHByb3ZlcyB0aGF0IHRoZSBiYXNlbGluZSBzY29yZXMgYW5kIHN0dWR5IGhvdXJzIGFyZSB2YWxpZCBwcmVkaWN0b3JzIHRoYXQgY2FuIGVmZmVjdGl2ZWx5ICJjbGVhbiIgdGhlIHBvc3QtdGVzdCBkYXRhIGluIHRoZSBNQU5DT1ZBIG1vZGVsLg0KDQojIyBTdGVwIDU6IEluZGVwZW5kZW5jZSBvZiBPYnNlcnZhdGlvbnMNCg0KVGhpcyBhc3N1bXB0aW9uIHJlcXVpcmVzIHRoYXQgZWFjaCBzdHVkZW50J3Mgc2NvcmUgaXMgaW5kZXBlbmRlbnQgYW5kIG5vdCBpbmZsdWVuY2VkIGJ5IG90aGVycy4gU2luY2UgdGhlcmUgaXMgbm8gc3BlY2lmaWMgc3RhdGlzdGljYWwgdGVzdCBmb3IgdGhpcywgd2UgZXhhbWluZSB0aGUgcmVzaWR1YWxzIGZvciByYW5kb20gZGlzdHJpYnV0aW9uLg0KDQpgYGB7cn0NCnJlc19maXQgPC0gbG0oYXMubWF0cml4KGRhdGFfY2xlYW5bZHZfY29sc10pIH4gaW50ZXJ2ZW50aW9uICsgYmFzZWxpbmVfbWF0aCwgZGF0YSA9IGRhdGFfY2xlYW4pDQpyZXNfZGF0YSA8LSByZXNpZHVhbHMocmVzX2ZpdClbLDFdDQpwbG90KHJlc19kYXRhLCBtYWluPSJJbmRlcGVuZGVuY2UgQ2hlY2s6IFJlc2lkdWFsIFBsb3QiLCANCiAgICAgeGxhYj0iU3R1ZGVudCBJbmRleCIsIHlsYWI9IlJlc2lkdWFscyIsIGNvbD0iZGFya2JsdWUiKQ0KYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIiwgbHdkID0gMikNCmBgYA0KDQpBIHJhbmRvbSBzY2F0dGVyIG9mIHBvaW50cyBhcm91bmQgdGhlIHplcm8gbGluZSBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBubyB0ZW1wb3JhbCBvciBncm91cC1iYXNlZCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHN0dWRlbnQgcmVjb3Jkcy4gVGhpcyBjb25maXJtcyB0aGUgSW5kZXBlbmRlbmNlIG9mIE9ic2VydmF0aW9ucywgZnVsZmlsbGluZyB0aGUgZmluYWwgcmVxdWlyZW1lbnQgZm9yIHRoZSBhbmFseXNpcy4NCg0KIyBJbml0aWFsIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMNCg0KQmVmb3JlIHJ1bm5pbmcgYW55IGZvcm1hbCB0ZXN0cywgd2UgbXVzdCB1bmRlcnN0YW5kIHRoZSBzaGFwZSBhbmQgYmVoYXZpb3Igb2Ygb3VyIGRhdGEgYWNyb3NzIGJvdGggb3V0Y29tZXMuIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgaGVscHMgdXMgdmlzdWFsaXplIHRoZSByYXcgcGVyZm9ybWFuY2UgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgaW50ZXJ2ZW50aW9uIGdyb3VwcyBhbmQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBiYXNlbGluZSBhbmQgcG9zdC10ZXN0IHNjb3JlcyBmb3IgYm90aCBtYXRoIGFuZCByZWFkaW5nLg0KDQojIyBWaXN1YWxpemluZyB0aGUgUmF3IEdyb3VwIERpZmZlcmVuY2VzDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiB8Pg0KICBwaXZvdF9sb25nZXIoY29scyA9IGMocG9zdF9tYXRoLCBwb3N0X3JlYWRpbmcpLCBuYW1lc190byA9ICdvdXRjb21lJywgdmFsdWVzX3RvID0gJ3Njb3JlJykgfD4NCiAgbXV0YXRlKG91dGNvbWUgPSBjYXNlX3doZW4oDQogICAgb3V0Y29tZSA9PSAncG9zdF9tYXRoJyAgICAgfiAnUG9zdCBNYXRoJywNCiAgICBvdXRjb21lID09ICdwb3N0X3JlYWRpbmcnICB+ICdQb3N0IFJlYWRpbmcnDQogICkpIHw+DQogIGdncGxvdChhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IHNjb3JlLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsNCiAgZmFjZXRfd3JhcCh+IG91dGNvbWUsIHNjYWxlcyA9ICdmcmVlX3knKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnUmF3IFBvc3QtVGVzdCBTY29yZXMgYnkgSW50ZXJ2ZW50aW9uIEdyb3VwJywNCiAgICB4ID0gJ0ludGVydmVudGlvbiBUeXBlJywNCiAgICB5ID0gJ1Njb3JlJw0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKQ0KYGBgDQoNCkZvciBtYXRoLCBibGVuZGVkIGFuZCBmbGlwcGVkIGdyb3VwcyBzaG93IHZpc2libHkgaGlnaGVyIG1lZGlhbnMgY29tcGFyZWQgdG8gY29udHJvbCwgd2l0aCBibGVuZGVkIGluIHBhcnRpY3VsYXIgc2l0dGluZyBub3RhYmx5IGFib3ZlIHRoZSByZXN0LiBUaGUgY29udHJvbCBncm91cCBhbHNvIGRpc3BsYXlzIGEgd2lkZXIgaW50ZXJxdWFydGlsZSByYW5nZSwgc3VnZ2VzdGluZyBtb3JlIHZhcmlhYmlsaXR5IGluIG1hdGggb3V0Y29tZXMgYW1vbmcgc3R1ZGVudHMgd2hvIHJlY2VpdmVkIG5vIGFjdGl2ZSBpbnRlcnZlbnRpb24uIEZvciByZWFkaW5nLCB0aGUgcGljdHVyZSBpcyBzdHJpa2luZ2x5IGRpZmZlcmVudCwgYXMgYWxsIGZvdXIgZ3JvdXBzIHNob3cgaGVhdmlseSBvdmVybGFwcGluZyBib3hlcyB3aXRoIG1lZGlhbnMgY2x1c3RlcmVkIGNsb3NlbHkgdG9nZXRoZXIsIGluZGljYXRpbmcgdGhhdCBpbnRlcnZlbnRpb24gdHlwZSBwcm9kdWNlcyBsaXR0bGUgdmlzaWJsZSBzZXBhcmF0aW9uIGluIHJhdyByZWFkaW5nIG91dGNvbWVzLiBOb3RhYmx5LCB0aGUgcmVhZGluZyBwbG90cyBhbHNvIHNob3cgd2lkZXIgc3ByZWFkcyBvdmVyYWxsIGNvbXBhcmVkIHRvIG1hdGgsIG1lYW5pbmcgaW5kaXZpZHVhbCByZWFkaW5nIHNjb3JlcyB2YXJ5IGNvbnNpZGVyYWJseSByZWdhcmRsZXNzIG9mIGdyb3VwLiBCb3RoIG9ic2VydmF0aW9ucyBhcmUgYmFzZWQgb24gdW5hZGp1c3RlZCByYXcgc2NvcmVzIGhvd2V2ZXIsIHNvIHRoZSBhcHBhcmVudCBtYXRoIGFkdmFudGFnZSBvZiBibGVuZGVkIGFuZCBmbGlwcGVkIG1heSBzaW1wbHkgcmVmbGVjdCB0aGUgZmFjdCB0aGF0IHRob3NlIHN0dWRlbnRzIHN0YXJ0ZWQgd2l0aCBzdHJvbmdlciBiYXNlbGluZSBtYXRoIGFiaWxpdHkgcmF0aGVyIHRoYW4gYmVuZWZpdGluZyBtb3JlIGZyb20gdGhlIGluc3RydWN0aW9uIGl0c2VsZi4NCg0KIyMgVmlzdWFsaXppbmcgdGhlIENvdmFyaWF0ZSBFZmZlY3QNCg0KYGBge3J9DQpkYXRhX2NsZWFuIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gYyhiYXNlbGluZV9tYXRoLCBiYXNlbGluZV9yZWFkaW5nKSwNCiAgICBuYW1lc190byA9ICdiYXNlbGluZV9vdXRjb21lJywNCiAgICB2YWx1ZXNfdG8gPSAnYmFzZWxpbmVfc2NvcmUnDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIHBvc3Rfc2NvcmUgPSBpZmVsc2UoYmFzZWxpbmVfb3V0Y29tZSA9PSAnYmFzZWxpbmVfbWF0aCcsIHBvc3RfbWF0aCwgcG9zdF9yZWFkaW5nKSwNCiAgICBvdXRjb21lID0gY2FzZV93aGVuKA0KICAgICAgYmFzZWxpbmVfb3V0Y29tZSA9PSAnYmFzZWxpbmVfbWF0aCcgICAgIH4gJ01hdGgnLA0KICAgICAgYmFzZWxpbmVfb3V0Y29tZSA9PSAnYmFzZWxpbmVfcmVhZGluZycgIH4gJ1JlYWRpbmcnDQogICAgKQ0KICApIHw+DQogIGdncGxvdChhZXMoeCA9IGJhc2VsaW5lX3Njb3JlLCB5ID0gcG9zdF9zY29yZSwgY29sb3IgPSBpbnRlcnZlbnRpb24pKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2UgPSBGQUxTRSkgKw0KICBmYWNldF93cmFwKH4gb3V0Y29tZSwgc2NhbGVzID0gJ2ZyZWUnKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnVHJhamVjdG9yeTogQmFzZWxpbmUgdnMgUG9zdC1UZXN0IFNjb3JlcycsDQogICAgeCA9ICdCYXNlbGluZSBTY29yZScsDQogICAgeSA9ICdQb3N0LVRlc3QgU2NvcmUnDQogICkNCmBgYA0KDQpCb3RoIHBsb3RzIGNvbmZpcm0gYSBzdHJvbmcgcG9zaXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGJhc2VsaW5lIGFuZCBwb3N0LXRlc3Qgc2NvcmVzIGZvciBtYXRoIGFuZCByZWFkaW5nIGFsaWtlLCBtZWFuaW5nIHN0dWRlbnRzIHdobyBlbnRlcmVkIHRoZSBzdHVkeSB3aXRoIGhpZ2hlciBwcmlvciBhYmlsaXR5IGNvbnNpc3RlbnRseSBzY29yZWQgaGlnaGVyIG9uIHRoZSBwb3N0LXRlc3QgcmVnYXJkbGVzcyBvZiB3aGljaCBpbnRlcnZlbnRpb24gdGhleSByZWNlaXZlZC4gVGhlIHJlZ3Jlc3Npb24gbGluZXMgYWNyb3NzIGFsbCBmb3VyIGludGVydmVudGlvbiBncm91cHMgYXJlIHN0cmlraW5nbHkgcGFyYWxsZWwgYW5kIHJ1biBpbiB0aGUgc2FtZSBkaXJlY3Rpb24gd2l0aG91dCBjcm9zc2luZywgd2hpY2ggcHJvdmlkZXMgZWFybHkgdmlzdWFsIGV2aWRlbmNlIHRoYXQgdGhlIGNvdmFyaWF0ZSBiZWhhdmVzIGNvbnNpc3RlbnRseSBhY3Jvc3MgZ3JvdXBzIGZvciBib3RoIG91dGNvbWVzLiBGb3IgbWF0aCwgdGhlIGNvbnRyb2wgZ3JvdXAgbGluZSBzaXRzIHZpc2libHkgbG93ZXIgdGhhbiB0aGUgYWN0aXZlIGludGVydmVudGlvbiBncm91cHMgYWNyb3NzIG1vc3Qgb2YgdGhlIGJhc2VsaW5lIHJhbmdlLCBoaW50aW5nIHRoYXQgdGhlIGludGVydmVudGlvbiBlZmZlY3QgbWF5IGJlIG1lYW5pbmdmdWwgb25jZSBiYXNlbGluZSBpcyBhY2NvdW50ZWQgZm9yLiBGb3IgcmVhZGluZywgdGhlIGZvdXIgbGluZXMgYXJlIGV2ZW4gbW9yZSB0aWdodGx5IGNsdXN0ZXJlZCB0b2dldGhlciwgcmVpbmZvcmNpbmcgdGhlIGVhcmxpZXIgYm94cGxvdCBvYnNlcnZhdGlvbiB0aGF0IGdyb3VwIHNlcGFyYXRpb24gaW4gcmVhZGluZyBpcyBtaW5pbWFsLiBUaGUgY29uc2lzdGVudCBzbG9wZXMgYWNyb3NzIGJvdGggb3V0Y29tZXMgYXJlIGFuIGVuY291cmFnaW5nIGVhcmx5IHNpZ24gdGhhdCB0aGUgaG9tb2dlbmVpdHkgb2YgcmVncmVzc2lvbiBzbG9wZXMgYXNzdW1wdGlvbiwgd2hpY2ggd2lsbCBiZSBmb3JtYWxseSB0ZXN0ZWQgbGF0ZXIsIGlzIGxpa2VseSB0byBiZSBzYXRpc2ZpZWQuDQoNCiMjIERpc3RyaWJ1dGlvbiBvZiBQb3N0LVRlc3QgU2NvcmVzIGJ5IEdyb3VwDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiB8Pg0KICBwaXZvdF9sb25nZXIoY29scyA9IGMocG9zdF9tYXRoLCBwb3N0X3JlYWRpbmcpLCBuYW1lc190byA9ICdvdXRjb21lJywgdmFsdWVzX3RvID0gJ3Njb3JlJykgfD4NCiAgbXV0YXRlKG91dGNvbWUgPSBjYXNlX3doZW4oDQogICAgb3V0Y29tZSA9PSAncG9zdF9tYXRoJyAgICAgfiAnUG9zdCBNYXRoJywNCiAgICBvdXRjb21lID09ICdwb3N0X3JlYWRpbmcnICB+ICdQb3N0IFJlYWRpbmcnDQogICkpIHw+DQogIGdncGxvdChhZXMoeCA9IHNjb3JlLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsNCiAgZmFjZXRfd3JhcCh+IG91dGNvbWUsIHNjYWxlcyA9ICdmcmVlJykgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gJ1Bvc3QtVGVzdCBTY29yZSBEaXN0cmlidXRpb24gYnkgSW50ZXJ2ZW50aW9uIEdyb3VwJywNCiAgICB4ID0gJ1Bvc3QtVGVzdCBTY29yZScsDQogICAgeSA9ICdEZW5zaXR5Jw0KICApDQpgYGANCg0KRm9yIG1hdGgsIHRoZSBkZW5zaXR5IGN1cnZlcyBzaG93IG1lYW5pbmdmdWwgc2VwYXJhdGlvbiBiZXR3ZWVuIGdyb3Vwcywgd2l0aCBibGVuZGVkIHBlYWtpbmcgZnVydGhlc3QgdG8gdGhlIHJpZ2h0IGFyb3VuZCA5MCBhbmQgY29udHJvbCBzcHJlYWRpbmcgYnJvYWRseSBhY3Jvc3MgYSBsb3dlciByYW5nZSwgY29uc2lzdGVudCB3aXRoIHRoZSBib3hwbG90IHBhdHRlcm4gb2JzZXJ2ZWQgZWFybGllci4gRmxpcHBlZCBhbmQgdHV0b3Jpbmcgc2l0IGluIGJldHdlZW4sIHdpdGggdGhlaXIgcGVha3MgY2x1c3RlcmluZyBhcm91bmQgODAuIFRoZSBjb250cm9sIGdyb3VwIG5vdGFibHkgcHJvZHVjZXMgdGhlIGZsYXR0ZXN0IGFuZCB3aWRlc3QgY3VydmUsIHJlZmxlY3RpbmcgZ3JlYXRlciBzY29yZSB2YXJpYWJpbGl0eSBhbW9uZyBzdHVkZW50cyB3aXRoIG5vIGFjdGl2ZSBpbnRlcnZlbnRpb24uIEZvciByZWFkaW5nLCB0aGUgcGljdHVyZSBpcyBtb3JlIGNoYW90aWMsIHdpdGggYWxsIGZvdXIgY3VydmVzIG92ZXJsYXBwaW5nIGhlYXZpbHkgYW5kIHBlYWtzIHNjYXR0ZXJlZCBhY3Jvc3MgYSBuYXJyb3cgYmFuZCBiZXR3ZWVuIDc1IGFuZCA4NS4gVHV0b3JpbmcgcHJvZHVjZXMgYSBzaGFycCBuYXJyb3cgcGVhayB3aGlsZSBjb250cm9sIHNwcmVhZHMgYnJvYWRseSwgYnV0IG5vIGdyb3VwIGNvbnNpc3RlbnRseSBkb21pbmF0ZXMgdGhlIGhpZ2hlciBzY29yZSByYW5nZSB0aGUgd2F5IGJsZW5kZWQgZG9lcyBpbiBtYXRoLiBUaGUgb3ZlcmFsbCByZWFkaW5nIGRpc3RyaWJ1dGlvbnMgYXJlIGxhcmdlbHkgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSBvbmUgYW5vdGhlciwgZnVydGhlciBjb25maXJtaW5nIHRoYXQgaW50ZXJ2ZW50aW9uIHR5cGUgY2FycmllcyB2ZXJ5IGxpdHRsZSBzaWduYWwgZm9yIHJlYWRpbmcgb3V0Y29tZXMgd2hlbiBiYXNlbGluZSBhYmlsaXR5IGlzIG5vdCBjb250cm9sbGVkIGZvci4NCg0KIyMgQmFzZWxpbmUgU2NvcmVzIGJ5IEdyb3VwOiBBcmUgR3JvdXBzIFN0YXJ0aW5nIEVxdWFsbHk/DQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiB8Pg0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoYmFzZWxpbmVfbWF0aCwgYmFzZWxpbmVfcmVhZGluZyksIG5hbWVzX3RvID0gJ291dGNvbWUnLCB2YWx1ZXNfdG8gPSAnc2NvcmUnKSB8Pg0KICBtdXRhdGUob3V0Y29tZSA9IGNhc2Vfd2hlbigNCiAgICBvdXRjb21lID09ICdiYXNlbGluZV9tYXRoJyAgICAgfiAnQmFzZWxpbmUgTWF0aCcsDQogICAgb3V0Y29tZSA9PSAnYmFzZWxpbmVfcmVhZGluZycgIH4gJ0Jhc2VsaW5lIFJlYWRpbmcnDQogICkpIHw+DQogIGdncGxvdChhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IHNjb3JlLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsNCiAgZmFjZXRfd3JhcCh+IG91dGNvbWUsIHNjYWxlcyA9ICdmcmVlX3knKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnQmFzZWxpbmUgU2NvcmVzIGJ5IEludGVydmVudGlvbiBHcm91cCcsDQogICAgeCA9ICdJbnRlcnZlbnRpb24gVHlwZScsDQogICAgeSA9ICdTY29yZScNCiAgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykNCmBgYA0KDQpGb3IgYmFzZWxpbmUgbWF0aCwgdGhlIGJsZW5kZWQgZ3JvdXAgZW50ZXJzIHRoZSBzdHVkeSB3aXRoIGEgbm90aWNlYWJseSBoaWdoZXIgbWVkaWFuIGNvbXBhcmVkIHRvIGNvbnRyb2wsIHdoaWxlIGZsaXBwZWQgYWxzbyBzaXRzIHNsaWdodGx5IGFib3ZlIGNvbnRyb2wgYW5kIHR1dG9yaW5nLiBUaGlzIG1lYW5zIHRoZSBncm91cHMgd2VyZSBub3Qgb24gZXF1YWwgZm9vdGluZyBiZWZvcmUgdGhlIGludGVydmVudGlvbiBldmVuIGJlZ2FuLCBzbyBhbnkgcmF3IHBvc3QtdGVzdCBtYXRoIGFkdmFudGFnZSBvYnNlcnZlZCBmb3IgYmxlbmRlZCBjYW5ub3QgYmUgY29uZmlkZW50bHkgYXR0cmlidXRlZCB0byB0aGUgaW5zdHJ1Y3Rpb24gYWxvbmUuIEZvciBiYXNlbGluZSByZWFkaW5nLCB0aGUgZm91ciBncm91cHMgYXJlIGNvbnNpZGVyYWJseSBtb3JlIGNvbXBhcmFibGUsIHdpdGggYWxsIG1lZGlhbnMgc2l0dGluZyBjbG9zZSB0b2dldGhlciBhcm91bmQgNzAgYW5kIGhlYXZpbHkgb3ZlcmxhcHBpbmcgaW50ZXJxdWFydGlsZSByYW5nZXMgYWNyb3NzIGdyb3Vwcy4gVGhlIG9uZSBleGNlcHRpb24gaXMgYSBzaW5nbGUgb3V0bGllciB2aXNpYmxlIGluIHRoZSB0dXRvcmluZyBncm91cCByZWFjaGluZyBuZWFyIDEwMC4gT3ZlcmFsbCwgdGhlIGJhc2VsaW5lIG1hdGggaW1iYWxhbmNlIGlzIHRoZSBtb3JlIGNvbmNlcm5pbmcgb2YgdGhlIHR3bywgYXMgaXQgZGlyZWN0bHkgZXhwbGFpbnMgd2h5IHRoZSByYXcgcG9zdC1tYXRoIGRpZmZlcmVuY2VzIHdlIG9ic2VydmVkIGVhcmxpZXIgbmVlZCB0byBiZSB0cmVhdGVkIHdpdGggY2F1dGlvbi4gVGhpcyBjb25maXJtcyB0aGF0IHN0YXRpc3RpY2FsbHkgY29udHJvbGxpbmcgZm9yIGJhc2VsaW5lIHNjb3JlcyBpbiBBTkNPVkEgYW5kIE1BTkNPVkEgaXMgbm90IGp1c3QgYSBtZXRob2RvbG9naWNhbCBmb3JtYWxpdHkgYnV0IGEgbmVjZXNzYXJ5IGNvcnJlY3Rpb24gZ2l2ZW4gdGhlIHByZS1leGlzdGluZyBkaWZmZXJlbmNlcyBiZXR3ZWVuIGdyb3Vwcy4NCg0KIyMgU3VtbWFyeSBTdGF0aXN0aWNzIGJ5IEdyb3VwDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiB8Pg0KICBncm91cF9ieShpbnRlcnZlbnRpb24pIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuICAgICAgICAgICAgICAgICAgICA9IG4oKSwNCiAgICBtZWFuX3Bvc3RfbWF0aCAgICAgICA9IHJvdW5kKG1lYW4ocG9zdF9tYXRoKSwgMiksDQogICAgc2RfcG9zdF9tYXRoICAgICAgICAgPSByb3VuZChzZChwb3N0X21hdGgpLCAyKSwNCiAgICBtZWFuX2Jhc2VsaW5lX21hdGggICA9IHJvdW5kKG1lYW4oYmFzZWxpbmVfbWF0aCksIDIpLA0KICAgIHNkX2Jhc2VsaW5lX21hdGggICAgID0gcm91bmQoc2QoYmFzZWxpbmVfbWF0aCksIDIpLA0KICAgIG1lYW5fcG9zdF9yZWFkaW5nICAgID0gcm91bmQobWVhbihwb3N0X3JlYWRpbmcpLCAyKSwNCiAgICBzZF9wb3N0X3JlYWRpbmcgICAgICA9IHJvdW5kKHNkKHBvc3RfcmVhZGluZyksIDIpLA0KICAgIG1lYW5fYmFzZWxpbmVfcmVhZGluZyA9IHJvdW5kKG1lYW4oYmFzZWxpbmVfcmVhZGluZyksIDIpLA0KICAgIHNkX2Jhc2VsaW5lX3JlYWRpbmcgID0gcm91bmQoc2QoYmFzZWxpbmVfcmVhZGluZyksIDIpDQogICkNCmBgYA0KDQojIEFOT1ZBDQoNCiMjIFVuaXZhcmlhdGUgRWZmZWN0IG9mIEludGVydmVudGlvbg0KDQpCZWZvcmUgY29udHJvbGxpbmcgZm9yIGFueSBiYXNlbGluZSBkaWZmZXJlbmNlcywgd2UgZmlyc3QgZXhhbWluZSB3aGV0aGVyIGludGVydmVudGlvbiB0eXBlIGFsb25lIHByb2R1Y2VzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IG1lYW4gc2NvcmVzIGFjcm9zcyBncm91cHMuIFRoaXMgZXN0YWJsaXNoZXMgYSByYXcgYmFzZWxpbmUgY29tcGFyaXNvbiB0aGF0IHdpbGwgbGF0ZXIgYmUgY29udHJhc3RlZCBhZ2FpbnN0IHRoZSBjb3ZhcmlhdGUtYWRqdXN0ZWQgcmVzdWx0cyBmcm9tIEFOQ09WQS4NCg0KLSAgIEgwOiBUaGUgbWVhbiBzY29yZXMgYXJlIGVxdWFsIGFjcm9zcyBhbGwgaW50ZXJ2ZW50aW9uIGdyb3Vwcy4NCg0KPCEtLSAtLT4NCg0KLSAgIEgxOiBBdCBsZWFzdCBvbmUgZ3JvdXAgZGlmZmVyDQoNCmBgYHtyfQ0KYW5vdmFfbWF0aCA8LSBhb3YocG9zdF9tYXRoIH4gaW50ZXJ2ZW50aW9uLCBkYXRhID0gZGF0YV9jbGVhbikNCmNhdCgnLS0tIE9uZS1XYXkgQU5PVkE6IFBvc3QgTWF0aCAtLS1cbicpDQpzdW1tYXJ5KGFub3ZhX21hdGgpDQpgYGANCg0KYGBge3J9DQphbm92YV9yZWFkaW5nIDwtIGFvdihwb3N0X3JlYWRpbmcgfiBpbnRlcnZlbnRpb24sIGRhdGEgPSBkYXRhX2NsZWFuKQ0KY2F0KCctLS0gT25lLVdheSBBTk9WQTogUG9zdCBSZWFkaW5nIC0tLVxuJykNCnN1bW1hcnkoYW5vdmFfcmVhZGluZykNCmBgYA0KDQpGb3IgcG9zdC1tYXRoIHNjb3JlcywgdGhlIGludGVydmVudGlvbiBlZmZlY3QgaXMgc2lnbmlmaWNhbnQgKEYoMywgMTE2KSA9IDMuMTcsIHAgPSAuMDI3KSwgbWVhbmluZyB0aGF0IGludGVydmVudGlvbiBncm91cCBtZW1iZXJzaGlwIGlzIGFzc29jaWF0ZWQgd2l0aCBkaWZmZXJlbnQgbWF0aCBvdXRjb21lcyBldmVuIHdpdGhvdXQgYmFzZWxpbmUgYWRqdXN0bWVudC4gRm9yIHBvc3QtcmVhZGluZywgdGhlIGVmZmVjdCBpcyBub24tc2lnbmlmaWNhbnQgKEYoMywgMTE2KSA9IDAuNDQsIHAgPSAuNzIyKSwgc3VnZ2VzdGluZyB0aGF0IHJlYWRpbmcgb3V0Y29tZXMgZG8gbm90IGRpZmZlciBtZWFuaW5nZnVsbHkgYWNyb3NzIGdyb3VwcyB3aGVuIHByaW9yIGFiaWxpdHkgaXMgaWdub3JlZC4NCg0KV2UgdGhlcmVmb3JlIHJlamVjdCBIMCBmb3IgbWF0aCBidXQgZmFpbCB0byByZWplY3QgSDAgZm9yIHJlYWRpbmcuDQoNClRoaXMgYXN5bW1ldHJ5IGlzIGV4cGVjdGVkIHJhdGhlciB0aGFuIGNvbmNlcm5pbmcuIE1hdGggb3V0Y29tZXMgdGVuZCB0byBiZSBtb3JlIGltbWVkaWF0ZWx5IHJlc3BvbnNpdmUgdG8gaW5zdHJ1Y3Rpb25hbCBkaWZmZXJlbmNlcywgd2hpbGUgcmVhZGluZyBkZXZlbG9wbWVudCBpcyBzbG93ZXIgYW5kIG1vcmUgZGVwZW5kZW50IG9uIGFjY3VtdWxhdGVkIHByaW9yIGFiaWxpdHkuIENydWNpYWxseSwgbmVpdGhlciByZXN1bHQgY2FuIGJlIGZ1bGx5IHRydXN0ZWQgYXQgZmFjZSB2YWx1ZS4NCg0KU3R1ZGVudHMgZW50ZXJpbmcgZGlmZmVyZW50IGludGVydmVudGlvbiBwcm9ncmFtcyBsaWtlbHkgY2FycmllZCBkaWZmZXJlbnQgYmFzZWxpbmUgYWJpbGl0eSBsZXZlbHMgaW50byB0aGUgc3R1ZHksIG1lYW5pbmcgdGhlc2UgcmF3IGdyb3VwIGRpZmZlcmVuY2VzIG1heSByZWZsZWN0IHByZS1leGlzdGluZyBhZHZhbnRhZ2VzIHJhdGhlciB0aGFuIHRoZSB0cnVlIGVmZmVjdCBvZiB0aGUgaW5zdHJ1Y3Rpb24gaXRzZWxmLiBUaGlzIGZ1bmRhbWVudGFsIGxpbWl0YXRpb24gb2YgdW5hZGp1c3RlZCBBTk9WQSBtb3RpdmF0ZXMgdGhlIHRyYW5zaXRpb24gdG8gQU5DT1ZBLCB3aGVyZSBiYXNlbGluZSBtYXRoIGFuZCByZWFkaW5nIHNjb3JlcyBhcmUgc3RhdGlzdGljYWxseSBjb250cm9sbGVkIHRvIGlzb2xhdGUgdGhlIGludGVydmVudGlvbidzIGdlbnVpbmUgY29udHJpYnV0aW9uIHRvIGVhY2ggb3V0Y29tZSBpbmRlcGVuZGVudGx5Lg0KDQojIyBFZmZlY3QgU2l6ZQ0KDQpQYXJ0aWFsIGV0YSBzcXVhcmVkIHF1YW50aWZpZXMgaG93IG11Y2ggb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIGVhY2ggb3V0Y29tZSBpcyBleHBsYWluZWQgYnkgaW50ZXJ2ZW50aW9uIGdyb3VwIG1lbWJlcnNoaXAgYWxvbmUsIGJlZm9yZSBhbnkgYmFzZWxpbmUgYWRqdXN0bWVudCBpcyBhcHBsaWVkLg0KDQpgYGB7cn0NCmV0YXNxKGFub3ZhX21hdGgsICAgIHBhcnRpYWwgPSBUUlVFKQ0KZXRhc3EoYW5vdmFfcmVhZGluZywgcGFydGlhbCA9IFRSVUUpDQpgYGANCg0KVGhlIHBhcnRpYWwgZXRhIHNxdWFyZWQgZm9yIHBvc3QtbWF0aCBpbmRpY2F0ZXMgdGhhdCBpbnRlcnZlbnRpb24gZ3JvdXAgbWVtYmVyc2hpcCBleHBsYWlucyBhcHByb3hpbWF0ZWx5IDcuNiUgb2YgdmFyaWFuY2UgaW4gbWF0aCBzY29yZXMgYmVmb3JlIGFueSBiYXNlbGluZSBhZGp1c3RtZW50LCBhIHJhdGhlciBzbWFsbC10by1tZWRpdW0gZWZmZWN0IHRoYXQgYWxpZ25zIHdpdGggdGhlIHNpZ25pZmljYW50IG9tbmlidXMgcmVzdWx0LiBGb3IgcG9zdC1yZWFkaW5nLCDOt8KyID0gMC4wMTEsIGEgbmVnbGlnaWJsZSBlZmZlY3QgY29uc2lzdGVudCB3aXRoIHRoZSBub24tc2lnbmlmaWNhbnQgQU5PVkEuIFRoZXNlIHVuYWRqdXN0ZWQgZWZmZWN0IHNpemVzIGxpa2VseSB1bmRlcmVzdGltYXRlIHRoZSB0cnVlIGludGVydmVudGlvbiBpbXBhY3QsIHNpbmNlIGEgc3Vic3RhbnRpYWwgcG9ydGlvbiBvZiBvdXRjb21lIHZhcmlhbmNlIGlzIGRyaXZlbiBieSBzdHVkZW50cycgcHJlLWV4aXN0aW5nIGFiaWxpdHkgbGV2ZWxzIHJhdGhlciB0aGFuIHRoZSBpbnN0cnVjdGlvbiB0aGV5IHJlY2VpdmVkLiBPbmNlIGJhc2VsaW5lIHNjb3JlcyBhcmUgY29udHJvbGxlZCBpbiBBTkNPVkEsIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIHVuaXF1ZWx5IGF0dHJpYnV0YWJsZSB0byB0aGUgaW50ZXJ2ZW50aW9uIGlzIGV4cGVjdGVkIHRvIGJlY29tZSBjbGVhcmVyIGFuZCBtb3JlIHByZWNpc2UuDQoNCiMjIFBvc3QtSG9jOiBXaGljaCBncm91cCBkaWZmZXJzPw0KDQpTaW5jZSB0aGUgb21uaWJ1cyBBTk9WQSB3YXMgc2lnbmlmaWNhbnQgZm9yIHBvc3QtbWF0aCAocCA9IC4wMjcpLCBCb25mZXJyb25pLWFkanVzdGVkIHBhaXJ3aXNlIGNvbXBhcmlzb25zIGFyZSBjb25kdWN0ZWQgdG8gaWRlbnRpZnkgd2hpY2ggc3BlY2lmaWMgaW50ZXJ2ZW50aW9uIHBhaXJzIGFyZSBkcml2aW5nIHRoZSBkaWZmZXJlbmNlLiBUaGVzZSByZXN1bHRzIHNlcnZlIGFzIGNvbmZpcm1hdG9yeSBldmlkZW5jZSBvZiBncm91cCBzZXBhcmF0aW9uIGluIG1hdGggb3V0Y29tZXMuDQoNCmBgYHtyfQ0KcGFpcnMoZW1tZWFucyhhbm92YV9tYXRoLCAgICB+IGludGVydmVudGlvbiksIGFkanVzdCA9ICdib25mZXJyb25pJykNCmBgYA0KDQpgYGB7cn0NCmVtbV9tYXRoX2Fub3ZhIDwtIGFzLmRhdGEuZnJhbWUoZW1tZWFucyhhbm92YV9tYXRoLCB+IGludGVydmVudGlvbikpDQplbW1fbWF0aF9hbm92YSRvdXRjb21lIDwtICdQb3N0IE1hdGgnDQpuYW1lcyhlbW1fbWF0aF9hbm92YSlbbmFtZXMoZW1tX21hdGhfYW5vdmEpID09ICdlbW1lYW4nXSA8LSAnbWVhbicNCg0KZ2dwbG90KGVtbV9tYXRoX2Fub3ZhLCBhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IG1lYW4sIGZpbGwgPSBpbnRlcnZlbnRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCB3aWR0aCA9IDAuNikgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIuQ0wsIHltYXggPSB1cHBlci5DTCksIHdpZHRoID0gMC4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnR3JvdXAgTWVhbnMgYnkgSW50ZXJ2ZW50aW9uIChBTk9WQSknLA0KICAgIHN1YnRpdGxlID0gJ1Bvc3QgTWF0aCcsDQogICAgeCA9ICdJbnRlcnZlbnRpb24nLCB5ID0gJ01lYW4gU2NvcmUnDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpDQpgYGANCg0KRm9yIHBvc3QtbWF0aCBzY29yZXMsIHRoZSBvbmx5IHNpZ25pZmljYW50IHBhaXJ3aXNlIGNvbnRyYXN0IGFmdGVyIEJvbmZlcnJvbmkgYWRqdXN0bWVudCB3YXMgYmxlbmRlZCB2cy4gY29udHJvbCAoZGlmZmVyZW5jZSA9IDkuOTYsIHAgPSAuMDMyKSwgd2hlcmUgdGhlIGJsZW5kZWQgZ3JvdXAgc2NvcmVkIG5vdGFibHkgaGlnaGVyIHRoYW4gdGhlIGNvbnRyb2wgZ3JvdXAuIEFsbCBvdGhlciBwYWlyd2lzZSBjb21wYXJpc29ucyB3ZXJlIG5vbi1zaWduaWZpY2FudCwgc3VnZ2VzdGluZyB0aGF0IGZsaXBwZWQgYW5kIHR1dG9yaW5nIGdyb3VwcyBkaWQgbm90IGRpZmZlciBtZWFuaW5nZnVsbHkgZnJvbSBlaXRoZXIgdGhlIGNvbnRyb2wgb3IgZWFjaCBvdGhlciBhZnRlciBjb3JyZWN0aW9uLg0KDQpUaGUgYmFyIGNoYXJ0IHZpc3VhbGx5IGNvbmZpcm1zIHRoaXMgcGF0dGVybi4gQmxlbmRlZCBhbmQgZmxpcHBlZCBzaXQgdmlzaWJseSBoaWdoZXIgdGhhbiBjb250cm9sLCB3aGlsZSB0dXRvcmluZyBmYWxscyBjbG9zZXIgdG8gdGhlIG1pZGRsZSwgeWV0IG9ubHkgdGhlIGJsZW5kZWQtY29udHJvbCBnYXAgaXMgbGFyZ2UgZW5vdWdoIHRvIHN1cnZpdmUgdGhlIEJvbmZlcnJvbmkgY29ycmVjdGlvbi4gVGhlc2UgdW5hZGp1c3RlZCBncm91cCBtZWFucyBzdGlsbCByZWZsZWN0IHdoYXRldmVyIGJhc2VsaW5lIGFiaWxpdHkgZGlmZmVyZW5jZXMgZXhpc3RlZCBiZXR3ZWVuIHN0dWRlbnRzIGJlZm9yZSB0aGUgaW50ZXJ2ZW50aW9uIGJlZ2FuLCB3aGljaCBpcyBwcmVjaXNlbHkgd2h5IEFOQ09WQSBpcyBuZWVkZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhpcyBibGVuZGVkIGFkdmFudGFnZSBob2xkcyBhZnRlciBsZXZlbGluZyB0aGUgcGxheWluZyBmaWVsZC4NCg0KQWx0aG91Z2ggdGhlIG9tbmlidXMgQU5PVkEgZm9yIHBvc3QtcmVhZGluZyB3YXMgbm9uLXNpZ25pZmljYW50IChwID0gLjcyMiksIHdlIHByZXNlbnQgQm9uZmVycm9uaS1hZGp1c3RlZCBwYWlyd2lzZSBjb21wYXJpc29ucyBhcyBhbiBleHBsb3JhdG9yeSBleGVyY2lzZSB0byBleGFtaW5lIHRoZSBkaXJlY3Rpb24gb2YgZ3JvdXAgZGlmZmVyZW5jZXMuIFRoZXNlIHJlc3VsdHMgc2hvdWxkIGJlIGludGVycHJldGVkIHdpdGggY2F1dGlvbiBhbmQgYXJlIG5vdCBpbnRlbmRlZCBhcyBjb25maXJtYXRvcnkgZXZpZGVuY2UuDQoNCmBgYHtyfQ0KcGFpcnMoZW1tZWFucyhhbm92YV9yZWFkaW5nLCB+IGludGVydmVudGlvbiksIGFkanVzdCA9ICdib25mZXJyb25pJykNCmBgYA0KDQpgYGB7cn0NCmVtbV9yZWFkaW5nX2Fub3ZhIDwtIGFzLmRhdGEuZnJhbWUoZW1tZWFucyhhbm92YV9yZWFkaW5nLCB+IGludGVydmVudGlvbikpDQplbW1fcmVhZGluZ19hbm92YSRvdXRjb21lIDwtICdQb3N0IFJlYWRpbmcnDQpuYW1lcyhlbW1fcmVhZGluZ19hbm92YSlbbmFtZXMoZW1tX3JlYWRpbmdfYW5vdmEpID09ICdlbW1lYW4nXSA8LSAnbWVhbicNCg0KZ2dwbG90KGVtbV9yZWFkaW5nX2Fub3ZhLCBhZXMoeCA9IGludGVydmVudGlvbiwgeSA9IG1lYW4sIGZpbGwgPSBpbnRlcnZlbnRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCB3aWR0aCA9IDAuNikgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIuQ0wsIHltYXggPSB1cHBlci5DTCksIHdpZHRoID0gMC4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnR3JvdXAgTWVhbnMgYnkgSW50ZXJ2ZW50aW9uIChBTk9WQSknLA0KICAgIHN1YnRpdGxlID0gJ1Bvc3QgUmVhZGluZycsDQogICAgeCA9ICdJbnRlcnZlbnRpb24nLCB5ID0gJ01lYW4gU2NvcmUnDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpDQpgYGANCg0KQXMgZXhwZWN0ZWQgZnJvbSB0aGUgbm9uLXNpZ25pZmljYW50IG9tbmlidXMgcmVzdWx0LCBubyBwYWlyd2lzZSBjb21wYXJpc29uIHJlYWNoZWQgc2lnbmlmaWNhbmNlIGZvciBwb3N0LXJlYWRpbmcgc2NvcmVzLCBhbGwgcC12YWx1ZXMgd2VyZSAxLjAwMCBhZnRlciBCb25mZXJyb25pIGFkanVzdG1lbnQuIFRoZSBiYXIgY2hhcnQgdmlzdWFsbHkgZW5jb3VyYWdlcyB0aGlzLCBzaG93aW5nIGZvdXIgbmVhcmx5IGlkZW50aWNhbCBiYXIgaGVpZ2h0cyB3aXRoIGhlYXZpbHkgb3ZlcmxhcHBpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMgYWNyb3NzIGFsbCBpbnRlcnZlbnRpb24gZ3JvdXBzLiBSZWFkaW5nIG91dGNvbWVzIGFwcGVhciBlbnRpcmVseSB1bmlmb3JtIHJlZ2FyZGxlc3Mgb2Ygd2hpY2ggaW50ZXJ2ZW50aW9uIGEgc3R1ZGVudCByZWNlaXZlZCwgc3VnZ2VzdGluZyB0aGF0IGludGVydmVudGlvbiB0eXBlIGNhcnJpZXMgbm8gZGV0ZWN0YWJsZSBzaWduYWwgZm9yIHJlYWRpbmcgcGVyZm9ybWFuY2Ugd2hlbiBiYXNlbGluZSBhYmlsaXR5IGlzIG5vdCBhY2NvdW50ZWQgZm9yLiBUaGlzIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgZWFybGllciBkaXNjdXNzaW9uIHRoYXQgcmVhZGluZyBkZXZlbG9wbWVudCBpcyBzbG93ZXIgYW5kIG1vcmUgcmVzaXN0YW50IHRvIHNob3J0LXRlcm0gaW5zdHJ1Y3Rpb25hbCBkaWZmZXJlbmNlcywgYW5kIGZ1cnRoZXIgc3VwcG9ydHMgdGhlIG5lZWQgZm9yIEFOQ09WQSB0byBkZXRlcm1pbmUgd2hldGhlciBhbnkgcmVhZGluZyBzaWduYWwgZW1lcmdlcyBvbmNlIGJhc2VsaW5lIHNjb3JlcyBhcmUgcHJvcGVybHkgY29udHJvbGxlZC4NCg0KIyBBTkNPVkENCg0KTm93IHdlIG1vdmUgdG8gQU5DT1ZBLiBUaGUgZ29hbCBvZiBBTkNPVkEgaXMgdG8gYW5zd2VyIG9uZSBjcml0aWNhbCBxdWVzdGlvbjogaWYgYWxsIHN0dWRlbnRzIGhhZCBzdGFydGVkIHdpdGggdGhlIGV4YWN0IHNhbWUgYmFzZWxpbmUgc2NvcmVzLCB3b3VsZCB0aGUgaW50ZXJ2ZW50aW9uIHRoZXkgcmVjZWl2ZWQgc3RpbGwgbWFrZSBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlaXIgZmluYWwgYWNhZGVtaWMgcGVyZm9ybWFuY2U/IEJ5IHN0YXRpc3RpY2FsbHkgY29udHJvbGxpbmcgZm9yIGVhY2ggc3R1ZGVudCdzIHByaW9yIG1hdGggYW5kIHJlYWRpbmcgYWJpbGl0eSwgQU5DT1ZBIGlzb2xhdGVzIHRoZSBpbnRlcnZlbnRpb24ncyB0cnVlIGVmZmVjdCBvbiBlYWNoIG91dGNvbWUgaW5kZXBlbmRlbnRseSwgcmVtb3ZpbmcgdGhlIG5vaXNlIGNhdXNlZCBieSBwcmUtZXhpc3RpbmcgZGlmZmVyZW5jZXMgYmV0d2VlbiBzdHVkZW50cyBiZWZvcmUgdGhlIGluc3RydWN0aW9uIGV2ZW4gYmVnYW4uDQoNCiMjIENvdmFyaWF0ZS1BZGp1c3RlZCBFZmZlY3Qgb2YgSW50ZXJ2ZW50aW9uDQoNCkFOQ09WQSBleHRlbmRzIHRoZSBlYXJsaWVyIEFOT1ZBIGJ5IHN0YXRpc3RpY2FsbHkgcmVtb3ZpbmcgYmFzZWxpbmUgZGlmZmVyZW5jZXMgYmVmb3JlIGNvbXBhcmluZyBncm91cHMuIFdlIHJ1biBvbmUgbW9kZWwgcGVyIERWLCBlYWNoIGNvbnRyb2xsaW5nIGZvciBpdHMgb3duIHJlc3BlY3RpdmUgYmFzZWxpbmUgY292YXJpYXRlLg0KDQotICAgSDA6IENvbnRyb2xsaW5nIGZvciBiYXNlbGluZSBzY29yZXMsIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiBpbnRlcnZlbnRpb24gZ3JvdXBzLg0KLSAgIEgxOiBDb250cm9sbGluZyBmb3IgYmFzZWxpbmUgc2NvcmVzLCBhdCBsZWFzdCBvbmUgZ3JvdXAgZGlmZmVycyBzaWduaWZpY2FudGx5Lg0KDQpgYGB7cn0NCmFuY292YV9tYXRoIDwtIGxtKHBvc3RfbWF0aCB+IGJhc2VsaW5lX21hdGggKyBpbnRlcnZlbnRpb24sIGRhdGEgPSBkYXRhX2NsZWFuKSANCmNhdCgnLS0tIEFOQ09WQTogUG9zdCBNYXRoIC0tLVxuJykgDQpjYXI6OkFub3ZhKGFuY292YV9tYXRoLCB0eXBlID0gJ0lJSScpDQpgYGANCg0KYGBge3J9DQphbmNvdmFfcmVhZGluZyA8LSBsbShwb3N0X3JlYWRpbmcgfiBiYXNlbGluZV9yZWFkaW5nICsgaW50ZXJ2ZW50aW9uLCBkYXRhID0gZGF0YV9jbGVhbikgDQpjYXQoJy0tLSBBTkNPVkE6IFBvc3QgUmVhZGluZyAtLS1cbicpIA0KY2FyOjpBbm92YShhbmNvdmFfcmVhZGluZywgdHlwZSA9ICdJSUknKQ0KYGBgDQoNCkFmdGVyIHN0YXRpc3RpY2FsbHkgY29udHJvbGxpbmcgZm9yIHByaW9yIGFiaWxpdHksIHRoZSBBTkNPVkEgcmVzdWx0cyByZXZlYWwgYSBjbGVhciBhbmQgY29uc2lzdGVudCBwaWN0dXJlIGFjcm9zcyBib3RoIG91dGNvbWVzLg0KDQpGb3IgcG9zdC1tYXRoIHNjb3JlcywgYmFzZWxpbmUgbWF0aCBpcyBhbiBvdmVyd2hlbG1pbmdseSBzdHJvbmcgcHJlZGljdG9yIChGKDEsIDExNSkgPSA4NzEuMzEsIHAgXDwgLjAwMSksIGNvbmZpcm1pbmcgdGhhdCBwcmlvciBtYXRoIGFiaWxpdHkgZG9taW5hdGVzIHN0dWRlbnQgb3V0Y29tZXMuIENyaXRpY2FsbHksIGV2ZW4gYWZ0ZXIgcmVtb3ZpbmcgdGhpcyBiYXNlbGluZSBlZmZlY3QsIHRoZSBpbnRlcnZlbnRpb24gcmVtYWlucyBoaWdobHkgc2lnbmlmaWNhbnQgKEYoMywgMTE1KSA9IDYuMTUsIHAgXDwgLjAwMSksIG1lYW5pbmcgdGhlIHR5cGUgb2YgaW5zdHJ1Y3Rpb24gYSBzdHVkZW50IHJlY2VpdmVkIGhhZCBhIGdlbnVpbmUgaW1wYWN0IG9uIHRoZWlyIGZpbmFsIG1hdGggc2NvcmUgaW5kZXBlbmRlbnQgb2Ygd2hlcmUgdGhleSBzdGFydGVkLg0KDQpUaGUgc2FtZSBwYXR0ZXJuIGhvbGRzIGZvciBwb3N0LXJlYWRpbmcgc2NvcmVzLCB3aGVyZSBiYXNlbGluZSByZWFkaW5nIGlzIGFnYWluIHRoZSBkb21pbmFudCBwcmVkaWN0b3IgKEYoMSwgMTE1KSA9IDk2OS4zMywgcCBcPCAuMDAxKSwgeWV0IHRoZSBpbnRlcnZlbnRpb24gZWZmZWN0IHJlbWFpbnMgc2lnbmlmaWNhbnQgKEYoMywgMTE1KSA9IDMuOTksIHAgPSAuMDEwKS4NCg0KVGhlcmVmb3JlIHdlIHJlamVjdCBIMCBmb3IgYm90aCBvdXRjb21lcy4NCg0KVGhlc2UgcmVzdWx0cyBkZW1vbnN0cmF0ZSB0aGF0IGEgc3R1ZGVudCdzIHByaW9yIGFiaWxpdHkgaXMgYnkgZmFyIHRoZSBzdHJvbmdlc3QgZHJpdmVyIG9mIHRoZWlyIGZpbmFsIHNjb3JlLCBidXQgdGhlIHR5cGUgb2YgaW5zdHJ1Y3Rpb24gdGhleSByZWNlaXZlZCBzdGlsbCBjb250cmlidXRlcyBhIG1lYW5pbmdmdWwgYW5kIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRvcCBvZiB0aGF0LiBUaGlzIGFsc28gc2V0cyB1cCBhbiBpbXBvcnRhbnQgcXVlc3Rpb246IGRvIHRoZXNlIGludGVydmVudGlvbiBlZmZlY3RzIGhvbGQgd2hlbiBib3RoIG91dGNvbWVzIGFyZSBleGFtaW5lZCBzaW11bHRhbmVvdXNseSB3aGlsZSBjb250cm9sbGluZyBmb3IgYmFzZWxpbmVzIGFjcm9zcyB0aGUgYm9hcmQ/IFRoYXQgaXMgcHJlY2lzZWx5IHdoYXQgTUFOQ09WQSB3aWxsIGFkZHJlc3MuDQoNCiMjIEVmZmVjdCBTaXplDQoNCmBgYHtyfQ0KZXRhc3EoYW5jb3ZhX21hdGgsICAgIHBhcnRpYWwgPSBUUlVFKSANCmV0YXNxKGFuY292YV9yZWFkaW5nLCBwYXJ0aWFsID0gVFJVRSkNCmBgYA0KDQpUaGUgcGFydGlhbCBldGEgc3F1YXJlZCB2YWx1ZXMgcmVpbmZvcmNlIHRoZSBBTkNPVkEgZmluZGluZ3MuIEZvciBwb3N0LW1hdGgsIGJhc2VsaW5lIG1hdGggYWNjb3VudHMgZm9yIGFuIG92ZXJ3aGVsbWluZyA4OC4zJSBvZiB2YXJpYW5jZSBpbiBmaW5hbCBtYXRoIHNjb3JlcyAozrfCsiA9IDAuODgzKSwgd2hpbGUgdGhlIGludGVydmVudGlvbiBleHBsYWlucyBhbiBhZGRpdGlvbmFsIDEzLjglIGFmdGVyIHRoYXQgYmFzZWxpbmUgaXMgY29udHJvbGxlZCAozrfCsiA9IDAuMTM4KS4gRm9yIHBvc3QtcmVhZGluZywgdGhlIHBhdHRlcm4gaXMgbmVhcmx5IGlkZW50aWNhbCDigJQgYmFzZWxpbmUgcmVhZGluZyBhY2NvdW50cyBmb3IgODkuNCUgb2YgdmFyaWFuY2UgKM63wrIgPSAwLjg5NCksIHdpdGggdGhlIGludGVydmVudGlvbiBleHBsYWluaW5nIGEgZnVydGhlciA5LjQlIG9uIHRvcCAozrfCsiA9IDAuMDk0KS4gV2hpbGUgdGhlIGludGVydmVudGlvbiBlZmZlY3Qgc2l6ZXMgYXJlIG1vZGVzdCByZWxhdGl2ZSB0byB0aGUgY292YXJpYXRlLCBhIDEwLTE0JSBleHBsYWluZWQgdmFyaWFuY2UgYWZ0ZXIgYWxyZWFkeSBhY2NvdW50aW5nIGZvciBwcmlvciBhYmlsaXR5IGlzIGNvbnNpZGVyZWQgcHJhY3RpY2FsbHkgbWVhbmluZ2Z1bCBpbiBhbiBlZHVjYXRpb25hbCBjb250ZXh0LCB3aGVyZSBiYXNlbGluZSBwZXJmb3JtYW5jZSBuYXR1cmFsbHkgZG9taW5hdGVzIG91dGNvbWVzLg0KDQojIyBQb3N0LUhvYzogV2hpY2ggR3JvdXBzIERpZmZlcj8NCg0KUGFpcndpc2UgY29tcGFyaXNvbnMgdXNpbmcgYWRqdXN0ZWQgbWVhbnMuIFRoaXMgaXMgdGhlIGNvcmUgdmFsdWUgb2YgQU5DT1ZBLCBzaW5jZSBpdCBjb21wYXJlcyBncm91cHMgYXMgaWYgdGhleSBhbGwgc3RhcnRlZCBmcm9tIHRoZSBzYW1lIGJhc2VsaW5lLg0KDQpgYGB7cn0NCnBhaXJzKGVtbWVhbnMoYW5jb3ZhX21hdGgsICAgIH4gaW50ZXJ2ZW50aW9uKSwgYWRqdXN0ID0gJ2JvbmZlcnJvbmknKSANCnBhaXJzKGVtbWVhbnMoYW5jb3ZhX3JlYWRpbmcsIH4gaW50ZXJ2ZW50aW9uKSwgYWRqdXN0ID0gJ2JvbmZlcnJvbmknKQ0KYGBgDQoNCmBgYHtyfQ0KZW1tX2FuY292YV9tYXRoICAgIDwtIGFzLmRhdGEuZnJhbWUoZW1tZWFucyhhbmNvdmFfbWF0aCwgICAgfiBpbnRlcnZlbnRpb24pKQ0KZW1tX2FuY292YV9yZWFkaW5nIDwtIGFzLmRhdGEuZnJhbWUoZW1tZWFucyhhbmNvdmFfcmVhZGluZywgfiBpbnRlcnZlbnRpb24pKQ0KDQplbW1fYW5jb3ZhX21hdGgkb3V0Y29tZSAgICA8LSAnUG9zdCBNYXRoJw0KZW1tX2FuY292YV9yZWFkaW5nJG91dGNvbWUgPC0gJ1Bvc3QgUmVhZGluZycNCg0KbmFtZXMoZW1tX2FuY292YV9tYXRoKVtuYW1lcyhlbW1fYW5jb3ZhX21hdGgpICAgICAgID09ICdlbW1lYW4nXSA8LSAnYWRqX21lYW4nDQpuYW1lcyhlbW1fYW5jb3ZhX3JlYWRpbmcpW25hbWVzKGVtbV9hbmNvdmFfcmVhZGluZykgPT0gJ2VtbWVhbiddIDwtICdhZGpfbWVhbicNCg0KZW1tX2FuY292YSA8LSByYmluZChlbW1fYW5jb3ZhX21hdGgsIGVtbV9hbmNvdmFfcmVhZGluZykNCg0KZ2dwbG90KGVtbV9hbmNvdmEsIGFlcyh4ID0gaW50ZXJ2ZW50aW9uLCB5ID0gYWRqX21lYW4sIGZpbGwgPSBpbnRlcnZlbnRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCB3aWR0aCA9IDAuNikgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIuQ0wsIHltYXggPSB1cHBlci5DTCksIHdpZHRoID0gMC4yKSArDQogIGZhY2V0X3dyYXAofiBvdXRjb21lKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnQWRqdXN0ZWQgTWVhbnMgYnkgSW50ZXJ2ZW50aW9uIChBTkNPVkEpJywNCiAgICBzdWJ0aXRsZSA9ICdFYWNoIERWIGNvbnRyb2xsZWQgZm9yIGl0cyBvd24gYmFzZWxpbmUnLA0KICAgIHggPSAnSW50ZXJ2ZW50aW9uJywgeSA9ICdBZGp1c3RlZCBNZWFuIFNjb3JlJw0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKQ0KYGBgDQoNCkFmdGVyIGFkanVzdGluZyBmb3IgYmFzZWxpbmUgc2NvcmVzLCB0aGUgcGFpcndpc2UgY29tcGFyaXNvbnMgcmV2ZWFsIHNwZWNpZmljIGdyb3VwIGRpZmZlcmVuY2VzIHRoYXQgd2VyZSBub3QgdmlzaWJsZSBpbiB0aGUgcmF3IGRhdGEuIEZvciBwb3N0LW1hdGgsIHR3byBjb250cmFzdHMgcmVhY2hlZCBzaWduaWZpY2FuY2U6IGJsZW5kZWQgb3V0cGVyZm9ybWVkIGNvbnRyb2wgKGRpZmZlcmVuY2UgPSAzLjg3LCBwID0gLjAxMikgYW5kIHR1dG9yaW5nIG91dHBlcmZvcm1lZCBjb250cm9sIChkaWZmZXJlbmNlID0gNC44MSwgcCBcPCAuMDAxKSwgd2hpbGUgYWxsIG90aGVyIG1hdGggcGFpcnMgd2VyZSBub24tc2lnbmlmaWNhbnQuIEZvciBwb3N0LXJlYWRpbmcsIGJsZW5kZWQgb3V0cGVyZm9ybWVkIGNvbnRyb2wgKGRpZmZlcmVuY2UgPSAzLjAyLCBwID0gLjAzNCkgYW5kIGZsaXBwZWQgb3V0cGVyZm9ybWVkIGNvbnRyb2wgKGRpZmZlcmVuY2UgPSAzLjI5LCBwID0gLjAxNiksIHdpdGggcmVtYWluaW5nIHBhaXJzIG5vbi1zaWduaWZpY2FudC4NCg0KVGhlIGJhciBjaGFydCB2aXN1YWxseSBjb25maXJtcyB0aGlzIHBhdHRlcm4uIFRoZSBjb250cm9sIGdyb3VwIGNvbnNpc3RlbnRseSBzaXRzIGxvd2VyIHRoYW4gdGhlIGFjdGl2ZSBpbnRlcnZlbnRpb24gZ3JvdXBzIGFjcm9zcyBib3RoIG91dGNvbWVzLCB3aGlsZSBibGVuZGVkLCBmbGlwcGVkLCBhbmQgdHV0b3JpbmcgY2x1c3RlciBjbG9zZWx5IHRvZ2V0aGVyIHdpdGggaGVhdmlseSBvdmVybGFwcGluZyBjb25maWRlbmNlIGludGVydmFscy4gVGhlIHRpZ2h0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHJlZmxlY3QgdGhlIHJlZHVjZWQgZXJyb3IgdmFyaWFuY2UgYWNoaWV2ZWQgYnkgY29udHJvbGxpbmcgZm9yIGJhc2VsaW5lIHNjb3JlcywgZ2l2aW5nIHVzIGEgbW9yZSBwcmVjaXNlIGVzdGltYXRlIG9mIGVhY2ggZ3JvdXAncyB0cnVlIHBlcmZvcm1hbmNlLiBBY3Jvc3MgYm90aCBzdWJqZWN0cywgdGhlIGNvbnNpc3RlbnQgdGFrZWF3YXkgaXMgdGhhdCBhbnkgZm9ybSBvZiBhY3RpdmUgaW50ZXJ2ZW50aW9uIG91dHBlcmZvcm1zIG5vIGludGVydmVudGlvbiwgYnV0IG5vIHNpbmdsZSBpbnRlcnZlbnRpb24gbWV0aG9kIHN0YW5kcyBvdXQgYXMgc3VwZXJpb3IgdG8gdGhlIG90aGVycy4NCg0KIyMgSG9tb2dlbmVpdHkgb2YgUmVncmVzc2lvbiBTbG9wZQ0KDQpCZWZvcmUgdHJ1c3RpbmcgdGhlIEFOQ09WQSByZXN1bHRzLCB3ZSBtdXN0IHZlcmlmeSBhIGtleSBhc3N1bXB0aW9uOiBob21vZ2VuZWl0eSBvZiByZWdyZXNzaW9uIHNsb3Blcy4gVGhpcyBhc3N1bXB0aW9uIHJlcXVpcmVzIHRoYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBjb3ZhcmlhdGUgYW5kIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgaXMgY29uc2lzdGVudCBhY3Jvc3MgYWxsIGludGVydmVudGlvbiBncm91cHMuIEluIG90aGVyIHdvcmRzLCB0aGUgYmFzZWxpbmUtdG8tcG9zdC10ZXN0IHNsb3BlIHNob3VsZCBiZSByb3VnaGx5IHBhcmFsbGVsIGZvciBldmVyeSBncm91cC4gSWYgdGhlIHNsb3BlcyBkaWZmZXIgc2lnbmlmaWNhbnRseSBhY3Jvc3MgZ3JvdXBzLCBpdCBtZWFucyB0aGUgY292YXJpYXRlIGFmZmVjdHMgZWFjaCBncm91cCBkaWZmZXJlbnRseSwgYW5kIGEgc3RhbmRhcmQgQU5DT1ZBIHdvdWxkIGJlIGluYXBwcm9wcmlhdGUuDQoNCi0gICBIMDogVGhlIHJlZ3Jlc3Npb24gc2xvcGVzIGFyZSBlcXVhbCBhY3Jvc3MgYWxsIGludGVydmVudGlvbiBncm91cHMNCg0KLSAgIEgxOiBBdCBsZWFzdCBvbmUgZ3JvdXAgZGlmZmVyDQoNCmBgYHtyfQ0KYW5jb3ZhX3Nsb3BlX21hdGggPC0gbG0ocG9zdF9tYXRoIH4gYmFzZWxpbmVfbWF0aCAqIGludGVydmVudGlvbiwgZGF0YSA9IGRhdGFfY2xlYW4pDQpjYXQoIi0tLSBIb21vZ2VuZWl0eSBvZiBSZWdyZXNzaW9uIFNsb3BlczogUG9zdCBNYXRoIC0tLVxuIikNCmNhcjo6QW5vdmEoYW5jb3ZhX3Nsb3BlX21hdGgsIHR5cGUgPSAiSUlJIikNCg0KYW5jb3ZhX3Nsb3BlX3JlYWRpbmcgPC0gbG0ocG9zdF9yZWFkaW5nIH4gYmFzZWxpbmVfcmVhZGluZyAqIGludGVydmVudGlvbiwgZGF0YSA9IGRhdGFfY2xlYW4pDQpjYXQoIi0tLSBIb21vZ2VuZWl0eSBvZiBSZWdyZXNzaW9uIFNsb3BlczogUG9zdCBSZWFkaW5nIC0tLVxuIikNCmNhcjo6QW5vdmEoYW5jb3ZhX3Nsb3BlX3JlYWRpbmcsIHR5cGUgPSAiSUlJIikNCmBgYA0KDQpgYGB7cn0NCnAxIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGJhc2VsaW5lX21hdGgsIHkgPSBwb3N0X21hdGgsIGNvbG9yID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC40LCBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAxKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVncmVzc2lvbiBTbG9wZXM6IFBvc3QgTWF0aCIsDQogICAgeCA9ICJCYXNlbGluZSBNYXRoIiwNCiAgICB5ID0gIlBvc3QgTWF0aCIsDQogICAgY29sb3IgPSAiSW50ZXJ2ZW50aW9uIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnAyIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGJhc2VsaW5lX3JlYWRpbmcsIHkgPSBwb3N0X3JlYWRpbmcsIGNvbG9yID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC40LCBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAxKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVncmVzc2lvbiBTbG9wZXM6IFBvc3QgUmVhZGluZyIsDQogICAgeCA9ICJCYXNlbGluZSBSZWFkaW5nIiwNCiAgICB5ID0gIlBvc3QgUmVhZGluZyIsDQogICAgY29sb3IgPSAiSW50ZXJ2ZW50aW9uIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnAxICsgcDIgKyBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpDQpgYGANCg0KVGhlIGludGVyYWN0aW9uIHRlcm0gYmV0d2VlbiB0aGUgY292YXJpYXRlIGFuZCBpbnRlcnZlbnRpb24gZ3JvdXAgaXMgbm9uLXNpZ25pZmljYW50IGZvciBib3RoIHBvc3QtbWF0aCAoRigzLCAxMTIpID0gMC45NywgcCA9IC40MDgpIGFuZCBwb3N0LXJlYWRpbmcgKEYoMywgMTEyKSA9IDAuNjksIHAgPSAuNTYxKSwgbWVhbmluZyB3ZSBmYWlsIHRvIHJlamVjdCBIMC4gVGhpcyBjb25maXJtcyB0aGF0IHRoZSByZWdyZXNzaW9uIHNsb3BlcyBhcmUgcGFyYWxsZWwgYWNyb3NzIGFsbCBmb3VyIGludGVydmVudGlvbiBncm91cHMgZm9yIGJvdGggb3V0Y29tZXM6IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBiYXNlbGluZSBhbmQgcG9zdC10ZXN0IHNjb3JlcyBiZWhhdmVzIGNvbnNpc3RlbnRseSByZWdhcmRsZXNzIG9mIHdoaWNoIGludGVydmVudGlvbiBhIHN0dWRlbnQgcmVjZWl2ZWQuIFRoZSBhc3N1bXB0aW9uIG9mIGhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzIGlzIHRoZXJlZm9yZSBzYXRpc2ZpZWQsIGFuZCB3ZSBjYW4gcHJvY2VlZCB3aXRoIEFOQ09WQSB3aXRoIGNvbmZpZGVuY2UgdGhhdCB0aGUgY292YXJpYXRlIGFkanVzdG1lbnQgaXMgYmVpbmcgaW1wbGVtZW50ZWQgZXF1YWxseSBhbmQgZmFpcmx5IGFjcm9zcyBhbGwgZ3JvdXBzLg0KDQojIE1BTk9WQQ0KDQpUaGUgQU5DT1ZBIHN1Y2Nlc3NmdWxseSBwcm92ZWQgdGhhdCB0aGUgaW50ZXJ2ZW50aW9uIHdvcmtzIGZvciBNYXRoZW1hdGljcyB3aGVuIGNvbnRyb2xsaW5nIGZvciBwcmlvciBrbm93bGVkZ2UuIEhvd2V2ZXIsIGVkdWNhdGlvbiBpcyBtdWx0aWRpbWVuc2lvbmFsLiBEaWQgdGhlIG1hdGggdHV0b3JpbmcgaW5hZHZlcnRlbnRseSBodXJ0IHRoZWlyIHJlYWRpbmcgc2NvcmVzPyBEaWQgdGhlIGZsaXBwZWQgY2xhc3Nyb29tIGJvb3N0IGJvdGggZXF1YWxseT8NCg0KQmVjYXVzZSB3ZSB3YW50IHRvIGtub3cgdGhlIGltcGFjdCBvZiB0aGUgaW50ZXJ2ZW50aW9uIG9uIHRoZSBjb21iaW5lZCBlZHVjYXRpb25hbCBwcm9maWxlIChNYXRoIEFORCBSZWFkaW5nIHNpbXVsdGFuZW91c2x5KSB3aXRob3V0IG5lY2Vzc2FyaWx5IGNvbnRyb2xsaW5nIGZvciBiYXNlbGluZXMgaW4gZXZlcnkgc2luZ2xlIHNjZW5hcmlvLCBvdXIgbmV4dCBsb2dpY2FsIHN0ZXAgaXMgdG8gcGVyZm9ybSBhIE11bHRpdmFyaWF0ZSBBbmFseXNpcyBvZiBWYXJpYW5jZSAoTUFOT1ZBKS4NCg0KIyMgTXVsdGl2YXJpYXRlIEVmZmVjdCBvZiBJbnRlcnZlbnRpb24NCg0KVGhlIGdvYWwgaGVyZSBpcyB0byB0ZXN0IHdoZXRoZXIgaW50ZXJ2ZW50aW9uIHR5cGUgc2ltdWx0YW5lb3VzbHkgYWZmZWN0cyBwb3N0X21hdGggYW5kIHBvc3RfcmVhZGluZyB3aXRob3V0IGNvbnRyb2xsaW5nIGZvciBhbnkgYmFzZWxpbmUuIFVubGlrZSBBTkNPVkEsIG5vIGNvdmFyaWF0ZSBhZGp1c3RtZW50IGlzIG1hZGUsIHdlIGFyZSBjb21wYXJpbmcgdGhlIHJhdyBncm91cCBkaWZmZXJlbmNlcyBhY3Jvc3MgYm90aCBvdXRjb21lcyBhdCBvbmNlLg0KDQotICAgSDA6IFRoZSBtZWFuIHZlY3RvciBvZiAocG9zdF9tYXRoLCBwb3N0X3JlYWRpbmcpIGlzIGVxdWFsIGFjcm9zcyBhbGwgaW50ZXJ2ZW50aW9uIGdyb3Vwcy4NCi0gICBIMTogQXQgbGVhc3Qgb25lIGdyb3VwIGhhcyBhIGRpZmZlcmVudCBtZWFuIHZlY3Rvci4NCg0KYGBge3J9DQptYW5vdmFfbW9kZWwgPC0gbWFub3ZhKA0KICBjYmluZChwb3N0X21hdGgsIHBvc3RfcmVhZGluZykgfiBpbnRlcnZlbnRpb24sDQogIGRhdGEgPSBkYXRhX2NsZWFuDQopDQoNCmNhdCgnLS0tIE1BTk9WQTogUGlsbGFpXCdzIFRyYWNlIC0tLVxuJykNCnN1bW1hcnkobWFub3ZhX21vZGVsLCB0ZXN0ID0gJ1BpbGxhaScpDQpgYGANCg0KYGBge3J9DQpjYXQoJy0tLSBNQU5PVkE6IFdpbGtzXCcgTGFtYmRhIC0tLVxuJykNCnN1bW1hcnkobWFub3ZhX21vZGVsLCB0ZXN0ID0gJ1dpbGtzJykNCmBgYA0KDQpUaGUgTUFOT1ZBIHJldmVhbGVkIGEgbm9uLXNpZ25pZmljYW50IG11bHRpdmFyaWF0ZSBlZmZlY3Qgb2YgaW50ZXJ2ZW50aW9uIHR5cGUgb24gdGhlIGNvbWJpbmVkIG91dGNvbWUgb2YgcG9zdC10ZXN0IG1hdGggYW5kIHJlYWRpbmcgc2NvcmVzIChQaWxsYWkncyBUcmFjZSA9IDAuMDgzLCBGKDYsIDIzMikgPSAxLjY4LCBwID0gLjEyNzsgV2lsa3MnIExhbWJkYSA9IDAuOTE3LCBGKDYsIDIzMCkgPSAxLjY5LCBwID0gLjEyNCkuIEJvdGggdGVzdCBzdGF0aXN0aWNzIGFyZSBjb25zaXN0ZW50IHdpdGggZWFjaCBvdGhlciBhbmQgYm90aCBleGNlZWQgdGhlIM6xID0gMC4wNSB0aHJlc2hvbGQuIFRoZXJlZm9yZSwgd2UgZmFpbCB0byByZWplY3QgSDAsIG1lYW5pbmcgdGhhdCB3aGVuIGJhc2VsaW5lIGRpZmZlcmVuY2VzIGJldHdlZW4gc3R1ZGVudHMgYXJlIG5vdCBhY2NvdW50ZWQgZm9yLCB0aGUgaW50ZXJ2ZW50aW9uIGdyb3VwcyBkbyBub3QgYXBwZWFyIHRvIGRpZmZlciBzaWduaWZpY2FudGx5IGluIHRoZWlyIGNvbWJpbmVkIGFjYWRlbWljIG91dGNvbWVzLg0KDQpUaGlzIHJlc3VsdCBpcyBub3Qgc3VycHJpc2luZywgYXMgc3R1ZGVudHMgZW50ZXJpbmcgZGlmZmVyZW50IGludGVydmVudGlvbiBwcm9ncmFtcyBsaWtlbHkgaGFkIHZhcnlpbmcgbGV2ZWxzIG9mIHByaW9yIGtub3dsZWRnZSB0aGF0IG9ic2N1cmUgdGhlIHRydWUgZWZmZWN0IG9mIHRoZSBpbnN0cnVjdGlvbiBpdHNlbGYuIFRoaXMgbGltaXRhdGlvbiBtb3RpdmF0ZXMgdGhlIHRyYW5zaXRpb24gdG8gTUFOQ09WQSwgd2hlcmUgYmFzZWxpbmUgbWF0aCBhbmQgcmVhZGluZyBzY29yZXMgYXJlIHN0YXRpc3RpY2FsbHkgY29udHJvbGxlZCwgYWxsb3dpbmcgdXMgdG8gaXNvbGF0ZSB0aGUgaW50ZXJ2ZW50aW9uJ3MgZ2VudWluZSBjb250cmlidXRpb24gdG8gc3R1ZGVudCBvdXRjb21lcy4NCg0KIyMgQWZmZWN0ZWQgRFZzIChVbml2YXJpYXRlIEZvbGxvdy11cHMpDQoNCkFmdGVyIGNvbmZpcm1pbmcgYSBzaWduaWZpY2FudCBtdWx0aXZhcmlhdGUgZWZmZWN0LCB3ZSBicmVhayBpdCBkb3duIHRvIHNlZSB3aGljaCBpbmRpdmlkdWFsIG91dGNvbWUgKG1hdGggb3IgcmVhZGluZykgaXMgZHJpdmluZyB0aGUgcmVzdWx0Lg0KDQpgYGB7cn0NCnN1bW1hcnkuYW92KG1hbm92YV9tb2RlbCkNCmBgYA0KDQpCcmVha2luZyBkb3duIHRoZSBtdWx0aXZhcmlhdGUgcmVzdWx0IGludG8gaW5kaXZpZHVhbCBvdXRjb21lcyByZXZlYWxzIHRoYXQgdGhlIHR3byBEVnMgYmVoYXZlIGRpZmZlcmVudGx5LiBGb3IgcG9zdC1tYXRoIHNjb3JlcywgdGhlIGludGVydmVudGlvbiBlZmZlY3QgaXMgc2lnbmlmaWNhbnQgKEYoMywgMTE2KSA9IDMuMTcsIHAgPSAuMDI3KSwgbWVhbmluZyB0aGF0IGV2ZW4gd2l0aG91dCBiYXNlbGluZSBhZGp1c3RtZW50LCBpbnRlcnZlbnRpb24gZ3JvdXAgbWVtYmVyc2hpcCBpcyBhc3NvY2lhdGVkIHdpdGggZGlmZmVyZW50IG1hdGggb3V0Y29tZXMuIEZvciBwb3N0LXJlYWRpbmcgc2NvcmVzIGhvd2V2ZXIsIHRoZSBlZmZlY3QgaXMgY2xlYXJseSBub24tc2lnbmlmaWNhbnQgKEYoMywgMTE2KSA9IDAuNDQsIHAgPSAuNzIyKSwgc3VnZ2VzdGluZyB0aGF0IHJlYWRpbmcgb3V0Y29tZXMgZG8gbm90IGRpZmZlciBtZWFuaW5nZnVsbHkgYWNyb3NzIGdyb3VwcyB3aGVuIGJhc2VsaW5lIGlzIGlnbm9yZWQuDQoNClRoaXMgYXN5bW1ldHJ5IGV4cGxhaW5zIHdoeSB0aGUgb3ZlcmFsbCBNQU5PVkEgd2FzIG5vbi1zaWduaWZpY2FudC4gVGhlIHJlYWRpbmcgb3V0Y29tZSBjYXJyaWVzIG5vIGdyb3VwIHNpZ25hbCwgZGlsdXRpbmcgdGhlIGNvbWJpbmVkIG11bHRpdmFyaWF0ZSBlZmZlY3QuIEl0IGFsc28gcmVpbmZvcmNlcyB3aHkgY29udHJvbGxpbmcgZm9yIGJhc2VsaW5lIG1hdHRlcnM6IHRoZSBtYXRoIHNpZ25hbCB3ZSBzZWUgaGVyZSBtYXkgcGFydGx5IHJlZmxlY3QgcHJlLWV4aXN0aW5nIGRpZmZlcmVuY2VzIHJhdGhlciB0aGFuIHRoZSB0cnVlIGVmZmVjdCBvZiB0aGUgaW50ZXJ2ZW50aW9uLCB3aGljaCBhZ2FpbiBtb3RpdmF0ZXMgdGhlIHVzZSBvZiBNQU5DT1ZBLg0KDQojIyBFZmZlY3QgU2l6ZQ0KDQpQYXJ0aWFsIGV0YSBzcXVhcmVkIHRlbGxzIHVzIGhvdyBtdWNoIHZhcmlhbmNlIGluIHRoZSBjb21iaW5lZCBvdXRjb21lIGlzIGV4cGxhaW5lZCBieSBpbnRlcnZlbnRpb24gZ3JvdXAgbWVtYmVyc2hpcCBhbG9uZSwgYmVmb3JlIGFueSBiYXNlbGluZSBhZGp1c3RtZW50Lg0KDQpgYGB7cn0NCmV0YXNxKG1hbm92YV9tb2RlbCwgcGFydGlhbCA9IFRSVUUpDQpgYGANCg0KVGhlIHBhcnRpYWwgZXRhIHNxdWFyZWQgdmFsdWUgZm9yIGludGVydmVudGlvbiBncm91cCBtZW1iZXJzaGlwIGlzIM63wrIgPSAwLjA0MiwgaW5kaWNhdGluZyB0aGF0IGFwcHJveGltYXRlbHkgNC4yJSBvZiB0aGUgdG90YWwgdmFyaWFuY2UgaW4gdGhlIGNvbWJpbmVkIHBvc3QtdGVzdCBvdXRjb21lcyBpcyBleHBsYWluZWQgYnkgaW50ZXJ2ZW50aW9uIHR5cGUgYWxvbmUuIEJ5IGNvbnZlbnRpb25hbCBiZW5jaG1hcmtzIHRoaXMgaXMgYSBzbWFsbCBlZmZlY3Qgc2l6ZSwgd2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIHRoZSBub24tc2lnbmlmaWNhbnQgb3ZlcmFsbCBNQU5PVkEgcmVzdWx0LiBOb3RhYmx5LCB0aGlzIHVuYWRqdXN0ZWQgZmlndXJlIGxpa2VseSB1bmRlcmVzdGltYXRlcyB0aGUgdHJ1ZSBpbXBhY3Qgb2YgdGhlIGludGVydmVudGlvbiwgc2luY2UgYSBzdWJzdGFudGlhbCBwb3J0aW9uIG9mIHRoZSBvdXRjb21lIHZhcmlhbmNlIGlzIGRyaXZlbiBieSBzdHVkZW50cycgcHJlLWV4aXN0aW5nIGFiaWxpdHkgbGV2ZWxzIHJhdGhlciB0aGFuIHRoZSBpbnN0cnVjdGlvbiB0aGV5IHJlY2VpdmVkLiBUaGlzIGZ1cnRoZXIgaWxsdXN0cmF0ZXMgdGhlIHZhbHVlIG9mIE1BTkNPVkEsIGJ5IHBhcnRpYWxsaW5nIG91dCBiYXNlbGluZSBzY29yZXMsIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIHVuaXF1ZWx5IGF0dHJpYnV0YWJsZSB0byB0aGUgaW50ZXJ2ZW50aW9uIGJlY29tZXMgbXVjaCBjbGVhcmVyLg0KDQojIyBQb3N0LUhvYzogV2hpY2ggR3JvdXBzIERpZmZlcj8NCg0KQWx0aG91Z2ggdGhlIG92ZXJhbGwgTUFOT1ZBIHdhcyBub24tc2lnbmlmaWNhbnQgKHAgPSAuMTI3KSwgdGhlIHVuaXZhcmlhdGUgZm9sbG93LXVwIHJldmVhbGVkIGEgc2lnbmlmaWNhbnQgZWZmZWN0IGZvciBwb3N0LW1hdGggc2NvcmVzIHNwZWNpZmljYWxseSAocCA9IC4wMjcpLiBBcyBhbiBleHBsb3JhdG9yeSBleGVyY2lzZSwgd2UgcHJlc2VudCBCb25mZXJyb25pLWFkanVzdGVkIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHBlciBvdXRjb21lIHRvIGV4YW1pbmUgd2hpY2ggc3BlY2lmaWMgaW50ZXJ2ZW50aW9uIHBhaXJzIG1heSBiZSBkcml2aW5nIHRoZSBtYXRoIHNpZ25hbC4gVGhlc2UgcmVzdWx0cyBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgd2l0aCBjYXV0aW9uIGdpdmVuIHRoZSBub24tc2lnbmlmaWNhbnQgb21uaWJ1cyB0ZXN0LCBhbmQgYXJlIGludGVuZGVkIHRvIGlsbHVzdHJhdGUgdGhlIGRpcmVjdGlvbiBvZiBncm91cCBkaWZmZXJlbmNlcyByYXRoZXIgdGhhbiBzZXJ2ZSBhcyBjb25maXJtYXRvcnkgZXZpZGVuY2UuDQoNCmBgYHtyfQ0KcGFpcnMoZW1tZWFucyhsbShwb3N0X21hdGggICAgfiBpbnRlcnZlbnRpb24sIGRhdGEgPSBkYXRhX2NsZWFuKSwgfiBpbnRlcnZlbnRpb24pLCBhZGp1c3QgPSAnYm9uZmVycm9uaScpDQpwYWlycyhlbW1lYW5zKGxtKHBvc3RfcmVhZGluZyB+IGludGVydmVudGlvbiwgZGF0YSA9IGRhdGFfY2xlYW4pLCB+IGludGVydmVudGlvbiksIGFkanVzdCA9ICdib25mZXJyb25pJykNCmBgYA0KDQpgYGB7cn0NCmVtbV9tYXRoX21hbm92YSAgICA8LSBhcy5kYXRhLmZyYW1lKGVtbWVhbnMobG0ocG9zdF9tYXRoICAgIH4gaW50ZXJ2ZW50aW9uLCBkYXRhID0gZGF0YV9jbGVhbiksIH4gaW50ZXJ2ZW50aW9uKSkNCmVtbV9yZWFkaW5nX21hbm92YSA8LSBhcy5kYXRhLmZyYW1lKGVtbWVhbnMobG0ocG9zdF9yZWFkaW5nIH4gaW50ZXJ2ZW50aW9uLCBkYXRhID0gZGF0YV9jbGVhbiksIH4gaW50ZXJ2ZW50aW9uKSkNCg0KZW1tX21hdGhfbWFub3ZhJG91dGNvbWUgICAgPC0gJ1Bvc3QgTWF0aCcNCmVtbV9yZWFkaW5nX21hbm92YSRvdXRjb21lIDwtICdQb3N0IFJlYWRpbmcnDQoNCm5hbWVzKGVtbV9tYXRoX21hbm92YSlbbmFtZXMoZW1tX21hdGhfbWFub3ZhKSAgICAgICA9PSAnZW1tZWFuJ10gPC0gJ21lYW4nDQpuYW1lcyhlbW1fcmVhZGluZ19tYW5vdmEpW25hbWVzKGVtbV9yZWFkaW5nX21hbm92YSkgPT0gJ2VtbWVhbiddIDwtICdtZWFuJw0KDQplbW1fbWFub3ZhIDwtIHJiaW5kKGVtbV9tYXRoX21hbm92YSwgZW1tX3JlYWRpbmdfbWFub3ZhKQ0KDQpnZ3Bsb3QoZW1tX21hbm92YSwgYWVzKHggPSBpbnRlcnZlbnRpb24sIHkgPSBtZWFuLCBmaWxsID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5Jywgd2lkdGggPSAwLjYpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGxvd2VyLkNMLCB5bWF4ID0gdXBwZXIuQ0wpLCB3aWR0aCA9IDAuMikgKw0KICBmYWNldF93cmFwKH4gb3V0Y29tZSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gJ0dyb3VwIE1lYW5zIGJ5IEludGVydmVudGlvbiAoTUFOT1ZBKScsDQogICAgeCA9ICdJbnRlcnZlbnRpb24nLCB5ID0gJ01lYW4gU2NvcmUnDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpDQpgYGANCg0KRm9yIHBvc3QtbWF0aCBzY29yZXMsIHRoZSBvbmx5IHNpZ25pZmljYW50IHBhaXJ3aXNlIGRpZmZlcmVuY2Ugd2FzIGJldHdlZW4gYmxlbmRlZCBhbmQgY29udHJvbCAoZGlmZmVyZW5jZSA9IDkuOTYsIHAgPSAuMDMyKSwgd2hlcmUgdGhlIGJsZW5kZWQgZ3JvdXAgc2NvcmVkIG5vdGFibHkgaGlnaGVyLiBBbGwgb3RoZXIgbWF0aCBjb21wYXJpc29ucyB3ZXJlIG5vbi1zaWduaWZpY2FudCBhZnRlciBCb25mZXJyb25pIGFkanVzdG1lbnQsIHN1Z2dlc3RpbmcgdGhlIHJlbWFpbmluZyBpbnRlcnZlbnRpb24gcGFpcnMgcHJvZHVjZSBjb21wYXJhYmxlIG1hdGggb3V0Y29tZXMuIEZvciBwb3N0LXJlYWRpbmcgc2NvcmVzLCBubyBwYWlyd2lzZSBjb21wYXJpc29uIHJlYWNoZWQgc2lnbmlmaWNhbmNlIChhbGwgcC12YWx1ZXMgd2VyZSAxLjAwMCkgd2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIHRoZSBub24tc2lnbmlmaWNhbnQgdW5pdmFyaWF0ZSByZWFkaW5nIHJlc3VsdCBmcm9tIHRoZSBmb2xsb3ctdXAuIFZpc3VhbGx5LCB0aGUgYmFyIGNoYXJ0IGNvbmZpcm1zIHRoaXMgcGF0dGVybjogbWF0aCBzY29yZXMgc2hvdyBtb3JlIHZpc2libGUgc2VwYXJhdGlvbiBiZXR3ZWVuIGdyb3VwcywgcGFydGljdWxhcmx5IGJsZW5kZWQgdnMuIGNvbnRyb2wsIHdoaWxlIHJlYWRpbmcgc2NvcmVzIGFyZSBzdHJpa2luZ2x5IHVuaWZvcm0gYWNyb3NzIGFsbCBmb3VyIGdyb3VwcyB3aXRoIGhlYXZpbHkgb3ZlcmxhcHBpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMuDQoNCkhvd2V2ZXIsIHRoZXNlIGdyb3VwIG1lYW4gZGlmZmVyZW5jZXMgYXJlIHVuYWRqdXN0ZWQuIFRoZXkgcmVmbGVjdCB3aGF0ZXZlciBiYXNlbGluZSBhYmlsaXR5IGRpZmZlcmVuY2VzIGFscmVhZHkgZXhpc3RlZCBiZXR3ZWVuIHN0dWRlbnRzIGJlZm9yZSB0aGUgaW50ZXJ2ZW50aW9uIGJlZ2FuLiBJdCBpcyBlbnRpcmVseSBwb3NzaWJsZSB0aGF0IHRoZSBibGVuZGVkIGdyb3VwIHNpbXBseSBzdGFydGVkIHdpdGggaGlnaGVyIG1hdGggYWJpbGl0eSByYXRoZXIgdGhhbiBiZW5lZml0aW5nIG1vcmUgZnJvbSB0aGUgaW5zdHJ1Y3Rpb24uDQoNClRoaXMgaXMgdGhlIGZ1bmRhbWVudGFsIGxpbWl0YXRpb24gb2YgTUFOT1ZBLCBhbmQgcHJlY2lzZWx5IHdoeSB3ZSBwcm9jZWVkIHRvIE1BTkNPVkEuIEJ5IHN0YXRpc3RpY2FsbHkgY29udHJvbGxpbmcgZm9yIGVhY2ggc3R1ZGVudCdzIGJhc2VsaW5lIG1hdGggYW5kIHJlYWRpbmcgc2NvcmVzLCB3ZSBjYW4gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlc2UgZ3JvdXAgZGlmZmVyZW5jZXMgaG9sZCB1cCBhZnRlciBsZXZlbGluZyB0aGUgcGxheWluZyBmaWVsZC4NCg0KIyBNQU5DT1ZBDQoNCk1BTkNPVkEgYW5kIE1BTk9WQSBpcyB0aGUgc2FtZSBtZXRob2QgdGhhdCBhbnN3ZXIgYSBxdWVzdGlvbiBhYm91dCAiaG93IGRvIHRoZSBncm91cHMgc2NvcmUgZGlmZmVyZW50bHkgYWNyb3NzIG11bHRpcGxlIG91dGNvbWVzPyIgVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCBNQU5DT1ZBIGFkanVzdHMgZm9yIGVhY2ggc3R1ZGVudCBzdGFydGVkIGJlZm9yZSBjb21wYXJpbmcgZ3JvdXBzLiAqKldpdGhvdXQgdGhhdCBhZGp1c3RtZW50LCB0aGVyZSBpcyByaXNrIGdpdmluZyB0aGUgaW50ZXJ2ZW50aW9uIGNyZWRpdCBmb3Igc2NvcmUgZGlmZmVyZW5jZXMgdGhhdCBhbHJlYWR5IGV4aXN0ZWQgYmVmb3JlIGl0IGV2ZW4gYmVnYW4uKioNCg0KIyMgTXVsdGl2YXJpYXRlIEVmZmVjdCBvZiBJbnRlcnZlbnRpb24NCg0KYGBge3J9DQpkdl9tYXRyaXggPC0gY2JpbmQoZGF0YV9jbGVhbiRwb3N0X21hdGgsIGRhdGFfY2xlYW4kcG9zdF9yZWFkaW5nKQ0KDQptYW5jb3ZhX21vZGVsIDwtIG1hbm92YSgNCiAgZHZfbWF0cml4IH4gYmFzZWxpbmVfbWF0aCArIGJhc2VsaW5lX3JlYWRpbmcgKyBpbnRlcnZlbnRpb24sDQogIGRhdGEgPSBkYXRhX2NsZWFuDQopDQoNCiMgU3VtbWFyeSB1c2luZyBQaWxsYWkncyBUcmFjZSAobW9zdCByb2J1c3QpDQpzdW1tYXJ5KG1hbmNvdmFfbW9kZWwsIHRlc3QgPSAiUGlsbGFpIikNCg0KIyBjaGVjayBXaWxrcycgTGFtYmRhIGZvciBjb21wYXJpc29uDQpzdW1tYXJ5KG1hbmNvdmFfbW9kZWwsIHRlc3QgPSAiV2lsa3MiKQ0KYGBgDQoNCkFmdGVyIGNvbnRyb2xsaW5nIGZvciBiYXNlbGluZSBtYXRoIGFuZCByZWFkaW5nIHNjb3JlcywgdGhlIE1BTkNPVkEgcmV2ZWFsZWQgYSBzaWduaWZpY2FudCBtdWx0aXZhcmlhdGUgZWZmZWN0IG9mIGludGVydmVudGlvbiB0eXBlIG9uIHRoZSBjb21iaW5lZCBvdXRjb21lIG9mIHBvc3QtdGVzdCBtYXRoIGFuZCByZWFkaW5nIHNjb3JlcyAoUGlsbGFpJ3MgVHJhY2UgPSAwLjIzOSwgRig2LCAyMjgpID0gNS4xNiwgcCBcPCAuMDAxOyBXaWxrcycgTGFtYmRhID0gMC43NzEsIEYoNiwgMjI2KSA9IDUuMjIsIHAgXDwgLjAwMSkuIEJvdGggY292YXJpYXRlcyBhbHNvIHNob3dlZCBzaWduaWZpY2FudCBtdWx0aXZhcmlhdGUgZWZmZWN0cywgY29uZmlybWluZyB0aGF0IHByaW9yIHNjb3JlcyBzdHJvbmdseSBwcmVkaWN0ZWQgcG9zdC10ZXN0IHBlcmZvcm1hbmNlLg0KDQpUaGVzZSByZXN1bHRzIGluZGljYXRlIHRoYXQgc3R1ZGVudHMgaW4gZGlmZmVyZW50IGludGVydmVudGlvbiBncm91cHMgcGVyZm9ybWVkIGRpZmZlcmVudGx5IG92ZXJhbGwsIGV2ZW4gYWZ0ZXIgYWNjb3VudGluZyBmb3Igd2hlcmUgdGhleSBzdGFydGVkLiBUaGUgc2lnbmlmaWNhbmNlIG9mIGJvdGggdGVzdCBzdGF0aXN0aWNzIGFkZHMgY29uZmlkZW5jZSB0byB0aGlzIGNvbmNsdXNpb24uDQoNCiMjIEFmZmVjdGVkIERWcyAoVW5pdmFyaWF0ZSBGb2xsb3ctdXBzKQ0KDQpgYGB7cn0NCnN1bW1hcnkuYW92KG1hbmNvdmFfbW9kZWwpDQpgYGANCg0KVW5pdmFyaWF0ZSBmb2xsb3ctdXAgdGVzdHMgc2hvd2VkIHRoYXQgdGhlIGludGVydmVudGlvbiBlZmZlY3Qgd2FzIHNpZ25pZmljYW50IGZvciBib3RoIHBvc3QtdGVzdCBtYXRoIChGKDMsIDExNCkgPSA2Ljc5LCBwIFw8IC4wMDEpIGFuZCBwb3N0LXRlc3QgcmVhZGluZyAoRigzLCAxMTQpID0gNC4xNCwgcCA9IC4wMDgpLiBCYXNlbGluZSBtYXRoIHdhcyB0aGUgZG9taW5hbnQgcHJlZGljdG9yIG9mIHBvc3QtbWF0aCBzY29yZXMsIHdoaWxlIGJhc2VsaW5lIHJlYWRpbmcgd2FzIHRoZSBkb21pbmFudCBwcmVkaWN0b3Igb2YgcG9zdC1yZWFkaW5nIHNjb3JlcywgZWFjaCBleHBsYWluaW5nIHRoZSB2YXN0IG1ham9yaXR5IG9mIHZhcmlhbmNlIGluIHRoZWlyIHJlc3BlY3RpdmUgb3V0Y29tZXMuDQoNClRoaXMgbWVhbnMgdGhlIGludGVydmVudGlvbiBkaWQgbm90IGp1c3QgYWZmZWN0IG9uZSBzdWJqZWN0IGFyZWEuIEJvdGggbWF0aCBhbmQgcmVhZGluZyBvdXRjb21lcyBkaWZmZXJlZCBhY3Jvc3MgZ3JvdXBzLCBzdWdnZXN0aW5nIHRoZSB0eXBlIG9mIGluc3RydWN0aW9uIGhhZCBhIGJyb2FkIGFjYWRlbWljIGltcGFjdCByYXRoZXIgdGhhbiBhIG5hcnJvdyBvbmUuDQoNCiMjIEVmZmVjdCBTaXplDQoNCmBgYHtyfQ0KZXRhc3EobWFuY292YV9tb2RlbCwgcGFydGlhbCA9IFRSVUUpDQpgYGANCg0KUGFydGlhbCBldGEgc3F1YXJlZCB2YWx1ZXMgaW5kaWNhdGVkIHRoYXQgdGhlIGNvdmFyaWF0ZXMgYWNjb3VudGVkIGZvciBhIGxhcmdlIHByb3BvcnRpb24gb2YgdmFyaWFuY2U6IGJhc2VsaW5lIG1hdGggZXhwbGFpbmVkIDg4LjElIG9mIHZhcmlhbmNlIGluIHRoZSBvdXRjb21lcywgYW5kIGJhc2VsaW5lIHJlYWRpbmcgZXhwbGFpbmVkIDg5LjIlLiBUaGUgaW50ZXJ2ZW50aW9uIGl0c2VsZiBleHBsYWluZWQgYSBzbWFsbGVyIGJ1dCBwcmFjdGljYWxseSBtZWFuaW5nZnVsIDExLjklIG9mIHZhcmlhbmNlIGFmdGVyIGNvbnRyb2xsaW5nIGZvciBiYXNlbGluZSBzY29yZXMuDQoNCldoaWxlIHRoZSBpbnRlcnZlbnRpb24gZWZmZWN0IHNpemUgaXMgbW9kZXN0IGNvbXBhcmVkIHRvIHRoZSBjb3ZhcmlhdGVzLCBhIHJvdWdobHkgMTIlIGV4cGxhaW5lZCB2YXJpYW5jZSBpbiBhbiBlZHVjYXRpb25hbCBzZXR0aW5nIGlzIGNvbnNpZGVyZWQgbWVhbmluZ2Z1bCwgcGFydGljdWxhcmx5IGdpdmVuIHRoYXQgcHJpb3IgYWNoaWV2ZW1lbnQgYWxyZWFkeSBkb21pbmF0ZXMgc3R1ZGVudCBvdXRjb21lcy4NCg0KIyMgUG9zdC1Ib2M6IFdoaWNoIEdyb3VwcyBEaWZmZXI/DQoNCmBgYHtyfQ0KIyBBZGp1c3RlZCBtZWFucyBmb3IgcG9zdF9tYXRoDQplbW1fbWF0aCA8LSBlbW1lYW5zKA0KICBsbShwb3N0X21hdGggfiBiYXNlbGluZV9tYXRoICsgYmFzZWxpbmVfcmVhZGluZyArIGludGVydmVudGlvbiwgZGF0YSA9IGRhdGFfY2xlYW4pLA0KICB+IGludGVydmVudGlvbg0KKQ0KcGFpcnMoZW1tX21hdGgsIGFkanVzdCA9ICJib25mZXJyb25pIikNCg0KIyBBZGp1c3RlZCBtZWFucyBmb3IgcG9zdF9yZWFkaW5nDQplbW1fcmVhZGluZyA8LSBlbW1lYW5zKA0KICBsbShwb3N0X3JlYWRpbmcgfiBiYXNlbGluZV9tYXRoICsgYmFzZWxpbmVfcmVhZGluZyArIGludGVydmVudGlvbiwgZGF0YSA9IGRhdGFfY2xlYW4pLA0KICB+IGludGVydmVudGlvbg0KKQ0KcGFpcnMoZW1tX3JlYWRpbmcsIGFkanVzdCA9ICJib25mZXJyb25pIikNCmBgYA0KDQpgYGB7cn0NCiMgRml0IHVuaXZhcmlhdGUgbW9kZWxzDQptb2RlbF9tYXRoICAgIDwtIGxtKHBvc3RfbWF0aCAgICB+IGJhc2VsaW5lX21hdGggKyBiYXNlbGluZV9yZWFkaW5nICsgaW50ZXJ2ZW50aW9uLCBkYXRhID0gZGF0YV9jbGVhbikNCm1vZGVsX3JlYWRpbmcgPC0gbG0ocG9zdF9yZWFkaW5nIH4gYmFzZWxpbmVfbWF0aCArIGJhc2VsaW5lX3JlYWRpbmcgKyBpbnRlcnZlbnRpb24sIGRhdGEgPSBkYXRhX2NsZWFuKQ0KDQojIEV4dHJhY3QgYWRqdXN0ZWQgbWVhbnMNCmVtbV9tYXRoICAgIDwtIGFzLmRhdGEuZnJhbWUoZW1tZWFucyhtb2RlbF9tYXRoLCAgICB+IGludGVydmVudGlvbikpDQplbW1fcmVhZGluZyA8LSBhcy5kYXRhLmZyYW1lKGVtbWVhbnMobW9kZWxfcmVhZGluZywgfiBpbnRlcnZlbnRpb24pKQ0KDQplbW1fbWF0aCRvdXRjb21lICAgIDwtICJQb3N0IE1hdGgiDQplbW1fcmVhZGluZyRvdXRjb21lIDwtICJQb3N0IFJlYWRpbmciDQoNCiMgUmVuYW1lIGVtbWVhbiBjb2x1bW4gdG8gJ2FkanVzdGVkX21lYW4nDQpuYW1lcyhlbW1fbWF0aClbbmFtZXMoZW1tX21hdGgpICAgICAgID09ICJlbW1lYW4iXSA8LSAiYWRqdXN0ZWRfbWVhbiINCm5hbWVzKGVtbV9yZWFkaW5nKVtuYW1lcyhlbW1fcmVhZGluZykgPT0gImVtbWVhbiJdIDwtICJhZGp1c3RlZF9tZWFuIg0KDQplbW1fY29tYmluZWQgPC0gcmJpbmQoZW1tX21hdGgsIGVtbV9yZWFkaW5nKQ0KDQojIFBsb3QNCmdncGxvdChlbW1fY29tYmluZWQsIGFlcyh4ID0gaW50ZXJ2ZW50aW9uLCB5ID0gYWRqdXN0ZWRfbWVhbiwgZmlsbCA9IGludGVydmVudGlvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjYpICsNCiAgZ2VvbV9lcnJvcmJhcigNCiAgICBhZXMoeW1pbiA9IGxvd2VyLkNMLCB5bWF4ID0gdXBwZXIuQ0wpLA0KICAgIHdpZHRoID0gMC4yDQogICkgKw0KICBmYWNldF93cmFwKH4gb3V0Y29tZSkgKw0KICBsYWJzKA0KICAgIHRpdGxlICAgID0gIkFkanVzdGVkIE1lYW5zIGJ5IEludGVydmVudGlvbiBHcm91cCIsDQogICAgc3VidGl0bGUgPSAiQ29udHJvbGxpbmcgZm9yIGJhc2VsaW5lIG1hdGggYW5kIHJlYWRpbmcgc2NvcmVzIiwNCiAgICB4ICAgICAgICA9ICJJbnRlcnZlbnRpb24iLA0KICAgIHkgICAgICAgID0gIkFkanVzdGVkIE1lYW4gU2NvcmUiLA0KICAgIGZpbGwgICAgID0gIkludGVydmVudGlvbiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpCb25mZXJyb25pLWFkanVzdGVkIHBhaXJ3aXNlIGNvbXBhcmlzb25zIGZvciBwb3N0LW1hdGggc2NvcmVzIHNob3dlZCB0aGF0IHRoZSBibGVuZGVkIGdyb3VwIHNjb3JlZCBzaWduaWZpY2FudGx5IGhpZ2hlciB0aGFuIHRoZSBjb250cm9sIGdyb3VwIChkaWZmZXJlbmNlID0gNC4xMSwgcCA9IC4wMDUpLCBhbmQgdHV0b3Jpbmcgc2NvcmVkIHNpZ25pZmljYW50bHkgaGlnaGVyIHRoYW4gY29udHJvbCAoZGlmZmVyZW5jZSA9IDQuOTMsIHAgXDwgLjAwMSkuIEZvciBwb3N0LXJlYWRpbmcsIGJsZW5kZWQgb3V0cGVyZm9ybWVkIGNvbnRyb2wgKGRpZmZlcmVuY2UgPSAzLjE2LCBwID0gLjAyNyksIGFuZCBmbGlwcGVkIG91dHBlcmZvcm1lZCBjb250cm9sIChkaWZmZXJlbmNlID0gMy40MCwgcCA9IC4wMTMpLg0KDQpBY3Jvc3MgYm90aCBvdXRjb21lcywgdGhlIGNvbnRyb2wgZ3JvdXAgY29uc2lzdGVudGx5IHNjb3JlZCBsb3dlciB0aGFuIHRoZSBhY3RpdmUgaW50ZXJ2ZW50aW9uIGdyb3Vwcy4gTm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgZW1lcmdlZCBiZXR3ZWVuIGJsZW5kZWQsIGZsaXBwZWQsIGFuZCB0dXRvcmluZyBncm91cHMsIHN1Z2dlc3RpbmcgdGhlc2UgdGhyZWUgYXBwcm9hY2hlcyBwcm9kdWNlZCBjb21wYXJhYmxlIHJlc3VsdHMgcmVsYXRpdmUgdG8gb25lIGFub3RoZXIuDQoNCiMjIEhvbW9nZW5laXR5IG9mIFJlZ3Jlc3Npb24gU2xvcGVzDQoNCmBgYHtyfQ0KbWFuY292YV9pbnRlcmFjdGlvbl90ZXN0IDwtIG1hbm92YSgNCiAgZHZfbWF0cml4IH4gYmFzZWxpbmVfbWF0aCAqIGludGVydmVudGlvbiArIGJhc2VsaW5lX3JlYWRpbmcgKiBpbnRlcnZlbnRpb24sDQogIGRhdGEgPSBkYXRhX2NsZWFuDQopDQpzdW1tYXJ5KG1hbmNvdmFfaW50ZXJhY3Rpb25fdGVzdCwgdGVzdCA9ICJQaWxsYWkiKQ0KYGBgDQoNCmBgYHtyfQ0KDQojIE1hdGgNCnAxIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGJhc2VsaW5lX21hdGgsIHkgPSBwb3N0X21hdGgsIGNvbG9yID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC40LCBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAxKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVncmVzc2lvbiBTbG9wZXM6IE1hdGgiLA0KICAgIHggPSAiQmFzZWxpbmUgTWF0aCIsDQogICAgeSA9ICJQb3N0IE1hdGgiLA0KICAgIGNvbG9yID0gIkludGVydmVudGlvbiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIFJlYWRpbmcNCnAyIDwtIGdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGJhc2VsaW5lX3JlYWRpbmcsIHkgPSBwb3N0X3JlYWRpbmcsIGNvbG9yID0gaW50ZXJ2ZW50aW9uKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC40LCBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAxKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVncmVzc2lvbiBTbG9wZXM6IFJlYWRpbmciLA0KICAgIHggPSAiQmFzZWxpbmUgUmVhZGluZyIsDQogICAgeSA9ICJQb3N0IFJlYWRpbmciLA0KICAgIGNvbG9yID0gIkludGVydmVudGlvbiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpwMSArIHAyICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKQ0KYGBgDQoNClRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIGVhY2ggY292YXJpYXRlIGFuZCBpbnRlcnZlbnRpb24gZ3JvdXAgd2FzIG5vbi1zaWduaWZpY2FudCBmb3IgYm90aCBiYXNlbGluZSBtYXRoIChQaWxsYWkgPSAwLjA5NSwgRig2LCAyMTYpID0gMS43OSwgcCA9IC4xMDMpIGFuZCBiYXNlbGluZSByZWFkaW5nIChQaWxsYWkgPSAwLjAzOCwgRig2LCAyMTYpID0gMC43MCwgcCA9IC42NDkpLiBUaGlzIGNvbmZpcm1zIHRoYXQgdGhlIGFzc3VtcHRpb24gb2YgaG9tb2dlbmVpdHkgb2YgcmVncmVzc2lvbiBzbG9wZXMgd2FzIG1ldCwgbWVhbmluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYmFzZWxpbmUgYW5kIHBvc3QtdGVzdCBzY29yZXMgd2FzIGNvbnNpc3RlbnQgYWNyb3NzIGFsbCBmb3VyIGludGVydmVudGlvbiBncm91cHMuDQoNClRoZSByZWdyZXNzaW9uIHNsb3BlIHBsb3RzIHZpc3VhbGx5IHN1cHBvcnQgdGhpcyBmaW5kaW5nLiBMaW5lcyBhY3Jvc3MgYWxsIGZvdXIgZ3JvdXBzIHJ1biByb3VnaGx5IHBhcmFsbGVsIGZvciBib3RoIG1hdGggYW5kIHJlYWRpbmcsIHdpdGggbm8gbWVhbmluZ2Z1bCBjcm9zc2luZyBvciBmYW5uaW5nLCB3aGljaCB2YWxpZGF0ZXMgdGhlIHVzZSBvZiBNQU5DT1ZBIGZvciB0aGlzIGRhdGFzZXQuDQoNCiMgR3JhbmQgQ29uY2x1c2lvbg0KDQpBTk9WQSBpbml0aWFsbHkgc3VnZ2VzdGVkIHRoYXQgTWF0aCBzY29yZXMgZGlmZmVyZWQgc2lnbmlmaWNhbnRseSBhY3Jvc3MgaW50ZXJ2ZW50aW9uIGdyb3VwcyB3aGlsZSBSZWFkaW5nIHNob3dlZCBubyBlZmZlY3QsIGJ1dCB0aGlzIHdhcyBtaXNsZWFkaW5nIGJlY2F1c2UgZ3JvdXBzIHN0YXJ0ZWQgd2l0aCB1bmVxdWFsIGJhc2VsaW5lcywgcGFydGljdWxhcmx5IHdpdGggdGhlIGJsZW5kZWQgZ3JvdXAgaGF2aW5nIGhpZ2hlciBpbml0aWFsIE1hdGggc2NvcmVzLiBBTkNPVkEgYWRkcmVzc2VkIHRoaXMgYnkgY29udHJvbGxpbmcgZm9yIHByaW9yIGFiaWxpdHksIHJldmVhbGluZyBzaWduaWZpY2FudCBpbnRlcnZlbnRpb24gZWZmZWN0cyBpbiBib3RoIE1hdGggKEYoMywxMTUpPTYuMTUsIHBcPC4wMDEsIM63wrI9LjEzOCkgYW5kIFJlYWRpbmcgKEYoMywxMTUpPTMuOTksIHA9LjAxMCwgzrfCsj0uMDk0KSwgd2l0aCBibGVuZGVkIGFuZCB0dXRvcmluZyBvdXRwZXJmb3JtaW5nIGNvbnRyb2wgaW4gTWF0aCwgYW5kIGJsZW5kZWQgYW5kIGZsaXBwZWQgb3V0cGVyZm9ybWluZyBjb250cm9sIGluIFJlYWRpbmcsIHRob3VnaCBubyBpbnRlcnZlbnRpb24gd2FzIHN1cGVyaW9yIHRvIGFub3RoZXIuDQoNCkluIGNvbnRyYXN0LCBNQU5PVkEgd2l0aG91dCBjb3ZhcmlhdGUgYWRqdXN0bWVudCBmb3VuZCBubyBzaWduaWZpY2FudCBtdWx0aXZhcmlhdGUgZWZmZWN0IChQaWxsYWk9LjA4MywgcD0uMTI3KSwgaGlnaGxpZ2h0aW5nIGhvdyBiYXNlbGluZSBkaWZmZXJlbmNlcyBjYW4gb2JzY3VyZSByZXN1bHRzLiBGaW5hbGx5LCBNQU5DT1ZBLCB3aGljaCBjb250cm9sbGVkIGZvciBib3RoIGJhc2VsaW5lIE1hdGggYW5kIFJlYWRpbmcsIHNob3dlZCBhIHN0cm9uZyBtdWx0aXZhcmlhdGUgaW50ZXJ2ZW50aW9uIGVmZmVjdCAoUGlsbGFpPS4yMzksIEYoNiwyMjgpPTUuMTYsIHBcPC4wMDEpLCBjb25maXJtaW5nIHRoYXQgdGhlIGludGVydmVudGlvbiBzaWduaWZpY2FudGx5IGltcHJvdmVkIGJvdGggb3V0Y29tZXMsIHdpdGggYXNzdW1wdGlvbnMgc3VjaCBhcyBob21vZ2VuZWl0eSBvZiByZWdyZXNzaW9uIHNsb3BlcyBzYXRpc2ZpZWQuDQoNClRoZSBmaW5hbCBwaWN0dXJlIGlzIHRoaXM6IHByaW9yIGFjYWRlbWljIGFiaWxpdHkgaXMgYnkgZmFyIHRoZSBzdHJvbmdlc3QgZGV0ZXJtaW5hbnQgb2Ygc3R1ZGVudCBvdXRjb21lcywgYWNjb3VudGluZyBmb3Igcm91Z2hseSA4OCB0byA4OSBwZXJjZW50IG9mIHZhcmlhbmNlIGluIGVhY2ggc3ViamVjdC4gWWV0IGV2ZW4gYWZ0ZXIgdGhhdCBkb21pbmFudCBpbmZsdWVuY2UgaXMgcmVtb3ZlZCwgdGhlIHR5cGUgb2YgaW5zdHJ1Y3Rpb24gYSBzdHVkZW50IHJlY2VpdmVkIHN0aWxsIGV4cGxhaW5zIGFuIGFkZGl0aW9uYWwgMTIgcGVyY2VudCBvZiB2YXJpYW5jZSBpbiB0aGVpciBjb21iaW5lZCBhY2FkZW1pYyBwZXJmb3JtYW5jZS4gQWNyb3NzIGJvdGggc3ViamVjdHMgYW5kIGFjcm9zcyBldmVyeSBhbmFseXRpYyBmcmFtZXdvcmsgdGhhdCBjb250cm9sbGVkIGZvciBiYXNlbGluZSwgdGhlIGNvbnRyb2wgZ3JvdXAgY29uc2lzdGVudGx5IGZpbmlzaGVkIGJlbG93IGV2ZXJ5IGFjdGl2ZSBpbnRlcnZlbnRpb24gY29uZGl0aW9uLiBCbGVuZGVkIGxlYXJuaW5nIGluIHBhcnRpY3VsYXIgc2hvd2VkIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYWR2YW50YWdlcyBvdmVyIGNvbnRyb2wgaW4gYm90aCBNYXRoIGFuZCBSZWFkaW5nLCBtYWtpbmcgaXQgdGhlIG1vc3QgY29uc2lzdGVudGx5IGVmZmVjdGl2ZSBtZXRob2QgaW4gdGhpcyBkYXRhc2V0LCB0aG91Z2ggdHV0b3JpbmcgYW5kIGZsaXBwZWQgY2xhc3Nyb29tIHdlcmUgY29tcGV0aXRpdmUgYWNyb3NzIHNwZWNpZmljIG91dGNvbWVzIGFzIHdlbGwuDQoNClRvIGNvbmNsdWRlLCB0aGUgZWR1Y2F0aW9uYWwgaW50ZXJ2ZW50aW9uIHdvcmtlZC4gSXQgd29ya2VkIGFmdGVyIGxldmVsaW5nIGZvciBwcmlvciBhYmlsaXR5LCBpdCB3b3JrZWQgYWNyb3NzIG11bHRpcGxlIG91dGNvbWVzIHNpbXVsdGFuZW91c2x5LCBhbmQgaXQgd29ya2VkIGFjY29yZGluZyB0byBldmVyeSBzdGF0aXN0aWNhbCBmcmFtZXdvcmsgZGVzaWduZWQgdG8gaXNvbGF0ZSBpdHMgdHJ1ZSBjb250cmlidXRpb24gZnJvbSBwcmUtZXhpc3Rpbmcgc3R1ZGVudCBkaWZmZXJlbmNlcy4gVGhlIHJlY29tbWVuZGF0aW9uIHRoYXQgZm9sbG93cyBmcm9tIHRoaXMgYW5hbHlzaXMgaXMgc3RyYWlnaHRmb3J3YXJkOiBwYXNzaXZlIGNvbnRyb2wgY29uZGl0aW9ucyBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aCBhY3RpdmUgaW5zdHJ1Y3Rpb25hbCBtZXRob2RzLCBhbmQgZnV0dXJlIHN0dWRpZXMgc2hvdWxkIHByaW9yaXRpemUgYmFzZWxpbmUtYWRqdXN0ZWQgZGVzaWducyBmcm9tIHRoZSBvdXRzZXQgdG8gYXZvaWQgc3lzdGVtYXRpY2FsbHkgdW5kZXJlc3RpbWF0aW5nIHRoZSBlZmZlY3Qgb2YgaW5zdHJ1Y3Rpb24uDQo=