In this lab, we perform PCA on the USArrests data set, which is part of the base R package. The rows of the data set contain the 50 states, in alphabetical order.

states=row.names(USArrests )#create states vector as names in USArrests data
states #look at it
 [1] "Alabama"        "Alaska"         "Arizona"        "Arkansas"       "California"    
 [6] "Colorado"       "Connecticut"    "Delaware"       "Florida"        "Georgia"       
[11] "Hawaii"         "Idaho"          "Illinois"       "Indiana"        "Iowa"          
[16] "Kansas"         "Kentucky"       "Louisiana"      "Maine"          "Maryland"      
[21] "Massachusetts"  "Michigan"       "Minnesota"      "Mississippi"    "Missouri"      
[26] "Montana"        "Nebraska"       "Nevada"         "New Hampshire"  "New Jersey"    
[31] "New Mexico"     "New York"       "North Carolina" "North Dakota"   "Ohio"          
[36] "Oklahoma"       "Oregon"         "Pennsylvania"   "Rhode Island"   "South Carolina"
[41] "South Dakota"   "Tennessee"      "Texas"          "Utah"           "Vermont"       
[46] "Virginia"       "Washington"     "West Virginia"  "Wisconsin"      "Wyoming"       

The columns of the data set contain the four variables.

names(USArrests ) #explore USArrests data
[1] "Murder"   "Assault"  "UrbanPop" "Rape"    

We first briefly examine the data. We notice that the variables have vastly different means.

apply(USArrests , 2, mean)#explore USArrests data
  Murder  Assault UrbanPop     Rape 
   7.788  170.760   65.540   21.232 

Note that the apply() function allows us to apply a function-in this case, the mean() function-to each row or column of the data set. The second input here denotes whether we wish to compute the mean of the rows, 1, or the columns, 2. We see that there are on average three times as many rapes as murders, and more than eight times as many assaults as rapes. We can also examine the variances of the four variables using the apply() function.

apply(USArrests , 2, var)#explore USArrests data
    Murder    Assault   UrbanPop       Rape 
  18.97047 6945.16571  209.51878   87.72916 

Not surprisingly, the variables also have vastly different variances: the UrbanPop variable measures the percentage of the population in each state living in an urban area, which is not a comparable number to the number of rapes in each state per 100,000 individuals. If we failed to scale the variables before performing PCA, then most of the principal components that we observed would be driven by the Assault variable, since it has by far the largest mean and variance. Thus, it is important to standardize the variables to have mean zero and standard deviation one before performing PCA.

We now perform principal components analysis using the prcomp() function, which is one of several functions in R that perform PCA.

pr.out=prcomp(USArrests , scale=TRUE)#perform principle components analysis

By default, the prcomp() function centers the variables to have mean zero. By using the option scale=TRUE, we scale the variables to have standard deviation one. The output from prcomp() contains a number of useful quantities.

names(pr.out)#examine the objects created by prcomp function
[1] "sdev"     "rotation" "center"   "scale"    "x"       

The center and scale components correspond to the means and standard deviations of the variables that were used for scaling prior to implementing PCA.

pr.out$center #the center object
  Murder  Assault UrbanPop     Rape 
   7.788  170.760   65.540   21.232 
pr.out$scale #the scale object
   Murder   Assault  UrbanPop      Rape 
 4.355510 83.337661 14.474763  9.366385 

The rotation matrix provides the principal component loadings; each column of pr.out$rotation contains the corresponding principal component loading vector. This function names it the rotation matrix, because when we matrix-multiply the X matrix by pr.out$rotation, it gives us the coordinates of the data in the rotated coordinate system. These coordinates are the principal component scores.

pr.out$rotation #the rotation object
                PC1        PC2        PC3         PC4
Murder   -0.5358995  0.4181809 -0.3412327  0.64922780
Assault  -0.5831836  0.1879856 -0.2681484 -0.74340748
UrbanPop -0.2781909 -0.8728062 -0.3780158  0.13387773
Rape     -0.5434321 -0.1673186  0.8177779  0.08902432

