This supplement presents an empirical investigation into the characteristics of a set of \(M=5\) fully-synthetic samples generated from a single sample of \(n=10,000\) records from the California data using CART FCS synthesizers; see main text for a detailed description. The set of synthetic samples corresponds to the first replication of the repeated sampling experiment (Section 3.1 from main text), using the the CART FCS synthesizer with a small (cp = 0.0001) complexity parameter.

The complexity, or ``contamination" parameter in CART models determine the maximum level, relative to the root node, of impurity on the leaves that is acceptable to stop splitting (see Hastie, Tibshirani, and Friedman 2009, p305). In the case of discrete data, this is usually measured using the Gini index (Hastie, Tibshirani, and Friedman 2009, Drechsler and Reiter (2011)). Smaller complexity parameters leads to better fitted trees, at the risk of overfitting. Thus, as noted by (Drechsler and Reiter 2011), CART FCS synthesizers with a small contamination parameter can lead to very high-utility data. However, as we will show here, in some cases they achieve this extreme performance in part by essentially reproducing a fair portion the original confidential data. This behavior defeats the purpose of generating synthetic data for mitigating disclosure risk.

What follows can be seen as an informal investigation into the disclosure risk of the synthetic data generated by the aforementioned CART FCS synthesizer.

FCS CART Can Create Extremely High-utility Synthetic Samples

We start by loading the original population (into “popu_tab”), the sample of \(n=10,000\) records from that population (into “samp”), and the \(M = 5\) synthetic datasets generated from that data using the CART synthesizer tuned with the small contamination parameter 0.0001 (into list “col_cart”). We chose the sample so that it corresponds to the first of the 200 replications in the repeated sampling experiment presented in the main article.

As expected, the synthetic data produces extremely high-quality inferences of the population quantities:

The left plot (MI_CART vs Population, left plot) shows that values calculated from the CART synthesizer are excellent. In fact, they are comparable to the ones obtained from the actual sample (right plot). Moreover, calculations with synthetic data are almost indistinguishable from calculations with the original data themselves:

Therefore, from a purely analytical utility-based perspective, it seems that the FCS CART synthesizer with small contamination parameter is the way to go. But let us now look at the actual synthetic datasets.

But it does so by directly disclosing large portions of the original data

FCS synthesizers work by, starting from the original data, vary one coordinate at a time by regressing said coordinate on the rest of the values, and using that model to generate replacing values for that coordinate using the Bayesian bootstrap, conditioning on the rest of the multivariate vector in a Gibbs sampler-like manner (J. P. Reiter 2005). The idea is that after at least a few full cycles, all entries in the dataset would be replaced by predicted values, forming the synthesized dataset. However, there is always a possibility that the regression ends up working too well (overfitting) and thus that the generated predicted values end up being too close, or even equal, to the original ones.

We start by checking how many of the \(n=10,000\) records have \(k \in \{0,1,...,17\}\) variables unchanged with respect to the original sample, in each of the \(M = 5\) synthetic data replications:

Here we can see that in each of the \(M = 5\) replications there are several records that are completely unchanged. For example, in the first replication (column labeled “Synth_Dat_1”) 386 records did not change at all after the application of the CART FCS synthesizer. This means that if the Agency were to release that supposedly safe synthetic dataset, they would be also releasing 386 of the original records. Furthermore, several of the records that have actually been altered have been so by just a few variables:

In this table we can see that in the first synthetic dataset more than half of the records (5535) are copies of the original records with at most 3 altered variables. Furthermore, we can see that there are no synthetic records that are not the result of keeping at least 5 variables unchanged.

Now let us look at how individual variables (the columns in the original dataset) are preserved after the application of the CART synthesizer. Here we calculated the percentage of records in each synthetic dataset where each variable has been left untouched, for each of the 17 variables. We have sorted the variables in descending order.

In this table we see that there are 9 variables (OWNERSHP, SCHLTYPE, EMPSTAT, VETSTAT, GRADEATT, DISABWRK, MORTGAGE and LOOKING) that after the application of the CART synthesizer are completely preserved in at least 80% of the records. Moreover, one variable (SCHOOL) is completely preserved in all synthetic datasets. This means that the supposedly synthetic data contains several variables that are almost verbatim copies of the confidential data, and one that is a perfect copy.

What is happening here?

To better understand this issue we will look closer to the synthesis of one particularly problematic record from the original sample. Record 1297 is an instance of a data point that after the application of the CART synthesizer was left completely unmodified in all \(M = 5\) synthetic datasets—and therefore perfectly disclosed.

We first select the record from the original data,

and also fit the 17 full conditional CART regression models, corresponding to each of the variables, using the original sample.

Now let us look at the predictions that we can obtain for each for the variables when conditioning on the rest of the row, following the FCS approach. In the next output we detail, for each of the \(j=1,...,17\) variables, its current value (“curr. value”) and the prediction probabilities associated with each of the levels of said variable (“p(level1), p(level2), etc.”), obtained from the fitted CARTs keeping the rest of the vector at their original values.

OWNERSHP: (3 levels)
    curr. value: 2
    Predictions:    p(0)=0.017 p(1)=0 p(2)=0.983 
