Setup

Required Packages

knitr::opts_chunk$set(echo = TRUE)
#--loading my packages
if (!require("pacman")) install.packages("pacman")
library(pacman)
# Load installed packages, install and load the package if not installed
pacman::p_load(here, rio, conflicted, tidyverse, janitor, summarytools, skimr, 
               DataExplorer, inspectdf, Hmisc, readr, dplyr, tinytex,
               # loading SEM related packages
               lavaan, semTools, semoutput, semPlot, sjPlot, psych, 
               GPArotation, psychTools, semptools, lm.beta)

Background

The statistician George Box famously said “All models are wrong, but some models are useful”. This statement is particularly applicable to SEM. By definition, models are simplified representations of phenomena. Models need to be simple enough to facilitate our understanding of the phenomenon under study, but not so simple that we miss important, often subtle, aspects of the phenomenon.

When working within the SEM framework we postulate a model to account for the pattern of variances and covariances we observe in a set of relevant variables. Confirming that our model fits the data is the desired result, but we must keep in mind that our model may be one of several that could explain the data. So, while we can rule out some models because they do not fit the data, we cannot claim that our model is the model simply because it is consistent with the observed data.

In summarizing the strategic framework for testing structural equation models, Karl Joreskog distinguished between three scenarios that he called strictly confirmatory (SC), alternative models (AM), and model generating (MG).

In the SC mode the researcher postulates a single model based on theory, collects the data, then tests the fit of the hypothesized model to the sample data. Based on the results of this test, the researcher either rejects or fails to reject the model; no further modifications to the model are made.

In the AM mode, the researcher proposes several alternative (i.e., competing) models, all of which are grounded in theory. Following analysis of a single sample he/she selects one model as most appropriate.

The model generating (MG) mode represents the case where the researcher, having postulated and rejected a model on the basis of poor fit, proceeds in an exploratory fashion to modify and re-estimate the model. This involves inspection of what are called modification indices. MG mode is typically atheoretic and data-driven.

In this lecture we start with the SC case. We propose and test a model; we will either accept or reject it. (Heads up, the hypothesized model does not fit well.) This will provide opportunity to demonstrate how one may go about the MG approach. Finally, we examine a second hypothesized model (now we are working from the AM perspective) and compare it to the initial hypothesized model.

The Example

The Rosenburg Self-Esteem Scale contains 10 items hypothesized to measure Self-Esteem as a uni-dimensional construct. Here are the items, response scale options and citation. Note that to control for response set bias, five of the items are negatively worded (and reverse scored) while five are positively worded. The sample size for analyses is 973.

Reading in the Data

The data are in the form of a correlation matrix plus a vector of standard deviations. These are combined to form a covariance matrix for analysis.

corr <- '
1.000
.158 1.000
.463  .220 1.000
.302  .288  .296 1.000
.407  .293  .422  .348 1.000
.234  .285  .245  .319  .370 1.000
.332  .216  .359  .450  .359  .385 1.000
.388  .134  .417  .246  .354  .213  .313 1.000
.325  .245  .335  .368  .386  .457  .509  .243 1.000
.401  .212  .429  .295  .487  .285  .410  .382  .383 1.000
'
# add variable names and convert to full correlation matrix
corrfull <- lavaan::getCov(corr, names=c('v1','v2','v3','v4','v5','v6','v7','v8','v9','v10'))
# add SDs and convert to full covariance matrix
covfull <- lavaan::cor2cov(corrfull, sds=c(0.732,1.106,0.819,0.948,0.929,0.860,0.824,0.738,0.851,0.864))
# MEANS; not used 3.78 2.96 4.09 4.00 3.80 3.37 4.30 3.92 4.07 4.02   # N = 973

The Correlations

Here are the observed correlations among the 10 items, labeled v1 to v10.

# Uses sjPlot to print a nice looking correlation table
tab_corr(corrfull, na.deletion = "listwise", digits = 2, triangle = "lower",
         title="Correlations among Self-Esteem Items",
         string.diag=c('1','1','1','1','1','1','1','1','1','1'))
Correlations among Self-Esteem Items
  v1 v2 v3 v4 v5 v6 v7 v8 v9 v10
v1 1                  
v2 0.16 1                
v3 0.46 0.22 1              
v4 0.30 0.29 0.30 1            
v5 0.41 0.29 0.42 0.35 1          
v6 0.23 0.28 0.24 0.32 0.37 1        
v7 0.33 0.22 0.36 0.45 0.36 0.38 1      
v8 0.39 0.13 0.42 0.25 0.35 0.21 0.31 1    
v9 0.32 0.24 0.34 0.37 0.39 0.46 0.51 0.24 1  
v10 0.40 0.21 0.43 0.29 0.49 0.28 0.41 0.38 0.38 1
Computed correlation used pearson-method with listwise-deletion.

The CFA Model

The hypothesis to be tested is that the items making up the scale measure a uni-dimensional construct, Self-Esteem. A confirmatory factor model where all 10 items load onto a single latent variable and their residual variance terms are uncorrelated represents this hypothesis. We run the model; if it fits well we have support for our hypothesis, if the model fit is poor then our hypothesis of a single underlying factor is rejected.

Specify and run the model:

model1 <- ' SE  =~ v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 '
fit1 <- cfa(model1, sample.cov=covfull, sample.nobs=973, std.lv=F )

Path Diagram Model 1

#--making CFA path diagram---------------------mar(bot,lft,top,rgt)
fig1 <-semPlot::semPaths(fit1, whatLabels = "std", layout = "tree2", 
                         rotation = 1, style = "lisrel", optimizeLatRes = T, 
                         structural = F, layoutSplit = F,
                         intercepts = F, residuals = T, 
                         curve = 1, curvature = 3, nCharNodes = 8, 
                         sizeLat = 8, sizeMan = 6, sizeMan2 = 6, 
                         edge.label.cex = 0.9, label.cex=1.1, residScale=10, mar=c(19,2,19,2), 
                         edge.color = "black", edge.label.position = .60, DoNotPlot=T)
fig1.1 <- fig1 |> mark_sig(fit1, alpha = c("(n.s.)" = 1.00, "*" = .05))
plot(fig1.1)  

Note that the path connecting the latent factor with v1 is dashed. This is to indicate that v1 was used as a “reference variable” to define the metric of the latent variable, so there is no test of significance associated with it. The loadings range from .38 to .66. The residual terms, estimating the proportion of variance in each item that is not associated with the latent factor range from .58 to .86. v2 has considerable measurement error in comparison to the other items.

Full output 1

summary(fit1, fit.measures=T, standardized=T, rsquare=T)
## lavaan 0.6.16 ended normally after 32 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        20
## 
##   Number of observations                           973
## 
## Model Test User Model:
##                                                       
##   Test statistic                               283.142
##   Degrees of freedom                                35
##   P-value (Chi-square)                           0.000
## 
## Model Test Baseline Model:
## 
##   Test statistic                              2603.344
##   Degrees of freedom                                45
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.903
##   Tucker-Lewis Index (TLI)                       0.875
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)             -11187.810
##   Loglikelihood unrestricted model (H1)     -11046.239
##                                                       
##   Akaike (AIC)                               22415.620
##   Bayesian (BIC)                             22513.228
##   Sample-size adjusted Bayesian (SABIC)      22449.708
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.085
##   90 Percent confidence interval - lower         0.076
##   90 Percent confidence interval - upper         0.095
##   P-value H_0: RMSEA <= 0.050                    0.000
##   P-value H_0: RMSEA >= 0.080                    0.838
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.052
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   SE =~                                                                 
##     v1                1.000                               0.430    0.587
##     v2                0.971    0.096   10.097    0.000    0.417    0.377
##     v3                1.177    0.079   14.964    0.000    0.506    0.618
##     v4                1.214    0.088   13.748    0.000    0.521    0.550
##     v5                1.436    0.091   15.726    0.000    0.617    0.664
##     v6                1.057    0.079   13.330    0.000    0.454    0.528
##     v7                1.242    0.080   15.459    0.000    0.533    0.648
##     v8                0.897    0.068   13.206    0.000    0.385    0.522
##     v9                1.247    0.082   15.169    0.000    0.536    0.630
##     v10               1.304    0.084   15.477    0.000    0.560    0.649
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .v1                0.351    0.018   19.895    0.000    0.351    0.655
##    .v2                1.048    0.049   21.377    0.000    1.048    0.858
##    .v3                0.414    0.021   19.517    0.000    0.414    0.618
##    .v4                0.626    0.031   20.274    0.000    0.626    0.697
##    .v5                0.482    0.026   18.804    0.000    0.482    0.559
##    .v6                0.533    0.026   20.467    0.000    0.533    0.721
##    .v7                0.394    0.021   19.083    0.000    0.394    0.581
##    .v8                0.396    0.019   20.520    0.000    0.396    0.727
##    .v9                0.436    0.023   19.349    0.000    0.436    0.603
##    .v10               0.432    0.023   19.065    0.000    0.432    0.579
##     SE                0.185    0.020    9.297    0.000    1.000    1.000
## 
## R-Square:
##                    Estimate
##     v1                0.345
##     v2                0.142
##     v3                0.382
##     v4                0.303
##     v5                0.441
##     v6                0.279
##     v7                0.419
##     v8                0.273
##     v9                0.397
##     v10               0.421

The \(\chi^2_{M1}\) = 283.124 with df = 35, p < .001. Based on the significance of the \(\chi^2_{M1}\) test we reject the model, however the value of \(\chi^2_{M1}\) is influenced by sample size so we examine other fit indices.
The RSMEA = .085 , TLI = .875, CFI = .903, SRMR = .052. There is considerable room for improvement in fit; the RMSEA and SRMR could be smaller, and the TLI (and CFI) could be larger.
So, from a strictly confirmatory perspective (SC) we conclude that the covariance structure of the Self-Esteem Scale items is more complex than a uni-dimensional model with a single latent variable.

Reliability 1

The semTools package has a command compRelSEM to obtain reliability estimates such as Cronbach’s \(\alpha\) coefficient.

semTools::compRelSEM(fit1, tau.eq=T, obs.var=T, return.total=F) 
##    SE 
## 0.827

In this sample the reliability of the scale is estimated by \(\alpha\) = .827.

Residual Correlations 1

The values below are the residual correlations (i.e., observed correlation - model estimated correlation). The average absolute values of these residuals is provided by the standardized root mean square residual (SRMR). Note that the largest residual correlation (.12) is between v6 and v9. While semoutput::sem_residuals() makes a nice table, I don’t believe that we can change the number of digits; it is limited to only two. More precise values (3 digits) are shown in the output from lavResiduals() below.

semoutput::sem_residuals(fit1)
v1 v2 v3 v4 v5 v6 v7 v8 v9 v10
v1
v2 -0.06
v3 0.10 -0.01
v4 -0.02 0.08 -0.04
v5 0.02 0.04 0.01 -0.02
v6 -0.08 0.09 -0.08 0.03 0.02
v7 -0.05 -0.03 -0.04 0.09 -0.07 0.04
v8 0.08 -0.06 0.09 -0.04 0.01 -0.06 -0.03
v9 -0.04 0.01 -0.05 0.02 -0.03 0.12 0.10 -0.09
v10 0.02 -0.03 0.03 -0.06 0.06 -0.06 -0.01 0.04 -0.03

Analysis of Residuals 1

The output below displays residual correlations and z-scores indicating the magnitude of the residuals. Typically, z values > |2.58| (which is the two-tailed critical value for \(\alpha = .01\)) are interpreted as significant and indicate where the model is doing a poor job of reproducing the observed correlations.

lavResiduals(fit1, type = "cor.bollen")
## $type
## [1] "cor.bollen"
## 
## $cov
##         v1     v2     v3     v4     v5     v6     v7     v8     v9    v10
## v1   0.000                                                               
## v2  -0.064  0.000                                                        
## v3   0.100 -0.013  0.000                                                 
## v4  -0.021  0.080 -0.044  0.000                                          
## v5   0.017  0.042  0.012 -0.018  0.000                                   
## v6  -0.076  0.086 -0.082  0.028  0.019  0.000                            
## v7  -0.048 -0.028 -0.041  0.094 -0.071  0.043  0.000                     
## v8   0.081 -0.063  0.094 -0.041  0.007 -0.063 -0.025  0.000              
## v9  -0.045  0.007 -0.054  0.021 -0.033  0.124  0.101 -0.086  0.000       
## v10  0.020 -0.033  0.028 -0.062  0.056 -0.058 -0.010  0.043 -0.026  0.000
## 
## $cov.z
##         v1     v2     v3     v4     v5     v6     v7     v8     v9    v10
## v1   0.000                                                               
## v2  -2.879  0.000                                                        
## v3   5.229 -0.616  0.000                                                 
## v4  -1.094  3.369 -2.408  0.000                                          
## v5   1.015  2.079  0.727 -1.024  0.000                                   
## v6  -3.932  3.512 -4.402  1.345  1.056  0.000                            
## v7  -2.921 -1.394 -2.602  4.926 -5.035  2.292  0.000                     
## v8   3.907 -2.655  4.655 -2.002  0.400 -2.990 -1.385  0.000              
## v9  -2.630  0.341 -3.351  1.154 -2.157  6.111  5.758 -4.706  0.000       
## v10  1.168 -1.615  1.696 -3.600  3.524 -3.265 -0.658  2.303 -1.644  0.000
## 
## $summary
##                            cov
## crmr                     0.057
## crmr.se                  0.002
## crmr.exactfit.z         15.799
## crmr.exactfit.pvalue     0.000
## ucrmr                    0.054
## ucrmr.se                 0.005
## ucrmr.ci.lower           0.047
## ucrmr.cilupper           0.062
## ucrmr.closefit.h0.value  0.050
## ucrmr.closefit.z         0.918
## ucrmr.closefit.pvalue    0.179

Notice that the largest residual correlation (.124) between v6 and v9 has the largest z value associated with it (6.111). In other words, the model is doing a poor job of reproducing this correlation.

Ideally the residual correlations should be normally distributed with a mean of 0.0. One way to examine the distribution of these residuals is with a stem-and-leaf plot which is a type of sideways histogram. The first 2 digits of each residual correlation are to the left of the | symbol and are referred to as the stem. The third digit of each residual correlation is to the right of the | and is referred to as a leaf. The plot shows the number (and value) of the leaves for each stem. Note that there are no decimal points in the plot; the implied decimal point is two digits to the left of the | symbol.

stem( lavResiduals(fit1, output = "table")$res ) # gives stem/leaf plot of resid cors
## 
##   The decimal point is 2 digit(s) to the left of the |
## 
##    -8 | 62
##    -6 | 614332
##    -4 | 8485411
##    -2 | 338651
##    -0 | 830
##     0 | 77279
##     2 | 0188
##     4 | 2336
##     6 | 
##     8 | 01644
##    10 | 01
##    12 | 4

For example in the first row of the plot there are two residuals for which the first two digits are -.08 and the third digits are 6 and 2, printed to the right of the | symbol. These two residual correlations are thus -.086 and -.082. The largest positive residual correlation .124 appears in the last row as “12 | 4”. This distribution is far from being normal.

Looking at the entire plot shows how many residuals begin with the same stem value. So, there are two that start with -.08, six that start with -.06, seven that start with -.04, five that start with .00, etc.