We see that there are four distinct principal components. This is to be expected because there are in general min(n - 1, p) informative principal components in a data set with n observations and p variables.

Using the prcomp() function, we do not need to explicitly multiply the data by the principal component loading vectors in order to obtain the principal component score vectors. Rather the 50 ? 4 matrix x has as its columns the principal component score vectors. That is, the kth column is the kth principal component score vector.

dim(pr.out$x)#look at the principle component score vectors
[1] 50  4

We can plot the first two principal components as follows:

biplot (pr.out , scale =0)#plot first two components

The scale=0 argument to biplot() ensures that the arrows are scaled to represent the loadings; other values for scale give slightly different biplots with different interpretations.

Notice that this figure is a mirror image of Figure 10.1. Recall that the principal components are only unique up to a sign change, so we can reproduce Figure 10.1 by making a few small changes:

pr.out$rotation=-pr.out$rotation#flip the rotation
pr.out$x=-pr.out$x #flip the component matrix
biplot(pr.out , scale =0) #plot the flipped components

The prcomp() function also outputs the standard deviation of each principal component. For instance, on the USArrests data set, we can access these standard deviations as follows:

pr.out$sdev #look at standard deviation of each component
[1] 1.5748783 0.9948694 0.5971291 0.4164494

The variance explained by each principal component is obtained by squaring these:

pr.var=pr.out$sdev^2 #calculate the variance explained by each principle component
pr.var #look at the variance explained by each principle component
[1] 2.4802416 0.9897652 0.3565632 0.1734301

To compute the proportion of variance explained by each principal component, we simply divide the variance explained by each principal component by the total variance explained by all four principal components:

pve=pr.var/sum(pr.var) #compute the proportion of variance explained
pve #look at it
[1] 0.62006039 0.24744129 0.08914080 0.04335752

We see that the first principal component explains 62.0 % of the variance in the data, the next principal component explains 24.7 % of the variance, and so forth. We can plot the PVE explained by each component, as well as the cumulative PVE, as follows:

#plot the proportion of variance explained
plot(pve , xlab=" Principal Component ", ylab="Proportion of Variance Explained ", ylim=c(0,1),type='b') 

#plot the cumulative proportion of variance explained
plot(cumsum(pve), xlab="Principal Component ", ylab="Cumulative Proportion of Variance Explained ", ylim=c(0,1),type='b') 

The result is shown in Figure 10.4. Note that the function cumsum() computes the cumulative sum of the elements of a numeric vector. For instance:

