1 Rationale

Exploratory data analysis is important for understanding your data, checking for data issues/errors, and checking assumptions for different statistical models.

LOOK AT YOUR DATA—this is one of the most overlooked steps in data analysis!

2 Preamble

2.1 Install Libraries

#install.packages("remotes")
#remotes::install_github("DevPsyLab/petersenlab")

2.2 Load Libraries

library("petersenlab")
library("car")
library("vioplot")
library("ellipse")
library("nlme")
library("effects")
library("corrplot")
library("ggplot2")
library("psych")
library("tidyverse")
library("purrr")
library("naniar")
library("mvnormtest")
library("ggExtra")
library("XICOR")

3 Simulate Data

set.seed(52242)

n <- 1000

ID <- rep(1:100, each = 10)
predictor <- rbeta(n, 1.5, 5) * 100
outcome <- predictor + rnorm(n, mean = 0, sd = 20) + 50

predictorOverplot <- sample(1:50, n, replace = TRUE)
outcomeOverplot <- predictorOverplot + sample(1:75, n, replace = TRUE)

categorical1 <- sample(1:5, size = n, replace = TRUE)
categorical2 <- sample(1:5, size = n, replace = TRUE)

mydata <- data.frame(
  ID = ID,
  predictor = predictor,
  outcome = outcome,
  predictorOverplot = predictorOverplot,
  outcomeOverplot = outcomeOverplot,
  categorical1 = categorical1,
  categorical2 = categorical2)

mydata[sample(1:n, size = 10), "predictor"] <- NA
mydata[sample(1:n, size = 10), "outcome"] <- NA
mydata[sample(1:n, size = 10), "predictorOverplot"] <- NA
mydata[sample(1:n, size = 10), "outcomeOverplot"] <- NA
mydata[sample(1:n, size = 30), "categorical1"] <- NA
mydata[sample(1:n, size = 70), "categorical2"] <- NA

4 Descriptive statistics

round(data.frame(psych::describe(mydata)), 2)

4.1 Sample

  • Check the sample size (N)
    • Is the sample size in the data the expected sample size? Are there cases (participants) that are missing? Are there cases that should not be there?
    • Here is the sample size:
length(unique(mydata$ID))
[1] 100
  • Check the extent of missingness
    • How much data are missing in the model variables—including the predictor, outcome, and covariates?
    • Here are the proportion of missing data in each variable:
map(mydata, ~mean(is.na(.))) %>% t %>% t
                  [,1]
ID                0   
predictor         0.01
outcome           0.01
predictorOverplot 0.01
outcomeOverplot   0.01
categorical1      0.03
categorical2      0.07

4.2 Distribution

  • Frequencies
    • Examine the frequencies of categorical variables:
mydata %>% 
  select(categorical1, categorical2) %>%
  sapply(function(x) table(x, useNA = "always")) %>% 
  t()
               1   2   3   4   5 <NA>
categorical1 196 204 191 199 180   30
categorical2 195 179 193 202 161   70

4.3 Central Tendency

  • Mean
round(colMeans(mydata, na.rm = TRUE), 2)
               ID         predictor           outcome predictorOverplot 
            50.50             22.64             73.36             25.54 
  outcomeOverplot      categorical1      categorical2 
            63.53              2.96              2.95 
round(apply(mydata, 2, function(x) mean(x, na.rm = TRUE)), 2)
               ID         predictor           outcome predictorOverplot 
            50.50             22.64             73.36             25.54 
  outcomeOverplot      categorical1      categorical2 
            63.53              2.96              2.95 
mydata %>% 
  summarise(across(everything(),
                   .fns = list(mean = ~ mean(., na.rm = TRUE)))) %>% 
  round(., 2)
  • Median
round(apply(mydata, 2, function(x) median(x, na.rm = TRUE)), 2)
               ID         predictor           outcome predictorOverplot 
            50.50             19.61             73.17             26.00 
  outcomeOverplot      categorical1      categorical2 
            63.00              3.00              3.00 
mydata %>% 
  summarise(across(everything(),
                   .fns = list(median = ~ median(., na.rm = TRUE)))) %>% 
  round(., 2)
  • Mode
round(apply(mydata, 2, function(x) Mode(x, multipleModes = "mean")), 2)
               ID         predictor           outcome predictorOverplot 
            50.50             22.64             73.36             35.00 
  outcomeOverplot      categorical1      categorical2 
            63.33              2.00              4.00 
mydata %>% 
  summarise(across(everything(),
                   .fns = list(mode = ~ Mode(., multipleModes = "mean")))) %>% 
  round(., 2)

Compute all of these measures of central tendency:

mydata %>% 
  summarise(across(everything(),
                   .fns = list(mean = ~ mean(., na.rm = TRUE),
                               median = ~ median(., na.rm = TRUE),
                               mode = ~ Mode(., multipleModes = "mean")),
                   .names = "{.col}.{.fn}")) %>% 
  round(., 2) %>% 
  pivot_longer(cols = everything(),
               names_to = c("variable","index"),
               names_sep = "\\.") %>% 
  pivot_wider(names_from = index,
              values_from = value)

4.4 Dispersion

  • Standard deviation
  • Observed minimum and maximum (vis-à-vis possible minimum and maximum)
  • Skewness
  • Kurtosis

Compute all of these measures of dispersion:

mydata %>% 
  summarise(across(everything(),
                   .fns = list(SD = ~ sd(., na.rm = TRUE),
                               min = ~ min(., na.rm = TRUE),
                               max = ~ max(., na.rm = TRUE),
                               skewness = ~ skew(., na.rm = TRUE),
                               kurtosis = ~ kurtosi(., na.rm = TRUE)),
                   .names = "{.col}.{.fn}")) %>% 
  round(., 2) %>% 
  pivot_longer(cols = everything(),
               names_to = c("variable","index"),
               names_sep = "\\.") %>% 
  pivot_wider(names_from = index,
              values_from = value)

Consider transforming data if skewness > |0.8| or if kurtosis > |3.0|.

4.5 Summary Statistics

Add summary statistics to the bottom of correlation matrices in papers:

cor.table(mydata, type = "manuscript")
summaryTable <- mydata %>% 
  summarise(across(everything(),
                   .fns = list(n = ~ length(na.omit(.)),
                               missingness = ~ mean(is.na(.)) * 100,
                               M = ~ mean(., na.rm = TRUE),
                               SD = ~ sd(., na.rm = TRUE),
                               min = ~ min(., na.rm = TRUE),
                               max = ~ max(., na.rm = TRUE),
                               skewness = ~ skew(., na.rm = TRUE),
                               kurtosis = ~ kurtosi(., na.rm = TRUE)),
                   .names = "{.col}.{.fn}")) %>%  
  pivot_longer(cols = everything(),
               names_to = c("variable","index"),
               names_sep = "\\.") %>% 
  pivot_wider(names_from = index,
              values_from = value)

summaryTableTransposed <- summaryTable[-1] %>% 
  t() %>% 
  as.data.frame() %>% 
  setNames(summaryTable$variable) %>% 
  round(., digits = 2)

summaryTableTransposed

