Nota: Este case apresenta outras possibilidades de emprego com o R. Aqui temos PCA e Análise de clusters.
The data consists of 24 cars measured on the following six variables:
- Cylinders Number of cylinders (cm3)
- Horsepower Horsepower (hp)
- Speed Maximum speed (km/h)
- Weight weight of the car (kg)
- Length length of the car (mm)
- Width width of the car (mm)
descriptive statistics
Before performing a PCA (or any other multivariate method) we should start with some preliminary explorations
- Descriptive statistics
- Basic graphical displays
- Distribution of variables
- Pair-wise correlations among variables
- Perhaps transforming some variables
abbreviate used with non-ASCII chars

Look at the pair-wise scatterplot:
- What kind of patterns do you see?
- What variables seem to be correlated with each other?
- Are there any points (objects) that stand out?
- Is there anything in particular that calls your attention?

We can also examine the correlations among variables: all variables are positively correlated
Cylinders Horsepower Speed Weight Width
Horsepower 0.954
Speed 0.885 0.934
Weight 0.692 0.529 0.466
Width 0.706 0.730 0.619 0.477
Length 0.664 0.527 0.578 0.795 0.591
PCA functions in R
Function Package Author
- prcomp() stats R Core Team
- princomp() stats R Core Team
- PCA() FactoMineR Husson, Josse, Le, Mazet
- dudi.pca() ade4 Chessel, Dufour, Dray
- acp() amap Lucas
- nipals() plsdepot Sanchez
- rda() vegan Oksanen et al
- pca() pcaMethods * Stacklies, Redestig, Wright
The minimal output from any PCA should contain 3 things:
- Eigenvalues provide information about the amount of variability captured by each principal component
- Scores or PCs that provide coordinates to graphically represent objects in a lower dimensional space
- Loadings provide information to determine what variables characterize each principal component
PCA with prcomp() - one of the default PCA functions in R is prcomp():
[1] "sdev" "rotation" "center" "scale" "x"
[1] 4.41126759 0.85340979 0.43566395 0.23587059 0.05143668 0.01235140
PC1 PC2 PC3 PC4 PC5 PC6
Citroën C2 1.1 Base -2.54 -0.50 -0.18 0.16 -0.20 0.03
Smart Fortwo Coupé -4.06 -1.63 0.27 -0.90 -0.03 -0.03
Mini 1.6 170 -1.35 -0.80 0.36 -0.05 0.45 0.05
Nissan Micra 1.2 65 -2.46 -0.40 -0.17 0.12 -0.28 0.05
Renault Clio 3.0 V6 0.00 -0.90 0.38 -0.27 0.28 -0.13
PC1 PC2 PC3 PC4 PC5 PC6
Cylinders 0.46 -0.14 0.21 -0.23 -0.65 -0.50
Horsepower 0.44 -0.38 0.14 -0.17 -0.09 0.78
Speed 0.42 -0.37 0.31 0.41 0.57 -0.31
Weight 0.36 0.62 0.22 -0.53 0.39 -0.01
Width 0.38 -0.12 -0.88 -0.14 0.15 -0.13
PCA with princomp() - The other default PCA function is princomp()
[1] "sdev" "loadings" "center" "scale" "n.obs" "scores" "call"
Comp.1 Comp.2 Comp.3 Comp.4 Comp.5 Comp.6
4.41126759 0.85340979 0.43566395 0.23587059 0.05143668 0.01235140
Comp.1 Comp.2 Comp.3 Comp.4 Comp.5 Comp.6
Citroën C2 1.1 Base 2.596 -0.510 0.179 0.166 0.207 0.032
Smart Fortwo Coupé 4.150 -1.666 -0.274 -0.924 0.029 -0.034
Mini 1.6 170 1.382 -0.816 -0.372 -0.051 -0.464 0.051
Nissan Micra 1.2 65 2.513 -0.404 0.174 0.124 0.289 0.051
Renault Clio 3.0 V6 0.003 -0.916 -0.385 -0.274 -0.286 -0.134
Comp.1 Comp.2 Comp.3 Comp.4 Comp.5 Comp.6
Cylinders -0.458 -0.137 -0.214 -0.232 0.652 -0.496
Horsepower -0.440 -0.382 -0.137 -0.173 0.094 0.777
Speed -0.422 -0.367 -0.313 0.410 -0.569 -0.314
Weight -0.360 0.623 -0.223 -0.529 -0.389 -0.008
Width -0.381 -0.120 0.883 -0.140 -0.153 -0.132
PCA() with FactoMineR
**Results for the Principal Component Analysis (PCA)**
The analysis was performed on 24 individuals, described by 6 variables
*The results are available in the following objects:
name description
1 "$eig" "eigenvalues"
2 "$var" "results for the variables"
3 "$var$coord" "coord. for the variables"
4 "$var$cor" "correlations variables - dimensions"
5 "$var$cos2" "cos2 for the variables"
6 "$var$contrib" "contributions of the variables"
7 "$ind" "results for the individuals"
8 "$ind$coord" "coord. for the individuals"
9 "$ind$cos2" "cos2 for the individuals"
10 "$ind$contrib" "contributions of the individuals"
11 "$call" "summary statistics"
12 "$call$centre" "mean of the variables"
13 "$call$ecart.type" "standard error of the variables"
14 "$call$row.w" "weights for the individuals"
15 "$call$col.w" "weights for the variables"
Extensive output: As you can tell, there is an extensive list of results provided in the output of PCA() by FactoMineR
Reading results: We will discuss how to interpret the main results from PCA() and what things we should pay attention to
Graphical Examination: With the obtained scores and loadings we can get several graphical displays
Some graphics
- correlations between scores and variables
- relationships among variables
- positions of objects on the score plots
- (dis)siminalirities among objects
- relationships between objects and variables
Some questions to keep in mind
- How many PCs should be retained?
- How good (or bad) is the data approximation with the reatined PCs?
- What variables characterize each PC?
- Which variables are influential, and how are they correlated?
- Which variables are responsible for the patterns among objects?
- Are there any outlier objects?
How many PCs to retain? There is no universal criterion to determine the number of PCs to retain. But we must look at the eigenvalues and see what are the percentage of variance captured by each dimension:

