1 Preamble

1.1 Install Libraries

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

1.2 Load Libraries

library("tidyverse")
library("psych")
library("mice")
library("micemd")
library("miceadds")
library("mitml")
library("Amelia")
library("jomo")
library("parallel")
library("future")
library("furrr")
library("nlme")
library("MplusAutomation")

1.3 Data

data(Oxboys, package = "nlme")

Oxboys_addNA <- data.frame(Oxboys)
Oxboys_addNA <- Oxboys_addNA %>% 
  rename(id = Subject)

Oxboys_addNA$id <- as.integer(Oxboys_addNA$id)
Oxboys_addNA$Occasion <- as.integer(Oxboys_addNA$Occasion)

set.seed(52242)
Oxboys_addNA[sample(1:nrow(Oxboys_addNA), 25), "height"] <- NA

dataToImpute <- Oxboys_addNA
varsToImpute <- c("height")
Y <- varsToImpute

2 Types of Missingness

  1. Missing Completely at Random (MCAR)
    • the probability of being missing is the same for all cases
    • missingness is not related to variables in the model
  2. (Conditionally) Missing at Random (MAR)
    • missingness is related to variables in the model, but once we condition on the variables in the model, the missingness is haphazard
    • the unobserved values do not play a role
  3. Missing Not at Random (MNAR)
    • missingness is related to variables that are not in the model (i.e., for reasons that are unknown)
    • unobserved variables carry information about whether a case will have missing data

3 Approaches to Handle Missing Data

3.1 For MCAR/MAR Missingness

  1. Full Information Maximum Likelihood (FIML)
  2. Multiple Imputation

3.2 For MNAR Missingness

https://stefvanbuuren.name/fimd/sec-nonignorable.html (archived at https://perma.cc/N7WW-HDZF)

https://cran.r-project.org/web/packages/missingHE/vignettes/Fitting_MNAR_models_in_missingHE.html (archived at https://perma.cc/9X25-5D8G)

  1. find more data about the causes for the missingness
  2. sensitivity analyses (what-if analyses) to see how sensitive the results are under various scenarios
  3. selection models
    • simultaneously estimate the focal model and a missingness model, where the missingness model has the missing data indicator as a dependent variable, as predicted by the original dependent variable, the original predictors, and any additional covariates etc.
    • if the missingness model is approximately correct, the focal model adjusts in way that removes nonresponse bias
    • similar to a mediation process
      • X → Y
      • Y → missingness
      • X → missingness
    • https://quantitudepod.org/s4e08-craig-enders/ (archived at https://perma.cc/FY9L-L3F7)
  4. pattern-mixture models
    • missing data indicator is a predictor variable
    • similar to a moderation process; subgroups of cases have different parameter estimates

4 Approaches to Multiple Imputation

  • multiple imputation by joint modeling
    • assumes that the variables in follow a joint distribution, e.g.:
      • multivariate normal (i.e., multivariate normal imputation)
    • R packages:
      • jomo
      • pan
      • Amelia
      • Mplus
  • multiple imputation by chained equations
    • aka:
      • fully conditional specification multiple imputation
      • sequential regression multiple imputation
    • R packages:
      • mice
        • predictive mean matching (?mice::mice.impute.pmm) can be useful to obtain bounded imputations for non-normally distributed variables

5 Describe Missing Data

describe(dataToImpute)
md.pattern(dataToImpute, rotate.names = TRUE)

    id age Occasion height   
209  1   1        1      1  0
25   1   1        1      0  1
     0   0        0     25 25

6 Pre-Imputation Setup

6.1 Specify Number of Imputations

numImputations <- 5 # generally use 100 imputations; this example uses 5 for speed

6.2 Detect Cores

numCores <- parallel::detectCores() - 1

7 Multilevel Multiple Imputation

7.2 Methods

7.2.1 mice

7.2.1.1 Types

7.2.1.1.1 Continuous Outcomes

https://stefvanbuuren.name/fimd/sec-multioutcome.html#methods (archived at https://perma.cc/8CDA-TS3K)

?mice::mice.impute.2l.norm
?mice::mice.impute.2l.pan
?mice::mice.impute.2l.lmer
?miceadds::mice.impute.2l.pmm
?miceadds::mice.impute.2l.contextual.pmm
?miceadds::mice.impute.2l.continuous
?micemd::mice.impute.2l.2stage.norm
?micemd::mice.impute.2l.2stage.pmm
?micemd::mice.impute.2l.glm.norm
?micemd::mice.impute.2l.jomo
7.2.1.1.2 Binary Outcomes

https://stefvanbuuren.name/fimd/sec-catoutcome.html#methods-1 (archived at https://perma.cc/5QHF-YRP6)

?mice::mice.impute.2l.bin
?miceadds::mice.impute.2l.binary
?miceadds::mice.impute.2l.pmm
?miceadds::mice.impute.2l.contextual.pmm
?micemd::mice.impute.2l.2stage.bin
?micemd::mice.impute.2l.glm.bin
7.2.1.1.3 Ordinal Outcomes

https://stefvanbuuren.name/fimd/sec-multioutcome.html#methods (archived at https://perma.cc/8CDA-TS3K)

?miceadds::mice.impute.2l.pmm
?miceadds::mice.impute.2l.contextual.pmm
?micemd::mice.impute.2l.2stage.pmm
7.2.1.1.4 Count Outcomes

https://stefvanbuuren.name/fimd/sec-catoutcome.html#methods-1 (archived at https://perma.cc/5QHF-YRP6)

?micemd::mice.impute.2l.2stage.pois
?micemd::mice.impute.2l.glm.pois
?countimp::mice.impute.2l.poisson
?countimp::mice.impute.2l.nb2
?countimp::mice.impute.2l.zihnb

7.2.1.2 Specifying the Imputation Method

meth <- make.method(dataToImpute)
meth[1:length(meth)] <- ""
meth[Y] <- "2l.pmm" # specify the imputation method here; this can differ by outcome variable

7.2.1.3 Specifying the Predictor Matrix

A predictor matrix is a matrix of values, where:

  • columns with non-zero values are predictors of the variable specified in the given row
  • the diagonal of the predictor matrix should be zero because a variable cannot predict itself

The values are:

  • NOT a predictor of the outcome: 0
  • cluster variable: -2
  • fixed effect of predictor: 1
  • fixed effect and random effect of predictor: 2
  • include cluster mean of predictor in addition to fixed effect of predictor: 3
  • include cluster mean of predictor in addition to fixed effect and random effect of predictor: 4