4.6 Distribution Plots

See here for resources for creating figures in R.

4.6.1 Histogram

4.6.1.1 Base R

hist(mydata$outcome)

4.6.1.2 ggplot2

ggplot(mydata, aes(x = outcome)) +
  geom_histogram(color = 1)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_bin()`).

4.6.2 Histogram overlaid with density plot and rug plot

4.6.2.1 Base R

hist(mydata$outcome, prob = TRUE)
lines(density(mydata$outcome, na.rm = TRUE))
rug(mydata$outcome)

4.6.2.2 ggplot2

ggplot(mydata, aes(x = outcome)) +
  geom_histogram(aes(y = after_stat(density)), color = 1) +
  geom_density() +
  geom_rug()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_bin()`).
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_density()`).

4.6.3 Density Plot

4.6.3.1 Base R

plot(density(mydata$outcome, na.rm = TRUE))

4.6.3.2 ggplot2

ggplot(mydata, aes(x = outcome)) +
  geom_density()
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_density()`).

4.6.4 Box and whisker plot (boxplot)

4.6.4.1 Base R

boxplot(mydata$outcome, horizontal = TRUE)

4.6.4.2 ggplot2

ggplot(mydata, aes(x = outcome)) +
  geom_boxplot()
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_boxplot()`).

4.6.5 Violin plot

4.6.5.1 Base R

vioplot(na.omit(mydata$outcome), horizontal = TRUE)

4.6.5.2 ggplot2

ggplot(mydata, aes(x = "", y = outcome)) +
  geom_violin()
Warning: Removed 10 rows containing non-finite outside the scale range
(`stat_ydensity()`).

5 Bivariate Associations

For more advanced scatterplots, see here.

5.1 Correlation Coefficients

5.1.1 Pearson Correlation

cor(mydata, use = "pairwise.complete.obs")
                            ID    predictor     outcome predictorOverplot
ID                 1.000000000 -0.019094589 -0.02501796        0.02984671
predictor         -0.019094589  1.000000000  0.63517610        0.04350431
outcome           -0.025017962  0.635176098  1.00000000        0.02976820
predictorOverplot  0.029846711  0.043504314  0.02976820        1.00000000
outcomeOverplot    0.003150872  0.043344473  0.06289224        0.56564445
categorical1       0.040442534 -0.002422711 -0.01532232        0.02498938
categorical2       0.008920415 -0.046927177 -0.01868628        0.03880135
                  outcomeOverplot categorical1 categorical2
ID                    0.003150872  0.040442534  0.008920415
predictor             0.043344473 -0.002422711 -0.046927177
outcome               0.062892238 -0.015322318 -0.018686282
predictorOverplot     0.565644447  0.024989385  0.038801346
outcomeOverplot       1.000000000  0.011871644  0.043682632
categorical1          0.011871644  1.000000000 -0.086310192
categorical2          0.043682632 -0.086310192  1.000000000
cor.test( ~ predictor + outcome, data = mydata)

    Pearson's product-moment correlation

data:  predictor and outcome
t = 25.718, df = 978, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.5962709 0.6711047
sample estimates:
      cor 
0.6351761 
cor.table(mydata)

5.1.2 Spearman Correlation

cor(mydata, use = "pairwise.complete.obs", method = "spearman")
                            ID   predictor     outcome predictorOverplot
ID                 1.000000000 -0.01181085 -0.02805450        0.02925155
predictor         -0.011810853  1.00000000  0.60003760        0.02672008
outcome           -0.028054497  0.60003760  1.00000000        0.02460831
predictorOverplot  0.029251546  0.02672008  0.02460831        1.00000000
outcomeOverplot    0.001416626  0.03278463  0.07073642        0.54841297
categorical1       0.040888369 -0.01162260 -0.01906631        0.02350886
categorical2       0.009137467 -0.03763251 -0.02273699        0.04062487
                  outcomeOverplot categorical1 categorical2
ID                    0.001416626   0.04088837  0.009137467
predictor             0.032784628  -0.01162260 -0.037632515
outcome               0.070736421  -0.01906631 -0.022736992
predictorOverplot     0.548412967   0.02350886  0.040624873
outcomeOverplot       1.000000000   0.01505255  0.044184959
categorical1          0.015052553   1.00000000 -0.086290083
categorical2          0.044184959  -0.08629008  1.000000000
cor.test( ~ predictor + outcome, data = mydata, method = "spearman")

    Spearman's rank correlation rho

data:  predictor and outcome
S = 62740170, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.6000376 
cor.table(mydata, correlation = "spearman")

5.1.3 Xi (\(\xi\))

Xi (\(\xi\)) is an index of the degree of dependence between two variables, which is useful as an index of nonlinear correlation.

Chatterjee, S. (2021). A new coefficient of correlation. Journal of the American Statistical Association, 116(536), 2009-2022. https://doi.org/10.1080/01621459.2020.1758115

calculateXI(
  mydata$predictor,
  mydata$outcome)
[1] 0.2319062

5.2 Scatterplot

5.2.1 Base R

plot(
  mydata$predictor,
  mydata$outcome)
abline(lm(
  outcomeOverplot ~ predictorOverplot,
  data = mydata,
  na.action = "na.exclude"))

5.2.2 ggplot2

ggplot(mydata, aes(x = predictor, y = outcome)) + 
  geom_point() +
  geom_smooth(method = "lm", se = TRUE)
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 20 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 20 rows containing missing values or values outside the scale range
(`geom_point()`).

5.3 Scatterplot with Marginal Density Plot

scatterplot <- 
  ggplot(mydata, aes(x = predictor, y = outcome)) + 
  geom_point() +
  geom_smooth(method = "lm", se = TRUE)
densityMarginal <- ggMarginal(
  scatterplot,
  type = "density",
  xparams = list(fill = "gray"),
  yparams = list(fill = "gray"))
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 20 rows containing non-finite outside the scale range
(`stat_smooth()`).
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 20 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 20 rows containing missing values or values outside the scale range
(`geom_point()`).
print(densityMarginal, newpage = TRUE)

5.4 High Density Scatterplot

ggplot(mydata, aes(x = predictorOverplot, y = outcomeOverplot)) + 
  geom_point(position = "jitter", alpha = 0.3) + 
  geom_density2d()
Warning: Removed 20 rows containing non-finite outside the scale range
(`stat_density2d()`).
Warning: Removed 20 rows containing missing values or values outside the scale range
(`geom_point()`).

smoothScatter(mydata$predictorOverplot, mydata$outcomeOverplot)

5.5 Data Ellipse

mydata_nomissing <- na.omit(mydata[,c("predictor","outcome")])
dataEllipse(mydata_nomissing$predictor, mydata_nomissing$outcome, levels = c(0.5, .95))

5.6 Visually Weighted Regression

vwReg(outcome ~ predictor, data = mydata)

6 Basic inferential statistics

6.1 Tests of Normality

6.1.1 Shapiro-Wilk test of normality

The Shapiro-Wilk test of normality does not accept more than 5000 cases because it will reject the hypothesis that data come from a normal distribution with even slight deviations from normality.

shapiro.test(na.omit(mydata$outcome)) #subset to keep only the first 5000 rows: mydata$outcome[1:5000]

    Shapiro-Wilk normality test

data:  na.omit(mydata$outcome)
W = 0.9971, p-value = 0.06998

6.1.2 Test of multivariate normality

mydata %>% 
  na.omit %>% 
  t %>% 
  mshapiro.test

    Shapiro-Wilk normality test

data:  Z
W = 0.98542, p-value = 1.339e-07

6.3 Tests of systematic missingness (i.e., whether missingness on a variable depends on other variables)

  • Generally test:
    • Whether data are consistent with a missing completely at random (MCAR) pattern—Little’s MCAR Test
    • Whether outcome variable(s) differ as a function of any model variables (predictors and covariates) and as a function of any key demographic characteristics (e.g., sex, ethnicity, socioeconomic status)
    • Whether focal predictor variable(s) differ as a function of any model variables (including outcome variable) and as a function of any key demographic characteristics
  • For instance:
    • Whether males are more likely than girls to be missing scores on the dependent variable
    • Whether longitudinal attrition is greater in lower socioeconomic status families
  • If missingness differs systematically as a function of other variables, you can include that variable as a control variable in models, and/or can include that variable in multiple imputation to inform imputed scores for missing values

6.3.1 Little’s MCAR Test

mcar_test(mydata)

6.4 Multivariate Associations

6.4.1 Correlation Matrix

6.4.1.1 Pearson Correlations

cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")])
cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], type = "manuscript")
cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], type = "manuscriptBig")

6.4.1.2 Spearman Correlations

cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], correlation = "spearman")
cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], type = "manuscript", correlation = "spearman")
cor.table(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], type = "manuscriptBig", correlation = "spearman")

6.4.1.3 Partial Correlations

Examine the associations among variables controlling for a covariate (outcomeOverplot).

partialcor.table(mydata[,c("predictor","outcome","predictorOverplot")], z = mydata[,c("outcomeOverplot")])
                       predictor outcome predictorOverplot
1. predictor.r              1.00  .63***               .02
2. sig                        NA     .00               .47
3. n                         980     970               971
4. outcome.r              .63***    1.00              -.01
5. sig                       .00      NA               .83
6. n                         970     980               970
7. predictorOverplot.r       .02    -.01              1.00
8. sig                       .47     .83                NA
9. n                         971     970               980
partialcor.table(mydata[,c("predictor","outcome","predictorOverplot")], z = mydata[,c("outcomeOverplot")], type = "manuscript")
partialcor.table(mydata[,c("predictor","outcome","predictorOverplot")], z = mydata[,c("outcomeOverplot")], type = "manuscriptBig")

6.4.2 Correlogram

corrplot(cor(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")], use = "pairwise.complete.obs"))

6.4.3 Scatterplot matrix

scatterplotMatrix(~ predictor + outcome + predictorOverplot + outcomeOverplot, data = mydata, use = "pairwise.complete.obs")

6.4.4 Pairs panels

pairs.panels(mydata[,c("predictor","outcome","predictorOverplot","outcomeOverplot")])

6.5 Effect Plots

6.5.1 Multiple Regression Model

multipleRegressionModel <- lm(outcome ~ predictor + predictorOverplot,
                              data = mydata,
                              na.action = "na.exclude")

allEffects(multipleRegressionModel)
 model: outcome ~ predictor + predictorOverplot

 predictor effect
predictor
      0.1        20        40        60        80 
 49.23335  70.37778  91.62847 112.87915 134.12983 

 predictorOverplot effect
predictorOverplot
       1       10       30       40       50 
73.13937 73.15070 73.17586 73.18845 73.20103 
plot(allEffects(multipleRegressionModel))

6.5.2 Multilevel Regression Model

multilevelRegressionModel <- lme(outcome ~ predictor + predictorOverplot, random = ~ 1|ID,
                                 method = "ML",
                                 data = mydata,
                                 na.action = "na.exclude")

allEffects(multilevelRegressionModel)
 model: outcome ~ predictor + predictorOverplot

 predictor effect
predictor
      0.1        20        40        60        80 
 49.23335  70.37778  91.62847 112.87915 134.12983 

 predictorOverplot effect
predictorOverplot
       1       10       30       40       50 
73.13937 73.15070 73.17586 73.18845 73.20103 
plot(allEffects(multilevelRegressionModel))

7 Session Info

sessionInfo()
R version 4.4.2 (2024-10-31)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 22.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
 [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
 [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

time zone: UTC
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] XICOR_0.4.1        ggExtra_0.10.1     mvnormtest_0.1-9-3 naniar_1.1.0      
 [5] lubridate_1.9.3    forcats_1.0.0      stringr_1.5.1      dplyr_1.1.4       
 [9] purrr_1.0.2        readr_2.1.5        tidyr_1.3.1        tibble_3.2.1      
[13] tidyverse_2.0.0    psych_2.4.6.26     ggplot2_3.5.1      corrplot_0.95     
[17] effects_4.2-2      nlme_3.1-166       ellipse_0.5.0      vioplot_0.5.0     
[21] zoo_1.8-12         sm_2.2-6.0         car_3.1-3          carData_3.0-5     
[25] petersenlab_1.1.0 

loaded via a namespace (and not attached):
 [1] DBI_1.2.3          mnormt_2.1.1       gridExtra_2.3      rlang_1.1.4       
 [5] magrittr_2.0.3     compiler_4.4.2     mgcv_1.9-1         vctrs_0.6.5       
 [9] reshape2_1.4.4     quadprog_1.5-8     pkgconfig_2.0.3    fastmap_1.2.0     
[13] backports_1.5.0    labeling_0.4.3     pbivnorm_0.6.0     utf8_1.2.4        
[17] promises_1.3.2     rmarkdown_2.29     psychTools_2.4.3   tzdb_0.4.0        
[21] nloptr_2.1.1       visdat_0.6.0       xfun_0.49          cachem_1.1.0      
[25] jsonlite_1.8.9     later_1.4.1        parallel_4.4.2     lavaan_0.6-19     
[29] cluster_2.1.6      R6_2.5.1           bslib_0.8.0        stringi_1.8.4     
[33] RColorBrewer_1.1-3 boot_1.3-31        rpart_4.1.23       estimability_1.5.1
[37] jquerylib_0.1.4    Rcpp_1.0.13-1      knitr_1.49         base64enc_0.1-3   
[41] httpuv_1.6.15      Matrix_1.7-1       splines_4.4.2      nnet_7.3-19       
[45] timechange_0.3.0   tidyselect_1.2.1   rstudioapi_0.17.1  abind_1.4-8       
[49] yaml_2.3.10        miniUI_0.1.1.1     lattice_0.22-6     plyr_1.8.9        
[53] shiny_1.9.1        withr_3.0.2        evaluate_1.0.1     foreign_0.8-87    
[57] survival_3.7-0     isoband_0.2.7      survey_4.4-2       norm_1.0-11.1     
[61] pillar_1.9.0       KernSmooth_2.23-24 rtf_0.4-14.1       checkmate_2.3.2   
[65] stats4_4.4.2       insight_1.0.0      generics_0.1.3     mix_1.0-12        
[69] hms_1.1.3          munsell_0.5.1      scales_1.3.0       minqa_1.2.8       
[73] xtable_1.8-4       glue_1.8.0         Hmisc_5.2-1        tools_4.4.2       
[77] data.table_1.16.2  lme4_1.1-35.5      mvtnorm_1.3-2      grid_4.4.2        
[81] mitools_2.4        colorspace_2.1-1   htmlTable_2.4.3    Formula_1.2-5     
[85] cli_3.6.3          fansi_1.0.6        viridisLite_0.4.2  gtable_0.3.6      
[89] R.methodsS3_1.8.2  sass_0.4.9         digest_0.6.37      farver_2.1.2      
[93] htmlwidgets_1.6.4  R.oo_1.27.0        htmltools_0.5.8.1  lifecycle_1.0.4   
[97] mime_0.12          MASS_7.3-61       
LS0tCnRpdGxlOiAiRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgZXJyb3IgPSBUUlVFLAogIGNvbW1lbnQgPSAiIikKYGBgCgojIFJhdGlvbmFsZQoKRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBpcyBpbXBvcnRhbnQgZm9yIHVuZGVyc3RhbmRpbmcgeW91ciBkYXRhLCBjaGVja2luZyBmb3IgZGF0YSBpc3N1ZXMvZXJyb3JzLCBhbmQgY2hlY2tpbmcgYXNzdW1wdGlvbnMgZm9yIGRpZmZlcmVudCBzdGF0aXN0aWNhbCBtb2RlbHMuCgpMT09LIEFUIFlPVVIgREFUQeKAlHRoaXMgaXMgb25lIG9mIHRoZSBtb3N0IG92ZXJsb29rZWQgc3RlcHMgaW4gZGF0YSBhbmFseXNpcyEKCiMgUHJlYW1ibGUKCiMjIEluc3RhbGwgTGlicmFyaWVzCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoInJlbW90ZXMiKQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoIkRldlBzeUxhYi9wZXRlcnNlbmxhYiIpCmBgYAoKIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KbGlicmFyeSgicGV0ZXJzZW5sYWIiKQpsaWJyYXJ5KCJjYXIiKQpsaWJyYXJ5KCJ2aW9wbG90IikKbGlicmFyeSgiZWxsaXBzZSIpCmxpYnJhcnkoIm5sbWUiKQpsaWJyYXJ5KCJlZmZlY3RzIikKbGlicmFyeSgiY29ycnBsb3QiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgicHN5Y2giKQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJwdXJyciIpCmxpYnJhcnkoIm5hbmlhciIpCmxpYnJhcnkoIm12bm9ybXRlc3QiKQpsaWJyYXJ5KCJnZ0V4dHJhIikKbGlicmFyeSgiWElDT1IiKQpgYGAKCiMgU2ltdWxhdGUgRGF0YQoKYGBge3J9CnNldC5zZWVkKDUyMjQyKQoKbiA8LSAxMDAwCgpJRCA8LSByZXAoMToxMDAsIGVhY2ggPSAxMCkKcHJlZGljdG9yIDwtIHJiZXRhKG4sIDEuNSwgNSkgKiAxMDAKb3V0Y29tZSA8LSBwcmVkaWN0b3IgKyBybm9ybShuLCBtZWFuID0gMCwgc2QgPSAyMCkgKyA1MAoKcHJlZGljdG9yT3ZlcnBsb3QgPC0gc2FtcGxlKDE6NTAsIG4sIHJlcGxhY2UgPSBUUlVFKQpvdXRjb21lT3ZlcnBsb3QgPC0gcHJlZGljdG9yT3ZlcnBsb3QgKyBzYW1wbGUoMTo3NSwgbiwgcmVwbGFjZSA9IFRSVUUpCgpjYXRlZ29yaWNhbDEgPC0gc2FtcGxlKDE6NSwgc2l6ZSA9IG4sIHJlcGxhY2UgPSBUUlVFKQpjYXRlZ29yaWNhbDIgPC0gc2FtcGxlKDE6NSwgc2l6ZSA9IG4sIHJlcGxhY2UgPSBUUlVFKQoKbXlkYXRhIDwtIGRhdGEuZnJhbWUoCiAgSUQgPSBJRCwKICBwcmVkaWN0b3IgPSBwcmVkaWN0b3IsCiAgb3V0Y29tZSA9IG91dGNvbWUsCiAgcHJlZGljdG9yT3ZlcnBsb3QgPSBwcmVkaWN0b3JPdmVycGxvdCwKICBvdXRjb21lT3ZlcnBsb3QgPSBvdXRjb21lT3ZlcnBsb3QsCiAgY2F0ZWdvcmljYWwxID0gY2F0ZWdvcmljYWwxLAogIGNhdGVnb3JpY2FsMiA9IGNhdGVnb3JpY2FsMikKCm15ZGF0YVtzYW1wbGUoMTpuLCBzaXplID0gMTApLCAicHJlZGljdG9yIl0gPC0gTkEKbXlkYXRhW3NhbXBsZSgxOm4sIHNpemUgPSAxMCksICJvdXRjb21lIl0gPC0gTkEKbXlkYXRhW3NhbXBsZSgxOm4sIHNpemUgPSAxMCksICJwcmVkaWN0b3JPdmVycGxvdCJdIDwtIE5BCm15ZGF0YVtzYW1wbGUoMTpuLCBzaXplID0gMTApLCAib3V0Y29tZU92ZXJwbG90Il0gPC0gTkEKbXlkYXRhW3NhbXBsZSgxOm4sIHNpemUgPSAzMCksICJjYXRlZ29yaWNhbDEiXSA8LSBOQQpteWRhdGFbc2FtcGxlKDE6biwgc2l6ZSA9IDcwKSwgImNhdGVnb3JpY2FsMiJdIDwtIE5BCmBgYAoKIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzCgpgYGB7cn0Kcm91bmQoZGF0YS5mcmFtZShwc3ljaDo6ZGVzY3JpYmUobXlkYXRhKSksIDIpCmBgYAoKIyMgU2FtcGxlCgotIENoZWNrIHRoZSBzYW1wbGUgc2l6ZSAoKk4qKQogIC0gSXMgdGhlIHNhbXBsZSBzaXplIGluIHRoZSBkYXRhIHRoZSBleHBlY3RlZCBzYW1wbGUgc2l6ZT8KICBBcmUgdGhlcmUgY2FzZXMgKHBhcnRpY2lwYW50cykgdGhhdCBhcmUgbWlzc2luZz8KICBBcmUgdGhlcmUgY2FzZXMgdGhhdCBzaG91bGQgbm90IGJlIHRoZXJlPwogIC0gSGVyZSBpcyB0aGUgc2FtcGxlIHNpemU6CiAgCmBgYHtyfQpsZW5ndGgodW5pcXVlKG15ZGF0YSRJRCkpCmBgYCAgIAoKLSBDaGVjayB0aGUgZXh0ZW50IG9mIG1pc3NpbmduZXNzCiAgICAtIEhvdyBtdWNoIGRhdGEgYXJlIG1pc3NpbmcgaW4gdGhlIG1vZGVsIHZhcmlhYmxlc+KAlGluY2x1ZGluZyB0aGUgcHJlZGljdG9yLCBvdXRjb21lLCBhbmQgY292YXJpYXRlcz8KICAgIC0gSGVyZSBhcmUgdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyBkYXRhIGluIGVhY2ggdmFyaWFibGU6CiAgICAKYGBge3J9Cm1hcChteWRhdGEsIH5tZWFuKGlzLm5hKC4pKSkgJT4lIHQgJT4lIHQKYGBgCgojIyBEaXN0cmlidXRpb24KCi0gRnJlcXVlbmNpZXMKICAgIC0gRXhhbWluZSB0aGUgZnJlcXVlbmNpZXMgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzOgoKYGBge3J9Cm15ZGF0YSAlPiUgCiAgc2VsZWN0KGNhdGVnb3JpY2FsMSwgY2F0ZWdvcmljYWwyKSAlPiUKICBzYXBwbHkoZnVuY3Rpb24oeCkgdGFibGUoeCwgdXNlTkEgPSAiYWx3YXlzIikpICU+JSAKICB0KCkKYGBgCgojIyBDZW50cmFsIFRlbmRlbmN5CgotIE1lYW4KCmBgYHtyfQpyb3VuZChjb2xNZWFucyhteWRhdGEsIG5hLnJtID0gVFJVRSksIDIpCnJvdW5kKGFwcGx5KG15ZGF0YSwgMiwgZnVuY3Rpb24oeCkgbWVhbih4LCBuYS5ybSA9IFRSVUUpKSwgMikKCm15ZGF0YSAlPiUgCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgICAuZm5zID0gbGlzdChtZWFuID0gfiBtZWFuKC4sIG5hLnJtID0gVFJVRSkpKSkgJT4lIAogIHJvdW5kKC4sIDIpCmBgYAoKLSBNZWRpYW4KCmBgYHtyfQpyb3VuZChhcHBseShteWRhdGEsIDIsIGZ1bmN0aW9uKHgpIG1lZGlhbih4LCBuYS5ybSA9IFRSVUUpKSwgMikKCm15ZGF0YSAlPiUgCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgICAuZm5zID0gbGlzdChtZWRpYW4gPSB+IG1lZGlhbiguLCBuYS5ybSA9IFRSVUUpKSkpICU+JSAKICByb3VuZCguLCAyKQpgYGAKCi0gTW9kZQoKYGBge3J9CnJvdW5kKGFwcGx5KG15ZGF0YSwgMiwgZnVuY3Rpb24oeCkgTW9kZSh4LCBtdWx0aXBsZU1vZGVzID0gIm1lYW4iKSksIDIpCgpteWRhdGEgJT4lIAogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLAogICAgICAgICAgICAgICAgICAgLmZucyA9IGxpc3QobW9kZSA9IH4gTW9kZSguLCBtdWx0aXBsZU1vZGVzID0gIm1lYW4iKSkpKSAlPiUgCiAgcm91bmQoLiwgMikKYGBgCgpDb21wdXRlIGFsbCBvZiB0aGVzZSBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5OgoKYGBge3J9Cm15ZGF0YSAlPiUgCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgICAuZm5zID0gbGlzdChtZWFuID0gfiBtZWFuKC4sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWRpYW4gPSB+IG1lZGlhbiguLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZSA9IH4gTW9kZSguLCBtdWx0aXBsZU1vZGVzID0gIm1lYW4iKSksCiAgICAgICAgICAgICAgICAgICAubmFtZXMgPSAiey5jb2x9LnsuZm59IikpICU+JSAKICByb3VuZCguLCAyKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gYygidmFyaWFibGUiLCJpbmRleCIpLAogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXFwuIikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbmRleCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHZhbHVlKQpgYGAKCiMjIERpc3BlcnNpb24KCi0gU3RhbmRhcmQgZGV2aWF0aW9uCi0gT2JzZXJ2ZWQgbWluaW11bSBhbmQgbWF4aW11bSAodmlzLcOgLXZpcyBwb3NzaWJsZSBtaW5pbXVtIGFuZCBtYXhpbXVtKQotIFNrZXduZXNzCi0gS3VydG9zaXMKCkNvbXB1dGUgYWxsIG9mIHRoZXNlIG1lYXN1cmVzIG9mIGRpc3BlcnNpb246CgpgYGB7cn0KbXlkYXRhICU+JSAKICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwKICAgICAgICAgICAgICAgICAgIC5mbnMgPSBsaXN0KFNEID0gfiBzZCguLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluID0gfiBtaW4oLiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heCA9IH4gbWF4KC4sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IH4gc2tldyguLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXMgPSB+IGt1cnRvc2koLiwgbmEucm0gPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAubmFtZXMgPSAiey5jb2x9LnsuZm59IikpICU+JSAKICByb3VuZCguLCAyKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gYygidmFyaWFibGUiLCJpbmRleCIpLAogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXFwuIikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbmRleCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHZhbHVlKQpgYGAKCkNvbnNpZGVyIHRyYW5zZm9ybWluZyBkYXRhIGlmIHNrZXduZXNzID4gfDAuOHwgb3IgaWYga3VydG9zaXMgPiB8My4wfC4KCiMjIFN1bW1hcnkgU3RhdGlzdGljcwoKQWRkIHN1bW1hcnkgc3RhdGlzdGljcyB0byB0aGUgYm90dG9tIG9mIGNvcnJlbGF0aW9uIG1hdHJpY2VzIGluIHBhcGVyczoKCmBgYHtyfQpjb3IudGFibGUobXlkYXRhLCB0eXBlID0gIm1hbnVzY3JpcHQiKQoKc3VtbWFyeVRhYmxlIDwtIG15ZGF0YSAlPiUgCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgICAuZm5zID0gbGlzdChuID0gfiBsZW5ndGgobmEub21pdCguKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaXNzaW5nbmVzcyA9IH4gbWVhbihpcy5uYSguKSkgKiAxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNID0gfiBtZWFuKC4sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTRCA9IH4gc2QoLiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbiA9IH4gbWluKC4sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXggPSB+IG1heCguLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3MgPSB+IHNrZXcoLiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gfiBrdXJ0b3NpKC4sIG5hLnJtID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgLm5hbWVzID0gInsuY29sfS57LmZufSIpKSAlPiUgIAogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLAogICAgICAgICAgICAgICBuYW1lc190byA9IGMoInZhcmlhYmxlIiwiaW5kZXgiKSwKICAgICAgICAgICAgICAgbmFtZXNfc2VwID0gIlxcLiIpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW5kZXgsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSB2YWx1ZSkKCnN1bW1hcnlUYWJsZVRyYW5zcG9zZWQgPC0gc3VtbWFyeVRhYmxlWy0xXSAlPiUgCiAgdCgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHNldE5hbWVzKHN1bW1hcnlUYWJsZSR2YXJpYWJsZSkgJT4lIAogIHJvdW5kKC4sIGRpZ2l0cyA9IDIpCgpzdW1tYXJ5VGFibGVUcmFuc3Bvc2VkCmBgYAoKIyMgRGlzdHJpYnV0aW9uIFBsb3RzCgpTZWUgW2hlcmVdKGZpZ3VyZXMuaHRtbCkgZm9yIHJlc291cmNlcyBmb3IgY3JlYXRpbmcgZmlndXJlcyBpbiBSLgoKIyMjIEhpc3RvZ3JhbQoKIyMjIyBCYXNlIFIKCmBgYHtyfQpoaXN0KG15ZGF0YSRvdXRjb21lKQpgYGAKCiMjIyMgYGdncGxvdDJgCgpgYGB7cn0KZ2dwbG90KG15ZGF0YSwgYWVzKHggPSBvdXRjb21lKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gMSkKYGBgCgojIyMgSGlzdG9ncmFtIG92ZXJsYWlkIHdpdGggZGVuc2l0eSBwbG90IGFuZCBydWcgcGxvdAoKIyMjIyBCYXNlIFIKCmBgYHtyfQpoaXN0KG15ZGF0YSRvdXRjb21lLCBwcm9iID0gVFJVRSkKbGluZXMoZGVuc2l0eShteWRhdGEkb3V0Y29tZSwgbmEucm0gPSBUUlVFKSkKcnVnKG15ZGF0YSRvdXRjb21lKQpgYGAKCiMjIyMgYGdncGxvdDJgCgpgYGB7cn0KZ2dwbG90KG15ZGF0YSwgYWVzKHggPSBvdXRjb21lKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksIGNvbG9yID0gMSkgKwogIGdlb21fZGVuc2l0eSgpICsKICBnZW9tX3J1ZygpCmBgYAoKIyMjIERlbnNpdHkgUGxvdAoKIyMjIyBCYXNlIFIKCmBgYHtyfQpwbG90KGRlbnNpdHkobXlkYXRhJG91dGNvbWUsIG5hLnJtID0gVFJVRSkpCmBgYAoKIyMjIyBgZ2dwbG90MmAKCmBgYHtyfQpnZ3Bsb3QobXlkYXRhLCBhZXMoeCA9IG91dGNvbWUpKSArCiAgZ2VvbV9kZW5zaXR5KCkKYGBgCgojIyMgQm94IGFuZCB3aGlza2VyIHBsb3QgKGJveHBsb3QpCgojIyMjIEJhc2UgUgoKYGBge3J9CmJveHBsb3QobXlkYXRhJG91dGNvbWUsIGhvcml6b250YWwgPSBUUlVFKQpgYGAKCiMjIyMgYGdncGxvdDJgCgpgYGB7cn0KZ2dwbG90KG15ZGF0YSwgYWVzKHggPSBvdXRjb21lKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKIyMjIFZpb2xpbiBwbG90CgojIyMjIEJhc2UgUgoKYGBge3J9CnZpb3Bsb3QobmEub21pdChteWRhdGEkb3V0Y29tZSksIGhvcml6b250YWwgPSBUUlVFKQpgYGAKCiMjIyMgYGdncGxvdDJgCgpgYGB7cn0KZ2dwbG90KG15ZGF0YSwgYWVzKHggPSAiIiwgeSA9IG91dGNvbWUpKSArCiAgZ2VvbV92aW9saW4oKQpgYGAKCiMgQml2YXJpYXRlIEFzc29jaWF0aW9ucwoKRm9yIG1vcmUgYWR2YW5jZWQgc2NhdHRlcnBsb3RzLCBzZWUgW2hlcmVdKGZpZ3VyZXMuaHRtbCNtYXJnaW5hbERpc3RyaWJ1dGlvbnMpLgoKIyMgQ29ycmVsYXRpb24gQ29lZmZpY2llbnRzCgojIyMgUGVhcnNvbiBDb3JyZWxhdGlvbgoKYGBge3J9CmNvcihteWRhdGEsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpjb3IudGVzdCggfiBwcmVkaWN0b3IgKyBvdXRjb21lLCBkYXRhID0gbXlkYXRhKQpjb3IudGFibGUobXlkYXRhKQpgYGAKCiMjIyBTcGVhcm1hbiBDb3JyZWxhdGlvbgoKYGBge3J9CmNvcihteWRhdGEsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAic3BlYXJtYW4iKQpjb3IudGVzdCggfiBwcmVkaWN0b3IgKyBvdXRjb21lLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAic3BlYXJtYW4iKQpjb3IudGFibGUobXlkYXRhLCBjb3JyZWxhdGlvbiA9ICJzcGVhcm1hbiIpCmBgYAoKIyMjIFhpICgkXHhpJCkKClhpICgkXHhpJCkgaXMgYW4gaW5kZXggb2YgdGhlIGRlZ3JlZSBvZiBkZXBlbmRlbmNlIGJldHdlZW4gdHdvIHZhcmlhYmxlcywgd2hpY2ggaXMgdXNlZnVsIGFzIGFuIGluZGV4IG9mIG5vbmxpbmVhciBjb3JyZWxhdGlvbi4KCkNoYXR0ZXJqZWUsIFMuICgyMDIxKS4gQSBuZXcgY29lZmZpY2llbnQgb2YgY29ycmVsYXRpb24uICpKb3VybmFsIG9mIHRoZSBBbWVyaWNhbiBTdGF0aXN0aWNhbCBBc3NvY2lhdGlvbiwgMTE2Kig1MzYpLCAyMDA5LTIwMjIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAxNjIxNDU5LjIwMjAuMTc1ODExNQoKYGBge3J9CmNhbGN1bGF0ZVhJKAogIG15ZGF0YSRwcmVkaWN0b3IsCiAgbXlkYXRhJG91dGNvbWUpCmBgYAoKIyMgU2NhdHRlcnBsb3QKCiMjIyBCYXNlIFIKCmBgYHtyfQpwbG90KAogIG15ZGF0YSRwcmVkaWN0b3IsCiAgbXlkYXRhJG91dGNvbWUpCmFibGluZShsbSgKICBvdXRjb21lT3ZlcnBsb3QgfiBwcmVkaWN0b3JPdmVycGxvdCwKICBkYXRhID0gbXlkYXRhLAogIG5hLmFjdGlvbiA9ICJuYS5leGNsdWRlIikpCmBgYAoKIyMjIGBnZ3Bsb3QyYAoKYGBge3J9CmdncGxvdChteWRhdGEsIGFlcyh4ID0gcHJlZGljdG9yLCB5ID0gb3V0Y29tZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUpCmBgYAoKIyMgU2NhdHRlcnBsb3Qgd2l0aCBNYXJnaW5hbCBEZW5zaXR5IFBsb3QKCmBgYHtyfQpzY2F0dGVycGxvdCA8LSAKICBnZ3Bsb3QobXlkYXRhLCBhZXMoeCA9IHByZWRpY3RvciwgeSA9IG91dGNvbWUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFKQpgYGAKCmBgYHtyfQpkZW5zaXR5TWFyZ2luYWwgPC0gZ2dNYXJnaW5hbCgKICBzY2F0dGVycGxvdCwKICB0eXBlID0gImRlbnNpdHkiLAogIHhwYXJhbXMgPSBsaXN0KGZpbGwgPSAiZ3JheSIpLAogIHlwYXJhbXMgPSBsaXN0KGZpbGwgPSAiZ3JheSIpKQpgYGAKCmBgYHtyfQpwcmludChkZW5zaXR5TWFyZ2luYWwsIG5ld3BhZ2UgPSBUUlVFKQpgYGAKCiMjIEhpZ2ggRGVuc2l0eSBTY2F0dGVycGxvdAoKYGBge3J9CmdncGxvdChteWRhdGEsIGFlcyh4ID0gcHJlZGljdG9yT3ZlcnBsb3QsIHkgPSBvdXRjb21lT3ZlcnBsb3QpKSArIAogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIiwgYWxwaGEgPSAwLjMpICsgCiAgZ2VvbV9kZW5zaXR5MmQoKQoKc21vb3RoU2NhdHRlcihteWRhdGEkcHJlZGljdG9yT3ZlcnBsb3QsIG15ZGF0YSRvdXRjb21lT3ZlcnBsb3QpCmBgYAoKIyMgRGF0YSBFbGxpcHNlCgpgYGB7cn0KbXlkYXRhX25vbWlzc2luZyA8LSBuYS5vbWl0KG15ZGF0YVssYygicHJlZGljdG9yIiwib3V0Y29tZSIpXSkKZGF0YUVsbGlwc2UobXlkYXRhX25vbWlzc2luZyRwcmVkaWN0b3IsIG15ZGF0YV9ub21pc3Npbmckb3V0Y29tZSwgbGV2ZWxzID0gYygwLjUsIC45NSkpCmBgYAoKIyMgVmlzdWFsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgcmVzdWx0cyA9ICJoaWRlIn0KdndSZWcob3V0Y29tZSB+IHByZWRpY3RvciwgZGF0YSA9IG15ZGF0YSkKYGBgCgojIEJhc2ljIGluZmVyZW50aWFsIHN0YXRpc3RpY3MKCiMjIFRlc3RzIG9mIE5vcm1hbGl0eQoKIyMjIFNoYXBpcm8tV2lsayB0ZXN0IG9mIG5vcm1hbGl0eQoKVGhlIFNoYXBpcm8tV2lsayB0ZXN0IG9mIG5vcm1hbGl0eSBkb2VzIG5vdCBhY2NlcHQgbW9yZSB0aGFuIDUwMDAgY2FzZXMgYmVjYXVzZSBpdCB3aWxsIHJlamVjdCB0aGUgaHlwb3RoZXNpcyB0aGF0IGRhdGEgY29tZSBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIGV2ZW4gc2xpZ2h0IGRldmlhdGlvbnMgZnJvbSBub3JtYWxpdHkuCgpgYGB7cn0Kc2hhcGlyby50ZXN0KG5hLm9taXQobXlkYXRhJG91dGNvbWUpKSAjc3Vic2V0IHRvIGtlZXAgb25seSB0aGUgZmlyc3QgNTAwMCByb3dzOiBteWRhdGEkb3V0Y29tZVsxOjUwMDBdCmBgYAoKIyMjIFRlc3Qgb2YgbXVsdGl2YXJpYXRlIG5vcm1hbGl0eQoKYGBge3J9Cm15ZGF0YSAlPiUgCiAgbmEub21pdCAlPiUgCiAgdCAlPiUgCiAgbXNoYXBpcm8udGVzdApgYGAKCiMjIFN0YXRpc3RpY2FsIGRlY2lzaW9uIHRyZWUKCmh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvNy83NC9JbmZlcmVudGlhbFN0YXRpc3RpY2FsRGVjaXNpb25NYWtpbmdUcmVlcy5wZGYgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvTDJRUi1BTEZBKQoKIyMgVGVzdHMgb2Ygc3lzdGVtYXRpYyBtaXNzaW5nbmVzcyAoaS5lLiwgd2hldGhlciBtaXNzaW5nbmVzcyBvbiBhIHZhcmlhYmxlIGRlcGVuZHMgb24gb3RoZXIgdmFyaWFibGVzKQoKLSBHZW5lcmFsbHkgdGVzdDoKICAgIC0gV2hldGhlciBkYXRhIGFyZSBjb25zaXN0ZW50IHdpdGggYSBtaXNzaW5nIGNvbXBsZXRlbHkgYXQgcmFuZG9tIChNQ0FSKSBwYXR0ZXJu4oCUTGl0dGxlJ3MgTUNBUiBUZXN0CiAgICAtIFdoZXRoZXIgb3V0Y29tZSB2YXJpYWJsZShzKSBkaWZmZXIgYXMgYSBmdW5jdGlvbiBvZiBhbnkgbW9kZWwgdmFyaWFibGVzIChwcmVkaWN0b3JzIGFuZCBjb3ZhcmlhdGVzKSBhbmQgYXMgYSBmdW5jdGlvbiBvZiBhbnkga2V5IGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyAoZS5nLiwgc2V4LCBldGhuaWNpdHksIHNvY2lvZWNvbm9taWMgc3RhdHVzKQogICAgLSBXaGV0aGVyIGZvY2FsIHByZWRpY3RvciB2YXJpYWJsZShzKSBkaWZmZXIgYXMgYSBmdW5jdGlvbiBvZiBhbnkgbW9kZWwgdmFyaWFibGVzIChpbmNsdWRpbmcgb3V0Y29tZSB2YXJpYWJsZSkgYW5kIGFzIGEgZnVuY3Rpb24gb2YgYW55IGtleSBkZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3MKLSBGb3IgaW5zdGFuY2U6CiAgICAtIFdoZXRoZXIgbWFsZXMgYXJlIG1vcmUgbGlrZWx5IHRoYW4gZ2lybHMgdG8gYmUgbWlzc2luZyBzY29yZXMgb24gdGhlIGRlcGVuZGVudCB2YXJpYWJsZQogICAgLSBXaGV0aGVyIGxvbmdpdHVkaW5hbCBhdHRyaXRpb24gaXMgZ3JlYXRlciBpbiBsb3dlciBzb2Npb2Vjb25vbWljIHN0YXR1cyBmYW1pbGllcwotIElmIG1pc3NpbmduZXNzIGRpZmZlcnMgc3lzdGVtYXRpY2FsbHkgYXMgYSBmdW5jdGlvbiBvZiBvdGhlciB2YXJpYWJsZXMsIHlvdSBjYW4gaW5jbHVkZSB0aGF0IHZhcmlhYmxlIGFzIGEgY29udHJvbCB2YXJpYWJsZSBpbiBtb2RlbHMsIGFuZC9vciBjYW4gaW5jbHVkZSB0aGF0IHZhcmlhYmxlIGluIG11bHRpcGxlIGltcHV0YXRpb24gdG8gaW5mb3JtIGltcHV0ZWQgc2NvcmVzIGZvciBtaXNzaW5nIHZhbHVlcwoKIyMjIExpdHRsZSdzIE1DQVIgVGVzdAoKYGBge3J9Cm1jYXJfdGVzdChteWRhdGEpCmBgYAoKIyMgTXVsdGl2YXJpYXRlIEFzc29jaWF0aW9ucwoKIyMjIENvcnJlbGF0aW9uIE1hdHJpeAoKIyMjIyBQZWFyc29uIENvcnJlbGF0aW9ucwoKYGBge3J9CmNvci50YWJsZShteWRhdGFbLGMoInByZWRpY3RvciIsIm91dGNvbWUiLCJwcmVkaWN0b3JPdmVycGxvdCIsIm91dGNvbWVPdmVycGxvdCIpXSkKY29yLnRhYmxlKG15ZGF0YVssYygicHJlZGljdG9yIiwib3V0Y29tZSIsInByZWRpY3Rvck92ZXJwbG90Iiwib3V0Y29tZU92ZXJwbG90IildLCB0eXBlID0gIm1hbnVzY3JpcHQiKQpjb3IudGFibGUobXlkYXRhWyxjKCJwcmVkaWN0b3IiLCJvdXRjb21lIiwicHJlZGljdG9yT3ZlcnBsb3QiLCJvdXRjb21lT3ZlcnBsb3QiKV0sIHR5cGUgPSAibWFudXNjcmlwdEJpZyIpCmBgYAoKIyMjIyBTcGVhcm1hbiBDb3JyZWxhdGlvbnMKCmBgYHtyfQpjb3IudGFibGUobXlkYXRhWyxjKCJwcmVkaWN0b3IiLCJvdXRjb21lIiwicHJlZGljdG9yT3ZlcnBsb3QiLCJvdXRjb21lT3ZlcnBsb3QiKV0sIGNvcnJlbGF0aW9uID0gInNwZWFybWFuIikKY29yLnRhYmxlKG15ZGF0YVssYygicHJlZGljdG9yIiwib3V0Y29tZSIsInByZWRpY3Rvck92ZXJwbG90Iiwib3V0Y29tZU92ZXJwbG90IildLCB0eXBlID0gIm1hbnVzY3JpcHQiLCBjb3JyZWxhdGlvbiA9ICJzcGVhcm1hbiIpCmNvci50YWJsZShteWRhdGFbLGMoInByZWRpY3RvciIsIm91dGNvbWUiLCJwcmVkaWN0b3JPdmVycGxvdCIsIm91dGNvbWVPdmVycGxvdCIpXSwgdHlwZSA9ICJtYW51c2NyaXB0QmlnIiwgY29ycmVsYXRpb24gPSAic3BlYXJtYW4iKQpgYGAKCiMjIyMgUGFydGlhbCBDb3JyZWxhdGlvbnMKCkV4YW1pbmUgdGhlIGFzc29jaWF0aW9ucyBhbW9uZyB2YXJpYWJsZXMgY29udHJvbGxpbmcgZm9yIGEgY292YXJpYXRlIChgb3V0Y29tZU92ZXJwbG90YCkuCgpgYGB7cn0KcGFydGlhbGNvci50YWJsZShteWRhdGFbLGMoInByZWRpY3RvciIsIm91dGNvbWUiLCJwcmVkaWN0b3JPdmVycGxvdCIpXSwgeiA9IG15ZGF0YVssYygib3V0Y29tZU92ZXJwbG90IildKQpwYXJ0aWFsY29yLnRhYmxlKG15ZGF0YVssYygicHJlZGljdG9yIiwib3V0Y29tZSIsInByZWRpY3Rvck92ZXJwbG90IildLCB6ID0gbXlkYXRhWyxjKCJvdXRjb21lT3ZlcnBsb3QiKV0sIHR5cGUgPSAibWFudXNjcmlwdCIpCnBhcnRpYWxjb3IudGFibGUobXlkYXRhWyxjKCJwcmVkaWN0b3IiLCJvdXRjb21lIiwicHJlZGljdG9yT3ZlcnBsb3QiKV0sIHogPSBteWRhdGFbLGMoIm91dGNvbWVPdmVycGxvdCIpXSwgdHlwZSA9ICJtYW51c2NyaXB0QmlnIikKYGBgCgojIyMgQ29ycmVsb2dyYW0KCmBgYHtyfQpjb3JycGxvdChjb3IobXlkYXRhWyxjKCJwcmVkaWN0b3IiLCJvdXRjb21lIiwicHJlZGljdG9yT3ZlcnBsb3QiLCJvdXRjb21lT3ZlcnBsb3QiKV0sIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKSkKYGBgCgojIyMgU2NhdHRlcnBsb3QgbWF0cml4CgpgYGB7cn0Kc2NhdHRlcnBsb3RNYXRyaXgofiBwcmVkaWN0b3IgKyBvdXRjb21lICsgcHJlZGljdG9yT3ZlcnBsb3QgKyBvdXRjb21lT3ZlcnBsb3QsIGRhdGEgPSBteWRhdGEsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpgYGAKCiMjIyBQYWlycyBwYW5lbHMKCmBgYHtyfQpwYWlycy5wYW5lbHMobXlkYXRhWyxjKCJwcmVkaWN0b3IiLCJvdXRjb21lIiwicHJlZGljdG9yT3ZlcnBsb3QiLCJvdXRjb21lT3ZlcnBsb3QiKV0pCmBgYAoKIyMgRWZmZWN0IFBsb3RzCgojIyMgTXVsdGlwbGUgUmVncmVzc2lvbiBNb2RlbAoKYGBge3J9Cm11bHRpcGxlUmVncmVzc2lvbk1vZGVsIDwtIGxtKG91dGNvbWUgfiBwcmVkaWN0b3IgKyBwcmVkaWN0b3JPdmVycGxvdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEuYWN0aW9uID0gIm5hLmV4Y2x1ZGUiKQoKYWxsRWZmZWN0cyhtdWx0aXBsZVJlZ3Jlc3Npb25Nb2RlbCkKcGxvdChhbGxFZmZlY3RzKG11bHRpcGxlUmVncmVzc2lvbk1vZGVsKSkKYGBgCgojIyMgTXVsdGlsZXZlbCBSZWdyZXNzaW9uIE1vZGVsCgpgYGB7cn0KbXVsdGlsZXZlbFJlZ3Jlc3Npb25Nb2RlbCA8LSBsbWUob3V0Y29tZSB+IHByZWRpY3RvciArIHByZWRpY3Rvck92ZXJwbG90LCByYW5kb20gPSB+IDF8SUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJNTCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLmFjdGlvbiA9ICJuYS5leGNsdWRlIikKCmFsbEVmZmVjdHMobXVsdGlsZXZlbFJlZ3Jlc3Npb25Nb2RlbCkKcGxvdChhbGxFZmZlY3RzKG11bHRpbGV2ZWxSZWdyZXNzaW9uTW9kZWwpKQpgYGAKCiMgU2Vzc2lvbiBJbmZvCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CnNlc3Npb25JbmZvKCkKYGBgCg==



Developmental Psychopathology Lab