What variables characterize each PC?
To see how each PC is characterized, we either check the loadings or the correlations between the variables and the PCs:
Dim.1 Dim.2
Cylinders 0.9624 -0.1269
Horsepower 0.9233 -0.3527
Speed 0.8861 -0.3387
Weight 0.7569 0.5757
Width 0.8012 -0.1110
Length 0.7953 0.5044
Circle of Correlations
- We can read this plot as a radar.
- The closer an arrow is to the circumference of the circle, the better its representation on the given axes.
- Also note how the variables are grouped.

Influence of variables on each PC?
We can also examine the contributions of the variables
If all variables were to contribute uniformly, they would have a contribution of 1/6 or 16.67%.
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
Cylinders 20.99685 1.888053 4.5963914 5.385321 42.5754114
Horsepower 19.32581 14.572896 1.8738150 2.986455 0.8920753
Speed 17.79960 13.445643 9.7721157 16.807651 32.3352042
Weight 12.98761 38.836725 4.9895558 28.029702 15.1507636
Width 14.55312 1.444225 77.9635912 1.958483 2.3414907
Length 14.33701 29.812457 0.8045309 44.832387 6.7050548
TOTAL 100.00000 100.000000 100.0000000 100.000000 100.0000000
To inspect what variables are above and below 16.67 we can create a barplot of variable contributions in the following form:

PC scores: We can use the scores as coordinates to plot the objects in a scatterplot
Dim.1 Dim.2
Citroën C2 1.1 Base -2.596 -0.510
Smart Fortwo Coupé -4.150 -1.666
Mini 1.6 170 -1.382 -0.816
Nissan Micra 1.2 65 -2.513 -0.404
Renault Clio 3.0 V6 -0.003 -0.916
Audi A3 1.9 TDI -1.121 0.169
Peugeot 307 1.4 HDI 70 -1.725 0.300
Peugeot 407 3.0 V6 BVA 0.553 0.523
Mercedes Classe C 270 CDI 0.078 0.482
BMW 530d 0.838 0.460
Jaguar S-Type 2.7 V6 Bi-Turbo 0.721 0.898
BMW 745i 2.126 0.610
Mercedes Classe S 400 CDI 2.167 0.810
Citroën C3 Pluriel 1.6i -1.623 -0.218
BMW Z4 2.5i -0.399 -0.596
Audi TT 1.8T 180 -0.751 -0.459
Aston Martin Vanquish 3.155 -0.639
Bentley Continental GT 4.161 0.064
Ferrari Enzo 4.946 -2.580
Renault Scenic 1.9 dCi 120 -0.842 0.380
Volkswagen Touran 1.9 TDI 105 -0.805 0.713
Land Rover Defender Td5 -1.072 0.751
Land Rover Discovery Td5 0.851 1.920
Nissan X-Trail 2.2 dCi -0.614 0.722
Default plot of objects in FactoMineR

Alternative plot of objects with ggplot2

Contributions of objects to PCs
The contributions (in percentage) reflect the influence that each object has on the formation of the PCs. If all objects had the same contribution on each PC, they would contribute with a value of 4.16 = 100/24
Dim.1 Dim.2
Citroën C2 1.1 Base 6.365 1.270
Smart Fortwo Coupé 16.269 13.550
Mini 1.6 170 1.804 3.249
Nissan Micra 1.2 65 5.967 0.795
Renault Clio 3.0 V6 0.000 4.092
Audi A3 1.9 TDI 1.186 0.139
Peugeot 307 1.4 HDI 70 2.812 0.441
Peugeot 407 3.0 V6 BVA 0.288 1.336
Mercedes Classe C 270 CDI 0.006 1.133
BMW 530d 0.663 1.033
Jaguar S-Type 2.7 V6 Bi-Turbo 0.492 3.935
BMW 745i 4.271 1.816
Mercedes Classe S 400 CDI 4.434 3.201
Citroën C3 Pluriel 1.6i 2.487 0.231
BMW Z4 2.5i 0.150 1.734
Audi TT 1.8T 180 0.533 1.030
Aston Martin Vanquish 9.404 1.997
Bentley Continental GT 16.352 0.020
Ferrari Enzo 23.110 32.503
Renault Scenic 1.9 dCi 120 0.669 0.706
Volkswagen Touran 1.9 TDI 105 0.612 2.481
Land Rover Defender Td5 1.085 2.757
Land Rover Discovery Td5 0.683 18.004
Nissan X-Trail 2.2 dCi 0.357 2.547
Barplots of object contributions to PCs
abbreviate used with non-ASCII chars
abbreviate used with non-ASCII chars