pred <- make.predictorMatrix(dataToImpute)
pred[1:nrow(pred), 1:ncol(pred)] <- 0
pred[Y, "id"] <- (-2) # cluster variable
pred[Y, "Occasion"] <- 1 # fixed effect predictor
pred[Y, "age"] <- 2 # random effect predictor
pred[Y, Y] <- 1 # fixed effect predictor

diag(pred) <- 0
pred
         id age height Occasion
id        0   0      0        0
age       0   0      0        0
height   -2   2      0        1
Occasion  0   0      0        0

7.2.1.4 Syntax

mi_mice <- mice(
  as.data.frame(dataToImpute),
  method = meth,
  predictorMatrix = pred,
  m = numImputations,
  maxit = 5, # generally use 100 maximum iterations; this example uses 5 for speed
  seed = 52242)

 iter imp variable
  1   1  height
  1   2  height
  1   3  height
  1   4  height
  1   5  height
  2   1  height
  2   2  height
  2   3  height
  2   4  height
  2   5  height
  3   1  height
  3   2  height
  3   3  height
  3   4  height
  3   5  height
  4   1  height
  4   2  height
  4   3  height
  4   4  height
  4   5  height
  5   1  height
  5   2  height
  5   3  height
  5   4  height
  5   5  height

7.2.2 jomo

level1Vars <- c("height")
level2Vars <- c("v3","v4")
clusterVars <- c("id")
fullyObservedCovariates <- c("age","Occasion")

set.seed(52242)

mi_jomo <- jomo(
  Y = data.frame(dataToImpute[, level1Vars]),
  #Y2 = data.frame(dataToImpute[, level2Vars]),
  X = data.frame(dataToImpute[, fullyObservedCovariates]),
  clus = data.frame(dataToImpute[, clusterVars]),
  nimp = numImputations,
  meth = "random"
)
Clustered data, using functions for two-level imputation.
Found  1 continuous outcomes and no categorical. Using function jomo1ranconhr with random cluster-specific covariance matrices. 
..................................................
..................................................
First imputation registered. 
..................................................
..................................................
Imputation number  2 registered 
..................................................
..................................................
Imputation number  3 registered 
..................................................
..................................................
Imputation number  4 registered 
..................................................
..................................................
Imputation number  5 registered 
The posterior mean of the fixed effects estimates is:
                                 age Occasion
dataToImpute...level1Vars. -113.0757 30.04838

The posterior mean of the random effects estimates is:
   dataToImpute...level1Vars..Z1
1                   -16.20902733
2                    -8.65212774
3                    -6.73361991
4                    -8.48037088
5                    -4.01165035
6                    -0.82193207
7                    -1.06273621
8                    -4.25225948
9                    -0.08327231
10                   -3.34891121
11                    2.57532592
12                    3.66401069
13                    0.48966344
14                    3.47497904
15                    3.90412653
16                    3.19938056
17                    2.40548040
18                    3.27865186
19                    6.09683973
20                    5.55557617
21                    6.75778040
22                    8.90157501
23                    8.52601382
24                   10.62696736
25                   16.84089878
26                   17.23746838

The posterior mean of the level 1 covariance matrices is:
                              dataToImpute...level1Vars.
dataToImpute...level1Vars..1                    20.55420
dataToImpute...level1Vars..2                    21.18287
dataToImpute...level1Vars..3                    15.70618
dataToImpute...level1Vars..4                    25.93674
dataToImpute...level1Vars..5                    20.32710
dataToImpute...level1Vars..6                    25.51296
dataToImpute...level1Vars..7                    23.47148
dataToImpute...level1Vars..8                    22.76608
dataToImpute...level1Vars..9                    24.07566
dataToImpute...level1Vars..10                   26.87790
dataToImpute...level1Vars..11                   20.55911
dataToImpute...level1Vars..12                   21.56772
dataToImpute...level1Vars..13                   24.82955
dataToImpute...level1Vars..14                   17.19218
dataToImpute...level1Vars..15                   21.30695
dataToImpute...level1Vars..16                   25.49398
dataToImpute...level1Vars..17                   21.73770
dataToImpute...level1Vars..18                   20.28903
dataToImpute...level1Vars..19                   22.74839
dataToImpute...level1Vars..20                   24.93717
dataToImpute...level1Vars..21                   19.27750
dataToImpute...level1Vars..22                   17.73270
dataToImpute...level1Vars..23                   21.87620
dataToImpute...level1Vars..24                   20.96218
dataToImpute...level1Vars..25                   18.61259
dataToImpute...level1Vars..26                   20.21037

The posterior mean of the level 2 covariance matrix is:
                              dataToImpute...level1Vars..Z1
dataToImpute...level1Vars.*Z1                      66.59035

7.2.3 Amelia

  • ! in the console output indicates that the current estimated complete data covariance matrix is not invertible
  • * in the console output indicates that the likelihood has not monotonically increased in that step
boundVars <- c("height")
boundCols <- which(names(dataToImpute) %in% boundVars)
boundLower <- 100
boundUpper <- 200

varBounds <- cbind(boundCols, boundLower, boundUpper)

set.seed(52242)

mi_amelia <- amelia(
  dataToImpute,
  m = numImputations,
  ts = "age",
  cs = "id",
  polytime = 1,
  intercs = TRUE,
  #ords = ordinalVars,
  #bounds = varBounds,
  parallel = "snow",
  #ncpus = numCores,
  empri = .01*nrow(dataToImpute)) # ridge prior for numerical stability
-- Imputation 1 --

  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
 21

-- Imputation 2 --

  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18

-- Imputation 3 --

  1  2  3  4  5  6  7  8

-- Imputation 4 --

  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
 121 122 123

-- Imputation 5 --

  1  2  3  4  5  6  7  8  9 10 11 12

7.2.4 Mplus

7.2.4.1 Save Mplus Data File

Save R object as Mplus data file:

prepareMplusData(dataToImpute, file.path("dataToImpute.dat"))
TITLE: Your title goes here
DATA: FILE = "dataToImpute.dat";
VARIABLE: 
NAMES = id age height Occasion; 
MISSING=.;

7.2.4.2 Mplus Syntax for Multilevel Imputation

Mplus syntax for multilevel imputation:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!  MPLUS SYNTAX LINES CANNOT EXCEED 90 CHARACTERS;
!!!!!  VARIABLE NAMES AND PARAMETER LABELS CANNOT EXCEED 8 CHARACTERS EACH;
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