Modification Indices 1

The values below indicate the drop in \(\chi^2_M\) (i.e., model improvement) anticipated if parameters currently fixed at 0.0 are freed to be estimated; all freely estimated parameters automatically have an MI of zero. Note that lhs op rhs refers to the variable on the left hand side and on the right hand side of the operation symbol ~~ which indicates a correlation between the residual variances of two items. The critical value of \(\chi^2\) with df = 1 and \(\alpha\) = .05 is 3.841, so any MI greater than this value is worth examination.

modificationIndices(fit1, sort. = TRUE, minimum.value = 3)
##    lhs op rhs     mi    epc sepc.lv sepc.all sepc.nox
## 59  v6 ~~  v9 43.804  0.115   0.115    0.239    0.239
## 62  v7 ~~  v9 40.031  0.100   0.100    0.241    0.241
## 23  v1 ~~  v3 31.612  0.079   0.079    0.206    0.206
## 48  v4 ~~  v7 27.683  0.096   0.096    0.193    0.193
## 43  v3 ~~  v8 24.152  0.071   0.071    0.176    0.176
## 53  v5 ~~  v7 22.438 -0.080  -0.080   -0.185   -0.185
## 64  v8 ~~  v9 20.753 -0.068  -0.068   -0.164   -0.164
## 41  v3 ~~  v6 18.246 -0.072  -0.072   -0.154   -0.154
## 28  v1 ~~  v8 16.553  0.054   0.054    0.144    0.144
## 26  v1 ~~  v6 14.713 -0.059  -0.059   -0.136   -0.136
## 56  v5 ~~ v10 13.975  0.066   0.066    0.146    0.146
## 34  v2 ~~  v6 12.909  0.091   0.091    0.122    0.122
## 51  v4 ~~ v10 12.165 -0.067  -0.067   -0.128   -0.128
## 32  v2 ~~  v4 11.887  0.095   0.095    0.118    0.118
## 44  v3 ~~  v9 10.491 -0.052  -0.052   -0.121   -0.121
## 60  v6 ~~ v10 10.097 -0.056  -0.056   -0.116   -0.116
## 58  v6 ~~  v8  8.670 -0.047  -0.047   -0.103   -0.103
## 22  v1 ~~  v2  8.098 -0.059  -0.059   -0.098   -0.098
## 27  v1 ~~  v7  8.044 -0.039  -0.039   -0.106   -0.106
## 36  v2 ~~  v8  6.931 -0.057  -0.057   -0.089   -0.089
## 29  v1 ~~  v9  6.589 -0.037  -0.037   -0.095   -0.095
## 42  v3 ~~  v7  6.385 -0.039  -0.039   -0.096   -0.096
## 65  v8 ~~ v10  5.584  0.036   0.036    0.086    0.086
## 39  v3 ~~  v4  5.569 -0.043  -0.043   -0.085   -0.085
## 57  v6 ~~  v7  5.505  0.039   0.039    0.086    0.086
## 33  v2 ~~  v5  4.467  0.053   0.053    0.075    0.075
## 55  v5 ~~  v9  4.407 -0.037  -0.037   -0.081   -0.081
## 49  v4 ~~  v8  3.909 -0.034  -0.034   -0.069   -0.069
## 45  v3 ~~ v10  3.009  0.028   0.028    0.066    0.066

Here the largest MI is listed first and it suggests that if we re-run the model and allow the residual terms between v6 and v9 to correlate, the \(\chi^2_M\) is expected to decrease by about 43.80. The other columns show the expected value (epc) of the parameter if it were to be estimated. Note that this finding confirms what we saw when inspecting the residual correlations; the residual correlation between v6 and v9 was the largest.
The heading sepc.lv is the value if the latent variabl(s) are standardized and the column heading sepc.all gives the completely standardized values. So the anticipated covariance and correlation between these two residual terms, if this parameter where to be estimated, are .115, .239, respectively.

A Revised Model

Here we are operating in the MG mode; our re-specification is atheoretic and simply data-driven. Nonetheless, we illustrate how one might specify and fit such a model.

Re-Specify and Re-Run the model:
I added one additional parameter v6 ~~ v9, the correlation between the residual variances of these two items because the MI from Model 1 indicated that doing so would have the greatest impact on improving model fit. There is no theoretical rationale for adding this type of parameter because in traditional CFA models the residual terms are assumed to be independent (i.e., uncorrelated).

model2 <- ' SE  =~ v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10
            v6 ~~ v9 '
fit2 <- cfa(model2, sample.cov=covfull, sample.nobs=973, std.lv=F )

Path Diagram Model 2

#--making CFA path diagram---------------------mar(bot,lft,top,rgt)
fig2 <-semPlot::semPaths(fit2, whatLabels = "std", layout = "tree2", 
                         rotation = 1, style = "lisrel", optimizeLatRes = T, 
                         structural = F, layoutSplit = F,
                         intercepts = F, residuals = T, 
                         curve = 1, curvature = 3, nCharNodes = 8, 
                         sizeLat = 8, sizeMan = 6, sizeMan2 = 6, 
                         edge.label.cex = 0.9, label.cex=1.1, residScale=10, mar=c(19,2,19,2), 
                         edge.color = "black", edge.label.position = .60, DoNotPlot=T)
fig2.1 <- fig2 |> mark_sig(fit2, alpha = c("(n.s.)" = 1.00, "*" = .05))
plot(fig2.1)  

Note that the correlation between the two residuals is .23, as was suggested by the MI from Model 1.

Full output 2

summary(fit2, fit.measures=T, standardized=T, rsquare=T)
## lavaan 0.6.16 ended normally after 32 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        21
## 
##   Number of observations                           973
## 
## Model Test User Model:
##                                                       
##   Test statistic                               239.464
##   Degrees of freedom                                34
##   P-value (Chi-square)                           0.000
## 
## Model Test Baseline Model:
## 
##   Test statistic                              2603.344
##   Degrees of freedom                                45
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.920
##   Tucker-Lewis Index (TLI)                       0.894
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)             -11165.971
##   Loglikelihood unrestricted model (H1)     -11046.239
##                                                       
##   Akaike (AIC)                               22373.942
##   Bayesian (BIC)                             22476.430
##   Sample-size adjusted Bayesian (SABIC)      22409.734
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.079
##   90 Percent confidence interval - lower         0.070
##   90 Percent confidence interval - upper         0.088
##   P-value H_0: RMSEA <= 0.050                    0.000
##   P-value H_0: RMSEA >= 0.080                    0.430
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.049
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   SE =~                                                                 
##     v1                1.000                               0.438    0.598
##     v2                0.940    0.094   10.000    0.000    0.411    0.372
##     v3                1.179    0.077   15.319    0.000    0.516    0.630
##     v4                1.182    0.086   13.772    0.000    0.517    0.546
##     v5                1.418    0.089   15.956    0.000    0.620    0.668
##     v6                0.968    0.077   12.617    0.000    0.424    0.493
##     v7                1.202    0.078   15.464    0.000    0.526    0.639
##     v8                0.899    0.066   13.523    0.000    0.394    0.534
##     v9                1.171    0.079   14.796    0.000    0.512    0.602
##     v10               1.297    0.082   15.779    0.000    0.568    0.657
## 
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##  .v6 ~~                                                                 
##    .v9                0.117    0.019    6.260    0.000    0.117    0.230
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .v1                0.344    0.017   19.669    0.000    0.344    0.642
##    .v2                1.053    0.049   21.371    0.000    1.053    0.861
##    .v3                0.404    0.021   19.230    0.000    0.404    0.603
##    .v4                0.630    0.031   20.238    0.000    0.630    0.702
##    .v5                0.477    0.026   18.591    0.000    0.477    0.554
##    .v6                0.559    0.027   20.567    0.000    0.559    0.757
##    .v7                0.402    0.021   19.101    0.000    0.402    0.592
##    .v8                0.389    0.019   20.355    0.000    0.389    0.715
##    .v9                0.461    0.024   19.534    0.000    0.461    0.637
##    .v10               0.424    0.023   18.788    0.000    0.424    0.568
##     SE                0.192    0.020    9.475    0.000    1.000    1.000
## 
## R-Square:
##                    Estimate
##     v1                0.358
##     v2                0.139
##     v3                0.397
##     v4                0.298
##     v5                0.446
##     v6                0.243
##     v7                0.408
##     v8                0.285
##     v9                0.363
##     v10               0.432

The \(\chi^2_{M2}\) = 239.464 with df = 34, p < .001.
The RSMEA = .079, TLI = .894, CFI = .920, SRMR = .049. So, the fit is somewhat improved relative to Model 1. A formal test comparing the two models is shown below.

Residual Correlations 2

The values below are the residual correlations (i.e., observed correlation - model estimated correlation). The average absolute values of these residuals is provided by the standardized root mean square residual (SRMR). Note that the residual correlation between v6 and v9 is now 0.00.

sem_residuals(fit2)
v1 v2 v3 v4 v5 v6 v7 v8 v9 v10
v1
v2 -0.06
v3 0.09 -0.01
v4 -0.02 0.08 -0.05
v5 0.01 0.04 0.00 -0.02
v6 -0.06 0.10 -0.07 0.05 0.04
v7 -0.05 -0.02 -0.04 0.10 -0.07 0.07
v8 0.07 -0.06 0.08 -0.05 0.00 -0.05 -0.03
v9 -0.04 0.02 -0.04 0.04 -0.02 0.00 0.12 -0.08
v10 0.01 -0.03 0.01 -0.06 0.05 -0.04 -0.01 0.03 -0.01

Analysis of Residuals 2

The output below displays residual correlations and z-scores indicating the magnitude of the residuals. Typically, z values > |2.58| are interpreted as significant and indicate where the model is doing a poor job of reproducing the observed correlations.

lavResiduals(fit2, type = "cor.bollen")
## $type
## [1] "cor.bollen"
## 
## $cov
##         v1     v2     v3     v4     v5     v6     v7     v8     v9    v10
## v1   0.000                                                               
## v2  -0.065  0.000                                                        
## v3   0.086 -0.015  0.000                                                 
## v4  -0.025  0.085 -0.048  0.000                                          
## v5   0.007  0.044  0.001 -0.017  0.000                                   
## v6  -0.061  0.102 -0.066  0.050  0.041  0.000                            
## v7  -0.050 -0.022 -0.043  0.101 -0.068  0.070  0.000                     
## v8   0.069 -0.065  0.081 -0.045 -0.002 -0.050 -0.028  0.000              
## v9  -0.035  0.021 -0.045  0.039 -0.017  0.000  0.124 -0.078  0.000       
## v10  0.008 -0.033  0.015 -0.064  0.048 -0.039 -0.010  0.031 -0.013  0.000
## 
## $cov.z
##         v1     v2     v3     v4     v5     v6     v7     v8     v9    v10
## v1   0.000                                                               
## v2  -2.972  0.000                                                        
## v3   4.700 -0.693  0.000                                                 
## v4  -1.304  3.532 -2.703  0.000                                          
## v5   0.457  2.192  0.063 -0.999  0.000                                   
## v6  -3.108  4.027 -3.539  2.279  2.225  0.000                            
## v7  -3.062 -1.050 -2.796  5.233 -4.805  3.492  0.000                     
## v8   3.419 -2.752  4.145 -2.231 -0.144 -2.361 -1.537  0.000              
## v9  -2.041  0.937 -2.733  2.005 -1.053  0.000  6.634 -4.214  0.000       
## v10  0.477 -1.633  0.941 -3.800  3.126 -2.174 -0.642  1.731 -0.818  0.000
## 
## $summary
##                            cov
## crmr                     0.054
## crmr.se                  0.002
## crmr.exactfit.z         14.435
## crmr.exactfit.pvalue     0.000
## ucrmr                    0.051
## ucrmr.se                 0.005
## ucrmr.ci.lower           0.043
## ucrmr.cilupper           0.058
## ucrmr.closefit.h0.value  0.050
## ucrmr.closefit.z         0.115
## ucrmr.closefit.pvalue    0.454

Modification Indices 2

The values may have changed from those derived from the first model.The values below indicate the drop in \(\chi^2_M\) (i.e., model improvement) anticipated if parameters currently fixed at 0.0 are freed to be estimated. Note that lhs op rhs refers to the variable on the left hand side and on the right hand side of the operation symbol ~~ which indicates a correlation between the residual variances of two items. The critical value of \(\chi^2\) with df = 1 and \(\alpha = .05\) is 3.841, so any MI greater than this value is worth examination.

modificationIndices(fit2, sort. = TRUE, minimum.value = 3)
##    lhs op rhs     mi    epc sepc.lv sepc.all sepc.nox
## 62  v7 ~~  v9 43.209  0.102   0.102    0.236    0.236
## 49  v4 ~~  v7 31.570  0.104   0.104    0.207    0.207
## 24  v1 ~~  v3 25.358  0.070   0.070    0.188    0.188
## 54  v5 ~~  v7 20.424 -0.078  -0.078   -0.178   -0.178
## 44  v3 ~~  v8 19.030  0.063   0.063    0.159    0.159
## 35  v2 ~~  v6 15.698  0.098   0.098    0.128    0.128
## 52  v4 ~~ v10 13.446 -0.070  -0.070   -0.136   -0.136
## 33  v2 ~~  v4 13.106  0.101   0.101    0.124    0.124
## 64  v8 ~~  v9 12.614 -0.052  -0.052   -0.122   -0.122
## 29  v1 ~~  v8 12.604  0.047   0.047    0.128    0.128
## 57  v5 ~~ v10 10.927  0.059   0.059    0.132    0.132
## 28  v1 ~~  v7  8.786 -0.041  -0.041   -0.111   -0.111
## 23  v1 ~~  v2  8.611 -0.061  -0.061   -0.102   -0.102
## 42  v3 ~~  v6  8.146 -0.047  -0.047   -0.099   -0.099
## 37  v2 ~~  v8  7.433 -0.059  -0.059   -0.093   -0.093
## 43  v3 ~~  v7  7.313 -0.042  -0.042   -0.103   -0.103
## 40  v3 ~~  v4  6.954 -0.049  -0.049   -0.097   -0.097
## 27  v1 ~~  v6  6.782 -0.039  -0.039   -0.089   -0.089
## 53  v5 ~~  v6  6.304  0.046   0.046    0.089    0.089
## 34  v2 ~~  v5  4.987  0.057   0.057    0.080    0.080
## 50  v4 ~~  v8  4.833 -0.038  -0.038   -0.078   -0.078
## 58  v6 ~~  v7  4.317  0.034   0.034    0.072    0.072
## 60  v6 ~~ v10  3.840 -0.033  -0.033   -0.069   -0.069
## 48  v4 ~~  v6  3.563  0.037   0.037    0.063    0.063
## 45  v3 ~~  v9  3.333 -0.028  -0.028   -0.065   -0.065
## 65  v8 ~~ v10  3.123  0.027   0.027    0.065    0.065

Comparing Models 1 v 2

The difference in the fit of the two models is itself distributed as a \(\chi^2_\Delta\) with df equal to the difference in the number of df for the two models.
Here \(\chi^2_\Delta\) = \(\chi^2_{M1}\) - \(\chi^2_{M2}\).

