Start Using the neg.semfit() Function

From the negligible R package


Introduction

What is the purpose/goal of neg.semfit()?

The function neg.semfit performs three different types of equivalence tests for the fit indices RMSEA, CFI, and SRMR. This function can be used instead of using neg.rmsea, neg.cfi, and neg.srmr separately.

What is the theory behind neg.semfit()?

For each of the three equivalence tests conducted, the function will compare one bound of the confidence interval (pertaining to the fit index) to one bound of an equivalence interval (also known as an equivalence bound).

For RMSEA and SRMR (because they are lower values are better fit indices), the upper bound of the confidence interval will be compared to the equivalence bound.

For CFI (because it is a higher value is better fit index), the lower bound of the confidence interval will be compared to the equivalence bound.

For more information on the theory behind these tests and choices of equivalence bounds see:

Beribisky, N., & Cribbie, R. A. (2023). Evaluating the performance of existing and novel equivalence tests for fit indices in structural equation modelling. British Journal of Mathematical and Statistical Psychology. 77(1), 103-129. https://doi.org/10.1111/bmsp.12317

MacCallum, R. C., Browne, M. W., & Sugawara, H. M. (1996). Power analysis and determination of sample size for covariance structure modeling. Psychological Methods, 1(2), 130–149. https://doi.org/10.1037/1082-989X.1.2.130

Maydeu-Olivares, A. (2017). Assessing the size of model misfit in structural equation models. Psychometrika, 82(3), 533–558. https://doi.org/10.1007/s11336-016-9552-7

Shi, D., Maydeu-Olivares, A., & DiStefano, C. (2018). The relationship between the standardized root mean square residual and model misspecification in factor analysis models. Multivariate Behavioral Research, 53(5), 676-694. https://doi.org/10.1080/00273171.2018.1476221

Yuan, K. H., Chan, W., Marcoulides, G. A., & Bentler, P. M. (2016). Assessing structural equation models by equivalence testing with adjusted fit indexes. Structural Equation Modeling: A Multidisciplinary Journal, 23(3), 319-330. https://doi.org/10.1080/10705511.2015.1065414

Null and Alternate Hypotheses of the Procedure

RMSEA: \(H_{0}: RMSEA_{pop} \ge MMES\) | \(H_{1}: RMSEA_{pop} < MMES\)

SRMR: \(H_{0}: SRMR_{pop} \ge MMES\) | \(H_{1}: SRMR_{pop} < MMES\)

CFI: \(H_{0}: CFI_{pop} \le MMES\) | \(H_{1}: CFI_{pop} > MMES\)

Note that the MMES is the minimally meaningful effect size, as approximated by the equivalence bound.

Using neg.semfit()

Now let’s use the function. By default, doing so requires a fitted model object from lavaan.

Required arguments (no default)

mod: the fitted model object (from lavaan)

Optional arguments (has a default)

alpha: the optional argument for the alpha level (default is .05),

round: the optional argument for the number of digits to round equivalence bound and confidence interval bounds (default is 3),

rmsea.eq.bound: the upper bound of the equivalence interval for RMSEA .Note that if rmsea.modif.eq.bound = TRUE, this value must be one of .01, .05, .08, or .10 (default is .05),

rmsea.modif.eq.bound: should the upper bound of the equivalence interval for RMSEA be modified (default is FALSE),

rmsea.ci.method: method used to calculate confidence interval for RMSEA; options are “not.close” or “yhy.boot”; “not.close” corresponds to (1-2alpha) percent CI, “yhy.boot” corresponds to (1-2alpha) percent boot CI (default is “not.close”),

rmsea.nboot: number of bootstrap samples if “yhy.boot” is selected as rmsea.ci.method (default is 250L)

cfi.eq.bound: lower bound of equivalence interval for CFI for comparison. This value must be one of .99, .95, .92 or .90 if cfi.modif.eq.bound = TRUE (default is FALSE),

cfi.modif.eq.bound: should the lower bound of the equivalence interval for CFI be modified (default is FALSE),

cfi.ci.method: method used to calculate confidence interval for CFI; options are “yuan”, “equiv” or “yhy.boot”; “yuan” corresponds to (1-alpha) percent CI, “equiv” corresponds to (1-2alpha) percent CI, “yhy.boot” corresponds to (1-2alpha) percent boot CI (default is “equiv”),

cfi.nboot: number of bootstrap samples if “yhy.boot” is selected as cfi.ci.method (default is 250L),

srmr.eq.bound: upper bound of equivalence interval for SRMR for comparison; note that this value must be one of .05 or .10 if modif.eq.bound = TRUE (default is .08),

srmr.modif.eq.bound: should the upper bound of the equivalence interval for SRMR be modified? (default is FALSE)

srmr.ci.method: method used to calculate confidence interval for SRMR; options are “MO” or “yhy.boot”; “MO” corresponds to (1-2alpha) percent CI, “yhy.boot” corresponds to (1-2alpha) percent boot CI (default is “MO”),

usrmr: fit index around which equivalence test should be structured. When usrmr = TRUE the usrmr from Maydeu-Olivares, 2017 will be used, otherwise srmr from fitmeasures() output in lavaan will be used (default is TRUE),

srmr.nboot: number of bootstrap samples if “yhy.boot” is selected as srmr.ci.method (default is 250L)

Examples

Example 1

First we need to create a model object using lavaan. Let’s use the Holzinger and Swineford dataset that is part of the lavaan package.