a=c(1,2,8,-3) #create fake data to look at the cumsum() function
cumsum(a) #look at how cumsum effects 'a'
[1]  1  3 11  8
LS0tDQp0aXRsZTogIlByaW5jaXBsZSBDb21vbmVudHMgQW5hbHlzaXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UpDQpgYGANCg0KSW4gdGhpcyBsYWIsIHdlIHBlcmZvcm0gUENBIG9uIHRoZSBgVVNBcnJlc3RzYCBkYXRhIHNldCwgd2hpY2ggaXMgcGFydCBvZiB0aGUgYmFzZSBgUmAgcGFja2FnZS4gVGhlIHJvd3Mgb2YgdGhlIGRhdGEgc2V0IGNvbnRhaW4gdGhlIDUwIHN0YXRlcywgaW4gYWxwaGFiZXRpY2FsIG9yZGVyLg0KDQpgYGB7cn0NCnN0YXRlcz1yb3cubmFtZXMoVVNBcnJlc3RzICkjY3JlYXRlIHN0YXRlcyB2ZWN0b3IgYXMgbmFtZXMgaW4gVVNBcnJlc3RzIGRhdGENCnN0YXRlcyAjbG9vayBhdCBpdA0KYGBgDQoNClRoZSBjb2x1bW5zIG9mIHRoZSBkYXRhIHNldCBjb250YWluIHRoZSBmb3VyIHZhcmlhYmxlcy4NCg0KYGBge3J9DQpuYW1lcyhVU0FycmVzdHMgKSAjZXhwbG9yZSBVU0FycmVzdHMgZGF0YQ0KYGBgDQoNCldlIGZpcnN0IGJyaWVmbHkgZXhhbWluZSB0aGUgZGF0YS4gV2Ugbm90aWNlIHRoYXQgdGhlIHZhcmlhYmxlcyBoYXZlIHZhc3RseSBkaWZmZXJlbnQgbWVhbnMuDQoNCmBgYHtyfQ0KYXBwbHkoVVNBcnJlc3RzICwgMiwgbWVhbikjZXhwbG9yZSBVU0FycmVzdHMgZGF0YQ0KYGBgDQoNCk5vdGUgdGhhdCB0aGUgYGFwcGx5KClgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBhcHBseSBhIGZ1bmN0aW9uLWluIHRoaXMgY2FzZSwgdGhlIGBtZWFuKClgIGZ1bmN0aW9uLXRvIGVhY2ggcm93IG9yIGNvbHVtbiBvZiB0aGUgZGF0YSBzZXQuIFRoZSBzZWNvbmQgaW5wdXQgaGVyZSBkZW5vdGVzIHdoZXRoZXIgd2Ugd2lzaCB0byBjb21wdXRlIHRoZSBtZWFuIG9mIHRoZSByb3dzLCAxLCBvciB0aGUgY29sdW1ucywgMi4gV2Ugc2VlIHRoYXQgdGhlcmUgYXJlIG9uIGF2ZXJhZ2UgdGhyZWUgdGltZXMgYXMgbWFueSByYXBlcyBhcyBtdXJkZXJzLCBhbmQgbW9yZSB0aGFuIGVpZ2h0IHRpbWVzIGFzIG1hbnkgYXNzYXVsdHMgYXMgcmFwZXMuIFdlIGNhbiBhbHNvIGV4YW1pbmUgdGhlIHZhcmlhbmNlcyBvZiB0aGUgZm91ciB2YXJpYWJsZXMgdXNpbmcgdGhlIGBhcHBseSgpYCBmdW5jdGlvbi4NCg0KYGBge3J9DQphcHBseShVU0FycmVzdHMgLCAyLCB2YXIpI2V4cGxvcmUgVVNBcnJlc3RzIGRhdGENCmBgYA0KDQpOb3Qgc3VycHJpc2luZ2x5LCB0aGUgdmFyaWFibGVzIGFsc28gaGF2ZSB2YXN0bHkgZGlmZmVyZW50IHZhcmlhbmNlczogdGhlIGBVcmJhblBvcGAgdmFyaWFibGUgbWVhc3VyZXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIHBvcHVsYXRpb24gaW4gZWFjaCBzdGF0ZSBsaXZpbmcgaW4gYW4gdXJiYW4gYXJlYSwgd2hpY2ggaXMgbm90IGEgY29tcGFyYWJsZSBudW1iZXIgdG8gdGhlIG51bWJlciBvZiByYXBlcyBpbiBlYWNoIHN0YXRlIHBlciAxMDAsMDAwIGluZGl2aWR1YWxzLiBJZiB3ZSBmYWlsZWQgdG8gc2NhbGUgdGhlIHZhcmlhYmxlcyBiZWZvcmUgcGVyZm9ybWluZyBQQ0EsIHRoZW4gbW9zdCBvZiB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudHMgdGhhdCB3ZSBvYnNlcnZlZCB3b3VsZCBiZSBkcml2ZW4gYnkgdGhlIGBBc3NhdWx0YCB2YXJpYWJsZSwgc2luY2UgaXQgaGFzIGJ5IGZhciB0aGUgbGFyZ2VzdCBtZWFuIGFuZCB2YXJpYW5jZS4gVGh1cywgaXQgaXMgaW1wb3J0YW50IHRvIHN0YW5kYXJkaXplIHRoZSB2YXJpYWJsZXMgdG8gaGF2ZSBtZWFuIHplcm8gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvbmUgYmVmb3JlIHBlcmZvcm1pbmcgUENBLg0KDQpXZSBub3cgcGVyZm9ybSBwcmluY2lwYWwgY29tcG9uZW50cyBhbmFseXNpcyB1c2luZyB0aGUgYHByY29tcCgpYCBmdW5jdGlvbiwgd2hpY2ggaXMgb25lIG9mIHNldmVyYWwgZnVuY3Rpb25zIGluIFIgdGhhdCBwZXJmb3JtIFBDQS4NCg0KYGBge3J9DQpwci5vdXQ9cHJjb21wKFVTQXJyZXN0cyAsIHNjYWxlPVRSVUUpI3BlcmZvcm0gcHJpbmNpcGxlIGNvbXBvbmVudHMgYW5hbHlzaXMNCmBgYA0KDQpCeSBkZWZhdWx0LCB0aGUgYHByY29tcCgpYCBmdW5jdGlvbiBjZW50ZXJzIHRoZSB2YXJpYWJsZXMgdG8gaGF2ZSBtZWFuIHplcm8uIEJ5IHVzaW5nIHRoZSBvcHRpb24gYHNjYWxlPVRSVUVgLCB3ZSBzY2FsZSB0aGUgdmFyaWFibGVzIHRvIGhhdmUgc3RhbmRhcmQgZGV2aWF0aW9uIG9uZS4gVGhlIG91dHB1dCBmcm9tIGBwcmNvbXAoKWAgY29udGFpbnMgYSBudW1iZXIgb2YgdXNlZnVsIHF1YW50aXRpZXMuDQoNCmBgYHtyfQ0KbmFtZXMocHIub3V0KSNleGFtaW5lIHRoZSBvYmplY3RzIGNyZWF0ZWQgYnkgcHJjb21wIGZ1bmN0aW9uDQpgYGANCg0KVGhlIGBjZW50ZXJgIGFuZCBgc2NhbGVgIGNvbXBvbmVudHMgY29ycmVzcG9uZCB0byB0aGUgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlIHZhcmlhYmxlcyB0aGF0IHdlcmUgdXNlZCBmb3Igc2NhbGluZyBwcmlvciB0byBpbXBsZW1lbnRpbmcgUENBLg0KDQpgYGB7cn0NCnByLm91dCRjZW50ZXIgI3RoZSBjZW50ZXIgb2JqZWN0DQpwci5vdXQkc2NhbGUgI3RoZSBzY2FsZSBvYmplY3QNCmBgYA0KDQpUaGUgYHJvdGF0aW9uYCBtYXRyaXggcHJvdmlkZXMgdGhlIHByaW5jaXBhbCBjb21wb25lbnQgbG9hZGluZ3M7IGVhY2ggY29sdW1uIG9mIGBwci5vdXQkcm90YXRpb25gIGNvbnRhaW5zIHRoZSBjb3JyZXNwb25kaW5nIHByaW5jaXBhbCBjb21wb25lbnQgbG9hZGluZyB2ZWN0b3IuIFRoaXMgZnVuY3Rpb24gbmFtZXMgaXQgdGhlIHJvdGF0aW9uIG1hdHJpeCwgYmVjYXVzZSB3aGVuIHdlIG1hdHJpeC1tdWx0aXBseSB0aGUgKipYKiogbWF0cml4IGJ5IGBwci5vdXQkcm90YXRpb25gLCBpdCBnaXZlcyB1cyB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIGRhdGEgaW4gdGhlIHJvdGF0ZWQgY29vcmRpbmF0ZSBzeXN0ZW0uIFRoZXNlIGNvb3JkaW5hdGVzIGFyZSB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudCBzY29yZXMuDQoNCmBgYHtyfQ0KcHIub3V0JHJvdGF0aW9uICN0aGUgcm90YXRpb24gb2JqZWN0DQpgYGANCg0KV2Ugc2VlIHRoYXQgdGhlcmUgYXJlIGZvdXIgZGlzdGluY3QgcHJpbmNpcGFsIGNvbXBvbmVudHMuIFRoaXMgaXMgdG8gYmUgZXhwZWN0ZWQgYmVjYXVzZSB0aGVyZSBhcmUgaW4gZ2VuZXJhbCBtaW4obiAtIDEsIHApIGluZm9ybWF0aXZlIHByaW5jaXBhbCBjb21wb25lbnRzIGluIGEgZGF0YSBzZXQgd2l0aCAqbiogb2JzZXJ2YXRpb25zIGFuZCAqcCogdmFyaWFibGVzLg0KDQpVc2luZyB0aGUgYHByY29tcCgpYCBmdW5jdGlvbiwgd2UgZG8gbm90IG5lZWQgdG8gZXhwbGljaXRseSBtdWx0aXBseSB0aGUgZGF0YSBieSB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudCBsb2FkaW5nIHZlY3RvcnMgaW4gb3JkZXIgdG8gb2J0YWluIHRoZSBwcmluY2lwYWwgY29tcG9uZW50IHNjb3JlIHZlY3RvcnMuIFJhdGhlciB0aGUgNTAgPyA0IG1hdHJpeCBgeGAgaGFzIGFzIGl0cyBjb2x1bW5zIHRoZSBwcmluY2lwYWwgY29tcG9uZW50IHNjb3JlIHZlY3RvcnMuIFRoYXQgaXMsIHRoZSAqayp0aCBjb2x1bW4gaXMgdGhlICprKnRoIHByaW5jaXBhbCBjb21wb25lbnQgc2NvcmUgdmVjdG9yLg0KDQpgYGB7cn0NCmRpbShwci5vdXQkeCkjbG9vayBhdCB0aGUgcHJpbmNpcGxlIGNvbXBvbmVudCBzY29yZSB2ZWN0b3JzDQpgYGANCg0KV2UgY2FuIHBsb3QgdGhlIGZpcnN0IHR3byBwcmluY2lwYWwgY29tcG9uZW50cyBhcyBmb2xsb3dzOg0KDQpgYGB7cn0NCmJpcGxvdCAocHIub3V0ICwgc2NhbGUgPTApI3Bsb3QgZmlyc3QgdHdvIGNvbXBvbmVudHMNCmBgYA0KDQpUaGUgYHNjYWxlPTBgIGFyZ3VtZW50IHRvIGBiaXBsb3QoKWAgZW5zdXJlcyB0aGF0IHRoZSBhcnJvd3MgYXJlIHNjYWxlZCB0byByZXByZXNlbnQgdGhlIGxvYWRpbmdzOyBvdGhlciB2YWx1ZXMgZm9yIGBzY2FsZWAgZ2l2ZSBzbGlnaHRseSBkaWZmZXJlbnQgYmlwbG90cyB3aXRoIGRpZmZlcmVudCBpbnRlcnByZXRhdGlvbnMuDQoNCk5vdGljZSB0aGF0IHRoaXMgZmlndXJlIGlzIGEgbWlycm9yIGltYWdlIG9mIEZpZ3VyZSAxMC4xLiBSZWNhbGwgdGhhdCB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudHMgYXJlIG9ubHkgdW5pcXVlIHVwIHRvIGEgc2lnbiBjaGFuZ2UsIHNvIHdlIGNhbiByZXByb2R1Y2UgRmlndXJlIDEwLjEgYnkgbWFraW5nIGEgZmV3IHNtYWxsIGNoYW5nZXM6DQoNCmBgYHtyfQ0KcHIub3V0JHJvdGF0aW9uPS1wci5vdXQkcm90YXRpb24jZmxpcCB0aGUgcm90YXRpb24NCnByLm91dCR4PS1wci5vdXQkeCAjZmxpcCB0aGUgY29tcG9uZW50IG1hdHJpeA0KYmlwbG90KHByLm91dCAsIHNjYWxlID0wKSAjcGxvdCB0aGUgZmxpcHBlZCBjb21wb25lbnRzDQpgYGANCg0KVGhlIGBwcmNvbXAoKWAgZnVuY3Rpb24gYWxzbyBvdXRwdXRzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50LiBGb3IgaW5zdGFuY2UsIG9uIHRoZSBgVVNBcnJlc3RzYCBkYXRhIHNldCwgd2UgY2FuIGFjY2VzcyB0aGVzZSBzdGFuZGFyZCBkZXZpYXRpb25zIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KcHIub3V0JHNkZXYgI2xvb2sgYXQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGVhY2ggY29tcG9uZW50DQpgYGANCg0KVGhlIHZhcmlhbmNlIGV4cGxhaW5lZCBieSBlYWNoIHByaW5jaXBhbCBjb21wb25lbnQgaXMgb2J0YWluZWQgYnkgc3F1YXJpbmcgdGhlc2U6DQoNCmBgYHtyfQ0KcHIudmFyPXByLm91dCRzZGV2XjIgI2NhbGN1bGF0ZSB0aGUgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGxlIGNvbXBvbmVudA0KcHIudmFyICNsb29rIGF0IHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwbGUgY29tcG9uZW50DQpgYGANCg0KVG8gY29tcHV0ZSB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50LCB3ZSBzaW1wbHkgZGl2aWRlIHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50IGJ5IHRoZSB0b3RhbCB2YXJpYW5jZSBleHBsYWluZWQgYnkgYWxsIGZvdXIgcHJpbmNpcGFsIGNvbXBvbmVudHM6DQoNCmBgYHtyfQ0KcHZlPXByLnZhci9zdW0ocHIudmFyKSAjY29tcHV0ZSB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQNCnB2ZSAjbG9vayBhdCBpdA0KDQpgYGANCg0KV2Ugc2VlIHRoYXQgdGhlIGZpcnN0IHByaW5jaXBhbCBjb21wb25lbnQgZXhwbGFpbnMgNjIuMCAlIG9mIHRoZSB2YXJpYW5jZSBpbiB0aGUgZGF0YSwgdGhlIG5leHQgcHJpbmNpcGFsIGNvbXBvbmVudCBleHBsYWlucyAyNC43ICUgb2YgdGhlIHZhcmlhbmNlLCBhbmQgc28gZm9ydGguIFdlIGNhbiBwbG90IHRoZSBQVkUgZXhwbGFpbmVkIGJ5IGVhY2ggY29tcG9uZW50LCBhcyB3ZWxsIGFzIHRoZSBjdW11bGF0aXZlIFBWRSwgYXMgZm9sbG93czoNCg0KYGBge3J9DQojcGxvdCB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQNCnBsb3QocHZlICwgeGxhYj0iIFByaW5jaXBhbCBDb21wb25lbnQgIiwgeWxhYj0iUHJvcG9ydGlvbiBvZiBWYXJpYW5jZSBFeHBsYWluZWQgIiwgeWxpbT1jKDAsMSksdHlwZT0nYicpIA0KI3Bsb3QgdGhlIGN1bXVsYXRpdmUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQNCnBsb3QoY3Vtc3VtKHB2ZSksIHhsYWI9IlByaW5jaXBhbCBDb21wb25lbnQgIiwgeWxhYj0iQ3VtdWxhdGl2ZSBQcm9wb3J0aW9uIG9mIFZhcmlhbmNlIEV4cGxhaW5lZCAiLCB5bGltPWMoMCwxKSx0eXBlPSdiJykgDQpgYGANCg0KVGhlIHJlc3VsdCBpcyBzaG93biBpbiBGaWd1cmUgMTAuNC4gTm90ZSB0aGF0IHRoZSBmdW5jdGlvbiBjdW1zdW0oKSBjb21wdXRlcyB0aGUgY3VtdWxhdGl2ZSBzdW0gb2YgdGhlIGVsZW1lbnRzIG9mIGEgbnVtZXJpYyB2ZWN0b3IuIEZvciBpbnN0YW5jZToNCg0KYGBge3J9DQphPWMoMSwyLDgsLTMpICNjcmVhdGUgZmFrZSBkYXRhIHRvIGxvb2sgYXQgdGhlIGN1bXN1bSgpIGZ1bmN0aW9uDQpjdW1zdW0oYSkgI2xvb2sgYXQgaG93IGN1bXN1bSBlZmZlY3RzICdhJw0KYGBgDQoNCg0KDQo=