# comparing nested models via chisq likelihood ratio test
lavTestLRT(fit2,fit1, type = "chisq")
## 
## Chi-Squared Difference Test
## 
##      Df   AIC   BIC  Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
## fit2 34 22374 22476 239.46                                          
## fit1 35 22416 22513 283.14     43.678 0.20943       1  3.871e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Note that the model comparison test is significant; \(\chi^2_\Delta\) = 43.678, df = 1, p < .05. (Recall that the anticipated drop in \(\chi^2_{M}\) based on the MI from Model 1 was 43.804.) Allowing the residual terms of v6 and v9 to correlate significantly improved the fit of the model. We could continue in the MG mode by freeing the parameter with the next largest MI and re-running the model to improve model fit, but this strategy is simply data driven and we are left with a model that we cannot defend on theoretical grounds.

An Alternative CFA Model

Inspection of the MI and residuals (from Models 1 and 2) led me to formulate a a second hypothesis regarding the factor structure of the Self-Esteem Scale. I noticed that pairs of items that are negatively worded had large MI values. This pattern suggested a type of two-factor model referred to in the psychometrics literature as a common method variance model.

My alternative model (Model 3) posits two correlated latent factors. The items that are negatively worded (and reverse scored) load on one factor (SEn) and the items that are positively worded load on the second factor (SEp). All 10 items measure Self-Esteem, but the way that the items are worded contributes systematically to their inter-item covariances/correlations.
Note that Model 3 has only one more parameter than Model 1, and the same number of parameters as Model 2, but unlike Model 2, Model 3 is theoretically based.

Specify and run the model:

model3 <- ' 
SEp  =~ v1 + v3 + v5 + v8 + v10 
SEn  =~ v2 + v4 + v6 + v7 + v9 
'
fit3 <- cfa(model3, sample.cov=covfull, sample.nobs=973, std.lv=F )

Path Diagram Model 3

#--making CFA path diagram---------------------mar(bot,lft,top,rgt)
fig3 <-semPlot::semPaths(fit3, whatLabels = "std", layout = "tree2", 
                         rotation = 1, style = "lisrel", optimizeLatRes = T, 
                         structural = F, layoutSplit = F,
                         intercepts = F, residuals = T, 
                         curve = 1, curvature = 3, nCharNodes = 8, 
                         sizeLat = 8, sizeMan = 6, sizeMan2 = 6, 
                         edge.label.cex = 0.9, label.cex=1.1, residScale=10, mar=c(19,2,19,2), 
                         edge.color = "black", edge.label.position = .60, DoNotPlot=T)
fig3.1 <- fig3 |> mark_sig(fit3, alpha = c("(n.s.)" = 1.00, "*" = .05))
plot(fig3.1)  

Note that the paths connecting v1 to SEp and v2 to SEn are dashed. This is to indicate that each was used as a “reference variable” to define the metric of the latent variables, so there are no tests of significance associated with them. For the SEp factor the loadings range from .56 to .68, and for the SEn factor, loadings range from .39 to .71.

The correlation between the two latent factors is .77, suggesting that the two factors are not very distinct from one another.

The residual terms, estimating the proportion of variance in each item that is not associated with its respective latent factor range from .50 to .85. v2 still has considerable measurement error.

Full output 3

summary(fit3, fit.measures=T, standardized=T, rsquare=T)
## lavaan 0.6.16 ended normally after 33 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        21
## 
##   Number of observations                           973
## 
## Model Test User Model:
##                                                       
##   Test statistic                               119.926
##   Degrees of freedom                                34
##   P-value (Chi-square)                           0.000
## 
## Model Test Baseline Model:
## 
##   Test statistic                              2603.344
##   Degrees of freedom                                45
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.966
##   Tucker-Lewis Index (TLI)                       0.956
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)             -11106.202
##   Loglikelihood unrestricted model (H1)     -11046.239
##                                                       
##   Akaike (AIC)                               22254.404
##   Bayesian (BIC)                             22356.892
##   Sample-size adjusted Bayesian (SABIC)      22290.196
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.051
##   90 Percent confidence interval - lower         0.041
##   90 Percent confidence interval - upper         0.061
##   P-value H_0: RMSEA <= 0.050                    0.418
##   P-value H_0: RMSEA >= 0.080                    0.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.032
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   SEp =~                                                                
##     v1                1.000                               0.460    0.629
##     v3                1.178    0.073   16.115    0.000    0.542    0.662
##     v5                1.374    0.084   16.426    0.000    0.632    0.681
##     v8                0.906    0.063   14.294    0.000    0.417    0.565
##     v10               1.274    0.078   16.396    0.000    0.586    0.679
##   SEn =~                                                                
##     v2                1.000                               0.433    0.392
##     v4                1.292    0.128   10.118    0.000    0.559    0.590
##     v6                1.160    0.115   10.080    0.000    0.502    0.584
##     v7                1.350    0.126   10.723    0.000    0.585    0.710
##     v9                1.371    0.128   10.676    0.000    0.594    0.698
## 
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   SEp ~~                                                                
##     SEn               0.153    0.017    8.944    0.000    0.767    0.767
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .v1                0.324    0.017   18.748    0.000    0.324    0.605
##    .v3                0.376    0.021   18.096    0.000    0.376    0.562
##    .v5                0.463    0.026   17.674    0.000    0.463    0.537
##    .v8                0.370    0.019   19.695    0.000    0.370    0.681
##    .v10               0.402    0.023   17.718    0.000    0.402    0.539
##    .v2                1.034    0.049   21.065    0.000    1.034    0.847
##    .v4                0.585    0.031   19.092    0.000    0.585    0.651
##    .v6                0.486    0.025   19.183    0.000    0.486    0.658
##    .v7                0.336    0.021   16.358    0.000    0.336    0.496
##    .v9                0.371    0.022   16.729    0.000    0.371    0.513
##     SEp               0.212    0.021    9.906    0.000    1.000    1.000
##     SEn               0.188    0.033    5.701    0.000    1.000    1.000
## 
## R-Square:
##                    Estimate
##     v1                0.395
##     v3                0.438
##     v5                0.463
##     v8                0.319
##     v10               0.461
##     v2                0.153
##     v4                0.349
##     v6                0.342
##     v7                0.504
##     v9                0.487

The \(\chi^2_{M3}\) = 119.926 with df = 34, p < .001.
The RSMEA = .051, TLI = .956, CFI = .966, SRMR = .032. So, all indices suggest a good fit.
A formal test comparing this alternative model with the original model is shown below.

Residual Correlations 3

The values below are the residual correlations (i.e., observed correlation - model estimated correlation). The average absolute values of these residuals is provided by the standardized root mean square residual (SRMR).

sem_residuals(fit3)
v1 v3 v5 v8 v10 v2 v4 v6 v7 v9
v1
v3 0.05
v5 -0.02 -0.03
v8 0.03 0.04 -0.03
v10 -0.03 -0.02 0.03 0.00
v2 -0.03 0.02 0.09 -0.04 0.01
v4 0.02 0.00 0.04 -0.01 -0.01 0.06
v6 -0.05 -0.05 0.07 -0.04 -0.02 0.06 -0.03
v7 -0.01 0.00 -0.01 0.01 0.04 -0.06 0.03 -0.03
v9 -0.01 -0.02 0.02 -0.06 0.02 -0.03 -0.04 0.05 0.01

Analysis of Residuals 3

The output below displays residual correlations and z-scores indicating the magnitude of the residuals. Typically, z values > |2.58| are interpreted as significant and indicate where the model is doing a poor job of reproducing the observed correlations.

lavResiduals(fit3, type = "cor.bollen")
## $type
## [1] "cor.bollen"
## 
## $cov
##         v1     v3     v5     v8    v10     v2     v4     v6     v7     v9
## v1   0.000                                                               
## v3   0.047  0.000                                                        
## v5  -0.021 -0.029  0.000                                                 
## v8   0.033  0.043 -0.030  0.000                                          
## v10 -0.026 -0.020  0.025 -0.001  0.000                                   
## v2  -0.031  0.021  0.089 -0.036  0.008  0.000                            
## v4   0.017 -0.004  0.040 -0.010 -0.012  0.057  0.000                     
## v6  -0.048 -0.052  0.065 -0.040 -0.019  0.056 -0.026  0.000              
## v7  -0.010 -0.001 -0.011  0.006  0.041 -0.062  0.031 -0.030  0.000       
## v9  -0.011 -0.019  0.022 -0.059  0.020 -0.028 -0.044  0.049  0.013  0.000
## 
## $cov.z
##         v1     v3     v5     v8    v10     v2     v4     v6     v7     v9
## v1   0.000                                                               
## v3   3.032  0.000                                                        
## v5  -1.527 -2.284  0.000                                                 
## v8   1.849  2.545 -2.007  0.000                                          
## v10 -1.887 -1.604  1.928 -0.093  0.000                                   
## v2  -1.234  0.864  3.746 -1.360  0.345  0.000                            
## v4   0.792 -0.173  1.944 -0.419 -0.594  2.590  0.000                     
## v6  -2.167 -2.433  3.103 -1.714 -0.923  2.541 -1.519  0.000              
## v7  -0.534 -0.074 -0.643  0.268  2.233 -3.779  2.215 -2.307  0.000       
## v9  -0.588 -1.037  1.194 -2.861  1.075 -1.650 -3.381  3.290  1.287  0.000
## 
## $summary
##                            cov
## crmr                     0.036
## crmr.se                  0.003
## crmr.exactfit.z          6.796
## crmr.exactfit.pvalue     0.000
## ucrmr                    0.031
## ucrmr.se                 0.004
## ucrmr.ci.lower           0.024
## ucrmr.cilupper           0.037
## ucrmr.closefit.h0.value  0.050
## ucrmr.closefit.z        -4.728
## ucrmr.closefit.pvalue    1.000

The z-scores associated with the residual correlations are less extreme that those from Model 1 above.

Ideally the residual correlations should be normally distributed with a mean of 0.0. One way to examine the distribution of these residuals is with a stem-and-leaf plot which is a type of sideways histogram. The first 2 digits of each residual correlation are to the left of the | symbol and are referred to as the stem. The third digit of each residual correlation is to the right of the | and is referred to as a leaf. The plot shows the number (and value) of the leaves for each stem. Note that there are no decimal points in the plot; the implied decimal point is two digits to the left of the | symbol.

stem( lavResiduals(fit3, output = "table")$res ) # gives stem/leaf plot of resid cors
## 
##   The decimal point is 2 digit(s) to the left of the |
## 
##   -6 | 2
##   -4 | 92840
##   -2 | 6100986610
##   -0 | 9921100411
##    0 | 6837
##    2 | 012513
##    4 | 0137967
##    6 | 5
##    8 | 9

Based on the stem-and-leaf plot, the distribution of the residual correlations looks a bit more normal and the values are less extreme than those from Model 1 above. Here most of the residuals are between -.029 and -.009 (there are more leaves on the two stems -2 and -0 than there are on any of the other stems).

Modification Indices 3

The values below indicate the drop in \(\chi^2_M\) (i.e., model improvement) anticipated if parameters currently fixed at 0.0 are freed to be estimated. Note that lhs op rhs refers to the variable on the left hand side and on the right hand side of the operation symbol ~~ which indicates a correlation between the residual variances of two items.The critical value of \(\chi^2\) with df = 1 and \(\alpha = .05\) is 3.841, so any MI greater than this value is worth examination.

modificationIndices(fit3, sort. = TRUE, minimum.value = 3)
##    lhs op rhs     mi    epc sepc.lv sepc.all sepc.nox
## 71  v2 ~~  v7 13.233 -0.084  -0.084   -0.142   -0.142
## 55  v5 ~~  v6 13.205  0.065   0.065    0.136    0.136
## 53  v5 ~~  v2 12.593  0.088   0.088    0.127    0.127
## 77  v6 ~~  v9 12.380  0.064   0.064    0.151    0.151
## 75  v4 ~~  v9 10.234 -0.064  -0.064   -0.138   -0.138
## 34  v1 ~~  v3 10.214  0.046   0.046    0.131    0.131
## 31 SEn =~  v5  9.987  0.448   0.194    0.209    0.209
## 69  v2 ~~  v4  7.033  0.074   0.074    0.095    0.095
## 44  v3 ~~  v8  6.987  0.039   0.039    0.103    0.103
## 70  v2 ~~  v6  6.753  0.066   0.066    0.092    0.092
## 56  v5 ~~  v7  6.424 -0.040  -0.040   -0.102   -0.102
## 63  v8 ~~  v9  6.139 -0.035  -0.035   -0.094   -0.094
## 74  v4 ~~  v7  5.394  0.045   0.045    0.102    0.102
## 32 SEn =~  v8  5.204 -0.261  -0.113   -0.153   -0.153
## 67 v10 ~~  v7  5.043  0.033   0.033    0.090    0.090
## 76  v6 ~~  v7  4.938 -0.039  -0.039   -0.097   -0.097
## 43  v3 ~~  v5  4.809 -0.040  -0.040   -0.095   -0.095
## 48  v3 ~~  v6  4.383 -0.033  -0.033   -0.078   -0.078
## 52  v5 ~~ v10  4.039  0.038   0.038    0.089    0.089
## 51  v5 ~~  v8  3.814 -0.032  -0.032   -0.078   -0.078
## 36  v1 ~~  v8  3.592  0.025   0.025    0.072    0.072
## 37  v1 ~~ v10  3.342 -0.028  -0.028   -0.076   -0.076
## 40  v1 ~~  v6  3.135 -0.026  -0.026   -0.065   -0.065

Comparing Models 1 v 3

The difference in the fit of the two models is itself distributed as a \(\chi^2_\Delta\) with df equal to the difference in the number of df for the two models.
Here \(\chi^2_\Delta\) = \(\chi^2_{M1}\) - \(\chi^2_{M3}\).

# comparing nested models via chisq likelihood ratio test
lavTestLRT(fit3,fit1, type = "chisq")
## 
## Chi-Squared Difference Test
## 
##      Df   AIC   BIC  Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
## fit3 34 22254 22357 119.93                                          
## fit1 35 22416 22513 283.14     163.22 0.40831       1  < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

So the \(\chi^2_\Delta\) test indicates that the two-factor common method variance model fits the observed covariances (correlations) among the items better than the initial one-factor model. All 10 items measure Self-Esteem, but the way in which the items are worded contributes systematically to the inter-item correlations.

Reliability 3

semTools::compRelSEM(fit3, tau.eq=T, obs.var=T, return.total=T) 
##   SEp   SEn total 
## 0.778 0.717 0.827

The reliability analysis indicates that if two separate subscales (SEp and SEn) were to be used they would not be as reliable as the total scale score (.778, 717, and .827 respectively). Also, note that the correlation between the two factors is strong (.77) and so using two subscales as predictors in a regression model would likely result in colinearity problems. In practice, researchers are better off using the 10 items to form a single scale score.

Concluding Remarks