TITLE: Model Title

DATA: FILE = "dataToImpute.dat";

VARIABLE:
  NAMES = id age height Occasion;
  MISSING = .;
  USEVARIABLES ARE age height Occasion;
  !CATEGORICAL ARE INSERT_NAMES_OF_CATEGORICAL_VARIABLES_HERE;
  CLUSTER = id;

ANALYSIS:
  TYPE = twolevel basic;
  bseed = 52242;
  PROCESSORS = 2;
    
DATA IMPUTATION:
  IMPUTE = age(0-100) height Occasion; !put ' (c)' after categorical vars
  NDATASETS = 100;
  SAVE = imp*.dat

Putting a range of values after a variable (e.g., 0-100) sets the lower and upper bounds of the imputed values. This would save a implist.dat file that can be used to run the model on the multiply imputed data, as shown here.

8 Parallel Processing

https://www.gerkovink.com/miceVignettes/futuremice/Vignette_futuremice.html (archived at https://perma.cc/4SNE-RCSR)

mi_parallel_mice <- futuremice(
  dataToImpute,
  method = meth,
  predictorMatrix = pred,
  m = numImputations,
  maxit = 5, # generally use 100 maximum iterations; this example uses 5 for speed
  parallelseed = 52242,
  n.core = numCores,
  packages = "miceadds")

9 Imputation Diagnostics

9.1 Logged Events

mi_mice$loggedEvents
NULL

9.2 Trace Plots

On convergence, the streams of the trace plots should intermingle and be free of any trend (at the later iterations). Convergence is diagnosed when the variance between different sequences is no larger than the variance within each individual sequence.

plot(mi_mice, c("height"))

9.3 Density Plots

densityplot(mi_mice)

densityplot(mi_mice, ~ height)

9.4 Strip Plots

stripplot(mi_mice)

stripplot(mi_mice, height ~ .imp)

10 Post-Processing

10.1 Modify/Create New Variables

10.1.1 mice

mi_mice_long <- complete(
  mi_mice,
  action = "long",
  include = TRUE)

mi_mice_long$newVar <- mi_mice_long$age * mi_mice_long$height

10.1.2 jomo

mi_jomo <- mi_jomo %>% 
  rename(height = dataToImpute...level1Vars.)

mi_jomo$newVar <- mi_jomo$age * mi_jomo$height

10.1.3 Amelia

for(i in 1:length(mi_amelia$imputations)){
  mi_amelia$imputations[[i]]$newVar <- mi_amelia$imputations[[i]]$age * mi_amelia$imputations[[i]]$height
}

10.2 Convert to mids object

10.2.1 mice

mi_mice_mids <- as.mids(mi_mice_long)

10.2.2 jomo

mi_jomo_mids <- miceadds::jomo2mids(mi_jomo)
Warning: Number of logged events: 1

10.2.3 Amelia

mi_amelia_mids <- miceadds::datlist2mids(mi_amelia$imputations)

10.3 Export for Mplus