library(negligible)
library(lavaan)

d <- lavaan::HolzingerSwineford1939
hs.mod <- 'visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9'
fit1 <- lavaan::cfa(hs.mod, data = d)

Now we can use the function. Let’s say that we just go with the defaults first.

neg.semfit(mod = fit1)
** Equivalence/Negligible Effect Tests for Evaluating Model Fit ** 


* RMSEA-Based Test: * 

---- EBF-RMSEA: Equivalence Based Fit Test for RMSEA; the Not-Close Fit Test for RMSEA by MacCallum et al. (1996) ----

RMSEA index: 0.09212148 
*************************************
Confidence Interval Method Selected: not.close 
Upper end of 90% CI for RMSEA: 0.114
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.05 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 FAIL TO REJECT HO: We fail to find evidence to reject the hypothesis of not-close fit. 



* CFI-Based Test: * 
---- EBFB-CFI: Equivalence Based Fit Test for CFI using YHY Bootstrap for CI ----

CFI index: 0.9305597 
*************************************
Confidence Interval Method Selected: yhy.boot 
Lower end of 90% CI for CFI: 0.899
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.95 
*************************************
Test Decision (comparing confidence interval to equivalence bound): FAIL TO REJECT HO: We fail to reject the hypothesis that the specified model is not substantially better fitting than the baseline model. 



* SRMR-Based Test: * 
---- Equivalence Based Fit Test for Unbiased SRMR ----

uSRMR index: 0.05800319 
*************************************
Confidence Interval Method Selected: MO 
Upper bound of 90% CI for SRMR: 0.074
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.08 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 REJECT HO: The null hypothesis that the population SRMR exceeds the equivalence bound can be rejected. There is evidence to support satisfactory fit, given the value of the equivalence bound. 

Example 2

Of course we don’t have to rely on the defaults, and the equivalence bounds should be informed by the smallest misspecification a researcher would deem to be important. Let’s change some.

neg.semfit(mod = fit1,  rmsea.eq.bound = .10,
           cfi.eq.bound = .92,
           srmr.eq.bound = .10)
** Equivalence/Negligible Effect Tests for Evaluating Model Fit ** 


* RMSEA-Based Test: * 

---- EBF-RMSEA: Equivalence Based Fit Test for RMSEA; the Not-Close Fit Test for RMSEA by MacCallum et al. (1996) ----

RMSEA index: 0.09212148 
*************************************
Confidence Interval Method Selected: not.close 
Upper end of 90% CI for RMSEA: 0.114
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.1 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 FAIL TO REJECT HO: We fail to find evidence to reject the hypothesis of not-close fit. 



* CFI-Based Test: * 
---- EBFB-CFI: Equivalence Based Fit Test for CFI using YHY Bootstrap for CI ----

CFI index: 0.9305597 
*************************************
Confidence Interval Method Selected: yhy.boot 
Lower end of 90% CI for CFI: 0.901
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.92 
*************************************
Test Decision (comparing confidence interval to equivalence bound): FAIL TO REJECT HO: We fail to reject the hypothesis that the specified model is not substantially better fitting than the baseline model. 



* SRMR-Based Test: * 
---- Equivalence Based Fit Test for Unbiased SRMR ----

uSRMR index: 0.05800319 
*************************************
Confidence Interval Method Selected: MO 
Upper bound of 90% CI for SRMR: 0.074
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.1 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 REJECT HO: The null hypothesis that the population SRMR exceeds the equivalence bound can be rejected. There is evidence to support satisfactory fit, given the value of the equivalence bound. 

Example 3

We can also use modified equivalence bounds. For instance, if we wanted to modify according to the adapted cutoff formula provided by Shi et al. 2018, we can change the input to the srmr.modif.eq.bound argument. Note that we can only do this because our equivalence bound for SRMR is .10 (it needs to be either .05 or .10 to apply this change).

neg.semfit(mod = fit1,  rmsea.eq.bound = .10,
           cfi.eq.bound = .92,
           srmr.eq.bound = .10, srmr.modif.eq.bound = TRUE)
** Equivalence/Negligible Effect Tests for Evaluating Model Fit ** 


* RMSEA-Based Test: * 

---- EBF-RMSEA: Equivalence Based Fit Test for RMSEA; the Not-Close Fit Test for RMSEA by MacCallum et al. (1996) ----

RMSEA index: 0.09212148 
*************************************
Confidence Interval Method Selected: not.close 
Upper end of 90% CI for RMSEA: 0.114
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.1 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 FAIL TO REJECT HO: We fail to find evidence to reject the hypothesis of not-close fit. 



* CFI-Based Test: * 
---- EBFB-CFI: Equivalence Based Fit Test for CFI using YHY Bootstrap for CI ----

CFI index: 0.9305597 
*************************************
Confidence Interval Method Selected: yhy.boot 
Lower end of 90% CI for CFI: 0.898
*************************************
Modified Equivalence Bound: no 
Equivalence Bound: 0.92 
*************************************
Test Decision (comparing confidence interval to equivalence bound): FAIL TO REJECT HO: We fail to reject the hypothesis that the specified model is not substantially better fitting than the baseline model. 



* SRMR-Based Test: * 
---- Equivalence Based Fit Test for Unbiased SRMR and Modified Equivalence Interval ----