PCA with Clustering
We can gain some insight by combining PCA and Clustering
- Is there a typology of objects?
- How could they be clustered?
One option is to apply a hierarchical clustering to the obtained scores, and then add the clustered groups to the Scores scatterplot
Hierarchical Clustering

PC plot with clustering partition


LS0tDQp0aXRsZTogIkNhcnMgMjAwNCAtIFBDQSBhbmQgQ2x1c3RlcnMiDQphdXRob3I6ICJMZW9uaSwgUi4gQy4gUHJvZmVzc29yIERyLiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoqKioNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEYpDQpgYGANCg0KIyMgTm90YTogRXN0ZSBjYXNlIGFwcmVzZW50YSBvdXRyYXMgcG9zc2liaWxpZGFkZXMgZGUgZW1wcmVnbyBjb20gbyBSLiBBcXVpIHRlbW9zIFBDQSBlIEFuw6FsaXNlIGRlIGNsdXN0ZXJzLg0KDQo+IFRoZSBkYXRhIGNvbnNpc3RzIG9mIDI0IGNhcnMgbWVhc3VyZWQgb24gdGhlIGZvbGxvd2luZyBzaXggdmFyaWFibGVzOg0KDQoxLiBDeWxpbmRlcnMgTnVtYmVyIG9mIGN5bGluZGVycyAoY20zKQ0KMi4gSG9yc2Vwb3dlciBIb3JzZXBvd2VyIChocCkNCjMuIFNwZWVkIE1heGltdW0gc3BlZWQgKGttL2gpDQo0LiBXZWlnaHQgd2VpZ2h0IG9mIHRoZSBjYXIgKGtnKQ0KNS4gTGVuZ3RoIGxlbmd0aCBvZiB0aGUgY2FyIChtbSkNCjYuIFdpZHRoIHdpZHRoIG9mIHRoZSBjYXIgKG1tKQ0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KY2FyczIwMDQgPC0gcmVhZF9leGNlbCgiY2FyczIwMDQueGxzIikNCg0KY2FyczIwMDQgPC0gYXMuZGF0YS5mcmFtZShjYXJzMjAwNCkNCg0KIyBub21lYXIgYXMgbGluaGFzDQpub21lcyA8LSBjKGNhcnMyMDA0WzE6MjQsMV0pDQpyb3duYW1lcyhjYXJzMjAwNCkgPC0gbm9tZXMNCg0KIyBleGNsdWlyIGNvbHVuYSAxDQpjYXJzMjAwNCA8LSBjYXJzMjAwNFssLTFdDQoNCmhlYWQoY2FyczIwMDQpDQoNCmBgYA0KDQoNCj4gZGVzY3JpcHRpdmUgc3RhdGlzdGljcw0KDQpgYGB7cn0NCmNhcnNfc3RhdHMgPSBkYXRhLmZyYW1lKA0KTWluaW11bSA9IGFwcGx5KGNhcnMyMDA0LCAyLCBtaW4pLA0KTWF4aW11bSA9IGFwcGx5KGNhcnMyMDA0LCAyLCBtYXgpLA0KTWVhbiA9IGFwcGx5KGNhcnMyMDA0LCAyLCBtZWFuKSwNClN0ZF9EZXYgPSBhcHBseShjYXJzMjAwNCwgMiwgc2QpKQ0KcHJpbnQoY2Fyc19zdGF0cywgcHJpbnQuZ2FwID0gMykNCmBgYA0KDQo+IEJlZm9yZSBwZXJmb3JtaW5nIGEgUENBIChvciBhbnkgb3RoZXIgbXVsdGl2YXJpYXRlIG1ldGhvZCkgd2Ugc2hvdWxkIHN0YXJ0IHdpdGggc29tZSBwcmVsaW1pbmFyeSBleHBsb3JhdGlvbnMNCg0KMS4gRGVzY3JpcHRpdmUgc3RhdGlzdGljcw0KMi4gQmFzaWMgZ3JhcGhpY2FsIGRpc3BsYXlzDQozLiBEaXN0cmlidXRpb24gb2YgdmFyaWFibGVzDQo0LiBQYWlyLXdpc2UgY29ycmVsYXRpb25zIGFtb25nIHZhcmlhYmxlcw0KNS4gUGVyaGFwcyB0cmFuc2Zvcm1pbmcgc29tZSB2YXJpYWJsZXMNCg0KYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTksIG1lc3NhZ2U9Rn0NCiMgU3RhcnMgcGxvdA0KI1NpbmNlIHdlIGhhdmUgYSBzbWFsbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zICgyNCBjYXJzKSwgd2UgY2FuIHVzZQ0KI3RoZSBmdW5jdGlvbiBzdGFycygpIHRvIGdldCBhbiBpZGVhIG9mIHRoZSAoZGlzKXNpbWlsYXJpdGllcyBiZXR3ZWVuIHRoZSBjYXJzOg0KIyBzdGFyIHBsb3QNCnN0YXJzKGNhcnMyMDA0LCBsYWJlbHMgPSBhYmJyZXZpYXRlKHJvd25hbWVzKGNhcnMyMDA0KSwgNiksDQpucm93ID0gNCwga2V5LmxvYyA9IGMoOCwgMTEuMikpDQphYmxpbmUoaCA9IDkuODUsIGNvbCA9ICJncmF5OTAiKQ0KDQpgYGANCg0KPiBMb29rIGF0IHRoZSBwYWlyLXdpc2Ugc2NhdHRlcnBsb3Q6DQoNCjEuIFdoYXQga2luZCBvZiBwYXR0ZXJucyBkbyB5b3Ugc2VlPw0KMi4gV2hhdCB2YXJpYWJsZXMgc2VlbSB0byBiZSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlcj8NCjMuIEFyZSB0aGVyZSBhbnkgcG9pbnRzIChvYmplY3RzKSB0aGF0IHN0YW5kIG91dD8NCjQuIElzIHRoZXJlIGFueXRoaW5nIGluIHBhcnRpY3VsYXIgdGhhdCBjYWxscyB5b3VyIGF0dGVudGlvbj8NCg0KYGBge3J9DQojIHNjYXR0ZXJwbG90IHRvIGluc3BlY3QgcGFpci13aXNlIHJlbGF0aW9ucw0KcGFpcnMoY2FyczIwMDQpDQpgYGANCg0KPiBXZSBjYW4gYWxzbyBleGFtaW5lIHRoZSBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzOiBhbGwgdmFyaWFibGVzIGFyZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQNCg0KYGBge3J9DQojIHNob3cgbG93ZXIgdHJpYW5ndWxhciBwYXJ0IG9mIG1hdHJpeCBvZiBjb3JyZWxhdGlvbnMNCmFzLmRpc3Qocm91bmQoY29yKGNhcnMyMDA0KSwgMykpDQoNCmBgYA0KDQo+IFBDQSBmdW5jdGlvbnMgaW4gUg0KDQo+IEZ1bmN0aW9uIFBhY2thZ2UgQXV0aG9yDQoNCjEuIHByY29tcCgpIHN0YXRzIFIgQ29yZSBUZWFtDQoyLiBwcmluY29tcCgpIHN0YXRzIFIgQ29yZSBUZWFtDQozLiBQQ0EoKSBGYWN0b01pbmVSIEh1c3NvbiwgSm9zc2UsIExlLCBNYXpldA0KNC4gZHVkaS5wY2EoKSBhZGU0IENoZXNzZWwsIER1Zm91ciwgRHJheQ0KNS4gYWNwKCkgYW1hcCBMdWNhcw0KNi4gbmlwYWxzKCkgcGxzZGVwb3QgU2FuY2hleg0KNy4gcmRhKCkgdmVnYW4gT2tzYW5lbiBldCBhbA0KOC4gcGNhKCkgcGNhTWV0aG9kcyAqIFN0YWNrbGllcywgUmVkZXN0aWcsIFdyaWdodA0KDQoNCj4gVGhlIG1pbmltYWwgb3V0cHV0IGZyb20gYW55IFBDQSBzaG91bGQgY29udGFpbiAzIHRoaW5nczoNCg0KMS4gRWlnZW52YWx1ZXMgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgYW1vdW50IG9mIHZhcmlhYmlsaXR5IGNhcHR1cmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudA0KMi4gU2NvcmVzIG9yIFBDcyB0aGF0IHByb3ZpZGUgY29vcmRpbmF0ZXMgdG8gZ3JhcGhpY2FsbHkgcmVwcmVzZW50IG9iamVjdHMgaW4gYSBsb3dlciBkaW1lbnNpb25hbCBzcGFjZQ0KMy4gTG9hZGluZ3MgcHJvdmlkZSBpbmZvcm1hdGlvbiB0byBkZXRlcm1pbmUgd2hhdCB2YXJpYWJsZXMgY2hhcmFjdGVyaXplIGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudCANCg0KPiBQQ0Egd2l0aCBwcmNvbXAoKSAtIG9uZSBvZiB0aGUgZGVmYXVsdCBQQ0EgZnVuY3Rpb25zIGluIFIgaXMgcHJjb21wKCk6DQoNCmBgYHtyfQ0KIyBQQ0Egd2l0aCBwcmNvbXAoKQ0KY2Fyc19wcmNvbXAgPSBwcmNvbXAoY2FyczIwMDQsIHNjYWxlLiA9IFRSVUUpDQojIHdoYXQgZG9lcyBwcmNvbXAoKSBwcm92aWRlPw0KbmFtZXMoY2Fyc19wcmNvbXApDQojIGVpZ2VudmFsdWVzDQpjYXJzX3ByY29tcCRzZGV2XjINCiMgc2NvcmVzDQpyb3VuZChoZWFkKGNhcnNfcHJjb21wJHgsIDUpLCAyKQ0KIyBsb2FkaW5ncw0Kcm91bmQoaGVhZChjYXJzX3ByY29tcCRyb3RhdGlvbiwgNSksIDIpDQoNCmBgYA0KDQo+IFBDQSB3aXRoIHByaW5jb21wKCkgLSBUaGUgb3RoZXIgZGVmYXVsdCBQQ0EgZnVuY3Rpb24gaXMgcHJpbmNvbXAoKQ0KDQpgYGB7cn0NCiMgUENBIHdpdGggcHJpbmNvbXAoKQ0KY2Fyc19wcmluY29tcCA9IHByaW5jb21wKGNhcnMyMDA0LCBjb3IgPSBUUlVFKQ0KIyB3aGF0IGRvZXMgcHJpbmNvbXAoKSBwcm92aWRlPw0KbmFtZXMoY2Fyc19wcmluY29tcCkNCmNhcnNfcHJpbmNvbXAkc2Rldl4yDQojIHNjb3Jlcw0Kcm91bmQoaGVhZChjYXJzX3ByaW5jb21wJHNjb3JlcywgNSksIDMpDQojIGxvYWRpbmdzDQpyb3VuZChoZWFkKHVuY2xhc3MoY2Fyc19wcmluY29tcCRsb2FkaW5ncyksIDUpLCAzKQ0KYGBgDQoNCj4gUENBKCkgd2l0aCBGYWN0b01pbmVSDQoNCmBgYHtyLCBtZXNzYWdlPUZ9DQojbG9hZCBGYWN0b01pbmVSDQpsaWJyYXJ5KEZhY3RvTWluZVIpDQojIG5pY2UgUENBDQpjYXJzX3BjYSA9IFBDQShjYXJzMjAwNCwgZ3JhcGggPSBGQUxTRSkNCiMgd2hhdCBkb2VzIFBDQSBwcm92aWRlPw0KY2Fyc19wY2ENCg0KYGBgDQo+IEV4dGVuc2l2ZSBvdXRwdXQ6IEFzIHlvdSBjYW4gdGVsbCwgdGhlcmUgaXMgYW4gZXh0ZW5zaXZlIGxpc3Qgb2YgcmVzdWx0cyBwcm92aWRlZCBpbiB0aGUgb3V0cHV0IG9mIFBDQSgpIGJ5IEZhY3RvTWluZVINCg0KPiBSZWFkaW5nIHJlc3VsdHM6IFdlIHdpbGwgZGlzY3VzcyBob3cgdG8gaW50ZXJwcmV0IHRoZSBtYWluIHJlc3VsdHMgZnJvbSBQQ0EoKSBhbmQgd2hhdCB0aGluZ3Mgd2Ugc2hvdWxkIHBheSBhdHRlbnRpb24gdG8NCg0KPiBHcmFwaGljYWwgRXhhbWluYXRpb246ICBXaXRoIHRoZSBvYnRhaW5lZCBzY29yZXMgYW5kIGxvYWRpbmdzIHdlIGNhbiBnZXQgc2V2ZXJhbCBncmFwaGljYWwgZGlzcGxheXMNCg0KPiBTb21lIGdyYXBoaWNzDQoNCjEuIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHNjb3JlcyBhbmQgdmFyaWFibGVzDQoyLiByZWxhdGlvbnNoaXBzIGFtb25nIHZhcmlhYmxlcw0KMy4gcG9zaXRpb25zIG9mIG9iamVjdHMgb24gdGhlIHNjb3JlIHBsb3RzDQo0LiAoZGlzKXNpbWluYWxpcml0aWVzIGFtb25nIG9iamVjdHMNCjUuIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBvYmplY3RzIGFuZCB2YXJpYWJsZXMNCg0KPiBTb21lIHF1ZXN0aW9ucyB0byBrZWVwIGluIG1pbmQNCg0KMS4gSG93IG1hbnkgUENzIHNob3VsZCBiZSByZXRhaW5lZD8NCjIuIEhvdyBnb29kIChvciBiYWQpIGlzIHRoZSBkYXRhIGFwcHJveGltYXRpb24gd2l0aCB0aGUgcmVhdGluZWQgUENzPw0KMy4gV2hhdCB2YXJpYWJsZXMgY2hhcmFjdGVyaXplIGVhY2ggUEM/DQo0LiBXaGljaCB2YXJpYWJsZXMgYXJlIGluZmx1ZW50aWFsLCBhbmQgaG93IGFyZSB0aGV5IGNvcnJlbGF0ZWQ/DQo1LiBXaGljaCB2YXJpYWJsZXMgYXJlIHJlc3BvbnNpYmxlIGZvciB0aGUgcGF0dGVybnMgYW1vbmcgb2JqZWN0cz8NCjYuIEFyZSB0aGVyZSBhbnkgb3V0bGllciBvYmplY3RzPw0KDQo+IEhvdyBtYW55IFBDcyB0byByZXRhaW4/ICBUaGVyZSBpcyBubyB1bml2ZXJzYWwgY3JpdGVyaW9uIHRvIGRldGVybWluZSB0aGUgbnVtYmVyIG9mIFBDcyB0byByZXRhaW4uIEJ1dCB3ZSBtdXN0IGxvb2sgYXQgdGhlIGVpZ2VudmFsdWVzIGFuZCBzZWUgd2hhdCBhcmUgdGhlIHBlcmNlbnRhZ2Ugb2YgdmFyaWFuY2UgY2FwdHVyZWQgYnkgZWFjaCBkaW1lbnNpb246DQoNCmBgYHtyfQ0KIyB0YWJsZSBvZiBlaWdlbnZhbHVlcw0KY2Fyc19wY2EkZWlnDQojIHNjcmVlcGxvdCBvZiBlaWdlbnZhbHVlcw0KYmFycGxvdChjYXJzX3BjYSRlaWdbLCJlaWdlbnZhbHVlIl0sIGJvcmRlciA9IE5BLCBjb2wgPSAiZ3JheTgwIiwgbmFtZXMuYXJnID0gcm93bmFtZXMoY2Fyc19wY2EkZWlnKSkNCg0KYGBgDQoNCj4gV2hhdCB2YXJpYWJsZXMgY2hhcmFjdGVyaXplIGVhY2ggUEM/IA0KDQo+IFRvIHNlZSBob3cgZWFjaCBQQyBpcyBjaGFyYWN0ZXJpemVkLCB3ZSBlaXRoZXIgY2hlY2sgdGhlIGxvYWRpbmdzIG9yIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGFuZCB0aGUgUENzOg0KDQpgYGB7cn0NCiMgY29ycmVsYXRpb25zIGJldHdlZW4gdmFyaWFibGVzIGFuZCBQQ3MNCnJvdW5kKGNhcnNfcGNhJHZhciRjb29yZFssMToyXSwgNCkNCmBgYA0KDQo+IENpcmNsZSBvZiBDb3JyZWxhdGlvbnMNCg0KMS4gV2UgY2FuIHJlYWQgdGhpcyBwbG90IGFzIGEgcmFkYXIuDQoyLiBUaGUgY2xvc2VyIGFuIGFycm93IGlzIHRvIHRoZSBjaXJjdW1mZXJlbmNlIG9mIHRoZSBjaXJjbGUsIHRoZSBiZXR0ZXIgaXRzIHJlcHJlc2VudGF0aW9uIG9uIHRoZSBnaXZlbiBheGVzLg0KMy4gQWxzbyBub3RlIGhvdyB0aGUgdmFyaWFibGVzIGFyZSBncm91cGVkLg0KDQpgYGB7cn0NCiMgcGxvdCBjaXJjbGUgb2YgY29ycmVsYXRpb25zDQpwbG90KGNhcnNfcGNhLCBjaG9peCA9ICJ2YXIiKQ0KYGBgDQoNCj4gSW5mbHVlbmNlIG9mIHZhcmlhYmxlcyBvbiBlYWNoIFBDPw0KDQo+IFdlIGNhbiBhbHNvIGV4YW1pbmUgdGhlIGNvbnRyaWJ1dGlvbnMgb2YgdGhlIHZhcmlhYmxlcw0KDQo+IElmIGFsbCB2YXJpYWJsZXMgd2VyZSB0byBjb250cmlidXRlIHVuaWZvcm1seSwgdGhleSB3b3VsZCBoYXZlIGEgY29udHJpYnV0aW9uIG9mIDEvNiBvciAxNi42NyUuDQoNCmBgYHtyfQ0KIyBDb250cmlidXRpb24gb2YgdmFyaWFibGVzDQpwcmludChyYmluZChjYXJzX3BjYSR2YXIkY29udHJpYiwgVE9UQUwgPSBjb2xTdW1zKGNhcnNfcGNhJHZhciRjb250cmliKSksIHByaW50LmdhcCA9IDMpDQpgYGANCg0KDQo+IFRvIGluc3BlY3Qgd2hhdCB2YXJpYWJsZXMgYXJlIGFib3ZlIGFuZCBiZWxvdyAxNi42NyB3ZSBjYW4gY3JlYXRlIGEgYmFycGxvdCBvZiB2YXJpYWJsZSBjb250cmlidXRpb25zIGluIHRoZSBmb2xsb3dpbmcgZm9ybToNCg0KYGBge3J9DQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCiMgY29sb3IgcGFsZXR0ZQ0KY29scGFsID0gYnJld2VyLnBhbChuID0gNSwgbmFtZSA9ICJCbHVlcyIpWzU6MV0NCiMgQ29udHJpYnV0aW9uIG9mIHZhcmlhYmxlcw0KYmFycGxvdCh0KGNhcnNfcGNhJHZhciRjb250cmliKSwgYmVzaWRlID0gVFJVRSwNCmJvcmRlciA9IE5BLCB5bGltID0gYygwLCA5MCksIGNvbCA9IGNvbHBhbCwNCmxlZ2VuZC50ZXh0ID0gY29sbmFtZXMoY2Fyc19wY2EkdmFyJGNvbnRyaWIpLA0KYXJncy5sZWdlbmQgPSBsaXN0KHggPSAidG9wIiwgbmNvbCA9IDUsIGJ0eSA9ICduJykpDQphYmxpbmUoaCA9IDE2LCBjb2wgPSAiI2ZmNTcyMjU1IiwgbHdkID0gMikNCmBgYA0KDQoNCg0KPiAgUEMgc2NvcmVzOiBXZSBjYW4gdXNlIHRoZSBzY29yZXMgYXMgY29vcmRpbmF0ZXMgdG8gcGxvdCB0aGUgb2JqZWN0cyBpbiBhIHNjYXR0ZXJwbG90DQoNCmBgYHtyfQ0KIyBQQyBzY29yZXMgKGZpcnN0IDIgZGltZXNpb25zKQ0KcHJpbnQocm91bmQoY2Fyc19wY2EkaW5kJGNvb3JkWywxOjJdLCAzKSwNCnByaW50LmdhcCA9IDMpDQpgYGANCg0KPiBEZWZhdWx0IHBsb3Qgb2Ygb2JqZWN0cyBpbiBGYWN0b01pbmVSDQoNCmBgYHtyfQ0KIyBwbG90IG9mIHNjb3Jlcw0KcGxvdChjYXJzX3BjYSwgY2hvaXggPSAiaW5kIikNCmBgYA0KDQo+IEFsdGVybmF0aXZlIHBsb3Qgb2Ygb2JqZWN0cyB3aXRoIGdncGxvdDINCg0KYGBge3IsIG1lc3NhZ2U9Rn0NCiMgbG9hZCBnZ3Bsb3QyDQpsaWJyYXJ5KGdncGxvdDIpDQojIGRhdGEgZnJhbWUgd2l0aCBvYnNlcnZhdGlvbnMgZnJvbSBQQ0EgcmVzdWx0cw0KY2Fyc19wY2Ffb2JzID0gZGF0YS5mcmFtZShjYXJzX3BjYSRpbmQkY29vcmRbLDE6M10pDQojIFBDQSBwbG90cyBvZiBvYnNlcnZhdGlvbnMNCmdncGxvdChjYXJzX3BjYV9vYnMsIGFlcyh4ID0gRGltLjEsIHkgPSBEaW0uMiwgbGFiZWwgPSByb3duYW1lcyhjYXJzMjAwNCkpKSArDQpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmF5NzAiKSArDQpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmF5NzAiKSArDQpnZW9tX3BvaW50KGNvbG9yID0gIiM1NTU1NTU0NCIsIHNpemUgPSA1KSArDQpnZW9tX3RleHQoYWxwaGEgPSAwLjU1LCBzaXplID0gNCkgKw0KeGxhYigiUEMxIikgKw0KeWxhYigiUEMyIikgKw0KeGxpbSgtNSwgNikgKw0KZ2d0aXRsZSgiUENBIHBsb3Qgb2Ygb2JzZXJ2YXRpb25zIikgKyB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQo+IENvbnRyaWJ1dGlvbnMgb2Ygb2JqZWN0cyB0byBQQ3MNCg0KPiBUaGUgY29udHJpYnV0aW9ucyAoaW4gcGVyY2VudGFnZSkgcmVmbGVjdCB0aGUgaW5mbHVlbmNlIHRoYXQgZWFjaCBvYmplY3QgaGFzIG9uIHRoZSBmb3JtYXRpb24gb2YgdGhlDQpQQ3MuIElmIGFsbCBvYmplY3RzIGhhZCB0aGUgc2FtZSBjb250cmlidXRpb24gb24gZWFjaCBQQywgdGhleSB3b3VsZCBjb250cmlidXRlIHdpdGggYSB2YWx1ZSBvZiA0LjE2ID0gMTAwLzI0DQoNCmBgYHtyfQ0KIyBDb250cmlidXRpb25zIG9uIFBDcyAoZmlyc3QgMiBkaW1lc2lvbnMpDQpwcmludChyb3VuZChjYXJzX3BjYSRpbmQkY29udHJpYlssMToyXSwgMyksDQpwcmludC5nYXAgPSAzKQ0KYGBgDQoNCj4gQmFycGxvdHMgb2Ygb2JqZWN0IGNvbnRyaWJ1dGlvbnMgdG8gUENzDQoNCmBgYHtyLCBtZXNzYWdlPUZ9DQpvcCA9IHBhcihtZnJvdyA9IGMoMiwxKSkNCiMgYmFycGxvdCBvZiBvYmplY3QgY29udHJpYnV0aW9ucyBmb3IgUEMxDQpiYXJwbG90KGNhcnNfcGNhJGluZCRjb250cmliWywxXSwgYm9yZGVyID0gTkEsIGxhcyA9IDIsDQpuYW1lcy5hcmcgPSBhYmJyZXZpYXRlKHJvd25hbWVzKGNhcnMyMDA0KSwgOCksIGNleC5uYW1lcyA9IDAuOCkNCnRpdGxlKCJPYmplY3QgQ29udHJpYnV0aW9ucyBvbiBQQzEiLCBjZXgubWFpbiA9IDAuOSkNCmFibGluZShoID0gNC4xNiwgY29sID0gImdyYXk1MCIpDQojIGJhcnBsb3Qgb2Ygb2JqZWN0IGNvbnRyaWJ1dGlvbnMgZm9yIFBDMg0KYmFycGxvdChjYXJzX3BjYSRpbmQkY29udHJpYlssMl0sIGJvcmRlciA9IE5BLCBsYXMgPSAyLA0KbmFtZXMuYXJnID0gYWJicmV2aWF0ZShyb3duYW1lcyhjYXJzMjAwNCksIDgpLCBjZXgubmFtZXMgPSAwLjgpDQp0aXRsZSgiT2JqZWN0IENvbnRyaWJ1dGlvbnMgb24gUEMyIiwgY2V4Lm1haW4gPSAwLjkpDQphYmxpbmUoaCA9IDQuMTYsIGNvbCA9ICJncmF5NTAiKQ0KcGFyKG9wKQ0KYGBgDQoNCg0KPiBQQ0Egd2l0aCBDbHVzdGVyaW5nDQoNCj4gV2UgY2FuIGdhaW4gc29tZSBpbnNpZ2h0IGJ5IGNvbWJpbmluZyBQQ0EgYW5kIENsdXN0ZXJpbmcNCg0KMS4gSXMgdGhlcmUgYSB0eXBvbG9neSBvZiBvYmplY3RzPw0KMi4gSG93IGNvdWxkIHRoZXkgYmUgY2x1c3RlcmVkPw0KDQo+IE9uZSBvcHRpb24gaXMgdG8gYXBwbHkgYSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyB0byB0aGUgb2J0YWluZWQgc2NvcmVzLCBhbmQgdGhlbiBhZGQgdGhlIGNsdXN0ZXJlZCBncm91cHMgdG8gdGhlIFNjb3JlcyBzY2F0dGVycGxvdA0KDQo+IEhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nDQoNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTZ9DQojIGNsdXN0ZXJpbmcNCmNhcnNfY2x1c3RlcmluZyA9IGhjbHVzdChkaXN0KGNhcnNfcGNhJGluZCRjb29yZCksIG1ldGhvZCA9ICJ3YXJkLkQiKQ0KcGxvdChjYXJzX2NsdXN0ZXJpbmcsIHhsYWIgPSAiIiwgc3ViID0gIiIpDQpgYGANCg0KPiBQQyBwbG90IHdpdGggY2x1c3RlcmluZyBwYXJ0aXRpb24NCg0KYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9DQojIGdldCAzIGNsdXN0ZXINCmNhcnNfY2x1c3RlcnMgPSBjdXRyZWUoY2Fyc19jbHVzdGVyaW5nLCBrID0gMykNCg0KIyBhZGQgY2x1c3RlciB0byBkYXRhIGZyYW1lIG9mIHNjb3Jlcw0KY2Fyc19wY2Ffb2JzJGNsdXN0ZXIgPSBhcy5mYWN0b3IoY2Fyc19jbHVzdGVycykNCiMgZ2dwbG90DQpnZ3Bsb3QoY2Fyc19wY2Ffb2JzLCBhZXMoeD1EaW0uMSwgeT1EaW0uMiwgbGFiZWw9cm93bmFtZXMoY2FyczIwMDQpKSkgKw0KZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JheTcwIikgKw0KZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JheTcwIikgKw0KZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjbHVzdGVyKSwgYWxwaGEgPSAwLjU1LCBzaXplID0gMykgKw0KZ2VvbV90ZXh0KGFlcyhjb2xvciA9IGNsdXN0ZXIpLCBhbHBoYSA9IDAuNTUsIHNpemUgPSA0KSArDQp4bGFiKCJQQzEiKSArDQp5bGFiKCJQQzIiKSArDQp4bGltKC01LCA2KSArDQpnZ3RpdGxlKCJQQ0EgcGxvdCBvZiBvYnNlcnZhdGlvbnMiKSArIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9DQpsaWJyYXJ5KGdncmVwZWwpDQojIHZhbW9zIGFycnVtYXIgbyBncsOhZmljbyBhbnRlcmlvci4NCiMgZ2VvbV90ZXh0X3JlcGVsDQoNCiMgZ2V0IDMgY2x1c3Rlcg0KY2Fyc19jbHVzdGVycyA9IGN1dHJlZShjYXJzX2NsdXN0ZXJpbmcsIGsgPSAzKQ0KIyBhZGQgY2x1c3RlciB0byBkYXRhIGZyYW1lIG9mIHNjb3Jlcw0KY2Fyc19wY2Ffb2JzJGNsdXN0ZXIgPSBhcy5mYWN0b3IoY2Fyc19jbHVzdGVycykNCiMgZ2dwbG90DQpnZ3Bsb3QoY2Fyc19wY2Ffb2JzLCBhZXMoeD1EaW0uMSwgeT1EaW0uMiwgbGFiZWw9cm93bmFtZXMoY2FyczIwMDQpKSkgKw0KZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JheTcwIikgKw0KZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JheTcwIikgKw0KZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjbHVzdGVyKSwgYWxwaGEgPSAwLjU1LCBzaXplID0gMykgKw0KZ2VvbV90ZXh0X3JlcGVsKGFlcyhjb2xvciA9IGNsdXN0ZXIpLCBhbHBoYSA9IDAuNTUsIHNpemUgPSA0KSArDQp4bGFiKCJQQzEiKSArDQp5bGFiKCJQQzIiKSArDQp4bGltKC01LCA2KSArDQpnZ3RpdGxlKCJQQ0EgcGxvdCBvZiBvYnNlcnZhdGlvbnMiKSArIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KDQoNCg==