mids2mplus(mi_mice_mids, path = file.path("InsertFilePathHere", fsep = ""))
mids2mplus(mi_jomo_mids, path = file.path("InsertFilePathHere", fsep = ""))
mids2mplus(mi_amelia_mids, path = file.path("InsertFilePathHere", fsep = ""))
LS0tCnRpdGxlOiAiTXVsdGlwbGUgSW1wdXRhdGlvbiIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgZXJyb3IgPSBUUlVFLAogIGNvbW1lbnQgPSAiIiwKICBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IikKYGBgCgojIFByZWFtYmxlCgojIyBJbnN0YWxsIExpYnJhcmllcwoKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCJyZW1vdGVzIikKI3JlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJEZXZQc3lMYWIvcGV0ZXJzZW5sYWIiKQpgYGAKCiMjIExvYWQgTGlicmFyaWVzCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoInBzeWNoIikKbGlicmFyeSgibWljZSIpCmxpYnJhcnkoIm1pY2VtZCIpCmxpYnJhcnkoIm1pY2VhZGRzIikKbGlicmFyeSgibWl0bWwiKQpsaWJyYXJ5KCJBbWVsaWEiKQpsaWJyYXJ5KCJqb21vIikKbGlicmFyeSgicGFyYWxsZWwiKQpsaWJyYXJ5KCJmdXR1cmUiKQpsaWJyYXJ5KCJmdXJyciIpCmxpYnJhcnkoIm5sbWUiKQpsaWJyYXJ5KCJNcGx1c0F1dG9tYXRpb24iKQpgYGAKCiMjIERhdGEKCmBgYHtyfQpkYXRhKE94Ym95cywgcGFja2FnZSA9ICJubG1lIikKCk94Ym95c19hZGROQSA8LSBkYXRhLmZyYW1lKE94Ym95cykKT3hib3lzX2FkZE5BIDwtIE94Ym95c19hZGROQSAlPiUgCiAgcmVuYW1lKGlkID0gU3ViamVjdCkKCk94Ym95c19hZGROQSRpZCA8LSBhcy5pbnRlZ2VyKE94Ym95c19hZGROQSRpZCkKT3hib3lzX2FkZE5BJE9jY2FzaW9uIDwtIGFzLmludGVnZXIoT3hib3lzX2FkZE5BJE9jY2FzaW9uKQoKc2V0LnNlZWQoNTIyNDIpCk94Ym95c19hZGROQVtzYW1wbGUoMTpucm93KE94Ym95c19hZGROQSksIDI1KSwgImhlaWdodCJdIDwtIE5BCgpkYXRhVG9JbXB1dGUgPC0gT3hib3lzX2FkZE5BCnZhcnNUb0ltcHV0ZSA8LSBjKCJoZWlnaHQiKQpZIDwtIHZhcnNUb0ltcHV0ZQpgYGAKCiMgVHlwZXMgb2YgTWlzc2luZ25lc3MKCjEuIE1pc3NpbmcgQ29tcGxldGVseSBhdCBSYW5kb20gKE1DQVIpCiAgICAtIHRoZSBwcm9iYWJpbGl0eSBvZiBiZWluZyBtaXNzaW5nIGlzIHRoZSBzYW1lIGZvciBhbGwgY2FzZXMKICAgIC0gbWlzc2luZ25lc3MgaXMgbm90IHJlbGF0ZWQgdG8gdmFyaWFibGVzIGluIHRoZSBtb2RlbAoxLiAoQ29uZGl0aW9uYWxseSkgTWlzc2luZyBhdCBSYW5kb20gKE1BUikKICAgIC0gbWlzc2luZ25lc3MgaXMgcmVsYXRlZCB0byB2YXJpYWJsZXMgaW4gdGhlIG1vZGVsLCBidXQgb25jZSB3ZSBjb25kaXRpb24gb24gdGhlIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwsIHRoZSBtaXNzaW5nbmVzcyBpcyBoYXBoYXphcmQKICAgIC0gdGhlIHVub2JzZXJ2ZWQgdmFsdWVzIGRvIG5vdCBwbGF5IGEgcm9sZQoxLiBNaXNzaW5nIE5vdCBhdCBSYW5kb20gKE1OQVIpCiAgICAtIG1pc3NpbmduZXNzIGlzIHJlbGF0ZWQgdG8gdmFyaWFibGVzIHRoYXQgYXJlIG5vdCBpbiB0aGUgbW9kZWwgKGkuZS4sIGZvciByZWFzb25zIHRoYXQgYXJlIHVua25vd24pCiAgICAtIHVub2JzZXJ2ZWQgdmFyaWFibGVzIGNhcnJ5IGluZm9ybWF0aW9uIGFib3V0IHdoZXRoZXIgYSBjYXNlIHdpbGwgaGF2ZSBtaXNzaW5nIGRhdGEKCiMgQXBwcm9hY2hlcyB0byBIYW5kbGUgTWlzc2luZyBEYXRhCgojIyBGb3IgTUNBUi9NQVIgTWlzc2luZ25lc3MKCjEuIEZ1bGwgSW5mb3JtYXRpb24gTWF4aW11bSBMaWtlbGlob29kIChGSU1MKQoxLiBNdWx0aXBsZSBJbXB1dGF0aW9uCgojIyBGb3IgTU5BUiBNaXNzaW5nbmVzcwoKaHR0cHM6Ly9zdGVmdmFuYnV1cmVuLm5hbWUvZmltZC9zZWMtbm9uaWdub3JhYmxlLmh0bWwgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvTjdXVy1IRFpGKQoKaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21pc3NpbmdIRS92aWduZXR0ZXMvRml0dGluZ19NTkFSX21vZGVsc19pbl9taXNzaW5nSEUuaHRtbCAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85WDI1LTVEOEcpCgoxLiBmaW5kIG1vcmUgZGF0YSBhYm91dCB0aGUgY2F1c2VzIGZvciB0aGUgbWlzc2luZ25lc3MKMS4gc2Vuc2l0aXZpdHkgYW5hbHlzZXMgKHdoYXQtaWYgYW5hbHlzZXMpIHRvIHNlZSBob3cgc2Vuc2l0aXZlIHRoZSByZXN1bHRzIGFyZSB1bmRlciB2YXJpb3VzIHNjZW5hcmlvcwogICAgLSBodHRwczovL3N0ZWZ2YW5idXVyZW4ubmFtZS9maW1kL3NlYy1NQ0FSLmh0bWwgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvOUtNOS0zTlgzKQoxLiBzZWxlY3Rpb24gbW9kZWxzCiAgICAtIHNpbXVsdGFuZW91c2x5IGVzdGltYXRlIHRoZSBmb2NhbCBtb2RlbCBhbmQgYSBtaXNzaW5nbmVzcyBtb2RlbCwgd2hlcmUgdGhlIG1pc3NpbmduZXNzIG1vZGVsIGhhcyB0aGUgbWlzc2luZyBkYXRhIGluZGljYXRvciBhcyBhIGRlcGVuZGVudCB2YXJpYWJsZSwgYXMgcHJlZGljdGVkIGJ5IHRoZSBvcmlnaW5hbCBkZXBlbmRlbnQgdmFyaWFibGUsIHRoZSBvcmlnaW5hbCBwcmVkaWN0b3JzLCBhbmQgYW55IGFkZGl0aW9uYWwgY292YXJpYXRlcyBldGMuCiAgICAtIGlmIHRoZSBtaXNzaW5nbmVzcyBtb2RlbCBpcyBhcHByb3hpbWF0ZWx5IGNvcnJlY3QsIHRoZSBmb2NhbCBtb2RlbCBhZGp1c3RzIGluIHdheSB0aGF0IHJlbW92ZXMgbm9ucmVzcG9uc2UgYmlhcwogICAgLSBzaW1pbGFyIHRvIGEgbWVkaWF0aW9uIHByb2Nlc3MKICAgICAgICAtIFgg4oaSIFkKICAgICAgICAtIFkg4oaSIG1pc3NpbmduZXNzCiAgICAgICAgLSBYIOKGkiBtaXNzaW5nbmVzcwogICAgLSBodHRwczovL3F1YW50aXR1ZGVwb2Qub3JnL3M0ZTA4LWNyYWlnLWVuZGVycy8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvRlk5TC1MM0Y3KQoxLiBwYXR0ZXJuLW1peHR1cmUgbW9kZWxzCiAgICAtIG1pc3NpbmcgZGF0YSBpbmRpY2F0b3IgaXMgYSBwcmVkaWN0b3IgdmFyaWFibGUKICAgIC0gc2ltaWxhciB0byBhIG1vZGVyYXRpb24gcHJvY2Vzczsgc3ViZ3JvdXBzIG9mIGNhc2VzIGhhdmUgZGlmZmVyZW50IHBhcmFtZXRlciBlc3RpbWF0ZXMKCiMgQXBwcm9hY2hlcyB0byBNdWx0aXBsZSBJbXB1dGF0aW9uCgotIG11bHRpcGxlIGltcHV0YXRpb24gYnkgam9pbnQgbW9kZWxpbmcKICAgIC0gYXNzdW1lcyB0aGF0IHRoZSB2YXJpYWJsZXMgaW4gZm9sbG93IGEgam9pbnQgZGlzdHJpYnV0aW9uLCBlLmcuOgogICAgICAgIC0gbXVsdGl2YXJpYXRlIG5vcm1hbCAoaS5lLiwgbXVsdGl2YXJpYXRlIG5vcm1hbCBpbXB1dGF0aW9uKQogICAgLSBgUmAgcGFja2FnZXM6CiAgICAgICAgLSBgam9tb2AKICAgICAgICAtIGBwYW5gCiAgICAgICAgLSBgQW1lbGlhYAogICAgICAgIC0gYE1wbHVzYAotIG11bHRpcGxlIGltcHV0YXRpb24gYnkgY2hhaW5lZCBlcXVhdGlvbnMKICAgIC0gYWthOgogICAgICAgIC0gZnVsbHkgY29uZGl0aW9uYWwgc3BlY2lmaWNhdGlvbiBtdWx0aXBsZSBpbXB1dGF0aW9uCiAgICAgICAgLSBzZXF1ZW50aWFsIHJlZ3Jlc3Npb24gbXVsdGlwbGUgaW1wdXRhdGlvbgogICAgLSBgUmAgcGFja2FnZXM6CiAgICAgICAgLSBgbWljZWAKICAgICAgICAgICAgLSBwcmVkaWN0aXZlIG1lYW4gbWF0Y2hpbmcgKGA/bWljZTo6bWljZS5pbXB1dGUucG1tYCkgY2FuIGJlIHVzZWZ1bCB0byBvYnRhaW4gYm91bmRlZCBpbXB1dGF0aW9ucyBmb3Igbm9uLW5vcm1hbGx5IGRpc3RyaWJ1dGVkIHZhcmlhYmxlcwoKIyBEZXNjcmliZSBNaXNzaW5nIERhdGEKCmBgYHtyfQpkZXNjcmliZShkYXRhVG9JbXB1dGUpCm1kLnBhdHRlcm4oZGF0YVRvSW1wdXRlLCByb3RhdGUubmFtZXMgPSBUUlVFKQpgYGAKCiMgUHJlLUltcHV0YXRpb24gU2V0dXAKCiMjIFNwZWNpZnkgTnVtYmVyIG9mIEltcHV0YXRpb25zCgpgYGB7cn0KbnVtSW1wdXRhdGlvbnMgPC0gNSAjIGdlbmVyYWxseSB1c2UgMTAwIGltcHV0YXRpb25zOyB0aGlzIGV4YW1wbGUgdXNlcyA1IGZvciBzcGVlZApgYGAKCiMjIERldGVjdCBDb3JlcwoKYGBge3J9Cm51bUNvcmVzIDwtIHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpIC0gMQpgYGAKCiMgTXVsdGlsZXZlbCBNdWx0aXBsZSBJbXB1dGF0aW9uCgojIyBUaHJlZS1MZXZlbCBhbmQgQ3Jvc3MtQ2xhc3NpZmllZCBEYXRhCgpodHRwczovL3NpbW9uZ3J1bmQxLmdpdGh1Yi5pby9wb3N0cy9tdWx0aXBsZS1pbXB1dGF0aW9uLWZvci10aHJlZS1sZXZlbC1hbmQtY3Jvc3MtY2xhc3NpZmllZC1kYXRhLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9ONFBQLUEzVjYpCgojIyBNZXRob2RzCgojIyMgYG1pY2VgIHsjbWljZX0KCiMjIyMgVHlwZXMKCiMjIyMjIENvbnRpbnVvdXMgT3V0Y29tZXMKCmh0dHBzOi8vc3RlZnZhbmJ1dXJlbi5uYW1lL2ZpbWQvc2VjLW11bHRpb3V0Y29tZS5odG1sI21ldGhvZHMgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvOENEQS1UUzNLKQoKYGBge3IsIGV2YWwgPSBGQUxTRX0KP21pY2U6Om1pY2UuaW1wdXRlLjJsLm5vcm0KP21pY2U6Om1pY2UuaW1wdXRlLjJsLnBhbgo/bWljZTo6bWljZS5pbXB1dGUuMmwubG1lcgo/bWljZWFkZHM6Om1pY2UuaW1wdXRlLjJsLnBtbQo/bWljZWFkZHM6Om1pY2UuaW1wdXRlLjJsLmNvbnRleHR1YWwucG1tCj9taWNlYWRkczo6bWljZS5pbXB1dGUuMmwuY29udGludW91cwo/bWljZW1kOjptaWNlLmltcHV0ZS4ybC4yc3RhZ2Uubm9ybQo/bWljZW1kOjptaWNlLmltcHV0ZS4ybC4yc3RhZ2UucG1tCj9taWNlbWQ6Om1pY2UuaW1wdXRlLjJsLmdsbS5ub3JtCj9taWNlbWQ6Om1pY2UuaW1wdXRlLjJsLmpvbW8KYGBgCgojIyMjIyBCaW5hcnkgT3V0Y29tZXMKCmh0dHBzOi8vc3RlZnZhbmJ1dXJlbi5uYW1lL2ZpbWQvc2VjLWNhdG91dGNvbWUuaHRtbCNtZXRob2RzLTEgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNVFIRi1ZUlA2KQoKYGBge3IsIGV2YWwgPSBGQUxTRX0KP21pY2U6Om1pY2UuaW1wdXRlLjJsLmJpbgo/bWljZWFkZHM6Om1pY2UuaW1wdXRlLjJsLmJpbmFyeQo/bWljZWFkZHM6Om1pY2UuaW1wdXRlLjJsLnBtbQo/bWljZWFkZHM6Om1pY2UuaW1wdXRlLjJsLmNvbnRleHR1YWwucG1tCj9taWNlbWQ6Om1pY2UuaW1wdXRlLjJsLjJzdGFnZS5iaW4KP21pY2VtZDo6bWljZS5pbXB1dGUuMmwuZ2xtLmJpbgpgYGAKCiMjIyMjIE9yZGluYWwgT3V0Y29tZXMKCmh0dHBzOi8vc3RlZnZhbmJ1dXJlbi5uYW1lL2ZpbWQvc2VjLW11bHRpb3V0Y29tZS5odG1sI21ldGhvZHMgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvOENEQS1UUzNLKQoKYGBge3IsIGV2YWwgPSBGQUxTRX0KP21pY2VhZGRzOjptaWNlLmltcHV0ZS4ybC5wbW0KP21pY2VhZGRzOjptaWNlLmltcHV0ZS4ybC5jb250ZXh0dWFsLnBtbQo/bWljZW1kOjptaWNlLmltcHV0ZS4ybC4yc3RhZ2UucG1tCmBgYAoKIyMjIyMgQ291bnQgT3V0Y29tZXMKCmh0dHBzOi8vc3RlZnZhbmJ1dXJlbi5uYW1lL2ZpbWQvc2VjLWNhdG91dGNvbWUuaHRtbCNtZXRob2RzLTEgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNVFIRi1ZUlA2KQoKYGBge3IsIGV2YWwgPSBGQUxTRX0KP21pY2VtZDo6bWljZS5pbXB1dGUuMmwuMnN0YWdlLnBvaXMKP21pY2VtZDo6bWljZS5pbXB1dGUuMmwuZ2xtLnBvaXMKP2NvdW50aW1wOjptaWNlLmltcHV0ZS4ybC5wb2lzc29uCj9jb3VudGltcDo6bWljZS5pbXB1dGUuMmwubmIyCj9jb3VudGltcDo6bWljZS5pbXB1dGUuMmwuemlobmIKYGBgCgojIyMjIFNwZWNpZnlpbmcgdGhlIEltcHV0YXRpb24gTWV0aG9kCgpgYGB7cn0KbWV0aCA8LSBtYWtlLm1ldGhvZChkYXRhVG9JbXB1dGUpCm1ldGhbMTpsZW5ndGgobWV0aCldIDwtICIiCm1ldGhbWV0gPC0gIjJsLnBtbSIgIyBzcGVjaWZ5IHRoZSBpbXB1dGF0aW9uIG1ldGhvZCBoZXJlOyB0aGlzIGNhbiBkaWZmZXIgYnkgb3V0Y29tZSB2YXJpYWJsZQpgYGAKCiMjIyMgU3BlY2lmeWluZyB0aGUgUHJlZGljdG9yIE1hdHJpeAoKQSBwcmVkaWN0b3IgbWF0cml4IGlzIGEgbWF0cml4IG9mIHZhbHVlcywgd2hlcmU6CgotIGNvbHVtbnMgd2l0aCBub24temVybyB2YWx1ZXMgYXJlIHByZWRpY3RvcnMgb2YgdGhlIHZhcmlhYmxlIHNwZWNpZmllZCBpbiB0aGUgZ2l2ZW4gcm93Ci0gdGhlIGRpYWdvbmFsIG9mIHRoZSBwcmVkaWN0b3IgbWF0cml4IHNob3VsZCBiZSB6ZXJvIGJlY2F1c2UgYSB2YXJpYWJsZSBjYW5ub3QgcHJlZGljdCBpdHNlbGYKClRoZSB2YWx1ZXMgYXJlOgoKLSBOT1QgYSBwcmVkaWN0b3Igb2YgdGhlIG91dGNvbWU6IGAwYAotIGNsdXN0ZXIgdmFyaWFibGU6IGAtMmAKLSBmaXhlZCBlZmZlY3Qgb2YgcHJlZGljdG9yOiBgMWAKLSBmaXhlZCBlZmZlY3QgYW5kIHJhbmRvbSBlZmZlY3Qgb2YgcHJlZGljdG9yOiBgMmAKLSBpbmNsdWRlIGNsdXN0ZXIgbWVhbiBvZiBwcmVkaWN0b3IgaW4gYWRkaXRpb24gdG8gZml4ZWQgZWZmZWN0IG9mIHByZWRpY3RvcjogYDNgCi0gaW5jbHVkZSBjbHVzdGVyIG1lYW4gb2YgcHJlZGljdG9yIGluIGFkZGl0aW9uIHRvIGZpeGVkIGVmZmVjdCBhbmQgcmFuZG9tIGVmZmVjdCBvZiBwcmVkaWN0b3I6IGA0YAoKYGBge3J9CnByZWQgPC0gbWFrZS5wcmVkaWN0b3JNYXRyaXgoZGF0YVRvSW1wdXRlKQpwcmVkWzE6bnJvdyhwcmVkKSwgMTpuY29sKHByZWQpXSA8LSAwCnByZWRbWSwgImlkIl0gPC0gKC0yKSAjIGNsdXN0ZXIgdmFyaWFibGUKcHJlZFtZLCAiT2NjYXNpb24iXSA8LSAxICMgZml4ZWQgZWZmZWN0IHByZWRpY3RvcgpwcmVkW1ksICJhZ2UiXSA8LSAyICMgcmFuZG9tIGVmZmVjdCBwcmVkaWN0b3IKcHJlZFtZLCBZXSA8LSAxICMgZml4ZWQgZWZmZWN0IHByZWRpY3RvcgoKZGlhZyhwcmVkKSA8LSAwCnByZWQKYGBgCgojIyMjIFN5bnRheAoKYGBge3J9Cm1pX21pY2UgPC0gbWljZSgKICBhcy5kYXRhLmZyYW1lKGRhdGFUb0ltcHV0ZSksCiAgbWV0aG9kID0gbWV0aCwKICBwcmVkaWN0b3JNYXRyaXggPSBwcmVkLAogIG0gPSBudW1JbXB1dGF0aW9ucywKICBtYXhpdCA9IDUsICMgZ2VuZXJhbGx5IHVzZSAxMDAgbWF4aW11bSBpdGVyYXRpb25zOyB0aGlzIGV4YW1wbGUgdXNlcyA1IGZvciBzcGVlZAogIHNlZWQgPSA1MjI0MikKYGBgCgojIyMgYGpvbW9gIHsjam9tb30KCmBgYHtyfQpsZXZlbDFWYXJzIDwtIGMoImhlaWdodCIpCmxldmVsMlZhcnMgPC0gYygidjMiLCJ2NCIpCmNsdXN0ZXJWYXJzIDwtIGMoImlkIikKZnVsbHlPYnNlcnZlZENvdmFyaWF0ZXMgPC0gYygiYWdlIiwiT2NjYXNpb24iKQoKc2V0LnNlZWQoNTIyNDIpCgptaV9qb21vIDwtIGpvbW8oCiAgWSA9IGRhdGEuZnJhbWUoZGF0YVRvSW1wdXRlWywgbGV2ZWwxVmFyc10pLAogICNZMiA9IGRhdGEuZnJhbWUoZGF0YVRvSW1wdXRlWywgbGV2ZWwyVmFyc10pLAogIFggPSBkYXRhLmZyYW1lKGRhdGFUb0ltcHV0ZVssIGZ1bGx5T2JzZXJ2ZWRDb3ZhcmlhdGVzXSksCiAgY2x1cyA9IGRhdGEuZnJhbWUoZGF0YVRvSW1wdXRlWywgY2x1c3RlclZhcnNdKSwKICBuaW1wID0gbnVtSW1wdXRhdGlvbnMsCiAgbWV0aCA9ICJyYW5kb20iCikKYGBgCgojIyMgYEFtZWxpYWAgeyNhbWVsaWF9CgotIGAhYCBpbiB0aGUgY29uc29sZSBvdXRwdXQgaW5kaWNhdGVzIHRoYXQgdGhlIGN1cnJlbnQgZXN0aW1hdGVkIGNvbXBsZXRlIGRhdGEgY292YXJpYW5jZSBtYXRyaXggaXMgbm90IGludmVydGlibGUKLSBgKmAgaW4gdGhlIGNvbnNvbGUgb3V0cHV0IGluZGljYXRlcyB0aGF0IHRoZSBsaWtlbGlob29kIGhhcyBub3QgbW9ub3RvbmljYWxseSBpbmNyZWFzZWQgaW4gdGhhdCBzdGVwCgpgYGB7cn0KYm91bmRWYXJzIDwtIGMoImhlaWdodCIpCmJvdW5kQ29scyA8LSB3aGljaChuYW1lcyhkYXRhVG9JbXB1dGUpICVpbiUgYm91bmRWYXJzKQpib3VuZExvd2VyIDwtIDEwMApib3VuZFVwcGVyIDwtIDIwMAoKdmFyQm91bmRzIDwtIGNiaW5kKGJvdW5kQ29scywgYm91bmRMb3dlciwgYm91bmRVcHBlcikKCnNldC5zZWVkKDUyMjQyKQoKbWlfYW1lbGlhIDwtIGFtZWxpYSgKICBkYXRhVG9JbXB1dGUsCiAgbSA9IG51bUltcHV0YXRpb25zLAogIHRzID0gImFnZSIsCiAgY3MgPSAiaWQiLAogIHBvbHl0aW1lID0gMSwKICBpbnRlcmNzID0gVFJVRSwKICAjb3JkcyA9IG9yZGluYWxWYXJzLAogICNib3VuZHMgPSB2YXJCb3VuZHMsCiAgcGFyYWxsZWwgPSAic25vdyIsCiAgI25jcHVzID0gbnVtQ29yZXMsCiAgZW1wcmkgPSAuMDEqbnJvdyhkYXRhVG9JbXB1dGUpKSAjIHJpZGdlIHByaW9yIGZvciBudW1lcmljYWwgc3RhYmlsaXR5CmBgYAoKIyMjIGBNcGx1c2AgeyNtcGx1c30KCiMjIyMgU2F2ZSBgTXBsdXNgIERhdGEgRmlsZQoKU2F2ZSBgUmAgb2JqZWN0IGFzIGBNcGx1c2AgZGF0YSBmaWxlOgoKYGBge3J9CnByZXBhcmVNcGx1c0RhdGEoZGF0YVRvSW1wdXRlLCBmaWxlLnBhdGgoImRhdGFUb0ltcHV0ZS5kYXQiKSkKYGBgCgojIyMjIGBNcGx1c2AgU3ludGF4IGZvciBNdWx0aWxldmVsIEltcHV0YXRpb24KCmBNcGx1c2Agc3ludGF4IGZvciBtdWx0aWxldmVsIGltcHV0YXRpb246CgpgYGBNcGx1cwohISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhCiEhISEhICBNUExVUyBTWU5UQVggTElORVMgQ0FOTk9UIEVYQ0VFRCA5MCBDSEFSQUNURVJTOwohISEhISAgVkFSSUFCTEUgTkFNRVMgQU5EIFBBUkFNRVRFUiBMQUJFTFMgQ0FOTk9UIEVYQ0VFRCA4IENIQVJBQ1RFUlMgRUFDSDsKISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhIQoKVElUTEU6IE1vZGVsIFRpdGxlCgpEQVRBOiBGSUxFID0gImRhdGFUb0ltcHV0ZS5kYXQiOwoKVkFSSUFCTEU6CiAgTkFNRVMgPSBpZCBhZ2UgaGVpZ2h0IE9jY2FzaW9uOwogIE1JU1NJTkcgPSAuOwogIFVTRVZBUklBQkxFUyBBUkUgYWdlIGhlaWdodCBPY2Nhc2lvbjsKICAhQ0FURUdPUklDQUwgQVJFIElOU0VSVF9OQU1FU19PRl9DQVRFR09SSUNBTF9WQVJJQUJMRVNfSEVSRTsKICBDTFVTVEVSID0gaWQ7CgpBTkFMWVNJUzoKICBUWVBFID0gdHdvbGV2ZWwgYmFzaWM7CiAgYnNlZWQgPSA1MjI0MjsKICBQUk9DRVNTT1JTID0gMjsKICAgIApEQVRBIElNUFVUQVRJT046CiAgSU1QVVRFID0gYWdlKDAtMTAwKSBoZWlnaHQgT2NjYXNpb247ICFwdXQgJyAoYyknIGFmdGVyIGNhdGVnb3JpY2FsIHZhcnMKICBOREFUQVNFVFMgPSAxMDA7CiAgU0FWRSA9IGltcCouZGF0CmBgYAoKUHV0dGluZyBhIHJhbmdlIG9mIHZhbHVlcyBhZnRlciBhIHZhcmlhYmxlIChlLmcuLCBgMC0xMDBgKSBzZXRzIHRoZSBsb3dlciBhbmQgdXBwZXIgYm91bmRzIG9mIHRoZSBpbXB1dGVkIHZhbHVlcy4KVGhpcyB3b3VsZCBzYXZlIGEgYGltcGxpc3QuZGF0YCBmaWxlIHRoYXQgY2FuIGJlIHVzZWQgdG8gcnVuIHRoZSBtb2RlbCBvbiB0aGUgbXVsdGlwbHkgaW1wdXRlZCBkYXRhLCBhcyBzaG93biBbaGVyZV0obXBsdXMuaHRtbCNtdWx0aXBsZUltcHV0YXRpb24pLgoKIyBQYXJhbGxlbCBQcm9jZXNzaW5nCgpodHRwczovL3d3dy5nZXJrb3ZpbmsuY29tL21pY2VWaWduZXR0ZXMvZnV0dXJlbWljZS9WaWduZXR0ZV9mdXR1cmVtaWNlLmh0bWwgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNFNORS1SQ1NSKQoKYGBge3J9Cm1pX3BhcmFsbGVsX21pY2UgPC0gZnV0dXJlbWljZSgKICBkYXRhVG9JbXB1dGUsCiAgbWV0aG9kID0gbWV0aCwKICBwcmVkaWN0b3JNYXRyaXggPSBwcmVkLAogIG0gPSBudW1JbXB1dGF0aW9ucywKICBtYXhpdCA9IDUsICMgZ2VuZXJhbGx5IHVzZSAxMDAgbWF4aW11bSBpdGVyYXRpb25zOyB0aGlzIGV4YW1wbGUgdXNlcyA1IGZvciBzcGVlZAogIHBhcmFsbGVsc2VlZCA9IDUyMjQyLAogIG4uY29yZSA9IG51bUNvcmVzLAogIHBhY2thZ2VzID0gIm1pY2VhZGRzIikKYGBgCgojIEltcHV0YXRpb24gRGlhZ25vc3RpY3MKCiMjIExvZ2dlZCBFdmVudHMKCmBgYHtyfQptaV9taWNlJGxvZ2dlZEV2ZW50cwpgYGAKCiMjIFRyYWNlIFBsb3RzCgpPbiBjb252ZXJnZW5jZSwgdGhlIHN0cmVhbXMgb2YgdGhlIHRyYWNlIHBsb3RzIHNob3VsZCBpbnRlcm1pbmdsZSBhbmQgYmUgZnJlZSBvZiBhbnkgdHJlbmQgKGF0IHRoZSBsYXRlciBpdGVyYXRpb25zKS4KQ29udmVyZ2VuY2UgaXMgZGlhZ25vc2VkIHdoZW4gdGhlIHZhcmlhbmNlIGJldHdlZW4gZGlmZmVyZW50IHNlcXVlbmNlcyBpcyBubyBsYXJnZXIgdGhhbiB0aGUgdmFyaWFuY2Ugd2l0aGluIGVhY2ggaW5kaXZpZHVhbCBzZXF1ZW5jZS4KCi0gaHR0cHM6Ly9zdGVmdmFuYnV1cmVuLm5hbWUvZmltZC9zZWMtYWxnb3B0aW9ucy5odG1sIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzRTNTQtNDY1UikKCmBgYHtyfQpwbG90KG1pX21pY2UsIGMoImhlaWdodCIpKQpgYGAKCiMjIERlbnNpdHkgUGxvdHMKCmBgYHtyfQpkZW5zaXR5cGxvdChtaV9taWNlKQpkZW5zaXR5cGxvdChtaV9taWNlLCB+IGhlaWdodCkKYGBgCgojIyBTdHJpcCBQbG90cwoKYGBge3J9CnN0cmlwcGxvdChtaV9taWNlKQpzdHJpcHBsb3QobWlfbWljZSwgaGVpZ2h0IH4gLmltcCkKYGBgCgojIFBvc3QtUHJvY2Vzc2luZwoKIyMgTW9kaWZ5L0NyZWF0ZSBOZXcgVmFyaWFibGVzCgojIyMgYG1pY2VgCgpgYGB7cn0KbWlfbWljZV9sb25nIDwtIGNvbXBsZXRlKAogIG1pX21pY2UsCiAgYWN0aW9uID0gImxvbmciLAogIGluY2x1ZGUgPSBUUlVFKQoKbWlfbWljZV9sb25nJG5ld1ZhciA8LSBtaV9taWNlX2xvbmckYWdlICogbWlfbWljZV9sb25nJGhlaWdodApgYGAKCiMjIyBgam9tb2AKCmBgYHtyfQptaV9qb21vIDwtIG1pX2pvbW8gJT4lIAogIHJlbmFtZShoZWlnaHQgPSBkYXRhVG9JbXB1dGUuLi5sZXZlbDFWYXJzLikKCm1pX2pvbW8kbmV3VmFyIDwtIG1pX2pvbW8kYWdlICogbWlfam9tbyRoZWlnaHQKYGBgCgojIyMgYEFtZWxpYWAKCmBgYHtyfQpmb3IoaSBpbiAxOmxlbmd0aChtaV9hbWVsaWEkaW1wdXRhdGlvbnMpKXsKICBtaV9hbWVsaWEkaW1wdXRhdGlvbnNbW2ldXSRuZXdWYXIgPC0gbWlfYW1lbGlhJGltcHV0YXRpb25zW1tpXV0kYWdlICogbWlfYW1lbGlhJGltcHV0YXRpb25zW1tpXV0kaGVpZ2h0Cn0KYGBgCgojIyBDb252ZXJ0IHRvIGBtaWRzYCBvYmplY3QKCiMjIyBgbWljZWAKCmBgYHtyfQptaV9taWNlX21pZHMgPC0gYXMubWlkcyhtaV9taWNlX2xvbmcpCmBgYAoKIyMjIGBqb21vYAoKYGBge3J9Cm1pX2pvbW9fbWlkcyA8LSBtaWNlYWRkczo6am9tbzJtaWRzKG1pX2pvbW8pCmBgYAoKIyMjIGBBbWVsaWFgCgpgYGB7cn0KbWlfYW1lbGlhX21pZHMgPC0gbWljZWFkZHM6OmRhdGxpc3QybWlkcyhtaV9hbWVsaWEkaW1wdXRhdGlvbnMpCmBgYAoKIyMgRXhwb3J0IGZvciBgTXBsdXNgCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQptaWRzMm1wbHVzKG1pX21pY2VfbWlkcywgcGF0aCA9IGZpbGUucGF0aCgiSW5zZXJ0RmlsZVBhdGhIZXJlIiwgZnNlcCA9ICIiKSkKbWlkczJtcGx1cyhtaV9qb21vX21pZHMsIHBhdGggPSBmaWxlLnBhdGgoIkluc2VydEZpbGVQYXRoSGVyZSIsIGZzZXAgPSAiIikpCm1pZHMybXBsdXMobWlfYW1lbGlhX21pZHMsIHBhdGggPSBmaWxlLnBhdGgoIkluc2VydEZpbGVQYXRoSGVyZSIsIGZzZXAgPSAiIikpCmBgYAoKIyBSZXNvdXJjZXMKCmh0dHBzOi8vc3RlZnZhbmJ1dXJlbi5uYW1lL2ZpbWQgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNDZVMi1RVE02KQoKaHR0cHM6Ly93d3cuZ2Vya292aW5rLmNvbS9taWNlVmlnbmV0dGVzL011bHRpX2xldmVsL011bHRpX2xldmVsX2RhdGEuaHRtbCAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9TRjMyLUQ3WkYpCg==



Developmental Psychopathology Lab