In this lecture we worked through the three approaches to SEM; these are strictly confirmatory, model generation, and testing alternative models. The initial uni-dimensional model of the Rosenburg Self-Esteem Scale (Model 1) was not supported. Guided by the modification indices we illustrated how to add a correlation between two residual terms (Model 2). Model 2 improved fit, but technically it is not a true CFA measurement model because such models posit that the residual variances of the indicator variables (items) are all uncorrelated. We could have continued to add correlations among residual terms to improve the model fit, such a model would be difficult to defend on theoretical grounds.
Model 3 was an alternative model, based in theory (in this case the common method variance model) that was shown to be the best fitting model examined here. This result illustrates that the wording of items (positive or negative) that make up self-report scales can influence how people respond to them which in turn influences the correlations among the scale items.

Model 2 and Model 3 have the same number of parameters (21) and the same number of df (34) so they cannot be compared using the \(\chi^2_\Delta\) test for nested models. The Akaike information criteria (AIC) can be used to compare the relative fit of two non-nested models; smaller values indicate better fit. (see Full Outputs above for AIC values.) For Model 2, the AIC = 22373.942, and for Model 3 the AIC = 22254.404; so Model 3 fits better than Model 2 even though they have the same number of parameters. As an aside, Model 1 had AIC = 22415.620. Based on the AIC values from all three models, Model 3 is the preferred model.

SEM is a powerful tool allowing researchers to formulate and test hypotheses about the underlying structure of covariance matrices. When used wisely, structural equation models can provide useful insights into the complex relations among a set variables relevant to some phenomenon of interest.