MORTGAGE: (4 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(3)=0 p(4)=0 
SEX: (2 levels)
    curr. value: 1
    Predictions:    p(1)=0.569 p(2)=0.431 
AGE: (7 levels)
    curr. value: <15
    Predictions:    p([15,17])=0 p([18,24])=0 p([25,35])=0 p([36,50])=0 p([51,70])=0 p(<15)=1 p(>70)=0 
MARST: (6 levels)
    curr. value: 6
    Predictions:    p(1)=0 p(2)=0 p(3)=0 p(4)=0 p(5)=0 p(6)=1 
CITIZEN: (4 levels)
    curr. value: 0
    Predictions:    p(0)=0.938 p(1)=0 p(2)=0 p(3)=0.0619 
SPEAKENG: (6 levels)
    curr. value: 0
    Predictions:    p(0)=0.9 p(1)=0.02 p(3)=0.04 p(4)=0 p(5)=0.02 p(6)=0.02 
RACESING: (5 levels)
    curr. value: 1
    Predictions:    p(1)=0.806 p(2)=0.0583 p(3)=0.0291 p(4)=0.107 p(5)=0 
SCHOOL: (3 levels)
    curr. value: 1
    Predictions:    p(0)=0 p(1)=1 p(2)=0 
EDUC: (11 levels)
    curr. value: 0
    Predictions:    p(0)=0.979 p(1)=0.0209 p(2)=0 p(3)=0 p(4)=0 p(5)=0 p(6)=0 p(7)=0 p(8)=0 p(10)=0 p(11)=0 
GRADEATT: (8 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(2)=0 p(3)=0 p(4)=0 p(5)=0 p(6)=0 p(7)=0 
SCHLTYPE: (4 levels)
    curr. value: 1
    Predictions:    p(0)=0 p(1)=1 p(2)=0 p(3)=0 
EMPSTAT: (4 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(2)=0 p(3)=0 
CLASSWKR: (3 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(2)=0 
LOOKING: (4 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(2)=0 p(3)=0 
DISABWRK: (3 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(4)=0 
VETSTAT: (3 levels)
    curr. value: 0
    Predictions:    p(0)=1 p(1)=0 p(2)=0 

This output explains why this record is problematic. For most variables (MORTGAGE, AGE, MARST, SCHOOL, GRADEATT, SCHLTYPE, EMPSTAT, CLASSWKR, LOOKING, DISABWRK and VETSTAT) the only possible prediction is their current value. For example, for AGE (current value = ‘<15’), we have that p(<15) = 1, while the rest of the levels have all probability zero. This can be somewhat surprising until we realize that this particular variable is involved in several structural-zero definitions which drastically limit its acceptable values. For example, the current value of VETSTAT (veteran status) is ‘0’, which is the code for ‘N/A’; see Table 1 in Supplement #1 for variable codes. Looking at the definition of structural zeros (see Table 2 in Supplement #1) we note that such value for VETSTAT is only allowed for records with AGE=“<15”. In other words, conditional on VETSTAT=0, AGE can only be ‘<15’. This would not be too problematic if down the line we were able to change the value of VETSTAT. However, as we have seen, AGE=‘<15’ implies VETSTAT=0 and conversely, VETSTAT=0 also implies AGE=‘<15’. This makes it impossible for the CART synthesizer to ever change these values. Several other complex structural-zero conditions are at play here, further constraining the synthesis.

It is important to realize that this phenomenon is just an artifact of the strict FCS one-at-a-time conditional imputation strategy. In fact, the reason why we cannot escape the value \((AGE,VETSTAT) = (<15, 0)\) to reach any other combination (say e.g. \(([5,35], 1)\)) is only because doing so using the FCS approach would require sampling intermediate values that include impossible combinations. This problem is further compounded by tuning the CARTs using a small contamination parameter. Such a choice forces to grow large trees where the terminal nodes are more likely to be sparsely populated. This causes predictions to closely resemble the observed data, which further limit the some possible movements.

This said, we note that in our implementation of the CART-based FCS approach we have not explicitly enforced the structural zero restrictions. However, the fact that by definition a dataset cannot include structural zero data points, coupled with the nature of CART regression, results in a sort of empirical enforcement of structural zeros. Indeed, whenever the node splitting structure for the tree results in terminal nodes whose ancestors constrain predictor values in a way that matches a structural-zero restriction that involves the response, it will be impossible that such terminal node will contain any values that violate the restrictions simply because they cannot exist in a sample. This phenomenon is more likely when the contamination parameter of the tree is small, as small contamination parameter values usually result in the growth of large trees (see Drechsler and Reiter 2011). This results on terminal nodes which will likely descend from nodes that have a large number of variables involved, thus increasing the chance of matching a restriction.

References

Drechsler, Jörg, and Jerome P Reiter. 2011. “An Empirical Evaluation of Easily Implemented, Nonparametric Methods for Generating Synthetic Datasets.” Computational Statistics & Data Analysis 55 (12). Elsevier: 3232–43.

Hastie, Trevor, Robert Tibshirani, and Jerome Friedman. 2009. The Elements of Statistical Learning: Data Mining, Inference, and Prediction. Springer Series in Statistics. 2nd edition. New York: Springer-Verlag.

Reiter, J. P. 2005. “Using CART to Generate Partially Synthetic, Public Use Microdata.” Journal of Official Statistics 21: 441–62.

LS0tDQp0aXRsZTogJ1N1cHBsZW1lbnRhbCBNYXRlcmlhbHMgIzIgZm9yIEJheWVzaWFuIE5vbi1wYXJhbWV0cmljIEdlbmVyYXRpb24gb2YgRnVsbHkgU3ludGhldGljDQogIE11bHRpdmFyaWF0ZSBDYXRlZ29yaWNhbCBEYXRhIGluIHRoZSBQcmVzZW5jZSBvZiBTdHJ1Y3R1cmFsIFplcm9zJw0KYXV0aG9yOiAiRGFuaWVsIE1hbnJpcXVlLVZhbGxpZXIgYW5kIEppbmdjaGVuIEh1Ig0KZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiJUIgJWQsICVZIilgJw0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCnN1YnRpdGxlOiBJbnZlc3RpZ2F0aW9uIGludG8gQ0FSVCBGQ1Mgc3ludGhlc2l6ZXIgd2l0aCBzbWFsbCBpbXB1cml0eSBwYXJhbWV0ZXINCmJpYmxpb2dyYXBoeTogLi4vbWIuYmliDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCnJlcXVpcmUoZHBseXIpDQpyZXF1aXJlKHRpZHlyKQ0KcmVxdWlyZShtYWdyaXR0cikNCnJlcXVpcmUoZ2dwbG90MikNCnJlcXVpcmUoZ3JpZEV4dHJhKQ0KcmVxdWlyZShycHJvanJvb3QpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9IGZpbmRfcm9vdCgnTENNX1N5bnRoX1plcm9zLlJwcm9qJykpDQpgYGANCg0KYGBge3IgbG9hZCBhbmQgc2V0dXAsaW5jbHVkZT1GQUxTRX0NCnJlcXVpcmUodHJlZSwgbGliLmxvYyA9ICdmcm96ZW5fcGFja2FnZXMnKQ0Kc291cmNlKCdzcmMvZm5fdHJlZXMuUicpDQpmbnMgPC0gbmV3LmVudigpDQpzeXMuc291cmNlKGZpbGU9J3NyYy9mdW5jdGlvbnNfZm9yX3Rlc3RzLlInLCBlbnZpciA9IGZucykNCm91dGRpciA8LSAndG1wJw0KI3BvcHVsYXRpb24gcXVhbnRpdGllcw0KbG9hZCgnZGF0YS91c2FfMDlfMS5SRGF0YScpDQpwb3B1X3RhYiA8LSB1c2EwOV8xJGRhdF9wcm9jICU+JQ0KICBncm91cF9ieV9hbGwgJT4lDQogIGNvdW50KCkgJT4lDQogIHJlbmFtZShGcmVxID0gbikgJT4lDQogIGFzLmRhdGEuZnJhbWUNCg0KI3N5bnRoZXRpYyBkYXRhIChGaXJzdCByZXBsaWNhdGlvbikNCnNldC5zZWVkKDEyMykgI0ZpcnN0IHJlcGxpY2F0aW9uIGNvcnJlc3BvbmRzIHRvIHNhbXBsZSBnZW5lcmF0ZWQgd2l0aCB0aGlzIHNlZWQuDQpzYW1wIDwtIHVzYTA5XzEkZGF0X3Byb2Nbc2FtcGxlKDE6TlJPVyh1c2EwOV8xJGRhdF9wcm9jKSwgc2l6ZSA9IDEwMDAwLCByZXBsYWNlID0gVCksXQ0Kd2l0aChuZXcuZW52KCksIHsNCiAgbG9hZCgndG1wL1JlcGxpY19DQVJUMi9yZXBsaWNfQ0FSVF8xJywgZW52aXIgPSBlbnZpcm9ubWVudCgpKQ0KICBhc3NpZ24oJ2NvbF9jYXJ0JywgY29sbGVjdGlvbiRpbXB1dGF0aW9ucywgZW52aXIgPSBwYXJlbnQuZW52KGVudmlyb25tZW50KCkpKQ0KfSkNCmBgYA0KDQoNClRoaXMgc3VwcGxlbWVudCBwcmVzZW50cyBhbiBlbXBpcmljYWwgaW52ZXN0aWdhdGlvbiBpbnRvIHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgYSBzZXQgb2YgJE09NSQgZnVsbHktc3ludGhldGljIHNhbXBsZXMgZ2VuZXJhdGVkIGZyb20gYSBzaW5nbGUgc2FtcGxlIG9mICRuPTEwLDAwMCQgcmVjb3JkcyBmcm9tIHRoZSBDYWxpZm9ybmlhIGRhdGEgdXNpbmcgQ0FSVCBGQ1Mgc3ludGhlc2l6ZXJzOyBzZWUgbWFpbiB0ZXh0IGZvciBhIGRldGFpbGVkIGRlc2NyaXB0aW9uLiBUaGUgc2V0IG9mIHN5bnRoZXRpYyBzYW1wbGVzIGNvcnJlc3BvbmRzIHRvIHRoZSBmaXJzdCByZXBsaWNhdGlvbiBvZiB0aGUgcmVwZWF0ZWQgc2FtcGxpbmcgZXhwZXJpbWVudCAoU2VjdGlvbiAzLjEgZnJvbSBtYWluIHRleHQpLCB1c2luZyB0aGUgdGhlIENBUlQgRkNTIHN5bnRoZXNpemVyIHdpdGggYSBzbWFsbCAoY3AgPSAwLjAwMDEpIGNvbXBsZXhpdHkgcGFyYW1ldGVyLiAgDQoNClRoZSBjb21wbGV4aXR5LCBvciBgYGNvbnRhbWluYXRpb24iIHBhcmFtZXRlciBpbiBDQVJUIG1vZGVscyBkZXRlcm1pbmUgIHRoZSBtYXhpbXVtIGxldmVsLCByZWxhdGl2ZSB0byB0aGUgcm9vdCBub2RlLCAgb2YgaW1wdXJpdHkgb24gdGhlIGxlYXZlcyB0aGF0IGlzIGFjY2VwdGFibGUgdG8gc3RvcCBzcGxpdHRpbmcgW3NlZSBASGFzdGllMjAwOSwgcDMwNV0uIEluIHRoZSBjYXNlIG9mIGRpc2NyZXRlIGRhdGEsIHRoaXMgaXMgdXN1YWxseSBtZWFzdXJlZCB1c2luZyB0aGUgR2luaSBpbmRleCBbQEhhc3RpZTIwMDksIEBkcmVjaHNsZXIyMDExZW1waXJpY2FsXS4gU21hbGxlciBjb21wbGV4aXR5IHBhcmFtZXRlcnMgbGVhZHMgdG8gYmV0dGVyIGZpdHRlZCB0cmVlcywgYXQgdGhlIHJpc2sgb2Ygb3ZlcmZpdHRpbmcuIFRodXMsIGFzIG5vdGVkIGJ5IFtAZHJlY2hzbGVyMjAxMWVtcGlyaWNhbF0sIENBUlQgRkNTIHN5bnRoZXNpemVycyB3aXRoIGEgc21hbGwgY29udGFtaW5hdGlvbiBwYXJhbWV0ZXIgY2FuIGxlYWQgdG8gKnZlcnkqIGhpZ2gtdXRpbGl0eSBkYXRhLiBIb3dldmVyLCBhcyB3ZSB3aWxsIHNob3cgaGVyZSwgaW4gc29tZSBjYXNlcyB0aGV5IGFjaGlldmUgdGhpcyBleHRyZW1lIHBlcmZvcm1hbmNlIGluIHBhcnQgYnkgZXNzZW50aWFsbHkgKnJlcHJvZHVjaW5nKiBhIGZhaXIgcG9ydGlvbiB0aGUgb3JpZ2luYWwgY29uZmlkZW50aWFsIGRhdGEuIFRoaXMgYmVoYXZpb3IgZGVmZWF0cyB0aGUgcHVycG9zZSBvZiBnZW5lcmF0aW5nIHN5bnRoZXRpYyBkYXRhIGZvciBtaXRpZ2F0aW5nIGRpc2Nsb3N1cmUgcmlzay4NCg0KV2hhdCBmb2xsb3dzIGNhbiBiZSBzZWVuIGFzIGFuIGluZm9ybWFsIGludmVzdGlnYXRpb24gaW50byB0aGUgZGlzY2xvc3VyZSByaXNrIG9mIHRoZSBzeW50aGV0aWMgZGF0YSBnZW5lcmF0ZWQgYnkgdGhlIGFmb3JlbWVudGlvbmVkIENBUlQgRkNTIHN5bnRoZXNpemVyLg0KDQojIyBGQ1MgQ0FSVCBDYW4gQ3JlYXRlIEV4dHJlbWVseSBIaWdoLXV0aWxpdHkgU3ludGhldGljIFNhbXBsZXMNCg0KV2Ugc3RhcnQgYnkgbG9hZGluZyB0aGUgb3JpZ2luYWwgcG9wdWxhdGlvbiAoaW50byAicG9wdV90YWIiKSwgdGhlIHNhbXBsZSBvZiAkbj0xMCwwMDAkICByZWNvcmRzIGZyb20gdGhhdCBwb3B1bGF0aW9uIChpbnRvICJzYW1wIiksIGFuZCB0aGUgJE0gPSA1JCBzeW50aGV0aWMgZGF0YXNldHMgIGdlbmVyYXRlZCBmcm9tIHRoYXQgZGF0YSB1c2luZyB0aGUgQ0FSVCBzeW50aGVzaXplciB0dW5lZCB3aXRoIHRoZSBzbWFsbCBjb250YW1pbmF0aW9uIHBhcmFtZXRlciAwLjAwMDEgKGludG8gbGlzdCAiY29sX2NhcnQiKS4gV2UgY2hvc2UgdGhlIHNhbXBsZSBzbyB0aGF0IGl0IGNvcnJlc3BvbmRzIHRvIHRoZSBmaXJzdCBvZiB0aGUgMjAwIHJlcGxpY2F0aW9ucyBpbiB0aGUgcmVwZWF0ZWQgc2FtcGxpbmcgZXhwZXJpbWVudCBwcmVzZW50ZWQgaW4gdGhlIG1haW4gYXJ0aWNsZS4gDQoNCkFzIGV4cGVjdGVkLCB0aGUgc3ludGhldGljIGRhdGEgcHJvZHVjZXMgZXh0cmVtZWx5IGhpZ2gtcXVhbGl0eSBpbmZlcmVuY2VzIG9mIHRoZSBwb3B1bGF0aW9uIHF1YW50aXRpZXM6DQpgYGB7ciBzZWxlY3QgdGVzdCBtYXJnaW5zLGluY2x1ZGU9RkFMU0V9DQojIENyZWF0ZSB0aGUgbGlzdCBvZiBtYXJnaW5zIHdpdGggemVyb3MNCm1hcmdpbnNfd196ZXJvcyA8LSAgYXBwbHkodXNhMDlfMSRNQ1osIE1BUkdJTiA9IDIsIEZVTj0gZnVuY3Rpb24oeClhcy5mYWN0b3IoIWlzLm5hKHgpKSkgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGZucyRmbl9wYXJ0aWFsX2NvbnRpbmdlbmN5MigpICU+JSANCiAgc2VsZWN0KC1GcmVxKSAlPiUgDQogIGFwcGx5KC4sIE1BUkdJTiA9IDEsIEZVTiA9IGZ1bmN0aW9uKHgpKDE6bmNvbCguKSlbeD09J1RSVUUnXSkgJT4lIA0KICBzcGxpdCguLCBjb2woLikpDQojbW9kaWZpY2F0aW9uDQojbWFyZ2luc193X3plcm9zIDwtIGxpc3QoYygxLDIpKQ0KIyBDcmVhdGUgbGlzdCBvZiBtYXJnaW5zIHRvIGNvbXB1dGUNCnRlc3RfbWFyZ2lucyA8LSBtYXJnaW5zX3dfemVyb3MgJT4lDQogIGxhcHBseSguLCBGVU4gPSBmdW5jdGlvbih4KWZucyRmbl9td2F5X21hcmdpbnNfaW5jbHVkaW5nKDE6bmNvbCh1c2EwOV8xJE1DWiksIHgsIDMpKSAlPiUNCiAgUmVkdWNlKHVuaW9uLCAuKQ0KYGBgDQoNCmBgYHtyIHBvcHVsYXRpb24gZXN0aW1hdGlvbiBNSSBhbmQgc2FtcGxlLCBpbmNsdWRlID0gRkFMU0V9DQojcG0gPC0gZm5zJGZuX2FsbF9td2F5X21hcmdpbnNfdGFidWxhdGVkKGRmX3RhYnVsYXRlZCA9IHBvcHVfdGFiLCBtX3dheSA9IDMpJHAgJT4lIHVubGlzdA0KcG0gPC0gc2FwcGx5KHRlc3RfbWFyZ2lucywgRlVOID0gZnVuY3Rpb24oeClmbnMkZm5fbWFyZ19wcm9iX3RhYnVsYXRlZChwb3B1X3RhYiwgbWFyZ2luID0geCkkcG9pbnQpICU+JSB1bmxpc3QoKQ0KI3NtIDwtIGZucyRmbl9hbGxfbXdheV9tYXJnaW5zX3RhYnVsYXRlZChkZl90YWJ1bGF0ZWQgPSBzYW1wICU+JSBmbnMkZm5fcGFydGlhbF9jb250aW5nZW5jeTIoKSwgbV93YXkgPSAzKSRwICU+JSB1bmxpc3QNCnNtIDwtIHNhcHBseSh0ZXN0X21hcmdpbnMsIEZVTiA9IGZ1bmN0aW9uKHgpZm5zJGZuX21hcmdfcHJvYl90YWJ1bGF0ZWQoc2FtcCAlPiUgZm5zJGZuX3BhcnRpYWxfY29udGluZ2VuY3kyKCksIG1hcmdpbiA9IHgpJHBvaW50KSAlPiUgdW5saXN0KCkNCk1JbSA8LSBsYXBwbHkoY29sX2NhcnQsDQogIEZVTiA9IGZ1bmN0aW9uKHgpIHsNCiMgICAgZm5zJGZuX2FsbF9td2F5X21hcmdpbnNfdGFidWxhdGVkKA0KIyAgICAgIGRmX3RhYnVsYXRlZCA9IHggJT4lIGZucyRmbl9wYXJ0aWFsX2NvbnRpbmdlbmN5MigpLA0KIyAgICAgIG1fd2F5ID0gMw0KIyAgICApJHAgJT4lIHVubGlzdA0KICAgIHNhcHBseSgNCiAgICAgIHRlc3RfbWFyZ2lucywgDQogICAgICBGVU4gPSBmdW5jdGlvbih5KWZucyRmbl9tYXJnX3Byb2JfdGFidWxhdGVkKHggJT4lIGZucyRmbl9wYXJ0aWFsX2NvbnRpbmdlbmN5MigpLCBtYXJnaW4gPSB5KSRwb2ludA0KICAgICkgJT4lIHVubGlzdCgpDQogIH0NCikgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGFwcGx5KC4sIE1BUkdJTiA9IDEsIEZVTiA9IG1lYW4pDQpgYGANCg0KYGBge3IgcGxvdCByZXN1bHRzLGVjaG89RkFMU0UsZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMSkNCnRpYmJsZShQb3B1bGF0aW9uID0gcG0sIFNhbXBsZSA9IHNtLCBNSV9DQVJUID0gTUltKSAlPiUNCiAgZmlsdGVyKFNhbXBsZSAhPSAwKSAlPiUNCiAgZHBseXI6OnNhbXBsZV9uKDIwMDApICU+JQ0KICAgIHsNCiAgICAgIGdncGxvdCguKSArDQogICAgICBnZ3Bsb3QyOjpjb29yZF9maXhlZChyYXRpbyA9IDEpICsNCiAgICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sID0gJ2dyZXknKQ0KICAgIH0gICU+JSB7DQogICAgICBncmlkLmFycmFuZ2Uoew0KICAgICAgICAgIC4gKyBnZW9tX3BvaW50KGFlcyh5ID0gTUlfQ0FSVCwgeCA9IFBvcHVsYXRpb24pLCBhbHBoYSA9IDAuNiwgY29sID0gJ2JsYWNrJywgc2l6ZSA9IDEpICsNCiAgICAgICAgICBsYWJzKHRpdGxlID0gJ1N5bnRoZXRpYyBkYXRhIHZzLiBQb3B1bGF0aW9uJywgc3VidGl0bGUgPSAnRXN0aW1hdGVzIG9mIDMtd2F5IG1hcmdpbiBwcm9wb3J0aW9ucycpDQogICAgICAgIH0sIHsNCiAgICAgICAgICAuICsgZ2VvbV9wb2ludChhZXMoeSA9IFNhbXBsZSwgeCA9IFBvcHVsYXRpb24pLCBhbHBoYSA9IDAuNiwgY29sID0gJ2JsYWNrJywgc2l6ZSA9IDEpICsNCiAgICAgICAgICBsYWJzKHRpdGxlID0gJ09yaWdpbmFsIHNhbXBsZSB2cy4gUG9wdWxhdGlvbicsIHN1YnRpdGxlID0nRXN0aW1hdGVzIG9mIDMtd2F5IG1hcmdpbiBwcm9wb3J0aW9ucycgKQ0KICAgICAgICB9LCANCiAgICAgICAgbmNvbCA9IDIgDQogICAgICApDQogICAgfQ0KYGBgDQoNClRoZSBsZWZ0IHBsb3QgKE1JX0NBUlQgdnMgUG9wdWxhdGlvbiwgbGVmdCBwbG90KSBzaG93cyB0aGF0IHZhbHVlcyBjYWxjdWxhdGVkIGZyb20gIHRoZSBDQVJUIHN5bnRoZXNpemVyIGFyZSBleGNlbGxlbnQuIEluIGZhY3QsIHRoZXkgYXJlIGNvbXBhcmFibGUgdG8gdGhlIG9uZXMgb2J0YWluZWQgZnJvbSB0aGUgYWN0dWFsIHNhbXBsZSAocmlnaHQgcGxvdCkuIE1vcmVvdmVyLCBjYWxjdWxhdGlvbnMgd2l0aCBzeW50aGV0aWMgZGF0YSBhcmUgYWxtb3N0IGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gY2FsY3VsYXRpb25zIHdpdGggdGhlIG9yaWdpbmFsIGRhdGEgdGhlbXNlbHZlczoNCg0KYGBge3IgcGxvdCBzeW50aCB2cyBzYW1wbGUsZWNobz1GQUxTRSxmaWcuYWxpZ249J2NlbnRlcid9DQpzZXQuc2VlZCgxKQ0KdGliYmxlKFNhbXBsZSA9IHNtLCBNSV9DQVJUID0gTUltKSAlPiUNCiAgZmlsdGVyKFNhbXBsZSAhPSAwKSAlPiUNCiAgc2FtcGxlX24oMjAwMCkgJT4lDQogIGdncGxvdCguKSArDQogICAgZ2dwbG90Mjo6Y29vcmRfZml4ZWQocmF0aW8gPSAxKSArDQogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBjb2wgPSAnZ3JleScpICsNCiAgICBnZW9tX3BvaW50KGFlcyh5ID0gTUlfQ0FSVCwgeCA9IFNhbXBsZSksIGFscGhhID0gMC42LCBjb2wgPSAnYmxhY2snLCBzaXplID0gMSkgKyBsYWJzKHRpdGxlID0gJ1N5bnRoZXRpYyBkYXRhIHZzLiBPcmlnaW5hbCBzYW1wbGUnLCBzdWJ0aXRsZSA9ICdFc3RpbWF0ZXMgb2YgMy13YXkgbWFyZ2luIHByb3BvcnRpb25zJykNCmBgYA0KDQpUaGVyZWZvcmUsIGZyb20gYSBwdXJlbHkgYW5hbHl0aWNhbCB1dGlsaXR5LWJhc2VkIHBlcnNwZWN0aXZlLCBpdCBzZWVtcyB0aGF0IHRoZSBGQ1MgQ0FSVCBzeW50aGVzaXplciB3aXRoIHNtYWxsIGNvbnRhbWluYXRpb24gcGFyYW1ldGVyIGlzIHRoZSB3YXkgdG8gZ28uIEJ1dCBsZXQgdXMgbm93IGxvb2sgYXQgdGhlIGFjdHVhbCBzeW50aGV0aWMgZGF0YXNldHMuDQoNCiMjIEJ1dCBpdCBkb2VzIHNvIGJ5IGRpcmVjdGx5IGRpc2Nsb3NpbmcgbGFyZ2UgcG9ydGlvbnMgb2YgdGhlIG9yaWdpbmFsIGRhdGENCg0KRkNTIHN5bnRoZXNpemVycyB3b3JrIGJ5LCAqc3RhcnRpbmcgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YSosIHZhcnkgb25lIGNvb3JkaW5hdGUgYXQgYSB0aW1lIGJ5IHJlZ3Jlc3Npbmcgc2FpZCBjb29yZGluYXRlIG9uIHRoZSByZXN0IG9mIHRoZSB2YWx1ZXMsIGFuZCB1c2luZyB0aGF0IG1vZGVsIHRvIGdlbmVyYXRlIHJlcGxhY2luZyB2YWx1ZXMgZm9yIHRoYXQgY29vcmRpbmF0ZSB1c2luZyB0aGUgQmF5ZXNpYW4gYm9vdHN0cmFwLCBjb25kaXRpb25pbmcgb24gdGhlIHJlc3Qgb2YgdGhlIG11bHRpdmFyaWF0ZSB2ZWN0b3IgaW4gYSBHaWJicyBzYW1wbGVyLWxpa2UgbWFubmVyIFtAUmVpdGVyOjIwMDU6Q0FSVDpzeW50aGV0aWNdLiBUaGUgaWRlYSBpcyB0aGF0IGFmdGVyIGF0IGxlYXN0IGEgZmV3IGZ1bGwgY3ljbGVzLCBhbGwgZW50cmllcyBpbiB0aGUgZGF0YXNldCB3b3VsZCBiZSByZXBsYWNlZCBieSBwcmVkaWN0ZWQgdmFsdWVzLCBmb3JtaW5nIHRoZSBzeW50aGVzaXplZCBkYXRhc2V0LiAgSG93ZXZlciwgdGhlcmUgaXMgYWx3YXlzIGEgcG9zc2liaWxpdHkgdGhhdCB0aGUgcmVncmVzc2lvbiBlbmRzIHVwIHdvcmtpbmcgKnRvbyB3ZWxsKiAob3ZlcmZpdHRpbmcpIGFuZCB0aHVzIHRoYXQgdGhlIGdlbmVyYXRlZCBwcmVkaWN0ZWQgdmFsdWVzIGVuZCB1cCBiZWluZyB0b28gY2xvc2UsIG9yIGV2ZW4gZXF1YWwsIHRvIHRoZSBvcmlnaW5hbCBvbmVzLg0KDQpXZSBzdGFydCBieSBjaGVja2luZyBob3cgbWFueSBvZiB0aGUgJG49MTAsMDAwJCByZWNvcmRzIGhhdmUgJGsgXGluIFx7MCwxLC4uLiwxN1x9JCB2YXJpYWJsZXMgdW5jaGFuZ2VkIHdpdGggcmVzcGVjdCB0byB0aGUgb3JpZ2luYWwgc2FtcGxlLCBpbiBlYWNoIG9mIHRoZSAkTSA9IDUkIHN5bnRoZXRpYyBkYXRhIHJlcGxpY2F0aW9uczoNCmBgYHtyIHNhbXBsZXMgd2l0aCB1bmNoYW5nZWQgdmFyaWFibGVzLGVjaG89RkFMU0V9DQojSG93IG1hbnkgcmVjb3JkcyBpbiBlYWNoIHN5bnRoZXRpYyBkYXRhc2V0IGhhdmUgZXhhY3RseSBuIHZhcmlhYmxlcyB1bmNoYW5nZWQ6DQooDQogIHJlY29yZHNfdW5jaGFuZ2VkIDwtIGNvbF9jYXJ0ICU+JSBzYXBwbHkoDQogICAgRlVOID0gZnVuY3Rpb24oeCl7DQogICAgICAoc2FtcCA9PSB4KSAlPiUgDQogICAgICAgIGFwcGx5KC4sIE1BUkdJTiA9IDEsIEZVTiA9IHN1bSkgJT4lIA0KICAgICAgICBmYWN0b3IoLiwgbGV2ZWxzID0gMDoxNykgJT4lIA0KICAgICAgICB0YWJsZShkbm49bGlzdCgndW5jaGFuZ2VkX3ZhcmlhYmxlcycpKSAlPiUgDQogICAgICAgIGFzLmRhdGEuZnJhbWUoKQ0KICAgIH0sDQogICAgc2ltcGxpZnkgPSBGDQogICkgJT4lIGJpbmRfcm93cyguaWQgPSAnU3ludGhfRGF0JykgJT4lDQogICAgc3ByZWFkKFN5bnRoX0RhdCwgdmFsdWUgPSBGcmVxLCBzZXAgPSAnXycpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyh1bmNoYW5nZWRfdmFyaWFibGVzKSkNCikgJT4lIHByaW50DQoNCmBgYA0KDQpIZXJlIHdlIGNhbiBzZWUgdGhhdCBpbiBlYWNoIG9mIHRoZSAkTSA9IDUkIHJlcGxpY2F0aW9ucyB0aGVyZSBhcmUgc2V2ZXJhbCByZWNvcmRzIHRoYXQgYXJlIGNvbXBsZXRlbHkgdW5jaGFuZ2VkLiBGb3IgZXhhbXBsZSwgaW4gdGhlIGZpcnN0IHJlcGxpY2F0aW9uIChjb2x1bW4gbGFiZWxlZCAiU3ludGhfRGF0XzEiKSAzODYgcmVjb3JkcyBkaWQgbm90IGNoYW5nZSAqYXQgYWxsKiBhZnRlciB0aGUgYXBwbGljYXRpb24gb2YgdGhlIENBUlQgRkNTIHN5bnRoZXNpemVyLiBUaGlzIG1lYW5zIHRoYXQgaWYgdGhlIEFnZW5jeSB3ZXJlIHRvIHJlbGVhc2UgdGhhdCBzdXBwb3NlZGx5IHNhZmUgc3ludGhldGljIGRhdGFzZXQsIHRoZXkgd291bGQgYmUgYWxzbyByZWxlYXNpbmcgMzg2IG9mIHRoZSAqb3JpZ2luYWwqIHJlY29yZHMuIEZ1cnRoZXJtb3JlLCBzZXZlcmFsIG9mIHRoZSByZWNvcmRzIHRoYXQgaGF2ZSBhY3R1YWxseSBiZWVuIGFsdGVyZWQgaGF2ZSBiZWVuIHNvIGJ5IGp1c3QgYSBmZXcgdmFyaWFibGVzOg0KDQpgYGB7ciBhdCBsZWFzdCBuIHZhcmlhYmxlcyB1bmNoYW5nZWQsY29sbGFwc2U9VFJVRSxlY2hvPUZBTFNFfQ0KI0hvdyBtYW55IHNhbXBsZXMgaGF2ZSBhdCBsZWFzdCBuIHZhcmlhYmxlcyB1bmNoYW5nZWQ6DQpyZWNvcmRzX3VuY2hhbmdlZCAlPiUNCiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoJ1N5bnRoJykpLCBmdW5zKGN1bXN1bSkpICU+JQ0KICBhcnJhbmdlKGRlc2ModW5jaGFuZ2VkX3ZhcmlhYmxlcykpDQpgYGANCg0KSW4gdGhpcyB0YWJsZSB3ZSBjYW4gc2VlIHRoYXQgaW4gdGhlIGZpcnN0IHN5bnRoZXRpYyBkYXRhc2V0IG1vcmUgdGhhbiBoYWxmIG9mIHRoZSByZWNvcmRzICg1NTM1KSBhcmUgY29waWVzIG9mIHRoZSBvcmlnaW5hbCByZWNvcmRzIHdpdGggYXQgbW9zdCAzIGFsdGVyZWQgdmFyaWFibGVzLiBGdXJ0aGVybW9yZSwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBubyBzeW50aGV0aWMgcmVjb3JkcyB0aGF0IGFyZSBub3QgdGhlIHJlc3VsdCBvZiBrZWVwaW5nIGF0IGxlYXN0IDUgdmFyaWFibGVzIHVuY2hhbmdlZC4NCg0KTm93IGxldCB1cyBsb29rIGF0IGhvdyBpbmRpdmlkdWFsIHZhcmlhYmxlcyAodGhlIGNvbHVtbnMgaW4gdGhlIG9yaWdpbmFsIGRhdGFzZXQpIGFyZSBwcmVzZXJ2ZWQgYWZ0ZXIgdGhlIGFwcGxpY2F0aW9uIG9mIHRoZSBDQVJUIHN5bnRoZXNpemVyLiBIZXJlIHdlIGNhbGN1bGF0ZWQgdGhlIHBlcmNlbnRhZ2Ugb2YgcmVjb3JkcyBpbiBlYWNoIHN5bnRoZXRpYyBkYXRhc2V0IHdoZXJlIGVhY2ggdmFyaWFibGUgaGFzIGJlZW4gbGVmdCB1bnRvdWNoZWQsIGZvciBlYWNoIG9mIHRoZSAxNyB2YXJpYWJsZXMuIFdlIGhhdmUgc29ydGVkIHRoZSB2YXJpYWJsZXMgaW4gZGVzY2VuZGluZyBvcmRlci4NCg0KYGBge3IgdW50b3VjaGVkIHZhcmlhYmxlcyxjb2xsYXBzZT1UUlVFLGVjaG89RkFMU0V9DQojcGVyY2VudGFnZSBvZiByZWNvcmRzIHdoZXJlIHZhcmlhYmxlIGogaXMgdW5jaGFuZ2VkIHBlciBzeW50aGV0aWMgZGF0YXNldC4uLg0KY29sX2NhcnQgJT4lDQogIGxhcHBseSgNCiAgICBGVU4gPSBmdW5jdGlvbihhKXsNCiAgICAgICAgKHNhbXAgPT0gYSkgJT4lDQogICAgICAgIGFwcGx5KC4sIE1BUkdJTiA9IDIsIEZVTiA9IHN1bSkgJT4lDQogICAgICAgIHsuLzEwMDAwICogMTAwfSAlPiUNCiAgICAgICAgZGF0YS5mcmFtZShhPS4pICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigpICU+JSBzcHJlYWQocm93bmFtZSwgYSkNCiAgICB9DQogICkgJT4lIGJpbmRfcm93cyAlPiUNCiAgbXV0YXRlKFN5bnRoX0RhdCA9IGFzLmNoYXJhY3Rlcihyb3dfbnVtYmVyKCkpKSAlPiUNCiAgLlssIGMoJ1N5bnRoX0RhdCcse3NlbGVjdCguLCAtU3ludGhfRGF0KSAlPiUgYXBwbHkoLiwgTUFSR0lOID0gMiwgRlVOID0gbWluKSAlPiUgc29ydCguLGRlY3JlYXNpbmcgPVRSVUUpICU+JSBuYW1lc30pXSAlPiUNCiAgYmluZF9yb3dzKCAgc3VtbWFyaXplX2F0KC4sIHZhcnMoLVN5bnRoX0RhdCksIGZ1bnMobWluKSkgJT4lIA0KICAgICAgICAgICAgICBtdXRhdGUoU3ludGhfRGF0ID0nLS0tTUlOSU1VTS0tLScpICAlPiUNCiAgICAgICAgICAgICAgc2VsZWN0KFN5bnRoX0RhdCwgZXZlcnl0aGluZygpKQ0KICApICU+JQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVucyhyb3VuZCguLCBkaWdpdHMgPSAxKSkpICU+JQ0KICBwcmludCguKQ0KYGBgDQoNCkluIHRoaXMgdGFibGUgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIDkgdmFyaWFibGVzIChPV05FUlNIUCwgIFNDSExUWVBFLCAgRU1QU1RBVCwgIFZFVFNUQVQsICBHUkFERUFUVCwgIERJU0FCV1JLLCAgTU9SVEdBR0UgYW5kIExPT0tJTkcpIHRoYXQgYWZ0ZXIgdGhlIGFwcGxpY2F0aW9uIG9mIHRoZSBDQVJUIHN5bnRoZXNpemVyIGFyZSBjb21wbGV0ZWx5IHByZXNlcnZlZCBpbiBhdCBsZWFzdCA4MFwlIG9mIHRoZSByZWNvcmRzLiBNb3Jlb3Zlciwgb25lIHZhcmlhYmxlIChTQ0hPT0wpIGlzICpjb21wbGV0ZWx5KiBwcmVzZXJ2ZWQgaW4gYWxsIHN5bnRoZXRpYyBkYXRhc2V0cy4gVGhpcyBtZWFucyB0aGF0IHRoZSBzdXBwb3NlZGx5IHN5bnRoZXRpYyBkYXRhIGNvbnRhaW5zIHNldmVyYWwgdmFyaWFibGVzIHRoYXQgYXJlIGFsbW9zdCB2ZXJiYXRpbSBjb3BpZXMgb2YgdGhlIGNvbmZpZGVudGlhbCBkYXRhLCBhbmQgb25lIHRoYXQgaXMgYSBwZXJmZWN0IGNvcHkuDQoNCiMjIFdoYXQgaXMgaGFwcGVuaW5nIGhlcmU/DQoNClRvIGJldHRlciB1bmRlcnN0YW5kIHRoaXMgaXNzdWUgd2Ugd2lsbCBsb29rIGNsb3NlciB0byB0aGUgc3ludGhlc2lzIG9mIG9uZSBwYXJ0aWN1bGFybHkgcHJvYmxlbWF0aWMgcmVjb3JkIGZyb20gdGhlIG9yaWdpbmFsIHNhbXBsZS4gUmVjb3JkIDEyOTcgaXMgYW4gaW5zdGFuY2Ugb2YgYSBkYXRhIHBvaW50IHRoYXQgYWZ0ZXIgdGhlIGFwcGxpY2F0aW9uIG9mIHRoZSBDQVJUIHN5bnRoZXNpemVyIHdhcyBsZWZ0IGNvbXBsZXRlbHkgdW5tb2RpZmllZCBpbiBhbGwgJE0gPSA1JCBzeW50aGV0aWMgZGF0YXNldHMtLS1hbmQgdGhlcmVmb3JlIHBlcmZlY3RseSBkaXNjbG9zZWQuIA0KDQpXZSBmaXJzdCBzZWxlY3QgdGhlIHJlY29yZCBmcm9tIHRoZSBvcmlnaW5hbCBkYXRhLA0KYGBge3Isd2FybmluZz1GQUxTRSxlY2hvPUZBTFNFfQ0KKA0KICB0ZXN0X2VudHJ5IDwtIHNhbXAgJT4lDQogIHNsaWNlKDEyOTcpICU+JQ0KICBzZWxlY3RfaWYoaXMuZmFjdG9yKQ0KKQ0KYGBgDQoNCmFuZCBhbHNvIGZpdCB0aGUgMTcgZnVsbCBjb25kaXRpb25hbCBDQVJUIHJlZ3Jlc3Npb24gbW9kZWxzLCBjb3JyZXNwb25kaW5nIHRvIGVhY2ggb2YgdGhlIHZhcmlhYmxlcywgdXNpbmcgdGhlIG9yaWdpbmFsIHNhbXBsZS4NCg0KYGBge3Igc3ludGggZW5naW5lLGVjaG89RkFMU0V9DQplbmdpbmUgPC0gbGlzdCgpDQpmb3IgKGkgaW4gMTpOQ09MKHNhbXApKXsNCiAgeSA8LSBuYW1lcyhzYW1wKVtpXQ0KICBlbmdpbmVbW2ldXSA8LSB0cmVlKGZvcm11bGEgPSBwYXN0ZTAoeSwnfi4nKSwgZGF0YSA9IHNhbXAsIG1pbmRldiA9IDAuMDAwMSkNCn0NCmBgYA0KDQpOb3cgbGV0IHVzIGxvb2sgYXQgdGhlIHByZWRpY3Rpb25zIHRoYXQgd2UgY2FuIG9idGFpbiBmb3IgZWFjaCBmb3IgdGhlIHZhcmlhYmxlcyB3aGVuIGNvbmRpdGlvbmluZyBvbiB0aGUgcmVzdCBvZiB0aGUgcm93LCBmb2xsb3dpbmcgdGhlIEZDUyBhcHByb2FjaC4gSW4gdGhlIG5leHQgb3V0cHV0IHdlIGRldGFpbCwgZm9yIGVhY2ggb2YgdGhlICRqPTEsLi4uLDE3JCB2YXJpYWJsZXMsIGl0cyBjdXJyZW50IHZhbHVlICgiY3Vyci4gdmFsdWUiKSBhbmQgdGhlIHByZWRpY3Rpb24gcHJvYmFiaWxpdGllcyBhc3NvY2lhdGVkIHdpdGggZWFjaCBvZiB0aGUgbGV2ZWxzIG9mIHNhaWQgdmFyaWFibGUgKCJwKGxldmVsMSksIHAobGV2ZWwyKSwgZXRjLiIpLCBvYnRhaW5lZCBmcm9tIHRoZSBmaXR0ZWQgQ0FSVHMga2VlcGluZyB0aGUgcmVzdCBvZiB0aGUgdmVjdG9yIGF0IHRoZWlyIG9yaWdpbmFsIHZhbHVlcy4NCmBgYHtyIHByZWRpY3Rpb25zLGVjaG89RkFMU0V9DQojIGFuZCB0cnkgdG8gcHJlZGljdA0KcHJlZGljdGlvbnMgPC0gc2FwcGx5KGVuZ2luZSwgZnVuY3Rpb24oeCkgcHJlZGljdCh4LCB0ZXN0X2VudHJ5KSwgc2ltcGxpZnkgPSBUKQ0KbmFtZXMocHJlZGljdGlvbnMpIDwtIG5hbWVzKHNhbXApDQpmb3IoaSBpbiBzZXFfYWxvbmcocHJlZGljdGlvbnMpKXsNCiAgdiA8LSBwcmVkaWN0aW9uc1tbaV1dOyBubSA8LSBuYW1lcyhwcmVkaWN0aW9ucylbaV0NCiAgY2F0KA0KICAgIG5tLCAnOiAoJywgbGVuZ3RoKHYpLCcgbGV2ZWxzKVxuXHRjdXJyLiB2YWx1ZTogJywgYXMuZGF0YS5mcmFtZSh0ZXN0X2VudHJ5KVssaV0gJT4lIGFzLmNoYXJhY3RlcigpLA0KICAgICdcblx0UHJlZGljdGlvbnM6XHQnLCBzZXAgPSAnJw0KICApDQogIGZvcihqIGluIHNlcV9hbG9uZyh2KSl7DQogICAgY2F0KCdwKCcsIGNvbG5hbWVzKHYpW2pdLCAnKT0nLCBzaWduaWYodltqXSwgMyksICcgJywgc2VwID0gJycpDQogIH0NCiAgY2F0KCdcbicpDQp9DQoNCmBgYA0KDQpUaGlzIG91dHB1dCBleHBsYWlucyB3aHkgdGhpcyByZWNvcmQgaXMgcHJvYmxlbWF0aWMuIEZvciBtb3N0IHZhcmlhYmxlcyAoTU9SVEdBR0UsIEFHRSwgTUFSU1QsIFNDSE9PTCwgR1JBREVBVFQsIFNDSExUWVBFLCBFTVBTVEFULCBDTEFTU1dLUiwgTE9PS0lORywgRElTQUJXUksgYW5kIFZFVFNUQVQpIHRoZSBvbmx5IHBvc3NpYmxlIHByZWRpY3Rpb24gaXMgdGhlaXIgY3VycmVudCB2YWx1ZS4gRm9yIGV4YW1wbGUsIGZvciBBR0UgKGN1cnJlbnQgdmFsdWUgPSAnPDE1JyksIHdlIGhhdmUgdGhhdCBwKDwxNSkgPSAxLCB3aGlsZSB0aGUgcmVzdCBvZiB0aGUgbGV2ZWxzIGhhdmUgYWxsIHByb2JhYmlsaXR5IHplcm8uIFRoaXMgY2FuIGJlIHNvbWV3aGF0IHN1cnByaXNpbmcgdW50aWwgd2UgcmVhbGl6ZSB0aGF0IHRoaXMgcGFydGljdWxhciB2YXJpYWJsZSBpcyBpbnZvbHZlZCBpbiBzZXZlcmFsIHN0cnVjdHVyYWwtemVybyBkZWZpbml0aW9ucyB3aGljaCBkcmFzdGljYWxseSBsaW1pdCBpdHMgYWNjZXB0YWJsZSB2YWx1ZXMuIEZvciBleGFtcGxlLCB0aGUgY3VycmVudCB2YWx1ZSBvZiBWRVRTVEFUICh2ZXRlcmFuIHN0YXR1cykgaXMgJzAnLCB3aGljaCBpcyB0aGUgY29kZSBmb3IgJ04vQSc7IHNlZSBUYWJsZSAxIGluIFN1cHBsZW1lbnQgXCMxIGZvciB2YXJpYWJsZSBjb2Rlcy4gTG9va2luZyBhdCB0aGUgZGVmaW5pdGlvbiBvZiBzdHJ1Y3R1cmFsIHplcm9zIChzZWUgVGFibGUgMiBpbiBTdXBwbGVtZW50IFwjMSkgd2Ugbm90ZSB0aGF0IHN1Y2ggdmFsdWUgZm9yIFZFVFNUQVQgaXMgb25seSBhbGxvd2VkIGZvciByZWNvcmRzIHdpdGggQUdFPSI8MTUiLiBJbiBvdGhlciB3b3JkcywgY29uZGl0aW9uYWwgb24gVkVUU1RBVD0wLCBBR0UgY2FuIG9ubHkgYmUgJzwxNScuIFRoaXMgd291bGQgbm90IGJlIHRvbyBwcm9ibGVtYXRpYyBpZiAgZG93biB0aGUgbGluZSB3ZSB3ZXJlIGFibGUgdG8gY2hhbmdlIHRoZSB2YWx1ZSBvZiBWRVRTVEFULiBIb3dldmVyLCBhcyB3ZSBoYXZlIHNlZW4sIEFHRT0nPDE1JyBpbXBsaWVzIFZFVFNUQVQ9MCBhbmQgY29udmVyc2VseSwgVkVUU1RBVD0wIGFsc28gaW1wbGllcyBBR0U9JzwxNScuIFRoaXMgbWFrZXMgaXQgaW1wb3NzaWJsZSBmb3IgdGhlIENBUlQgc3ludGhlc2l6ZXIgdG8gKmV2ZXIqIGNoYW5nZSB0aGVzZSB2YWx1ZXMuIFNldmVyYWwgb3RoZXIgY29tcGxleCBzdHJ1Y3R1cmFsLXplcm8gY29uZGl0aW9ucyBhcmUgYXQgcGxheSBoZXJlLCBmdXJ0aGVyIGNvbnN0cmFpbmluZyB0aGUgc3ludGhlc2lzLg0KDQpJdCBpcyBpbXBvcnRhbnQgdG8gcmVhbGl6ZSB0aGF0IHRoaXMgcGhlbm9tZW5vbiBpcyBqdXN0IGFuIGFydGlmYWN0IG9mIHRoZSBzdHJpY3QgRkNTIG9uZS1hdC1hLXRpbWUgY29uZGl0aW9uYWwgaW1wdXRhdGlvbiBzdHJhdGVneS4gSW4gZmFjdCwgdGhlIHJlYXNvbiB3aHkgd2UgY2Fubm90IGVzY2FwZSB0aGUgdmFsdWUgJChBR0UsVkVUU1RBVCkgPSAoPDE1LCAwKSQgdG8gcmVhY2ggYW55IG90aGVyIGNvbWJpbmF0aW9uIChzYXkgZS5nLiAkKFs1LDM1XSwgMSkkKSBpcyBvbmx5IGJlY2F1c2UgZG9pbmcgc28gdXNpbmcgdGhlIEZDUyBhcHByb2FjaCB3b3VsZCByZXF1aXJlIHNhbXBsaW5nIGludGVybWVkaWF0ZSB2YWx1ZXMgdGhhdCBpbmNsdWRlIGltcG9zc2libGUgY29tYmluYXRpb25zLiAgVGhpcyBwcm9ibGVtIGlzIGZ1cnRoZXIgY29tcG91bmRlZCBieSB0dW5pbmcgdGhlIENBUlRzIHVzaW5nIGEgc21hbGwgY29udGFtaW5hdGlvbiBwYXJhbWV0ZXIuIFN1Y2ggYSBjaG9pY2UgZm9yY2VzIHRvIGdyb3cgbGFyZ2UgdHJlZXMgd2hlcmUgdGhlIHRlcm1pbmFsIG5vZGVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBzcGFyc2VseSBwb3B1bGF0ZWQuIFRoaXMgY2F1c2VzIHByZWRpY3Rpb25zIHRvIGNsb3NlbHkgcmVzZW1ibGUgdGhlIG9ic2VydmVkIGRhdGEsIHdoaWNoIGZ1cnRoZXIgbGltaXQgdGhlIHNvbWUgcG9zc2libGUgbW92ZW1lbnRzLg0KDQpUaGlzIHNhaWQsIHdlIG5vdGUgdGhhdCBpbiBvdXIgaW1wbGVtZW50YXRpb24gb2YgdGhlIENBUlQtYmFzZWQgRkNTIGFwcHJvYWNoIHdlIGhhdmUgbm90ICpleHBsaWNpdGx5KiBlbmZvcmNlZCB0aGUgc3RydWN0dXJhbCB6ZXJvIHJlc3RyaWN0aW9ucy4gSG93ZXZlciwgdGhlIGZhY3QgdGhhdCBieSBkZWZpbml0aW9uIGEgZGF0YXNldCBjYW5ub3QgaW5jbHVkZSBzdHJ1Y3R1cmFsIHplcm8gZGF0YSBwb2ludHMsIGNvdXBsZWQgd2l0aCB0aGUgbmF0dXJlIG9mIENBUlQgcmVncmVzc2lvbiwgcmVzdWx0cyBpbiBhIHNvcnQgb2YgZW1waXJpY2FsIGVuZm9yY2VtZW50IG9mIHN0cnVjdHVyYWwgemVyb3MuIEluZGVlZCwgd2hlbmV2ZXIgdGhlIG5vZGUgc3BsaXR0aW5nIHN0cnVjdHVyZSBmb3IgdGhlIHRyZWUgcmVzdWx0cyBpbiB0ZXJtaW5hbCBub2RlcyB3aG9zZSBhbmNlc3RvcnMgY29uc3RyYWluIHByZWRpY3RvciB2YWx1ZXMgaW4gYSB3YXkgdGhhdCBtYXRjaGVzIGEgc3RydWN0dXJhbC16ZXJvIHJlc3RyaWN0aW9uIHRoYXQgaW52b2x2ZXMgdGhlIHJlc3BvbnNlLCBpdCB3aWxsIGJlIGltcG9zc2libGUgdGhhdCBzdWNoIHRlcm1pbmFsIG5vZGUgd2lsbCBjb250YWluIGFueSB2YWx1ZXMgdGhhdCB2aW9sYXRlIHRoZSByZXN0cmljdGlvbnMgc2ltcGx5IGJlY2F1c2UgdGhleSBjYW5ub3QgZXhpc3QgaW4gYSBzYW1wbGUuIFRoaXMgcGhlbm9tZW5vbiBpcyBtb3JlIGxpa2VseSB3aGVuIHRoZSBjb250YW1pbmF0aW9uIHBhcmFtZXRlciBvZiB0aGUgdHJlZSBpcyBzbWFsbCwgYXMgc21hbGwgY29udGFtaW5hdGlvbiBwYXJhbWV0ZXIgdmFsdWVzIHVzdWFsbHkgcmVzdWx0IGluIHRoZSBncm93dGggb2YgbGFyZ2UgdHJlZXMgW3NlZSBAZHJlY2hzbGVyMjAxMWVtcGlyaWNhbF0uIFRoaXMgcmVzdWx0cyBvbiB0ZXJtaW5hbCBub2RlcyB3aGljaCB3aWxsIGxpa2VseSBkZXNjZW5kIGZyb20gbm9kZXMgdGhhdCBoYXZlIGEgbGFyZ2UgbnVtYmVyIG9mIHZhcmlhYmxlcyBpbnZvbHZlZCwgdGh1cyBpbmNyZWFzaW5nIHRoZSBjaGFuY2Ugb2YgbWF0Y2hpbmcgYSByZXN0cmljdGlvbi4NCg0KDQoNCg0KDQojUmVmZXJlbmNlcw0K