uSRMR index: 0.05800319 
*************************************
Confidence Interval Method Selected: MO 
Upper bound of 90% CI for SRMR: 0.074
*************************************
Modified Equivalence Bound: yes 
Equivalence Bound: 0.051 
*************************************
Test Decision (comparing confidence interval to equivalence bound):
 FAIL TO REJECT HO: The null hypothesis that the population SRMR exceeds the equivalence bound cannot be rejected. 

Extractable Elements

A number of elements of the output can be extracted, including the following (note that the setup below will follow the named object containing the results; thus if the results of the negsem.fit function are saved to an object named x, x$ with the following additions will produce the corresponding extractable elements):

rmsea.res$rmsea_index The RMSEA value

rmsea.res$ci.method The confidence interval method selected for computing the upper bound of the confidence interval for the RMSEA

rmsea.res$alpha Nominal Type I error rate (this value will be the same for all RMSEA/CFI/SRMR tests)

rmsea.res$rmsea_eq The value of the upper bound of the confidence interval for CFI

msea.res$modif.eq.bound Whether a modified equivalence bound was used for the RMSEA equivalence test

rmsea.res$eq.bound The value of the equivalence bound used for the RMSEA equivalence test

rmsea.res$decision NHST decision for the RMSEA equivalence test

cfi.res$cfi_index The CFI value

cfi.res$ci.method TThe confidence interval method selected for computing the lower bound of the confidence interval for the CFI

cfi.res$alpha Nominal Type I error rate (this value will be the same for all RMSEA/CFI/SRMR tests)

cfi.res$cfi_eq The value of the lower bound of the confidence interval for CFI

cfi.res$modif.eq.bound Whether a modified equivalence bound was used for the CFI equivalence test

cfi.res$eq.bound The value of the equivalence bound used for the CFI equivalence test

cfi.res$decision NHST decision for the CFI equivalence test

srmr.res$usrmr Whether the unbiased SRMR is used for the equivalence test

srmr.res$srmr_index The SRMR index (USRMR or original SRMR depending on whether usrmr is TRUE or FALSE)

srmr.res$ci.method The confidence interval method selected for computing the upper bound of the confidence interval for the SRMR

srmr.res$alpha Nominal Type I error rate (this value will be the same for all RMSEA/CFI/SRMR tests)

srmr.res$srmr_ci The value of the upper bound of the confidence interval for SRMR

srmr.res$modif.eq.bound Whether a modified equivalence bound was used for the SRMR equivalence test

srmr.res$eq.bound The value of the equivalence bound used for the SRMR equivalence test

srmr.res$decision NHST decision for the SRMR equivalence test