LS0tDQp0aXRsZTogIlN0cmF0ZWdpYyBBcHByb2FjaGVzIGluIFNFTTogQW4gRXhhbXBsZSBVc2luZyB0aGUgUm9zZW5idXJnIFNlbGYtRXN0ZWVtIFNjYWxlLiINCmF1dGhvcjogIkphc29uIEJlY2tzdGVhZCINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCi0tLQ0KIyMgU2V0dXANClJlcXVpcmVkIFBhY2thZ2VzDQpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCiMtLWxvYWRpbmcgbXkgcGFja2FnZXMNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpsaWJyYXJ5KHBhY21hbikNCiMgTG9hZCBpbnN0YWxsZWQgcGFja2FnZXMsIGluc3RhbGwgYW5kIGxvYWQgdGhlIHBhY2thZ2UgaWYgbm90IGluc3RhbGxlZA0KcGFjbWFuOjpwX2xvYWQoaGVyZSwgcmlvLCBjb25mbGljdGVkLCB0aWR5dmVyc2UsIGphbml0b3IsIHN1bW1hcnl0b29scywgc2tpbXIsIA0KICAgICAgICAgICAgICAgRGF0YUV4cGxvcmVyLCBpbnNwZWN0ZGYsIEhtaXNjLCByZWFkciwgZHBseXIsIHRpbnl0ZXgsDQogICAgICAgICAgICAgICAjIGxvYWRpbmcgU0VNIHJlbGF0ZWQgcGFja2FnZXMNCiAgICAgICAgICAgICAgIGxhdmFhbiwgc2VtVG9vbHMsIHNlbW91dHB1dCwgc2VtUGxvdCwgc2pQbG90LCBwc3ljaCwgDQogICAgICAgICAgICAgICBHUEFyb3RhdGlvbiwgcHN5Y2hUb29scywgc2VtcHRvb2xzLCBsbS5iZXRhKQ0KYGBgDQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQouc2Nyb2xsLTUwMCB7DQogIG1heC1oZWlnaHQ6IDUwMHB4Ow0KICBvdmVyZmxvdy15OiBhdXRvOw0KICBiYWNrZ3JvdW5kLWNvbG9yOiBpbmhlcml0Ow0KfQ0KYGBgDQojIyBCYWNrZ3JvdW5kIA0KVGhlIHN0YXRpc3RpY2lhbiBHZW9yZ2UgQm94IGZhbW91c2x5IHNhaWQgIipBbGwgbW9kZWxzIGFyZSB3cm9uZywgYnV0IHNvbWUgbW9kZWxzIGFyZSB1c2VmdWwqIi4gVGhpcyBzdGF0ZW1lbnQgaXMgcGFydGljdWxhcmx5IGFwcGxpY2FibGUgdG8gU0VNLiBCeSBkZWZpbml0aW9uLCBtb2RlbHMgYXJlIHNpbXBsaWZpZWQgcmVwcmVzZW50YXRpb25zIG9mIHBoZW5vbWVuYS4gTW9kZWxzIG5lZWQgdG8gYmUgc2ltcGxlIGVub3VnaCB0byBmYWNpbGl0YXRlIG91ciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBwaGVub21lbm9uIHVuZGVyIHN0dWR5LCBidXQgbm90IHNvIHNpbXBsZSB0aGF0IHdlIG1pc3MgaW1wb3J0YW50LCBvZnRlbiBzdWJ0bGUsIGFzcGVjdHMgb2YgdGhlIHBoZW5vbWVub24uICANCg0KV2hlbiB3b3JraW5nIHdpdGhpbiB0aGUgU0VNIGZyYW1ld29yayB3ZSBwb3N0dWxhdGUgYSBtb2RlbCB0byBhY2NvdW50IGZvciB0aGUgcGF0dGVybiBvZiB2YXJpYW5jZXMgYW5kIGNvdmFyaWFuY2VzIHdlIG9ic2VydmUgaW4gYSBzZXQgb2YgcmVsZXZhbnQgdmFyaWFibGVzLiBDb25maXJtaW5nIHRoYXQgb3VyIG1vZGVsIGZpdHMgdGhlIGRhdGEgaXMgdGhlIGRlc2lyZWQgcmVzdWx0LCBidXQgd2UgbXVzdCBrZWVwIGluIG1pbmQgdGhhdCBvdXIgbW9kZWwgbWF5IGJlIG9uZSBvZiBzZXZlcmFsIHRoYXQgY291bGQgZXhwbGFpbiB0aGUgZGF0YS4gU28sIHdoaWxlIHdlIGNhbiBydWxlIG91dCBzb21lIG1vZGVscyBiZWNhdXNlIHRoZXkgZG8gbm90IGZpdCB0aGUgZGF0YSwgd2UgY2Fubm90IGNsYWltIHRoYXQgb3VyIG1vZGVsIGlzICp0aGUqIG1vZGVsIHNpbXBseSBiZWNhdXNlIGl0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgb2JzZXJ2ZWQgZGF0YS4NCg0KSW4gc3VtbWFyaXppbmcgdGhlICoqc3RyYXRlZ2ljIGZyYW1ld29yayoqIGZvciB0ZXN0aW5nIHN0cnVjdHVyYWwgZXF1YXRpb24gbW9kZWxzLCBLYXJsIEpvcmVza29nIGRpc3Rpbmd1aXNoZWQgYmV0d2VlbiB0aHJlZSBzY2VuYXJpb3MgdGhhdCBoZSBjYWxsZWQgKipzdHJpY3RseSBjb25maXJtYXRvcnkqKiAoU0MpLCAqKmFsdGVybmF0aXZlIG1vZGVscyoqIChBTSksIGFuZCAqKm1vZGVsIGdlbmVyYXRpbmcqKiAoTUcpLiAgDQogIA0KSW4gdGhlIFNDIG1vZGUgdGhlIHJlc2VhcmNoZXIgcG9zdHVsYXRlcyBhIHNpbmdsZSBtb2RlbCBiYXNlZCBvbiB0aGVvcnksIGNvbGxlY3RzIHRoZSBkYXRhLCB0aGVuIHRlc3RzIHRoZSBmaXQgb2YgdGhlIGh5cG90aGVzaXplZCBtb2RlbCB0byB0aGUgc2FtcGxlIGRhdGEuIEJhc2VkIG9uIHRoZSByZXN1bHRzIG9mIHRoaXMgdGVzdCwgdGhlIHJlc2VhcmNoZXIgZWl0aGVyIHJlamVjdHMgb3IgZmFpbHMgdG8gcmVqZWN0IHRoZSBtb2RlbDsgbm8gZnVydGhlciBtb2RpZmljYXRpb25zIHRvIHRoZSBtb2RlbCBhcmUgbWFkZS4gIA0KICANCkluIHRoZSBBTSBtb2RlLCB0aGUgcmVzZWFyY2hlciBwcm9wb3NlcyBzZXZlcmFsIGFsdGVybmF0aXZlIChpLmUuLCBjb21wZXRpbmcpIG1vZGVscywgYWxsIG9mIHdoaWNoIGFyZSBncm91bmRlZCBpbiB0aGVvcnkuIEZvbGxvd2luZyBhbmFseXNpcyBvZiBhIHNpbmdsZSBzYW1wbGUgaGUvc2hlIHNlbGVjdHMgb25lIG1vZGVsIGFzIG1vc3QgYXBwcm9wcmlhdGUuICANCiAgDQogIA0KVGhlIG1vZGVsIGdlbmVyYXRpbmcgKE1HKSBtb2RlIHJlcHJlc2VudHMgdGhlIGNhc2Ugd2hlcmUgdGhlIHJlc2VhcmNoZXIsIGhhdmluZyBwb3N0dWxhdGVkIGFuZCByZWplY3RlZCBhIG1vZGVsIG9uIHRoZSBiYXNpcyBvZiBwb29yIGZpdCwgcHJvY2VlZHMgaW4gYW4gKmV4cGxvcmF0b3J5IGZhc2hpb24qIHRvIG1vZGlmeSBhbmQgcmUtZXN0aW1hdGUgdGhlIG1vZGVsLiBUaGlzIGludm9sdmVzIGluc3BlY3Rpb24gb2Ygd2hhdCBhcmUgY2FsbGVkIG1vZGlmaWNhdGlvbiBpbmRpY2VzLiBNRyBtb2RlIGlzIHR5cGljYWxseSBhdGhlb3JldGljIGFuZCBkYXRhLWRyaXZlbi4gIA0KICANCiAgDQpJbiB0aGlzIGxlY3R1cmUgd2Ugc3RhcnQgd2l0aCB0aGUgU0MgY2FzZS4gV2UgcHJvcG9zZSBhbmQgdGVzdCBhIG1vZGVsOyB3ZSB3aWxsIGVpdGhlciBhY2NlcHQgb3IgcmVqZWN0IGl0LiAoSGVhZHMgdXAsIHRoZSBoeXBvdGhlc2l6ZWQgbW9kZWwgZG9lcyBub3QgZml0IHdlbGwuKSBUaGlzIHdpbGwgcHJvdmlkZSBvcHBvcnR1bml0eSB0byBkZW1vbnN0cmF0ZSBob3cgb25lIG1heSBnbyBhYm91dCB0aGUgTUcgYXBwcm9hY2guIEZpbmFsbHksIHdlIGV4YW1pbmUgYSBzZWNvbmQgaHlwb3RoZXNpemVkIG1vZGVsIChub3cgd2UgYXJlIHdvcmtpbmcgZnJvbSB0aGUgQU0gcGVyc3BlY3RpdmUpIGFuZCBjb21wYXJlIGl0IHRvIHRoZSBpbml0aWFsIGh5cG90aGVzaXplZCBtb2RlbC4NCiAgDQoNCiMjIFRoZSBFeGFtcGxlDQpUaGUgUm9zZW5idXJnIFNlbGYtRXN0ZWVtIFNjYWxlIGNvbnRhaW5zIDEwIGl0ZW1zIGh5cG90aGVzaXplZCB0byBtZWFzdXJlIFNlbGYtRXN0ZWVtIGFzIGEgdW5pLWRpbWVuc2lvbmFsIGNvbnN0cnVjdC4gSGVyZSBhcmUgdGhlIGl0ZW1zLCByZXNwb25zZSBzY2FsZSBvcHRpb25zIGFuZCBjaXRhdGlvbi4gTm90ZSB0aGF0IHRvIGNvbnRyb2wgZm9yIHJlc3BvbnNlIHNldCBiaWFzLCBmaXZlIG9mIHRoZSBpdGVtcyBhcmUgbmVnYXRpdmVseSB3b3JkZWQgKGFuZCByZXZlcnNlIHNjb3JlZCkgd2hpbGUgZml2ZSBhcmUgcG9zaXRpdmVseSB3b3JkZWQuIFRoZSBzYW1wbGUgc2l6ZSBmb3IgYW5hbHlzZXMgaXMgOTczLiAgDQogIA0KICANCmBgYHtyIGFweCwgZWNobz1GQUxTRSwgb3V0LndpZHRoID0gJzkwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJkYXRhIiwiU2VsZi1Fc3RlZW0gU2NhbGUucG5nIikpDQpgYGANCg0KIyMgUmVhZGluZyBpbiB0aGUgRGF0YQ0KVGhlIGRhdGEgYXJlIGluIHRoZSBmb3JtIG9mIGEgY29ycmVsYXRpb24gbWF0cml4IHBsdXMgYSB2ZWN0b3Igb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucy4gVGhlc2UgYXJlIGNvbWJpbmVkIHRvIGZvcm0gYSBjb3ZhcmlhbmNlIG1hdHJpeCBmb3IgYW5hbHlzaXMuICANCmBgYHtyfQ0KY29yciA8LSAnDQoxLjAwMA0KLjE1OCAxLjAwMA0KLjQ2MyAgLjIyMCAxLjAwMA0KLjMwMiAgLjI4OCAgLjI5NiAxLjAwMA0KLjQwNyAgLjI5MyAgLjQyMiAgLjM0OCAxLjAwMA0KLjIzNCAgLjI4NSAgLjI0NSAgLjMxOSAgLjM3MCAxLjAwMA0KLjMzMiAgLjIxNiAgLjM1OSAgLjQ1MCAgLjM1OSAgLjM4NSAxLjAwMA0KLjM4OCAgLjEzNCAgLjQxNyAgLjI0NiAgLjM1NCAgLjIxMyAgLjMxMyAxLjAwMA0KLjMyNSAgLjI0NSAgLjMzNSAgLjM2OCAgLjM4NiAgLjQ1NyAgLjUwOSAgLjI0MyAxLjAwMA0KLjQwMSAgLjIxMiAgLjQyOSAgLjI5NSAgLjQ4NyAgLjI4NSAgLjQxMCAgLjM4MiAgLjM4MyAxLjAwMA0KJw0KIyBhZGQgdmFyaWFibGUgbmFtZXMgYW5kIGNvbnZlcnQgdG8gZnVsbCBjb3JyZWxhdGlvbiBtYXRyaXgNCmNvcnJmdWxsIDwtIGxhdmFhbjo6Z2V0Q292KGNvcnIsIG5hbWVzPWMoJ3YxJywndjInLCd2MycsJ3Y0JywndjUnLCd2NicsJ3Y3JywndjgnLCd2OScsJ3YxMCcpKQ0KIyBhZGQgU0RzIGFuZCBjb252ZXJ0IHRvIGZ1bGwgY292YXJpYW5jZSBtYXRyaXgNCmNvdmZ1bGwgPC0gbGF2YWFuOjpjb3IyY292KGNvcnJmdWxsLCBzZHM9YygwLjczMiwxLjEwNiwwLjgxOSwwLjk0OCwwLjkyOSwwLjg2MCwwLjgyNCwwLjczOCwwLjg1MSwwLjg2NCkpDQojIE1FQU5TOyBub3QgdXNlZCAzLjc4IDIuOTYgNC4wOSA0LjAwIDMuODAgMy4zNyA0LjMwIDMuOTIgNC4wNyA0LjAyICAgIyBOID0gOTczDQoNCmBgYA0KDQojIyBUaGUgQ29ycmVsYXRpb25zDQpIZXJlIGFyZSB0aGUgb2JzZXJ2ZWQgY29ycmVsYXRpb25zIGFtb25nIHRoZSAxMCBpdGVtcywgbGFiZWxlZCB2MSB0byB2MTAuDQpgYGB7cn0NCiMgVXNlcyBzalBsb3QgdG8gcHJpbnQgYSBuaWNlIGxvb2tpbmcgY29ycmVsYXRpb24gdGFibGUNCnRhYl9jb3JyKGNvcnJmdWxsLCBuYS5kZWxldGlvbiA9ICJsaXN0d2lzZSIsIGRpZ2l0cyA9IDIsIHRyaWFuZ2xlID0gImxvd2VyIiwNCiAgICAgICAgIHRpdGxlPSJDb3JyZWxhdGlvbnMgYW1vbmcgU2VsZi1Fc3RlZW0gSXRlbXMiLA0KICAgICAgICAgc3RyaW5nLmRpYWc9YygnMScsJzEnLCcxJywnMScsJzEnLCcxJywnMScsJzEnLCcxJywnMScpKQ0KYGBgDQoNCiMjIFRoZSBDRkEgTW9kZWwNClRoZSBoeXBvdGhlc2lzIHRvIGJlIHRlc3RlZCBpcyB0aGF0IHRoZSBpdGVtcyBtYWtpbmcgdXAgdGhlIHNjYWxlIG1lYXN1cmUgYSB1bmktZGltZW5zaW9uYWwgY29uc3RydWN0LCBTZWxmLUVzdGVlbS4gQSBjb25maXJtYXRvcnkgZmFjdG9yIG1vZGVsIHdoZXJlIGFsbCAxMCBpdGVtcyBsb2FkIG9udG8gYSBzaW5nbGUgbGF0ZW50IHZhcmlhYmxlIGFuZCB0aGVpciByZXNpZHVhbCB2YXJpYW5jZSB0ZXJtcyBhcmUgdW5jb3JyZWxhdGVkIHJlcHJlc2VudHMgdGhpcyBoeXBvdGhlc2lzLiBXZSBydW4gdGhlIG1vZGVsOyBpZiBpdCBmaXRzIHdlbGwgd2UgaGF2ZSBzdXBwb3J0IGZvciBvdXIgaHlwb3RoZXNpcywgaWYgdGhlIG1vZGVsIGZpdCBpcyBwb29yIHRoZW4gb3VyIGh5cG90aGVzaXMgb2YgYSBzaW5nbGUgdW5kZXJseWluZyBmYWN0b3IgaXMgcmVqZWN0ZWQuICANCiAgDQogIA0KU3BlY2lmeSBhbmQgcnVuIHRoZSBtb2RlbDoNCmBgYHtyfQ0KbW9kZWwxIDwtICcgU0UgID1+IHYxICsgdjIgKyB2MyArIHY0ICsgdjUgKyB2NiArIHY3ICsgdjggKyB2OSArIHYxMCAnDQpmaXQxIDwtIGNmYShtb2RlbDEsIHNhbXBsZS5jb3Y9Y292ZnVsbCwgc2FtcGxlLm5vYnM9OTczLCBzdGQubHY9RiApDQoNCmBgYA0KDQojIyMgUGF0aCBEaWFncmFtIE1vZGVsIDENCmBgYHtyfQ0KIy0tbWFraW5nIENGQSBwYXRoIGRpYWdyYW0tLS0tLS0tLS0tLS0tLS0tLS0tLS1tYXIoYm90LGxmdCx0b3Ascmd0KQ0KZmlnMSA8LXNlbVBsb3Q6OnNlbVBhdGhzKGZpdDEsIHdoYXRMYWJlbHMgPSAic3RkIiwgbGF5b3V0ID0gInRyZWUyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcm90YXRpb24gPSAxLCBzdHlsZSA9ICJsaXNyZWwiLCBvcHRpbWl6ZUxhdFJlcyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHN0cnVjdHVyYWwgPSBGLCBsYXlvdXRTcGxpdCA9IEYsDQogICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJjZXB0cyA9IEYsIHJlc2lkdWFscyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnZlID0gMSwgY3VydmF0dXJlID0gMywgbkNoYXJOb2RlcyA9IDgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVMYXQgPSA4LCBzaXplTWFuID0gNiwgc2l6ZU1hbjIgPSA2LCANCiAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlLmxhYmVsLmNleCA9IDAuOSwgbGFiZWwuY2V4PTEuMSwgcmVzaWRTY2FsZT0xMCwgbWFyPWMoMTksMiwxOSwyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgZWRnZS5jb2xvciA9ICJibGFjayIsIGVkZ2UubGFiZWwucG9zaXRpb24gPSAuNjAsIERvTm90UGxvdD1UKQ0KZmlnMS4xIDwtIGZpZzEgfD4gbWFya19zaWcoZml0MSwgYWxwaGEgPSBjKCIobi5zLikiID0gMS4wMCwgIioiID0gLjA1KSkNCnBsb3QoZmlnMS4xKSAgDQoNCmBgYA0KICANCk5vdGUgdGhhdCB0aGUgcGF0aCBjb25uZWN0aW5nIHRoZSBsYXRlbnQgZmFjdG9yIHdpdGggdjEgaXMgZGFzaGVkLiBUaGlzIGlzIHRvIGluZGljYXRlIHRoYXQgdjEgd2FzIHVzZWQgYXMgYSAicmVmZXJlbmNlIHZhcmlhYmxlIiB0byBkZWZpbmUgdGhlIG1ldHJpYyBvZiB0aGUgbGF0ZW50IHZhcmlhYmxlLCBzbyB0aGVyZSBpcyBubyB0ZXN0IG9mIHNpZ25pZmljYW5jZSBhc3NvY2lhdGVkIHdpdGggaXQuIFRoZSBsb2FkaW5ncyByYW5nZSBmcm9tIC4zOCB0byAuNjYuIFRoZSByZXNpZHVhbCB0ZXJtcywgZXN0aW1hdGluZyB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBpbiBlYWNoIGl0ZW0gdGhhdCBpcyBub3QgYXNzb2NpYXRlZCB3aXRoIHRoZSBsYXRlbnQgZmFjdG9yIHJhbmdlIGZyb20gLjU4IHRvIC44Ni4gdjIgaGFzIGNvbnNpZGVyYWJsZSBtZWFzdXJlbWVudCBlcnJvciBpbiBjb21wYXJpc29uIHRvIHRoZSBvdGhlciBpdGVtcy4gIA0KDQoNCiMjIyBGdWxsIG91dHB1dCAxDQpgYGB7ciwgY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCnN1bW1hcnkoZml0MSwgZml0Lm1lYXN1cmVzPVQsIHN0YW5kYXJkaXplZD1ULCByc3F1YXJlPVQpDQpgYGANCiAgDQogIA0KVGhlICRcY2hpXjJfe00xfSQgPSAyODMuMTI0IHdpdGggKmRmKiA9IDM1LCAqcCogPCAuMDAxLiBCYXNlZCBvbiB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSAkXGNoaV4yX3tNMX0kIHRlc3Qgd2UgcmVqZWN0IHRoZSBtb2RlbCwgaG93ZXZlciB0aGUgdmFsdWUgb2YgJFxjaGleMl97TTF9JCBpcyBpbmZsdWVuY2VkIGJ5IHNhbXBsZSBzaXplIHNvIHdlIGV4YW1pbmUgb3RoZXIgZml0IGluZGljZXMuICANClRoZSBSU01FQSA9IC4wODUgLCBUTEkgPSAuODc1LCBDRkkgPSAuOTAzLCBTUk1SID0gLjA1Mi4gVGhlcmUgaXMgY29uc2lkZXJhYmxlIHJvb20gZm9yIGltcHJvdmVtZW50IGluIGZpdDsgdGhlIFJNU0VBIGFuZCBTUk1SIGNvdWxkIGJlIHNtYWxsZXIsIGFuZCB0aGUgVExJIChhbmQgQ0ZJKSBjb3VsZCBiZSBsYXJnZXIuICAgDQpTbywgZnJvbSBhIHN0cmljdGx5IGNvbmZpcm1hdG9yeSBwZXJzcGVjdGl2ZSAoU0MpIHdlIGNvbmNsdWRlIHRoYXQgdGhlIGNvdmFyaWFuY2Ugc3RydWN0dXJlIG9mIHRoZSBTZWxmLUVzdGVlbSBTY2FsZSBpdGVtcyBpcyBtb3JlIGNvbXBsZXggdGhhbiBhIHVuaS1kaW1lbnNpb25hbCBtb2RlbCB3aXRoIGEgc2luZ2xlIGxhdGVudCB2YXJpYWJsZS4gIA0KDQogIA0KIyMjIFJlbGlhYmlsaXR5IDENClRoZSBgc2VtVG9vbHNgIHBhY2thZ2UgaGFzIGEgY29tbWFuZCBgY29tcFJlbFNFTWAgdG8gb2J0YWluIHJlbGlhYmlsaXR5IGVzdGltYXRlcyBzdWNoIGFzIENyb25iYWNoJ3MgJFxhbHBoYSQgY29lZmZpY2llbnQuDQpgYGB7cn0NCnNlbVRvb2xzOjpjb21wUmVsU0VNKGZpdDEsIHRhdS5lcT1ULCBvYnMudmFyPVQsIHJldHVybi50b3RhbD1GKSANCmBgYA0KICAgDQpJbiB0aGlzIHNhbXBsZSB0aGUgcmVsaWFiaWxpdHkgb2YgdGhlIHNjYWxlIGlzIGVzdGltYXRlZCBieSAkXGFscGhhJCA9IC44MjcuICAgDQoNCiAgIA0KIyMjIFJlc2lkdWFsIENvcnJlbGF0aW9ucyAxDQpUaGUgdmFsdWVzIGJlbG93IGFyZSB0aGUgcmVzaWR1YWwgY29ycmVsYXRpb25zIChpLmUuLCBvYnNlcnZlZCBjb3JyZWxhdGlvbiAtIG1vZGVsIGVzdGltYXRlZCBjb3JyZWxhdGlvbikuIFRoZSBhdmVyYWdlIGFic29sdXRlIHZhbHVlcyBvZiB0aGVzZSByZXNpZHVhbHMgaXMgcHJvdmlkZWQgYnkgdGhlIHN0YW5kYXJkaXplZCByb290IG1lYW4gc3F1YXJlIHJlc2lkdWFsIChTUk1SKS4gTm90ZSB0aGF0IHRoZSBsYXJnZXN0IHJlc2lkdWFsIGNvcnJlbGF0aW9uICguMTIpIGlzIGJldHdlZW4gdjYgYW5kIHY5LiBXaGlsZSBgc2Vtb3V0cHV0OjpzZW1fcmVzaWR1YWxzKClgIG1ha2VzIGEgbmljZSB0YWJsZSwgSSBkb24ndCBiZWxpZXZlIHRoYXQgd2UgY2FuIGNoYW5nZSB0aGUgbnVtYmVyIG9mIGRpZ2l0czsgaXQgaXMgbGltaXRlZCB0byBvbmx5IHR3by4gTW9yZSBwcmVjaXNlIHZhbHVlcyAoMyBkaWdpdHMpIGFyZSBzaG93biBpbiB0aGUgb3V0cHV0IGZyb20gYGxhdlJlc2lkdWFscygpYCBiZWxvdy4NCmBgYHtyfQ0Kc2Vtb3V0cHV0OjpzZW1fcmVzaWR1YWxzKGZpdDEpDQpgYGANCg0KIyMjIEFuYWx5c2lzIG9mIFJlc2lkdWFscyAxDQpUaGUgb3V0cHV0IGJlbG93IGRpc3BsYXlzIHJlc2lkdWFsIGNvcnJlbGF0aW9ucyBhbmQgei1zY29yZXMgaW5kaWNhdGluZyB0aGUgbWFnbml0dWRlIG9mIHRoZSByZXNpZHVhbHMuIFR5cGljYWxseSwgeiB2YWx1ZXMgPiB8Mi41OHwgKHdoaWNoIGlzIHRoZSB0d28tdGFpbGVkIGNyaXRpY2FsIHZhbHVlIGZvciAkXGFscGhhID0gLjAxJCkgYXJlIGludGVycHJldGVkIGFzIHNpZ25pZmljYW50IGFuZCBpbmRpY2F0ZSB3aGVyZSB0aGUgbW9kZWwgaXMgZG9pbmcgYSBwb29yIGpvYiBvZiByZXByb2R1Y2luZyB0aGUgb2JzZXJ2ZWQgY29ycmVsYXRpb25zLg0KYGBge3IsY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCmxhdlJlc2lkdWFscyhmaXQxLCB0eXBlID0gImNvci5ib2xsZW4iKQ0KYGBgDQogICANCk5vdGljZSB0aGF0IHRoZSBsYXJnZXN0IHJlc2lkdWFsIGNvcnJlbGF0aW9uICguMTI0KSBiZXR3ZWVuIHY2IGFuZCB2OSBoYXMgdGhlIGxhcmdlc3QgeiB2YWx1ZSBhc3NvY2lhdGVkIHdpdGggaXQgKDYuMTExKS4gSW4gb3RoZXIgd29yZHMsIHRoZSBtb2RlbCBpcyBkb2luZyBhIHBvb3Igam9iIG9mIHJlcHJvZHVjaW5nIHRoaXMgY29ycmVsYXRpb24uICANCg0KSWRlYWxseSB0aGUgcmVzaWR1YWwgY29ycmVsYXRpb25zIHNob3VsZCBiZSBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIGEgbWVhbiBvZiAwLjAuIE9uZSB3YXkgdG8gZXhhbWluZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIHJlc2lkdWFscyBpcyB3aXRoIGEgKipzdGVtLWFuZC1sZWFmIHBsb3QqKiB3aGljaCBpcyBhIHR5cGUgb2Ygc2lkZXdheXMgaGlzdG9ncmFtLiBUaGUgZmlyc3QgMiBkaWdpdHMgb2YgZWFjaCByZXNpZHVhbCBjb3JyZWxhdGlvbiBhcmUgdG8gdGhlIGxlZnQgb2YgdGhlIHwgc3ltYm9sIGFuZCBhcmUgcmVmZXJyZWQgdG8gYXMgdGhlICpzdGVtKi4gVGhlIHRoaXJkIGRpZ2l0IG9mIGVhY2ggcmVzaWR1YWwgY29ycmVsYXRpb24gaXMgdG8gdGhlIHJpZ2h0IG9mIHRoZSB8IGFuZCBpcyByZWZlcnJlZCB0byBhcyBhICpsZWFmKi4gVGhlIHBsb3Qgc2hvd3MgdGhlIG51bWJlciAoYW5kIHZhbHVlKSBvZiB0aGUgbGVhdmVzIGZvciBlYWNoIHN0ZW0uIE5vdGUgdGhhdCB0aGVyZSBhcmUgbm8gZGVjaW1hbCBwb2ludHMgaW4gdGhlIHBsb3Q7IHRoZSBpbXBsaWVkIGRlY2ltYWwgcG9pbnQgaXMgdHdvIGRpZ2l0cyB0byB0aGUgbGVmdCBvZiB0aGUgfCBzeW1ib2wuICANCg0KYGBge3IsY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCnN0ZW0oIGxhdlJlc2lkdWFscyhmaXQxLCBvdXRwdXQgPSAidGFibGUiKSRyZXMgKSAjIGdpdmVzIHN0ZW0vbGVhZiBwbG90IG9mIHJlc2lkIGNvcnMNCmBgYA0KICANCkZvciBleGFtcGxlIGluIHRoZSBmaXJzdCByb3cgb2YgdGhlIHBsb3QgdGhlcmUgYXJlIHR3byByZXNpZHVhbHMgZm9yIHdoaWNoIHRoZSBmaXJzdCB0d28gZGlnaXRzIGFyZSAtLjA4IGFuZCB0aGUgdGhpcmQgZGlnaXRzIGFyZSA2IGFuZCAyLCBwcmludGVkIHRvIHRoZSByaWdodCBvZiB0aGUgfCBzeW1ib2wuIFRoZXNlIHR3byByZXNpZHVhbCBjb3JyZWxhdGlvbnMgYXJlIHRodXMgLS4wODYgYW5kIC0uMDgyLiBUaGUgbGFyZ2VzdCBwb3NpdGl2ZSByZXNpZHVhbCBjb3JyZWxhdGlvbiAuMTI0IGFwcGVhcnMgaW4gdGhlIGxhc3Qgcm93IGFzICIxMiB8IDQiLiBUaGlzIGRpc3RyaWJ1dGlvbiBpcyBmYXIgZnJvbSBiZWluZyBub3JtYWwuICANCiAgDQpMb29raW5nIGF0IHRoZSBlbnRpcmUgcGxvdCBzaG93cyBob3cgbWFueSByZXNpZHVhbHMgYmVnaW4gd2l0aCB0aGUgc2FtZSBzdGVtIHZhbHVlLiBTbywgdGhlcmUgYXJlIHR3byB0aGF0IHN0YXJ0IHdpdGggLS4wOCwgc2l4IHRoYXQgc3RhcnQgd2l0aCAtLjA2LCBzZXZlbiB0aGF0IHN0YXJ0IHdpdGggLS4wNCwgZml2ZSB0aGF0IHN0YXJ0IHdpdGggLjAwLCBldGMuICANCg0KDQoNCg0KICANCiMjIyBNb2RpZmljYXRpb24gSW5kaWNlcyAxDQpUaGUgdmFsdWVzIGJlbG93IGluZGljYXRlIHRoZSBkcm9wIGluICRcY2hpXjJfTSQgKGkuZS4sIG1vZGVsIGltcHJvdmVtZW50KSBhbnRpY2lwYXRlZCBpZiBwYXJhbWV0ZXJzIGN1cnJlbnRseSBmaXhlZCBhdCAwLjAgYXJlIGZyZWVkIHRvIGJlIGVzdGltYXRlZDsgYWxsIGZyZWVseSBlc3RpbWF0ZWQgcGFyYW1ldGVycyBhdXRvbWF0aWNhbGx5IGhhdmUgYW4gTUkgb2YgemVyby4gTm90ZSB0aGF0IGBsaHMgb3AgcmhzYCByZWZlcnMgdG8gdGhlIHZhcmlhYmxlIG9uIHRoZSBsZWZ0IGhhbmQgc2lkZSBhbmQgb24gdGhlIHJpZ2h0IGhhbmQgc2lkZSBvZiB0aGUgb3BlcmF0aW9uIHN5bWJvbCAqKn5+Kiogd2hpY2ggaW5kaWNhdGVzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmVzaWR1YWwgdmFyaWFuY2VzIG9mIHR3byBpdGVtcy4gVGhlIGNyaXRpY2FsIHZhbHVlIG9mICRcY2hpXjIkIHdpdGggKmRmKiA9IDEgYW5kICRcYWxwaGEkID0gLjA1IGlzIDMuODQxLCBzbyBhbnkgTUkgZ3JlYXRlciB0aGFuIHRoaXMgdmFsdWUgaXMgd29ydGggZXhhbWluYXRpb24uICANCmBgYHtyLCBjbGFzcy5vdXRwdXQ9InNjcm9sbC01MDAifQ0KbW9kaWZpY2F0aW9uSW5kaWNlcyhmaXQxLCBzb3J0LiA9IFRSVUUsIG1pbmltdW0udmFsdWUgPSAzKQ0KYGBgDQpIZXJlIHRoZSBsYXJnZXN0IE1JIGlzIGxpc3RlZCBmaXJzdCBhbmQgaXQgc3VnZ2VzdHMgdGhhdCBpZiB3ZSByZS1ydW4gdGhlIG1vZGVsIGFuZCBhbGxvdyB0aGUgcmVzaWR1YWwgdGVybXMgYmV0d2VlbiB2NiBhbmQgdjkgdG8gY29ycmVsYXRlLCB0aGUgJFxjaGleMl9NJCBpcyBleHBlY3RlZCB0byBkZWNyZWFzZSBieSBhYm91dCA0My44MC4gVGhlIG90aGVyIGNvbHVtbnMgc2hvdyB0aGUgZXhwZWN0ZWQgdmFsdWUgKGVwYykgb2YgdGhlIHBhcmFtZXRlciBpZiBpdCB3ZXJlIHRvIGJlIGVzdGltYXRlZC4gTm90ZSB0aGF0IHRoaXMgZmluZGluZyBjb25maXJtcyB3aGF0IHdlIHNhdyB3aGVuIGluc3BlY3RpbmcgdGhlIHJlc2lkdWFsIGNvcnJlbGF0aW9uczsgdGhlIHJlc2lkdWFsIGNvcnJlbGF0aW9uIGJldHdlZW4gdjYgYW5kIHY5IHdhcyB0aGUgbGFyZ2VzdC4gIA0KVGhlIGhlYWRpbmcgKipzZXBjLmx2KiogaXMgdGhlIHZhbHVlIGlmIHRoZSBsYXRlbnQgdmFyaWFibChzKSBhcmUgc3RhbmRhcmRpemVkIGFuZCB0aGUgY29sdW1uIGhlYWRpbmcgKipzZXBjLmFsbCoqIGdpdmVzIHRoZSBjb21wbGV0ZWx5IHN0YW5kYXJkaXplZCB2YWx1ZXMuIFNvIHRoZSBhbnRpY2lwYXRlZCBjb3ZhcmlhbmNlIGFuZCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZXNlIHR3byByZXNpZHVhbCB0ZXJtcywgaWYgdGhpcyBwYXJhbWV0ZXIgd2hlcmUgdG8gYmUgZXN0aW1hdGVkLCBhcmUgLjExNSwgLjIzOSwgcmVzcGVjdGl2ZWx5LiAgIA0KDQojIyBBIFJldmlzZWQgTW9kZWwgDQpIZXJlIHdlIGFyZSBvcGVyYXRpbmcgaW4gdGhlIE1HIG1vZGU7IG91ciByZS1zcGVjaWZpY2F0aW9uIGlzIGF0aGVvcmV0aWMgYW5kIHNpbXBseSBkYXRhLWRyaXZlbi4gIE5vbmV0aGVsZXNzLCB3ZSBpbGx1c3RyYXRlIGhvdyBvbmUgbWlnaHQgc3BlY2lmeSBhbmQgZml0IHN1Y2ggYSBtb2RlbC4NCiAgDQpSZS1TcGVjaWZ5IGFuZCBSZS1SdW4gdGhlIG1vZGVsOiAgDQpJIGFkZGVkIG9uZSBhZGRpdGlvbmFsIHBhcmFtZXRlciBgdjYgfn4gdjlgLCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmVzaWR1YWwgdmFyaWFuY2VzIG9mIHRoZXNlIHR3byBpdGVtcyBiZWNhdXNlIHRoZSBNSSBmcm9tIE1vZGVsIDEgaW5kaWNhdGVkIHRoYXQgZG9pbmcgc28gd291bGQgaGF2ZSB0aGUgZ3JlYXRlc3QgaW1wYWN0IG9uIGltcHJvdmluZyBtb2RlbCBmaXQuIFRoZXJlIGlzIG5vIHRoZW9yZXRpY2FsIHJhdGlvbmFsZSBmb3IgYWRkaW5nIHRoaXMgdHlwZSBvZiBwYXJhbWV0ZXIgYmVjYXVzZSBpbiB0cmFkaXRpb25hbCBDRkEgbW9kZWxzIHRoZSByZXNpZHVhbCB0ZXJtcyBhcmUgYXNzdW1lZCB0byBiZSBpbmRlcGVuZGVudCAoaS5lLiwgdW5jb3JyZWxhdGVkKS4gIA0KYGBge3J9DQptb2RlbDIgPC0gJyBTRSAgPX4gdjEgKyB2MiArIHYzICsgdjQgKyB2NSArIHY2ICsgdjcgKyB2OCArIHY5ICsgdjEwDQogICAgICAgICAgICB2NiB+fiB2OSAnDQpmaXQyIDwtIGNmYShtb2RlbDIsIHNhbXBsZS5jb3Y9Y292ZnVsbCwgc2FtcGxlLm5vYnM9OTczLCBzdGQubHY9RiApDQpgYGANCg0KIyMjIFBhdGggRGlhZ3JhbSBNb2RlbCAyDQpgYGB7cn0NCiMtLW1ha2luZyBDRkEgcGF0aCBkaWFncmFtLS0tLS0tLS0tLS0tLS0tLS0tLS0tbWFyKGJvdCxsZnQsdG9wLHJndCkNCmZpZzIgPC1zZW1QbG90OjpzZW1QYXRocyhmaXQyLCB3aGF0TGFiZWxzID0gInN0ZCIsIGxheW91dCA9ICJ0cmVlMiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJvdGF0aW9uID0gMSwgc3R5bGUgPSAibGlzcmVsIiwgb3B0aW1pemVMYXRSZXMgPSBULCANCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3R1cmFsID0gRiwgbGF5b3V0U3BsaXQgPSBGLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyY2VwdHMgPSBGLCByZXNpZHVhbHMgPSBULCANCiAgICAgICAgICAgICAgICAgICAgICAgICBjdXJ2ZSA9IDEsIGN1cnZhdHVyZSA9IDMsIG5DaGFyTm9kZXMgPSA4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICBzaXplTGF0ID0gOCwgc2l6ZU1hbiA9IDYsIHNpemVNYW4yID0gNiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgZWRnZS5sYWJlbC5jZXggPSAwLjksIGxhYmVsLmNleD0xLjEsIHJlc2lkU2NhbGU9MTAsIG1hcj1jKDE5LDIsMTksMiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGVkZ2UuY29sb3IgPSAiYmxhY2siLCBlZGdlLmxhYmVsLnBvc2l0aW9uID0gLjYwLCBEb05vdFBsb3Q9VCkNCmZpZzIuMSA8LSBmaWcyIHw+IG1hcmtfc2lnKGZpdDIsIGFscGhhID0gYygiKG4ucy4pIiA9IDEuMDAsICIqIiA9IC4wNSkpDQpwbG90KGZpZzIuMSkgIA0KDQpgYGANCiAgDQpOb3RlIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3byByZXNpZHVhbHMgaXMgLjIzLCBhcyB3YXMgc3VnZ2VzdGVkIGJ5IHRoZSBNSSBmcm9tIE1vZGVsIDEuICANCiAgDQoNCiMjIyBGdWxsIG91dHB1dCAyDQpgYGB7ciwgY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCnN1bW1hcnkoZml0MiwgZml0Lm1lYXN1cmVzPVQsIHN0YW5kYXJkaXplZD1ULCByc3F1YXJlPVQpDQpgYGANCiAgDQpUaGUgJFxjaGleMl97TTJ9JCA9IDIzOS40NjQgd2l0aCAqZGYqID0gMzQsICpwKiA8IC4wMDEuICANClRoZSBSU01FQSA9IC4wNzksIFRMSSA9IC44OTQsIENGSSA9IC45MjAsIFNSTVIgPSAuMDQ5LiBTbywgdGhlIGZpdCBpcyBzb21ld2hhdCBpbXByb3ZlZCByZWxhdGl2ZSB0byBNb2RlbCAxLiBBIGZvcm1hbCB0ZXN0IGNvbXBhcmluZyB0aGUgdHdvIG1vZGVscyBpcyBzaG93biBiZWxvdy4NCg0KDQojIyMgUmVzaWR1YWwgQ29ycmVsYXRpb25zIDINClRoZSB2YWx1ZXMgYmVsb3cgYXJlIHRoZSByZXNpZHVhbCBjb3JyZWxhdGlvbnMgKGkuZS4sIG9ic2VydmVkIGNvcnJlbGF0aW9uIC0gbW9kZWwgZXN0aW1hdGVkIGNvcnJlbGF0aW9uKS4gVGhlIGF2ZXJhZ2UgYWJzb2x1dGUgdmFsdWVzIG9mIHRoZXNlIHJlc2lkdWFscyBpcyBwcm92aWRlZCBieSB0aGUgc3RhbmRhcmRpemVkIHJvb3QgbWVhbiBzcXVhcmUgcmVzaWR1YWwgKFNSTVIpLiBOb3RlIHRoYXQgdGhlIHJlc2lkdWFsIGNvcnJlbGF0aW9uIGJldHdlZW4gdjYgYW5kIHY5IGlzIG5vdyAwLjAwLg0KYGBge3J9DQpzZW1fcmVzaWR1YWxzKGZpdDIpDQpgYGANCg0KIyMjIEFuYWx5c2lzIG9mIFJlc2lkdWFscyAyDQpUaGUgb3V0cHV0IGJlbG93IGRpc3BsYXlzIHJlc2lkdWFsIGNvcnJlbGF0aW9ucyBhbmQgei1zY29yZXMgaW5kaWNhdGluZyB0aGUgbWFnbml0dWRlIG9mIHRoZSByZXNpZHVhbHMuIFR5cGljYWxseSwgeiB2YWx1ZXMgPiB8Mi41OHwgYXJlIGludGVycHJldGVkIGFzIHNpZ25pZmljYW50IGFuZCBpbmRpY2F0ZSB3aGVyZSB0aGUgbW9kZWwgaXMgZG9pbmcgYSBwb29yIGpvYiBvZiByZXByb2R1Y2luZyB0aGUgb2JzZXJ2ZWQgY29ycmVsYXRpb25zLg0KYGBge3IsY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCmxhdlJlc2lkdWFscyhmaXQyLCB0eXBlID0gImNvci5ib2xsZW4iKQ0KYGBgDQoNCiMjIyBNb2RpZmljYXRpb24gSW5kaWNlcyAyDQpUaGUgdmFsdWVzIG1heSBoYXZlIGNoYW5nZWQgZnJvbSB0aG9zZSBkZXJpdmVkIGZyb20gdGhlIGZpcnN0IG1vZGVsLlRoZSB2YWx1ZXMgYmVsb3cgaW5kaWNhdGUgdGhlIGRyb3AgaW4gJFxjaGleMl9NJCAoaS5lLiwgbW9kZWwgaW1wcm92ZW1lbnQpIGFudGljaXBhdGVkIGlmIHBhcmFtZXRlcnMgY3VycmVudGx5IGZpeGVkIGF0IDAuMCBhcmUgZnJlZWQgdG8gYmUgZXN0aW1hdGVkLiBOb3RlIHRoYXQgYGxocyBvcCByaHNgIHJlZmVycyB0byB0aGUgdmFyaWFibGUgb24gdGhlIGxlZnQgaGFuZCBzaWRlIGFuZCBvbiB0aGUgcmlnaHQgaGFuZCBzaWRlIG9mIHRoZSBvcGVyYXRpb24gc3ltYm9sICoqfn4qKiB3aGljaCBpbmRpY2F0ZXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSByZXNpZHVhbCB2YXJpYW5jZXMgb2YgdHdvIGl0ZW1zLiBUaGUgY3JpdGljYWwgdmFsdWUgb2YgJFxjaGleMiQgd2l0aCAqZGYqID0gMSBhbmQgJFxhbHBoYSA9IC4wNSQgaXMgMy44NDEsIHNvIGFueSBNSSBncmVhdGVyIHRoYW4gdGhpcyB2YWx1ZSBpcyB3b3J0aCBleGFtaW5hdGlvbi4gIA0KYGBge3IsIGNsYXNzLm91dHB1dD0ic2Nyb2xsLTUwMCJ9DQptb2RpZmljYXRpb25JbmRpY2VzKGZpdDIsIHNvcnQuID0gVFJVRSwgbWluaW11bS52YWx1ZSA9IDMpDQpgYGANCg0KIyMjIENvbXBhcmluZyBNb2RlbHMgMSB2IDINClRoZSBkaWZmZXJlbmNlIGluIHRoZSBmaXQgb2YgdGhlIHR3byBtb2RlbHMgaXMgaXRzZWxmIGRpc3RyaWJ1dGVkIGFzIGEgJFxjaGleMl9cRGVsdGEkIHdpdGggKmRmKiBlcXVhbCB0byB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgbnVtYmVyIG9mICpkZiogZm9yIHRoZSB0d28gbW9kZWxzLiAgDQpIZXJlICAkXGNoaV4yX1xEZWx0YSQgPSAkXGNoaV4yX3tNMX0kIC0gJFxjaGleMl97TTJ9JC4gIA0KYGBge3J9DQojIGNvbXBhcmluZyBuZXN0ZWQgbW9kZWxzIHZpYSBjaGlzcSBsaWtlbGlob29kIHJhdGlvIHRlc3QNCmxhdlRlc3RMUlQoZml0MixmaXQxLCB0eXBlID0gImNoaXNxIikNCg0KYGBgDQpOb3RlIHRoYXQgdGhlIG1vZGVsIGNvbXBhcmlzb24gdGVzdCBpcyBzaWduaWZpY2FudDsgJFxjaGleMl9cRGVsdGEkID0gNDMuNjc4LCAqZGYqID0gMSwgKnAqIDwgLjA1LiAoUmVjYWxsIHRoYXQgdGhlIGFudGljaXBhdGVkIGRyb3AgaW4gJFxjaGleMl97TX0kIGJhc2VkIG9uIHRoZSBNSSBmcm9tIE1vZGVsIDEgd2FzIDQzLjgwNC4pIEFsbG93aW5nIHRoZSByZXNpZHVhbCB0ZXJtcyBvZiB2NiBhbmQgdjkgdG8gY29ycmVsYXRlIHNpZ25pZmljYW50bHkgaW1wcm92ZWQgdGhlIGZpdCBvZiB0aGUgbW9kZWwuIFdlIGNvdWxkIGNvbnRpbnVlIGluIHRoZSBNRyBtb2RlIGJ5IGZyZWVpbmcgdGhlIHBhcmFtZXRlciB3aXRoIHRoZSBuZXh0IGxhcmdlc3QgTUkgYW5kIHJlLXJ1bm5pbmcgdGhlIG1vZGVsIHRvIGltcHJvdmUgbW9kZWwgZml0LCBidXQgdGhpcyBzdHJhdGVneSBpcyBzaW1wbHkgZGF0YSBkcml2ZW4gYW5kIHdlIGFyZSBsZWZ0IHdpdGggYSBtb2RlbCB0aGF0IHdlIGNhbm5vdCBkZWZlbmQgb24gdGhlb3JldGljYWwgZ3JvdW5kcy4NCg0KIyMgQW4gQWx0ZXJuYXRpdmUgQ0ZBIE1vZGVsDQpJbnNwZWN0aW9uIG9mIHRoZSBNSSBhbmQgcmVzaWR1YWxzIChmcm9tIE1vZGVscyAxIGFuZCAyKSBsZWQgbWUgdG8gZm9ybXVsYXRlIGEgKiphIHNlY29uZCBoeXBvdGhlc2lzKiogcmVnYXJkaW5nIHRoZSBmYWN0b3Igc3RydWN0dXJlIG9mIHRoZSBTZWxmLUVzdGVlbSBTY2FsZS4gSSBub3RpY2VkIHRoYXQgcGFpcnMgb2YgaXRlbXMgdGhhdCBhcmUgbmVnYXRpdmVseSB3b3JkZWQgaGFkIGxhcmdlIE1JIHZhbHVlcy4gVGhpcyBwYXR0ZXJuIHN1Z2dlc3RlZCBhIHR5cGUgb2YgdHdvLWZhY3RvciBtb2RlbCByZWZlcnJlZCB0byBpbiB0aGUgcHN5Y2hvbWV0cmljcyBsaXRlcmF0dXJlIGFzIGEgY29tbW9uIG1ldGhvZCB2YXJpYW5jZSBtb2RlbC4gIA0KICANCk15IGFsdGVybmF0aXZlIG1vZGVsIChNb2RlbCAzKSBwb3NpdHMgdHdvIGNvcnJlbGF0ZWQgbGF0ZW50IGZhY3RvcnMuIFRoZSBpdGVtcyB0aGF0IGFyZSBuZWdhdGl2ZWx5IHdvcmRlZCAoYW5kIHJldmVyc2Ugc2NvcmVkKSBsb2FkIG9uIG9uZSBmYWN0b3IgKFNFbikgYW5kIHRoZSBpdGVtcyB0aGF0IGFyZSBwb3NpdGl2ZWx5IHdvcmRlZCBsb2FkIG9uIHRoZSBzZWNvbmQgZmFjdG9yIChTRXApLiBBbGwgMTAgaXRlbXMgbWVhc3VyZSBTZWxmLUVzdGVlbSwgYnV0IHRoZSB3YXkgdGhhdCB0aGUgaXRlbXMgYXJlIHdvcmRlZCBjb250cmlidXRlcyBzeXN0ZW1hdGljYWxseSB0byB0aGVpciBpbnRlci1pdGVtIGNvdmFyaWFuY2VzL2NvcnJlbGF0aW9ucy4gIA0KTm90ZSB0aGF0IE1vZGVsIDMgaGFzIG9ubHkgb25lIG1vcmUgcGFyYW1ldGVyIHRoYW4gTW9kZWwgMSwgYW5kIHRoZSBzYW1lIG51bWJlciBvZiBwYXJhbWV0ZXJzIGFzIE1vZGVsIDIsIGJ1dCB1bmxpa2UgTW9kZWwgMiwgTW9kZWwgMyBpcyB0aGVvcmV0aWNhbGx5IGJhc2VkLiAgDQogIA0KICANClNwZWNpZnkgYW5kIHJ1biB0aGUgbW9kZWw6DQpgYGB7cn0NCm1vZGVsMyA8LSAnIA0KU0VwICA9fiB2MSArIHYzICsgdjUgKyB2OCArIHYxMCANClNFbiAgPX4gdjIgKyB2NCArIHY2ICsgdjcgKyB2OSANCicNCmZpdDMgPC0gY2ZhKG1vZGVsMywgc2FtcGxlLmNvdj1jb3ZmdWxsLCBzYW1wbGUubm9icz05NzMsIHN0ZC5sdj1GICkNCmBgYA0KDQojIyMgUGF0aCBEaWFncmFtIE1vZGVsIDMNCmBgYHtyfQ0KIy0tbWFraW5nIENGQSBwYXRoIGRpYWdyYW0tLS0tLS0tLS0tLS0tLS0tLS0tLS1tYXIoYm90LGxmdCx0b3Ascmd0KQ0KZmlnMyA8LXNlbVBsb3Q6OnNlbVBhdGhzKGZpdDMsIHdoYXRMYWJlbHMgPSAic3RkIiwgbGF5b3V0ID0gInRyZWUyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcm90YXRpb24gPSAxLCBzdHlsZSA9ICJsaXNyZWwiLCBvcHRpbWl6ZUxhdFJlcyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHN0cnVjdHVyYWwgPSBGLCBsYXlvdXRTcGxpdCA9IEYsDQogICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJjZXB0cyA9IEYsIHJlc2lkdWFscyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnZlID0gMSwgY3VydmF0dXJlID0gMywgbkNoYXJOb2RlcyA9IDgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVMYXQgPSA4LCBzaXplTWFuID0gNiwgc2l6ZU1hbjIgPSA2LCANCiAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlLmxhYmVsLmNleCA9IDAuOSwgbGFiZWwuY2V4PTEuMSwgcmVzaWRTY2FsZT0xMCwgbWFyPWMoMTksMiwxOSwyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgZWRnZS5jb2xvciA9ICJibGFjayIsIGVkZ2UubGFiZWwucG9zaXRpb24gPSAuNjAsIERvTm90UGxvdD1UKQ0KZmlnMy4xIDwtIGZpZzMgfD4gbWFya19zaWcoZml0MywgYWxwaGEgPSBjKCIobi5zLikiID0gMS4wMCwgIioiID0gLjA1KSkNCnBsb3QoZmlnMy4xKSAgDQoNCmBgYA0KICANCg0KTm90ZSB0aGF0IHRoZSBwYXRocyBjb25uZWN0aW5nIHYxIHRvIFNFcCBhbmQgdjIgdG8gU0VuIGFyZSBkYXNoZWQuIFRoaXMgaXMgdG8gaW5kaWNhdGUgdGhhdCBlYWNoIHdhcyB1c2VkIGFzIGEgInJlZmVyZW5jZSB2YXJpYWJsZSIgdG8gZGVmaW5lIHRoZSBtZXRyaWMgb2YgdGhlIGxhdGVudCB2YXJpYWJsZXMsIHNvIHRoZXJlIGFyZSBubyB0ZXN0cyBvZiBzaWduaWZpY2FuY2UgYXNzb2NpYXRlZCB3aXRoIHRoZW0uIEZvciB0aGUgU0VwIGZhY3RvciB0aGUgbG9hZGluZ3MgcmFuZ2UgZnJvbSAuNTYgdG8gLjY4LCBhbmQgZm9yIHRoZSBTRW4gZmFjdG9yLCBsb2FkaW5ncyByYW5nZSBmcm9tIC4zOSB0byAuNzEuICAgDQoNClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gbGF0ZW50IGZhY3RvcnMgaXMgLjc3LCBzdWdnZXN0aW5nIHRoYXQgdGhlIHR3byBmYWN0b3JzIGFyZSBub3QgdmVyeSBkaXN0aW5jdCBmcm9tIG9uZSBhbm90aGVyLiAgDQogIA0KVGhlIHJlc2lkdWFsIHRlcm1zLCBlc3RpbWF0aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGluIGVhY2ggaXRlbSB0aGF0IGlzIG5vdCBhc3NvY2lhdGVkIHdpdGggaXRzIHJlc3BlY3RpdmUgbGF0ZW50IGZhY3RvciByYW5nZSBmcm9tIC41MCB0byAuODUuIHYyIHN0aWxsIGhhcyBjb25zaWRlcmFibGUgbWVhc3VyZW1lbnQgZXJyb3IuICANCiAgDQoNCiMjIyBGdWxsIG91dHB1dCAzDQpgYGB7ciwgY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCnN1bW1hcnkoZml0MywgZml0Lm1lYXN1cmVzPVQsIHN0YW5kYXJkaXplZD1ULCByc3F1YXJlPVQpDQpgYGANCiAgDQpUaGUgJFxjaGleMl97TTN9JCA9IDExOS45MjYgd2l0aCAqZGYqID0gMzQsICpwKiA8IC4wMDEuICANClRoZSBSU01FQSA9IC4wNTEsIFRMSSA9IC45NTYsIENGSSA9IC45NjYsIFNSTVIgPSAuMDMyLiBTbywgYWxsIGluZGljZXMgc3VnZ2VzdCBhIGdvb2QgZml0LiAgIA0KQSBmb3JtYWwgdGVzdCBjb21wYXJpbmcgdGhpcyBhbHRlcm5hdGl2ZSBtb2RlbCB3aXRoIHRoZSBvcmlnaW5hbCBtb2RlbCBpcyBzaG93biBiZWxvdy4NCg0KIyMjIFJlc2lkdWFsIENvcnJlbGF0aW9ucyAzDQpUaGUgdmFsdWVzIGJlbG93IGFyZSB0aGUgcmVzaWR1YWwgY29ycmVsYXRpb25zIChpLmUuLCBvYnNlcnZlZCBjb3JyZWxhdGlvbiAtIG1vZGVsIGVzdGltYXRlZCBjb3JyZWxhdGlvbikuIFRoZSBhdmVyYWdlIGFic29sdXRlIHZhbHVlcyBvZiB0aGVzZSByZXNpZHVhbHMgaXMgcHJvdmlkZWQgYnkgdGhlIHN0YW5kYXJkaXplZCByb290IG1lYW4gc3F1YXJlIHJlc2lkdWFsIChTUk1SKS4NCmBgYHtyfQ0Kc2VtX3Jlc2lkdWFscyhmaXQzKQ0KYGBgDQoNCiMjIyBBbmFseXNpcyBvZiBSZXNpZHVhbHMgMw0KVGhlIG91dHB1dCBiZWxvdyBkaXNwbGF5cyByZXNpZHVhbCBjb3JyZWxhdGlvbnMgYW5kIHotc2NvcmVzIGluZGljYXRpbmcgdGhlIG1hZ25pdHVkZSBvZiB0aGUgcmVzaWR1YWxzLiBUeXBpY2FsbHksIHogdmFsdWVzID4gfDIuNTh8IGFyZSBpbnRlcnByZXRlZCBhcyBzaWduaWZpY2FudCBhbmQgaW5kaWNhdGUgd2hlcmUgdGhlIG1vZGVsIGlzIGRvaW5nIGEgcG9vciBqb2Igb2YgcmVwcm9kdWNpbmcgdGhlIG9ic2VydmVkIGNvcnJlbGF0aW9ucy4NCmBgYHtyLGNsYXNzLm91dHB1dD0ic2Nyb2xsLTUwMCJ9DQpsYXZSZXNpZHVhbHMoZml0MywgdHlwZSA9ICJjb3IuYm9sbGVuIikNCmBgYA0KVGhlIHotc2NvcmVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmVzaWR1YWwgY29ycmVsYXRpb25zIGFyZSBsZXNzIGV4dHJlbWUgdGhhdCB0aG9zZSBmcm9tIE1vZGVsIDEgYWJvdmUuDQogIA0KSWRlYWxseSB0aGUgcmVzaWR1YWwgY29ycmVsYXRpb25zIHNob3VsZCBiZSBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIGEgbWVhbiBvZiAwLjAuIE9uZSB3YXkgdG8gZXhhbWluZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIHJlc2lkdWFscyBpcyB3aXRoIGEgKipzdGVtLWFuZC1sZWFmIHBsb3QqKiB3aGljaCBpcyBhIHR5cGUgb2Ygc2lkZXdheXMgaGlzdG9ncmFtLiBUaGUgZmlyc3QgMiBkaWdpdHMgb2YgZWFjaCByZXNpZHVhbCBjb3JyZWxhdGlvbiBhcmUgdG8gdGhlIGxlZnQgb2YgdGhlIHwgc3ltYm9sIGFuZCBhcmUgcmVmZXJyZWQgdG8gYXMgdGhlICpzdGVtKi4gVGhlIHRoaXJkIGRpZ2l0IG9mIGVhY2ggcmVzaWR1YWwgY29ycmVsYXRpb24gaXMgdG8gdGhlIHJpZ2h0IG9mIHRoZSB8IGFuZCBpcyByZWZlcnJlZCB0byBhcyBhICpsZWFmKi4gVGhlIHBsb3Qgc2hvd3MgdGhlIG51bWJlciAoYW5kIHZhbHVlKSBvZiB0aGUgbGVhdmVzIGZvciBlYWNoIHN0ZW0uIE5vdGUgdGhhdCB0aGVyZSBhcmUgbm8gZGVjaW1hbCBwb2ludHMgaW4gdGhlIHBsb3Q7IHRoZSBpbXBsaWVkIGRlY2ltYWwgcG9pbnQgaXMgdHdvIGRpZ2l0cyB0byB0aGUgbGVmdCBvZiB0aGUgfCBzeW1ib2wuICANCg0KDQpgYGB7cixjbGFzcy5vdXRwdXQ9InNjcm9sbC01MDAifQ0Kc3RlbSggbGF2UmVzaWR1YWxzKGZpdDMsIG91dHB1dCA9ICJ0YWJsZSIpJHJlcyApICMgZ2l2ZXMgc3RlbS9sZWFmIHBsb3Qgb2YgcmVzaWQgY29ycw0KYGBgDQoNCkJhc2VkIG9uIHRoZSBzdGVtLWFuZC1sZWFmIHBsb3QsIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHJlc2lkdWFsIGNvcnJlbGF0aW9ucyBsb29rcyBhIGJpdCBtb3JlIG5vcm1hbCBhbmQgdGhlIHZhbHVlcyBhcmUgbGVzcyBleHRyZW1lIHRoYW4gdGhvc2UgZnJvbSBNb2RlbCAxIGFib3ZlLiBIZXJlIG1vc3Qgb2YgdGhlIHJlc2lkdWFscyBhcmUgYmV0d2VlbiAtLjAyOSBhbmQgLS4wMDkgKHRoZXJlIGFyZSBtb3JlIGxlYXZlcyBvbiB0aGUgdHdvIHN0ZW1zIC0yIGFuZCAtMCB0aGFuIHRoZXJlIGFyZSBvbiBhbnkgb2YgdGhlIG90aGVyIHN0ZW1zKS4NCg0KIyMjIE1vZGlmaWNhdGlvbiBJbmRpY2VzIDMNClRoZSB2YWx1ZXMgYmVsb3cgaW5kaWNhdGUgdGhlIGRyb3AgaW4gJFxjaGleMl9NJCAoaS5lLiwgbW9kZWwgaW1wcm92ZW1lbnQpIGFudGljaXBhdGVkIGlmIHBhcmFtZXRlcnMgY3VycmVudGx5IGZpeGVkIGF0IDAuMCBhcmUgZnJlZWQgdG8gYmUgZXN0aW1hdGVkLiBOb3RlIHRoYXQgYGxocyBvcCByaHNgIHJlZmVycyB0byB0aGUgdmFyaWFibGUgb24gdGhlIGxlZnQgaGFuZCBzaWRlIGFuZCBvbiB0aGUgcmlnaHQgaGFuZCBzaWRlIG9mIHRoZSBvcGVyYXRpb24gc3ltYm9sICoqfn4qKiB3aGljaCBpbmRpY2F0ZXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSByZXNpZHVhbCB2YXJpYW5jZXMgb2YgdHdvIGl0ZW1zLlRoZSBjcml0aWNhbCB2YWx1ZSBvZiAkXGNoaV4yJCB3aXRoICpkZiogPSAxIGFuZCAkXGFscGhhID0gLjA1JCBpcyAzLjg0MSwgc28gYW55IE1JIGdyZWF0ZXIgdGhhbiB0aGlzIHZhbHVlIGlzIHdvcnRoIGV4YW1pbmF0aW9uLiAgDQpgYGB7ciwgY2xhc3Mub3V0cHV0PSJzY3JvbGwtNTAwIn0NCm1vZGlmaWNhdGlvbkluZGljZXMoZml0Mywgc29ydC4gPSBUUlVFLCBtaW5pbXVtLnZhbHVlID0gMykNCmBgYA0KDQojIyMgQ29tcGFyaW5nIE1vZGVscyAxIHYgMw0KVGhlIGRpZmZlcmVuY2UgaW4gdGhlIGZpdCBvZiB0aGUgdHdvIG1vZGVscyBpcyBpdHNlbGYgZGlzdHJpYnV0ZWQgYXMgYSAkXGNoaV4yX1xEZWx0YSQgd2l0aCAqZGYqIGVxdWFsIHRvIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBudW1iZXIgb2YgKmRmKiBmb3IgdGhlIHR3byBtb2RlbHMuICANCkhlcmUgJFxjaGleMl9cRGVsdGEkID0gJFxjaGleMl97TTF9JCAtICRcY2hpXjJfe00zfSQuICANCg0KYGBge3J9DQojIGNvbXBhcmluZyBuZXN0ZWQgbW9kZWxzIHZpYSBjaGlzcSBsaWtlbGlob29kIHJhdGlvIHRlc3QNCmxhdlRlc3RMUlQoZml0MyxmaXQxLCB0eXBlID0gImNoaXNxIikNCg0KYGBgDQpTbyB0aGUgJFxjaGleMl9cRGVsdGEkIHRlc3QgaW5kaWNhdGVzIHRoYXQgdGhlIHR3by1mYWN0b3IgY29tbW9uIG1ldGhvZCB2YXJpYW5jZSBtb2RlbCBmaXRzIHRoZSBvYnNlcnZlZCBjb3ZhcmlhbmNlcyAoY29ycmVsYXRpb25zKSBhbW9uZyB0aGUgaXRlbXMgYmV0dGVyIHRoYW4gdGhlIGluaXRpYWwgb25lLWZhY3RvciBtb2RlbC4gQWxsIDEwIGl0ZW1zIG1lYXN1cmUgU2VsZi1Fc3RlZW0sIGJ1dCB0aGUgd2F5IGluIHdoaWNoIHRoZSBpdGVtcyBhcmUgd29yZGVkIGNvbnRyaWJ1dGVzIHN5c3RlbWF0aWNhbGx5IHRvIHRoZSBpbnRlci1pdGVtIGNvcnJlbGF0aW9ucy4gIA0KDQojIyMgUmVsaWFiaWxpdHkgMw0KYGBge3J9DQpzZW1Ub29sczo6Y29tcFJlbFNFTShmaXQzLCB0YXUuZXE9VCwgb2JzLnZhcj1ULCByZXR1cm4udG90YWw9VCkgDQpgYGANClRoZSByZWxpYWJpbGl0eSBhbmFseXNpcyBpbmRpY2F0ZXMgdGhhdCBpZiB0d28gc2VwYXJhdGUgc3Vic2NhbGVzIChTRXAgYW5kIFNFbikgd2VyZSB0byBiZSB1c2VkIHRoZXkgd291bGQgbm90IGJlIGFzIHJlbGlhYmxlIGFzIHRoZSB0b3RhbCBzY2FsZSBzY29yZSAoLjc3OCwgNzE3LCBhbmQgLjgyNyByZXNwZWN0aXZlbHkpLiBBbHNvLCBub3RlIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3byBmYWN0b3JzIGlzIHN0cm9uZyAoLjc3KSBhbmQgc28gdXNpbmcgdHdvIHN1YnNjYWxlcyBhcyBwcmVkaWN0b3JzIGluIGEgcmVncmVzc2lvbiBtb2RlbCB3b3VsZCBsaWtlbHkgcmVzdWx0IGluIGNvbGluZWFyaXR5IHByb2JsZW1zLiBJbiBwcmFjdGljZSwgcmVzZWFyY2hlcnMgYXJlIGJldHRlciBvZmYgdXNpbmcgdGhlIDEwIGl0ZW1zIHRvIGZvcm0gYSBzaW5nbGUgc2NhbGUgc2NvcmUuDQoNCg0KIyMgQ29uY2x1ZGluZyBSZW1hcmtzDQpJbiB0aGlzIGxlY3R1cmUgd2Ugd29ya2VkIHRocm91Z2ggdGhlIHRocmVlIGFwcHJvYWNoZXMgdG8gU0VNOyB0aGVzZSBhcmUgc3RyaWN0bHkgY29uZmlybWF0b3J5LCBtb2RlbCBnZW5lcmF0aW9uLCBhbmQgdGVzdGluZyBhbHRlcm5hdGl2ZSBtb2RlbHMuICBUaGUgaW5pdGlhbCB1bmktZGltZW5zaW9uYWwgbW9kZWwgb2YgdGhlIFJvc2VuYnVyZyBTZWxmLUVzdGVlbSBTY2FsZSAoTW9kZWwgMSkgd2FzIG5vdCBzdXBwb3J0ZWQuIEd1aWRlZCBieSB0aGUgbW9kaWZpY2F0aW9uIGluZGljZXMgd2UgaWxsdXN0cmF0ZWQgaG93IHRvIGFkZCBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdHdvIHJlc2lkdWFsIHRlcm1zIChNb2RlbCAyKS4gTW9kZWwgMiBpbXByb3ZlZCBmaXQsIGJ1dCB0ZWNobmljYWxseSBpdCBpcyBub3QgYSB0cnVlIENGQSBtZWFzdXJlbWVudCBtb2RlbCBiZWNhdXNlIHN1Y2ggbW9kZWxzIHBvc2l0IHRoYXQgdGhlIHJlc2lkdWFsIHZhcmlhbmNlcyBvZiB0aGUgaW5kaWNhdG9yIHZhcmlhYmxlcyAoaXRlbXMpIGFyZSBhbGwgdW5jb3JyZWxhdGVkLiBXZSBjb3VsZCBoYXZlIGNvbnRpbnVlZCB0byBhZGQgY29ycmVsYXRpb25zIGFtb25nIHJlc2lkdWFsIHRlcm1zIHRvIGltcHJvdmUgdGhlIG1vZGVsIGZpdCwgc3VjaCBhIG1vZGVsIHdvdWxkIGJlIGRpZmZpY3VsdCB0byBkZWZlbmQgb24gdGhlb3JldGljYWwgZ3JvdW5kcy4gICAgDQpNb2RlbCAzIHdhcyBhbiBhbHRlcm5hdGl2ZSBtb2RlbCwgYmFzZWQgaW4gdGhlb3J5IChpbiB0aGlzIGNhc2UgdGhlIGNvbW1vbiBtZXRob2QgdmFyaWFuY2UgbW9kZWwpIHRoYXQgd2FzIHNob3duIHRvIGJlIHRoZSBiZXN0IGZpdHRpbmcgbW9kZWwgZXhhbWluZWQgaGVyZS4gVGhpcyByZXN1bHQgaWxsdXN0cmF0ZXMgdGhhdCB0aGUgd29yZGluZyBvZiBpdGVtcyAocG9zaXRpdmUgb3IgbmVnYXRpdmUpIHRoYXQgbWFrZSB1cCBzZWxmLXJlcG9ydCBzY2FsZXMgY2FuIGluZmx1ZW5jZSBob3cgcGVvcGxlIHJlc3BvbmQgdG8gdGhlbSB3aGljaCBpbiB0dXJuIGluZmx1ZW5jZXMgdGhlIGNvcnJlbGF0aW9ucyBhbW9uZyB0aGUgc2NhbGUgaXRlbXMuICANCiAgDQpNb2RlbCAyIGFuZCBNb2RlbCAzIGhhdmUgdGhlIHNhbWUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgKDIxKSBhbmQgdGhlIHNhbWUgbnVtYmVyIG9mICpkZiogKDM0KSBzbyB0aGV5IGNhbm5vdCBiZSBjb21wYXJlZCB1c2luZyB0aGUgJFxjaGleMl9cRGVsdGEkIHRlc3QgZm9yIG5lc3RlZCBtb2RlbHMuIFRoZSBBa2Fpa2UgaW5mb3JtYXRpb24gY3JpdGVyaWEgKEFJQykgY2FuIGJlIHVzZWQgdG8gY29tcGFyZSB0aGUgcmVsYXRpdmUgZml0IG9mIHR3byBub24tbmVzdGVkIG1vZGVsczsgc21hbGxlciB2YWx1ZXMgaW5kaWNhdGUgYmV0dGVyIGZpdC4gKHNlZSBGdWxsIE91dHB1dHMgYWJvdmUgZm9yIEFJQyB2YWx1ZXMuKSBGb3IgTW9kZWwgMiwgdGhlIEFJQyA9IDIyMzczLjk0MiwgYW5kIGZvciBNb2RlbCAzIHRoZSBBSUMgPSAyMjI1NC40MDQ7IHNvIE1vZGVsIDMgZml0cyBiZXR0ZXIgdGhhbiBNb2RlbCAyIGV2ZW4gdGhvdWdoIHRoZXkgaGF2ZSB0aGUgc2FtZSBudW1iZXIgb2YgcGFyYW1ldGVycy4gQXMgYW4gYXNpZGUsIE1vZGVsIDEgaGFkIEFJQyA9IDIyNDE1LjYyMC4gQmFzZWQgb24gdGhlIEFJQyB2YWx1ZXMgZnJvbSBhbGwgdGhyZWUgbW9kZWxzLCBNb2RlbCAzIGlzIHRoZSBwcmVmZXJyZWQgbW9kZWwuICANCg0KU0VNIGlzIGEgcG93ZXJmdWwgdG9vbCBhbGxvd2luZyByZXNlYXJjaGVycyB0byBmb3JtdWxhdGUgYW5kIHRlc3QgaHlwb3RoZXNlcyBhYm91dCB0aGUgdW5kZXJseWluZyBzdHJ1Y3R1cmUgb2YgY292YXJpYW5jZSBtYXRyaWNlcy4gV2hlbiB1c2VkIHdpc2VseSwgc3RydWN0dXJhbCBlcXVhdGlvbiBtb2RlbHMgY2FuIHByb3ZpZGUgdXNlZnVsIGluc2lnaHRzIGludG8gdGhlIGNvbXBsZXggcmVsYXRpb25zIGFtb25nIGEgc2V0IHZhcmlhYmxlcyByZWxldmFudCB0byBzb21lIHBoZW5vbWVub24gb2YgaW50ZXJlc3QuIA0K