LS0tDQp0aXRsZTogIlN0YXJ0IFVzaW5nIHRoZSBgbmVnLnNlbWZpdCgpYCBGdW5jdGlvbiINCnN1YnRpdGxlOiB8IA0KICAgIEZyb20gdGhlIFtgbmVnbGlnaWJsZWBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9uZWdsaWdpYmxlL2luZGV4Lmh0bWwpIFIgcGFja2FnZSFbXShJOi9NeSBEcml2ZS9SZXNlYXJjaC9DcmliYmllIExhYi9uZWdsaWdpYmxlIFZpZ25ldHRlcy9UZW1wbGF0ZS9uZWcubG9nby5wbmcpe3dpZHRoPTEwJX0gIA0KYXV0aG9yOiAiW05hdGFseSBCZXJpYmlza3kgYW5kIFJvYiBDcmliYmllXSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSlgIg0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpyb2JvYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KYGBge3Igc2V0dXAsIGVjaG89RkFMU0UsIGNhY2hlPUZBTFNFLCBtZXNzYWdlcz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNpbnN0YWxsLnBhY2thZ2VzKCJybWRmb3JtYXRzIikNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHJtZGZvcm1hdHMsIHdhcm4uY29uZmxpY3RzPUZBTFNFKSkNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGtuaXRyLCB3YXJuLmNvbmZsaWN0cz1GQUxTRSkpDQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UsIHdhcm4uY29uZmxpY3RzPUZBTFNFKSkNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSwgd2Fybi5jb25mbGljdHM9RkFMU0UpKQ0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkocmVhZHhsLCB3YXJuLmNvbmZsaWN0cz1GQUxTRSkpDQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShwbG90bHksIHdhcm4uY29uZmxpY3RzPUZBTFNFKSkNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KE1ldEJyZXdlciwgd2Fybi5jb25mbGljdHM9RkFMU0UpKQ0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoZ2dhbmltYXRlLCB3YXJuLmNvbmZsaWN0cz1GQUxTRSkpDQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShkcGx5ciwgd2Fybi5jb25mbGljdHM9RkFMU0UpKQ0KDQojIyBHbG9iYWwgb3B0aW9ucw0Kb3B0aW9ucyhtYXgucHJpbnQ9Ijc1IikNCm9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwNCgkgICAgICAgICAgICAgY2FjaGU9VFJVRSwNCiAgICAgICAgICAgICAgIHByb21wdD1GQUxTRSwNCiAgICAgICAgICAgICAgIGNvbW1lbnQ9TkEsDQogICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLA0KICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkNCm9wdHNfa25pdCRzZXQod2lkdGg9NzUpDQpgYGANCg0KPGJyLz4NCg0KIyMgKipJbnRyb2R1Y3Rpb24qKg0KDQoNCg0KIyMjICoqV2hhdCBpcyB0aGUgcHVycG9zZS9nb2FsIG9mIGBuZWcuc2VtZml0KClgPyoqDQoNClRoZSBmdW5jdGlvbiBuZWcuc2VtZml0IHBlcmZvcm1zIHRocmVlIGRpZmZlcmVudCB0eXBlcyBvZiBlcXVpdmFsZW5jZSB0ZXN0cyBmb3IgdGhlIGZpdCBpbmRpY2VzIFJNU0VBLCBDRkksIGFuZCBTUk1SLiBUaGlzIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIGluc3RlYWQgb2YgdXNpbmcgbmVnLnJtc2VhLCBuZWcuY2ZpLCBhbmQgbmVnLnNybXIgc2VwYXJhdGVseS4NCg0KIyMjICoqV2hhdCBpcyB0aGUgdGhlb3J5IGJlaGluZCBgbmVnLnNlbWZpdCgpYD8qKg0KDQpGb3IgZWFjaCBvZiB0aGUgdGhyZWUgZXF1aXZhbGVuY2UgdGVzdHMgY29uZHVjdGVkLCB0aGUgZnVuY3Rpb24gd2lsbCBjb21wYXJlIG9uZSBib3VuZCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCAocGVydGFpbmluZyB0byB0aGUgZml0IGluZGV4KSB0byBvbmUgYm91bmQgb2YgYW4gZXF1aXZhbGVuY2UgaW50ZXJ2YWwgKGFsc28ga25vd24gYXMgYW4gZXF1aXZhbGVuY2UgYm91bmQpLg0KDQpGb3IgUk1TRUEgYW5kIFNSTVIgKGJlY2F1c2UgdGhleSBhcmUgbG93ZXIgdmFsdWVzIGFyZSBiZXR0ZXIgZml0IGluZGljZXMpLCB0aGUgdXBwZXIgYm91bmQgb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgd2lsbCBiZSBjb21wYXJlZCB0byB0aGUgZXF1aXZhbGVuY2UgYm91bmQuDQoNCkZvciBDRkkgKGJlY2F1c2UgaXQgaXMgYSBoaWdoZXIgdmFsdWUgaXMgYmV0dGVyIGZpdCBpbmRleCksIHRoZSBsb3dlciBib3VuZCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCB3aWxsIGJlIGNvbXBhcmVkIHRvIHRoZSBlcXVpdmFsZW5jZSBib3VuZC4NCg0KRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhlIHRoZW9yeSBiZWhpbmQgdGhlc2UgdGVzdHMgYW5kIGNob2ljZXMgb2YgZXF1aXZhbGVuY2UgYm91bmRzIHNlZToNCg0KQmVyaWJpc2t5LCBOLiwgJiBDcmliYmllLCBSLiBBLiAoMjAyMykuIEV2YWx1YXRpbmcgdGhlIHBlcmZvcm1hbmNlIG9mIGV4aXN0aW5nIGFuZCBub3ZlbCBlcXVpdmFsZW5jZSB0ZXN0cyBmb3IgZml0IGluZGljZXMgaW4gc3RydWN0dXJhbCBlcXVhdGlvbiBtb2RlbGxpbmcuIEJyaXRpc2ggSm91cm5hbCBvZiBNYXRoZW1hdGljYWwgYW5kIFN0YXRpc3RpY2FsIFBzeWNob2xvZ3kuIDc3KDEpLCAxMDMtMTI5LiBodHRwczovL2RvaS5vcmcvMTAuMTExMS9ibXNwLjEyMzE3DQoNCk1hY0NhbGx1bSwgUi4gQy4sIEJyb3duZSwgTS4gVy4sICYgU3VnYXdhcmEsIEguIE0uICgxOTk2KS4gUG93ZXIgYW5hbHlzaXMgYW5kIGRldGVybWluYXRpb24gb2Ygc2FtcGxlIHNpemUgZm9yIGNvdmFyaWFuY2Ugc3RydWN0dXJlIG1vZGVsaW5nLiBQc3ljaG9sb2dpY2FsIE1ldGhvZHMsIDEoMiksIDEzMOKAkzE0OS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzcvMTA4Mi05ODlYLjEuMi4xMzANCg0KTWF5ZGV1LU9saXZhcmVzLCBBLiAoMjAxNykuIEFzc2Vzc2luZyB0aGUgc2l6ZSBvZiBtb2RlbCBtaXNmaXQgaW4gc3RydWN0dXJhbCBlcXVhdGlvbiBtb2RlbHMuIFBzeWNob21ldHJpa2EsIDgyKDMpLCA1MzPigJM1NTguIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3L3MxMTMzNi0wMTYtOTU1Mi03DQoNClNoaSwgRC4sIE1heWRldS1PbGl2YXJlcywgQS4sICYgRGlTdGVmYW5vLCBDLiAoMjAxOCkuIFRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgc3RhbmRhcmRpemVkIHJvb3QgbWVhbiBzcXVhcmUgcmVzaWR1YWwgYW5kIG1vZGVsIG1pc3NwZWNpZmljYXRpb24gaW4gZmFjdG9yIGFuYWx5c2lzIG1vZGVscy4gTXVsdGl2YXJpYXRlIEJlaGF2aW9yYWwgUmVzZWFyY2gsIDUzKDUpLCA2NzYtNjk0LiBodHRwczovL2RvaS5vcmcvMTAuMTA4MC8wMDI3MzE3MS4yMDE4LjE0NzYyMjENCg0KWXVhbiwgSy4gSC4sIENoYW4sIFcuLCBNYXJjb3VsaWRlcywgRy4gQS4sICYgQmVudGxlciwgUC4gTS4gKDIwMTYpLiBBc3Nlc3Npbmcgc3RydWN0dXJhbCBlcXVhdGlvbiBtb2RlbHMgYnkgZXF1aXZhbGVuY2UgdGVzdGluZyB3aXRoIGFkanVzdGVkIGZpdCBpbmRleGVzLiBTdHJ1Y3R1cmFsIEVxdWF0aW9uIE1vZGVsaW5nOiBBIE11bHRpZGlzY2lwbGluYXJ5IEpvdXJuYWwsIDIzKDMpLCAzMTktMzMwLiBodHRwczovL2RvaS5vcmcvMTAuMTA4MC8xMDcwNTUxMS4yMDE1LjEwNjU0MTQNCg0KDQojIyMjICpOdWxsIGFuZCBBbHRlcm5hdGUgSHlwb3RoZXNlcyBvZiB0aGUgUHJvY2VkdXJlKg0KDQpSTVNFQToNCiRIX3swfTogUk1TRUFfe3BvcH0gXGdlIE1NRVMkIHwNCiRIX3sxfTogUk1TRUFfe3BvcH0gPCBNTUVTJA0KDQpTUk1SOg0KJEhfezB9OiBTUk1SX3twb3B9IFxnZSBNTUVTJCB8DQokSF97MX06IFNSTVJfe3BvcH0gPCBNTUVTJA0KDQpDRkk6DQokSF97MH06IENGSV97cG9wfSBcbGUgTU1FUyQgfA0KJEhfezF9OiBDRklfe3BvcH0gPiBNTUVTJA0KDQpOb3RlIHRoYXQgdGhlIE1NRVMgaXMgdGhlIG1pbmltYWxseSBtZWFuaW5nZnVsIGVmZmVjdCBzaXplLCBhcyBhcHByb3hpbWF0ZWQgYnkgdGhlIGVxdWl2YWxlbmNlIGJvdW5kLg0KDQoNCiMjIyAqKlVzaW5nIGBuZWcuc2VtZml0KClgKioNCg0KTm93IGxldCdzIHVzZSB0aGUgZnVuY3Rpb24uIEJ5IGRlZmF1bHQsIGRvaW5nIHNvIHJlcXVpcmVzIGEgZml0dGVkIG1vZGVsIG9iamVjdCBmcm9tIGxhdmFhbi4NCg0KIyMjIyAqUmVxdWlyZWQgYXJndW1lbnRzIChubyBkZWZhdWx0KSoNCg0KKm1vZCo6IHRoZSBmaXR0ZWQgbW9kZWwgb2JqZWN0IChmcm9tIGxhdmFhbikNCg0KDQoNCiMjIyMgKk9wdGlvbmFsIGFyZ3VtZW50cyAoaGFzIGEgZGVmYXVsdCkqDQoNCiphbHBoYSo6IHRoZSBvcHRpb25hbCBhcmd1bWVudCBmb3IgdGhlIGFscGhhIGxldmVsIChkZWZhdWx0IGlzIC4wNSksIA0KDQoqcm91bmQqOiB0aGUgb3B0aW9uYWwgYXJndW1lbnQgZm9yIHRoZSBudW1iZXIgb2YgZGlnaXRzIHRvIHJvdW5kIGVxdWl2YWxlbmNlIGJvdW5kIGFuZCBjb25maWRlbmNlIGludGVydmFsIGJvdW5kcyAoZGVmYXVsdCBpcyAzKSwNCg0KKnJtc2VhLmVxLmJvdW5kKjogdGhlIHVwcGVyIGJvdW5kIG9mIHRoZSBlcXVpdmFsZW5jZSBpbnRlcnZhbCBmb3IgUk1TRUEgLk5vdGUgdGhhdCBpZiBybXNlYS5tb2RpZi5lcS5ib3VuZCA9IFRSVUUsIHRoaXMgdmFsdWUgbXVzdCBiZSBvbmUgb2YgLjAxLCAuMDUsIC4wOCwgb3IgLjEwIChkZWZhdWx0IGlzIC4wNSksDQoNCipybXNlYS5tb2RpZi5lcS5ib3VuZCo6IHNob3VsZCB0aGUgdXBwZXIgYm91bmQgb2YgdGhlIGVxdWl2YWxlbmNlIGludGVydmFsIGZvciBSTVNFQSBiZSBtb2RpZmllZCAoZGVmYXVsdCBpcyBGQUxTRSksDQoNCipybXNlYS5jaS5tZXRob2QqOiBtZXRob2QgdXNlZCB0byBjYWxjdWxhdGUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgUk1TRUE7IG9wdGlvbnMgYXJlICJub3QuY2xvc2UiIG9yICJ5aHkuYm9vdCI7ICJub3QuY2xvc2UiIGNvcnJlc3BvbmRzIHRvICgxLTJhbHBoYSkgcGVyY2VudCBDSSwgInloeS5ib290IiBjb3JyZXNwb25kcyB0byAoMS0yYWxwaGEpIHBlcmNlbnQgYm9vdCBDSSAoZGVmYXVsdCBpcyAibm90LmNsb3NlIiksDQoNCipybXNlYS5uYm9vdCo6IG51bWJlciBvZiBib290c3RyYXAgc2FtcGxlcyBpZiAieWh5LmJvb3QiIGlzIHNlbGVjdGVkIGFzIHJtc2VhLmNpLm1ldGhvZCAoZGVmYXVsdCBpcyAyNTBMKQ0KDQoqY2ZpLmVxLmJvdW5kKjogbG93ZXIgYm91bmQgb2YgZXF1aXZhbGVuY2UgaW50ZXJ2YWwgZm9yIENGSSBmb3IgY29tcGFyaXNvbi4gVGhpcyB2YWx1ZSBtdXN0IGJlIG9uZSBvZiAuOTksIC45NSwgLjkyIG9yIC45MCBpZiBjZmkubW9kaWYuZXEuYm91bmQgPSBUUlVFDQooZGVmYXVsdCBpcyBGQUxTRSksDQoNCipjZmkubW9kaWYuZXEuYm91bmQqOiBzaG91bGQgdGhlIGxvd2VyIGJvdW5kIG9mIHRoZSBlcXVpdmFsZW5jZSBpbnRlcnZhbCBmb3IgQ0ZJIGJlIG1vZGlmaWVkIChkZWZhdWx0IGlzIEZBTFNFKSwNCg0KKmNmaS5jaS5tZXRob2QqOiBtZXRob2QgdXNlZCB0byBjYWxjdWxhdGUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgQ0ZJOyBvcHRpb25zIGFyZSAieXVhbiIsICJlcXVpdiIgb3IgInloeS5ib290IjsgInl1YW4iIGNvcnJlc3BvbmRzIHRvICgxLWFscGhhKSBwZXJjZW50IENJLCAiZXF1aXYiIGNvcnJlc3BvbmRzIHRvICgxLTJhbHBoYSkgcGVyY2VudCBDSSwgInloeS5ib290IiBjb3JyZXNwb25kcyB0byAoMS0yYWxwaGEpIHBlcmNlbnQgYm9vdCBDSSAoZGVmYXVsdCBpcyAiZXF1aXYiKSwNCg0KKmNmaS5uYm9vdCo6IG51bWJlciBvZiBib290c3RyYXAgc2FtcGxlcyBpZiAieWh5LmJvb3QiIGlzIHNlbGVjdGVkIGFzIGNmaS5jaS5tZXRob2QgKGRlZmF1bHQgaXMgMjUwTCksDQoNCipzcm1yLmVxLmJvdW5kKjogdXBwZXIgYm91bmQgb2YgZXF1aXZhbGVuY2UgaW50ZXJ2YWwgZm9yIFNSTVIgZm9yIGNvbXBhcmlzb247IG5vdGUgdGhhdCB0aGlzIHZhbHVlIG11c3QgYmUgb25lIG9mIC4wNSBvciAuMTAgaWYgbW9kaWYuZXEuYm91bmQgPSBUUlVFIChkZWZhdWx0IGlzIC4wOCksDQoNCipzcm1yLm1vZGlmLmVxLmJvdW5kKjogc2hvdWxkIHRoZSB1cHBlciBib3VuZCBvZiB0aGUgZXF1aXZhbGVuY2UgaW50ZXJ2YWwgZm9yIFNSTVIgYmUgbW9kaWZpZWQ/IChkZWZhdWx0IGlzIEZBTFNFKQ0KDQoqc3Jtci5jaS5tZXRob2QqOiBtZXRob2QgdXNlZCB0byBjYWxjdWxhdGUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgU1JNUjsgb3B0aW9ucyBhcmUgIk1PIiBvciAieWh5LmJvb3QiOyAiTU8iIGNvcnJlc3BvbmRzIHRvICgxLTJhbHBoYSkgcGVyY2VudCBDSSwgInloeS5ib290IiBjb3JyZXNwb25kcyB0byAoMS0yYWxwaGEpIHBlcmNlbnQgYm9vdCBDSSAoZGVmYXVsdCBpcyAiTU8iKSwNCg0KKnVzcm1yKjogZml0IGluZGV4IGFyb3VuZCB3aGljaCBlcXVpdmFsZW5jZSB0ZXN0IHNob3VsZCBiZSBzdHJ1Y3R1cmVkLiBXaGVuIHVzcm1yID0gVFJVRSB0aGUgdXNybXIgZnJvbSBNYXlkZXUtT2xpdmFyZXMsIDIwMTcgd2lsbCBiZSB1c2VkLCBvdGhlcndpc2Ugc3JtciBmcm9tIGZpdG1lYXN1cmVzKCkgb3V0cHV0IGluIGxhdmFhbiB3aWxsIGJlIHVzZWQgKGRlZmF1bHQgaXMgVFJVRSksDQoNCipzcm1yLm5ib290KjogbnVtYmVyIG9mIGJvb3RzdHJhcCBzYW1wbGVzIGlmICJ5aHkuYm9vdCIgaXMgc2VsZWN0ZWQgYXMgc3Jtci5jaS5tZXRob2QgKGRlZmF1bHQgaXMgMjUwTCkNCg0KDQoNCiMjICoqRXhhbXBsZXMqKg0KDQojIyMgKipFeGFtcGxlIDEqKg0KDQpGaXJzdCB3ZSBuZWVkIHRvIGNyZWF0ZSBhIG1vZGVsIG9iamVjdCB1c2luZyBsYXZhYW4uIExldCdzIHVzZSB0aGUgSG9semluZ2VyIGFuZCBTd2luZWZvcmQgZGF0YXNldCB0aGF0IGlzIHBhcnQgb2YgdGhlIGxhdmFhbiBwYWNrYWdlLg0KYGBge3J9DQpsaWJyYXJ5KG5lZ2xpZ2libGUpDQpsaWJyYXJ5KGxhdmFhbikNCg0KZCA8LSBsYXZhYW46OkhvbHppbmdlclN3aW5lZm9yZDE5MzkNCmhzLm1vZCA8LSAndmlzdWFsID1+IHgxICsgeDIgKyB4Mw0KdGV4dHVhbCA9fiB4NCArIHg1ICsgeDYNCnNwZWVkID1+IHg3ICsgeDggKyB4OScNCmZpdDEgPC0gbGF2YWFuOjpjZmEoaHMubW9kLCBkYXRhID0gZCkNCmBgYA0KDQpOb3cgd2UgY2FuIHVzZSB0aGUgZnVuY3Rpb24uIExldCdzIHNheSB0aGF0IHdlIGp1c3QgZ28gd2l0aCB0aGUgZGVmYXVsdHMgZmlyc3QuDQoNCmBgYHtyfQ0KbmVnLnNlbWZpdChtb2QgPSBmaXQxKQ0KYGBgDQoNCg0KIyMjICoqRXhhbXBsZSAyKioNCg0KT2YgY291cnNlIHdlIGRvbid0IGhhdmUgdG8gcmVseSBvbiB0aGUgZGVmYXVsdHMsIGFuZCB0aGUgZXF1aXZhbGVuY2UgYm91bmRzIHNob3VsZCBiZSBpbmZvcm1lZCBieSB0aGUgc21hbGxlc3QgbWlzc3BlY2lmaWNhdGlvbiBhIHJlc2VhcmNoZXIgd291bGQgZGVlbSB0byBiZSBpbXBvcnRhbnQuIExldCdzIGNoYW5nZSBzb21lLg0KDQpgYGB7cn0NCm5lZy5zZW1maXQobW9kID0gZml0MSwgIHJtc2VhLmVxLmJvdW5kID0gLjEwLA0KICAgICAgICAgICBjZmkuZXEuYm91bmQgPSAuOTIsDQogICAgICAgICAgIHNybXIuZXEuYm91bmQgPSAuMTApDQpgYGANCg0KIyMjICoqRXhhbXBsZSAzKioNCg0KV2UgY2FuIGFsc28gdXNlIG1vZGlmaWVkIGVxdWl2YWxlbmNlIGJvdW5kcy4gRm9yIGluc3RhbmNlLCBpZiB3ZSB3YW50ZWQgdG8gbW9kaWZ5IGFjY29yZGluZyB0byB0aGUgYWRhcHRlZCBjdXRvZmYgZm9ybXVsYSBwcm92aWRlZCBieSBTaGkgZXQgYWwuIDIwMTgsIHdlIGNhbiBjaGFuZ2UgdGhlIGlucHV0IHRvIHRoZSBzcm1yLm1vZGlmLmVxLmJvdW5kIGFyZ3VtZW50LiBOb3RlIHRoYXQgd2UgY2FuIG9ubHkgZG8gdGhpcyBiZWNhdXNlIG91ciBlcXVpdmFsZW5jZSBib3VuZCBmb3IgU1JNUiBpcyAuMTAgKGl0IG5lZWRzIHRvIGJlIGVpdGhlciAuMDUgb3IgLjEwIHRvIGFwcGx5IHRoaXMgY2hhbmdlKS4NCg0KYGBge3J9DQpuZWcuc2VtZml0KG1vZCA9IGZpdDEsICBybXNlYS5lcS5ib3VuZCA9IC4xMCwNCiAgICAgICAgICAgY2ZpLmVxLmJvdW5kID0gLjkyLA0KICAgICAgICAgICBzcm1yLmVxLmJvdW5kID0gLjEwLCBzcm1yLm1vZGlmLmVxLmJvdW5kID0gVFJVRSkNCmBgYA0KDQojIyAqKkV4dHJhY3RhYmxlIEVsZW1lbnRzKioNCg0KQSBudW1iZXIgb2YgZWxlbWVudHMgb2YgdGhlIG91dHB1dCBjYW4gYmUgZXh0cmFjdGVkLCBpbmNsdWRpbmcgdGhlIGZvbGxvd2luZyAobm90ZSB0aGF0IHRoZSBzZXR1cCBiZWxvdyB3aWxsIGZvbGxvdyB0aGUgbmFtZWQgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHJlc3VsdHM7IHRodXMgaWYgdGhlIHJlc3VsdHMgb2YgdGhlIG5lZ3NlbS5maXQgZnVuY3Rpb24gYXJlIHNhdmVkIHRvIGFuIG9iamVjdCBuYW1lZCB4LCB4JCB3aXRoIHRoZSBmb2xsb3dpbmcgYWRkaXRpb25zIHdpbGwgcHJvZHVjZSB0aGUgY29ycmVzcG9uZGluZyBleHRyYWN0YWJsZSBlbGVtZW50cyk6DQoNCipybXNlYS5yZXMkcm1zZWFfaW5kZXgqIFRoZSBSTVNFQSB2YWx1ZQ0KDQoqcm1zZWEucmVzJGNpLm1ldGhvZCogVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbWV0aG9kIHNlbGVjdGVkIGZvciBjb21wdXRpbmcgdGhlIHVwcGVyIGJvdW5kIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgUk1TRUENCg0KKnJtc2VhLnJlcyRhbHBoYSogTm9taW5hbCBUeXBlIEkgZXJyb3IgcmF0ZSAodGhpcyB2YWx1ZSB3aWxsIGJlIHRoZSBzYW1lIGZvciBhbGwgUk1TRUEvQ0ZJL1NSTVIgdGVzdHMpDQoNCipybXNlYS5yZXMkcm1zZWFfZXEqIFRoZSB2YWx1ZSBvZiB0aGUgdXBwZXIgYm91bmQgb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIENGSQ0KDQoqbXNlYS5yZXMkbW9kaWYuZXEuYm91bmQqIFdoZXRoZXIgYSBtb2RpZmllZCBlcXVpdmFsZW5jZSBib3VuZCB3YXMgdXNlZCBmb3IgdGhlIFJNU0VBIGVxdWl2YWxlbmNlIHRlc3QNCg0KKnJtc2VhLnJlcyRlcS5ib3VuZCogVGhlIHZhbHVlIG9mIHRoZSBlcXVpdmFsZW5jZSBib3VuZCB1c2VkIGZvciB0aGUgUk1TRUEgZXF1aXZhbGVuY2UgdGVzdA0KDQoqcm1zZWEucmVzJGRlY2lzaW9uKiBOSFNUIGRlY2lzaW9uIGZvciB0aGUgUk1TRUEgZXF1aXZhbGVuY2UgdGVzdA0KDQoqY2ZpLnJlcyRjZmlfaW5kZXgqIFRoZSBDRkkgdmFsdWUNCg0KKmNmaS5yZXMkY2kubWV0aG9kKiBUVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbWV0aG9kIHNlbGVjdGVkIGZvciBjb21wdXRpbmcgdGhlIGxvd2VyIGJvdW5kIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgQ0ZJDQoNCipjZmkucmVzJGFscGhhKiBOb21pbmFsIFR5cGUgSSBlcnJvciByYXRlICh0aGlzIHZhbHVlIHdpbGwgYmUgdGhlIHNhbWUgZm9yIGFsbCBSTVNFQS9DRkkvU1JNUiB0ZXN0cykNCg0KKmNmaS5yZXMkY2ZpX2VxKiBUaGUgdmFsdWUgb2YgdGhlIGxvd2VyIGJvdW5kIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciBDRkkNCg0KKmNmaS5yZXMkbW9kaWYuZXEuYm91bmQqIFdoZXRoZXIgYSBtb2RpZmllZCBlcXVpdmFsZW5jZSBib3VuZCB3YXMgdXNlZCBmb3IgdGhlIENGSSBlcXVpdmFsZW5jZSB0ZXN0DQoNCipjZmkucmVzJGVxLmJvdW5kKiBUaGUgdmFsdWUgb2YgdGhlIGVxdWl2YWxlbmNlIGJvdW5kIHVzZWQgZm9yIHRoZSBDRkkgZXF1aXZhbGVuY2UgdGVzdA0KDQoqY2ZpLnJlcyRkZWNpc2lvbiogTkhTVCBkZWNpc2lvbiBmb3IgdGhlIENGSSBlcXVpdmFsZW5jZSB0ZXN0DQoNCipzcm1yLnJlcyR1c3JtciogV2hldGhlciB0aGUgdW5iaWFzZWQgU1JNUiBpcyB1c2VkIGZvciB0aGUgZXF1aXZhbGVuY2UgdGVzdA0KDQoqc3Jtci5yZXMkc3Jtcl9pbmRleCogVGhlIFNSTVIgaW5kZXggKFVTUk1SIG9yIG9yaWdpbmFsIFNSTVIgZGVwZW5kaW5nIG9uIHdoZXRoZXIgdXNybXIgaXMgVFJVRSBvciBGQUxTRSkNCg0KKnNybXIucmVzJGNpLm1ldGhvZCogVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbWV0aG9kIHNlbGVjdGVkIGZvciBjb21wdXRpbmcgdGhlIHVwcGVyIGJvdW5kIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgU1JNUg0KDQoqc3Jtci5yZXMkYWxwaGEqIE5vbWluYWwgVHlwZSBJIGVycm9yIHJhdGUgKHRoaXMgdmFsdWUgd2lsbCBiZSB0aGUgc2FtZSBmb3IgYWxsIFJNU0VBL0NGSS9TUk1SIHRlc3RzKQ0KDQoqc3Jtci5yZXMkc3Jtcl9jaSogVGhlIHZhbHVlIG9mIHRoZSB1cHBlciBib3VuZCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgU1JNUg0KDQoqc3Jtci5yZXMkbW9kaWYuZXEuYm91bmQqIFdoZXRoZXIgYSBtb2RpZmllZCBlcXVpdmFsZW5jZSBib3VuZCB3YXMgdXNlZCBmb3IgdGhlIFNSTVIgZXF1aXZhbGVuY2UgdGVzdA0KDQoqc3Jtci5yZXMkZXEuYm91bmQqIFRoZSB2YWx1ZSBvZiB0aGUgZXF1aXZhbGVuY2UgYm91bmQgdXNlZCBmb3IgdGhlIFNSTVIgZXF1aXZhbGVuY2UgdGVzdA0KDQoqc3Jtci5yZXMkZGVjaXNpb24qIE5IU1QgZGVjaXNpb24gZm9yIHRoZSBTUk1SIGVxdWl2YWxlbmNlIHRlc3Q=