Principal component analysis, or PCA, is a common approach to dimensionality reduction. Learn exactly what PCA does, visualize the results of PCA with biplots and scree plots, and deal with practical issues such as centering and scaling the data before performing PCA.
library(readr)
library(dplyr)
library(ggplot2)
library(stringr)
3.1: PCA using prcomp()
In this exercise, you will create your first PCA model and observe the diagnostic results.
We have loaded the Pokemon data from earlier, which has four dimensions, and placed it in a variable called pokemon. Your task is to create a PCA model of the data, then to inspect the resulting model using the summary() function.
Instructions
100 XP
Create a PCA model of the data in pokemon, setting scale to TRUE. Store the result in pr.out.
Inspect the result with the summary() function.
pokemon<-read.csv("Pokemon.csv")
pokemon_pr <- pokemon %>% select(HP, Attack, Defense, Speed)
glimpse(pokemon_pr)
Observations: 800
Variables: 4
$ HP <int> 45, 60, 80, 80, 39, 58, 78, 78, 78, 44, 59, 79, 79, 45, 50, 60, 40, 45, 65, 65, 40...
$ Attack <int> 49, 62, 82, 100, 52, 64, 84, 130, 104, 48, 63, 83, 103, 30, 20, 45, 35, 25, 90, 15...
$ Defense <int> 49, 63, 83, 123, 43, 58, 78, 111, 78, 65, 80, 100, 120, 35, 55, 50, 30, 50, 40, 40...
$ Speed <int> 45, 60, 80, 80, 65, 80, 100, 100, 100, 43, 58, 78, 78, 45, 30, 70, 50, 35, 75, 145...
summary(pokemon_pr)
HP Attack Defense Speed
Min. : 1.00 Min. : 5 Min. : 5.00 Min. : 5.00
1st Qu.: 50.00 1st Qu.: 55 1st Qu.: 50.00 1st Qu.: 45.00
Median : 65.00 Median : 75 Median : 70.00 Median : 65.00
Mean : 69.26 Mean : 79 Mean : 73.84 Mean : 68.28
3rd Qu.: 80.00 3rd Qu.:100 3rd Qu.: 90.00 3rd Qu.: 90.00
Max. :255.00 Max. :190 Max. :230.00 Max. :180.00
pr.out <- prcomp(x = pokemon_pr, scale = TRUE, center = TRUE)
summary(pr.out)
Importance of components:
PC1 PC2 PC3 PC4
Standard deviation 1.3721 0.9933 0.8526 0.6354
Proportion of Variance 0.4707 0.2467 0.1817 0.1009
Cumulative Proportion 0.4707 0.7173 0.8991 1.0000
biplot(pr.out)

PCbiplot(pr.pokemon)
Error in PCbiplot(pr.pokemon) : could not find function "PCbiplot"
Remark: Attack & HP variables have approximately the same loadings in the first two principal components (similar directions)
3.2: Variance explained
The second common plot type for understanding PCA models is a scree plot. A scree plot shows the variance explained as the number of principal components increases. Sometimes the cumulative variance explained is plotted as well.
In this and the next exercise, you will prepare data from the pr.out model you created at the beginning of the chapter for use in a scree plot. Preparing the data for plotting is required because there is not a built-in function in R to create this type of plot.
Instructions
100 XP
pr.out and the pokemon data are still available in your workspace.
Assign to the variable pr.var the square of the standard deviations of the principal components (i.e. the variance). The standard deviation of the principal components is available in the sdev component of the PCA model object.
Assign to the variable pve the proportion of the variance explained, calculated by dividing pr.var by the total variance explained by all principal components.
# Variability of each principal component: pr.var
pr.var <- pr.out$sdev^2
# Variance explained by each principal component: pve
pve <- pr.var / sum(pr.var)
pve
[1] 0.4706937 0.2466505 0.1817326 0.1009233
3.3: Visualize variance explained
Now you will create a scree plot showing the proportion of variance explained by each principal component, as well as the cumulative proportion of variance explained.
Recall from the video that these plots can help to determine the number of principal components to retain. One way to determine the number of principal components to retain is by looking for an elbow in the scree plot showing that as the number of principal components increases, the rate at which variance is explained decreases substantially. In the absence of a clear elbow, you can use the scree plot as a guide for setting a threshold.
Instructions
100 XP
The proportion of variance explained is still available in the pve object you created in the last exercise.
Use plot() to plot the proportion of variance explained by each principal component.
Use plot() and cumsum() (cumulative sum) to plot the cumulative proportion of variance explained as a function of the number principal components.
# Plot variance explained for each principal component
plot(pve, xlab = "Principal Component",
ylab = "Proportion of Variance Explained",
ylim = c(0, 1), type = "b")

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

3.4: Practical issues: scaling
You saw in the video that scaling your data before doing PCA changes the results of the PCA modeling. Here, you will perform PCA with and without scaling, then visualize the results using biplots.
Sometimes scaling is appropriate when the variances of the variables are substantially different. This is commonly the case when variables have different units of measurement, for example, degrees Fahrenheit (temperature) and miles (distance). Making the decision to use scaling is an important step in performing a principal component analysis.
Instructions
100 XP
The same Pokemon dataset is available in your workspace as pokemon, but one new variable has been added: Total.
There is some code at the top of the editor to calculate the mean and standard deviation of each variable in the model. Run this code to see how the scale of the variables differs in the original data.
Create a PCA model of pokemon with scaling, assigning the result to pr.with.scaling.
Create a PCA model of pokemon without scaling, assigning the result to pr.without.scaling.
Use biplot() to plot both models (one at a time) and compare their outputs.
# Mean of each variable
pokemon_new<-read.csv("new_pokemon.csv")
colMeans(pokemon_new[,2:6])
Total HitPoints Attack Defense Speed
448.82 71.08 81.22 78.44 66.58
# Standard deviation of each variable
apply(pokemon_new[,2:6], 2, sd)
Total HitPoints Attack Defense Speed
119.32321 25.62193 33.03078 32.05809 27.51036
# PCA model with scaling: pr.with.scaling
pr.with.scaling <- prcomp(x = pokemon_new[,2:6], scale = T, center =T)
# PCA model without scaling: pr.without.scaling
pr.without.scaling <- prcomp(x = pokemon_new[,2:6], scale = F, center = T)
# Create biplots of both for comparison
biplot(pr.with.scaling)

biplot(pr.without.scaling)

Remark: The new Total column contains much more variation, on average, than the other four columns, so it has a disproportionate effect on the PCA model when scaling is not performed. After scaling the data, there’s a much more even distribution of the loading vectors.
LS0tDQp0aXRsZTogIkRhdGFjYW1wIFIgLSBVbnN1cGVydmlzZWQgTGVhcm5pbmcgaW4gUiA6IENoYXB0ZXIgMyAoRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIHdpdGggUENBKSINCmF1dGhvcjogIkNoZW4gV2VpcWlhbmciDQpkYXRlOiAiTm92ZW1iZXIgMjgsIDIwMTgiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpQcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzLCBvciBQQ0EsIGlzIGEgY29tbW9uIGFwcHJvYWNoIHRvIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbi4gTGVhcm4gZXhhY3RseSB3aGF0IFBDQSBkb2VzLCB2aXN1YWxpemUgdGhlIHJlc3VsdHMgb2YgUENBIHdpdGggYmlwbG90cyBhbmQgc2NyZWUgcGxvdHMsIGFuZCBkZWFsIHdpdGggcHJhY3RpY2FsIGlzc3VlcyBzdWNoIGFzIGNlbnRlcmluZyBhbmQgc2NhbGluZyB0aGUgZGF0YSBiZWZvcmUgcGVyZm9ybWluZyBQQ0EuDQoNCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpgYGANCg0KIyAzLjE6IFBDQSB1c2luZyBwcmNvbXAoKQ0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBjcmVhdGUgeW91ciBmaXJzdCBQQ0EgbW9kZWwgYW5kIG9ic2VydmUgdGhlIGRpYWdub3N0aWMgcmVzdWx0cy4NCg0KV2UgaGF2ZSBsb2FkZWQgdGhlIFBva2Vtb24gZGF0YSBmcm9tIGVhcmxpZXIsIHdoaWNoIGhhcyBmb3VyIGRpbWVuc2lvbnMsIGFuZCBwbGFjZWQgaXQgaW4gYSB2YXJpYWJsZSBjYWxsZWQgcG9rZW1vbi4gWW91ciB0YXNrIGlzIHRvIGNyZWF0ZSBhIFBDQSBtb2RlbCBvZiB0aGUgZGF0YSwgdGhlbiB0byBpbnNwZWN0IHRoZSByZXN1bHRpbmcgbW9kZWwgdXNpbmcgdGhlIHN1bW1hcnkoKSBmdW5jdGlvbi4NCg0KSW5zdHJ1Y3Rpb25zDQoNCjEwMCBYUA0KDQotIENyZWF0ZSBhIFBDQSBtb2RlbCBvZiB0aGUgZGF0YSBpbiBwb2tlbW9uLCBzZXR0aW5nIHNjYWxlIHRvIFRSVUUuIFN0b3JlIHRoZSByZXN1bHQgaW4gcHIub3V0Lg0KDQotIEluc3BlY3QgdGhlIHJlc3VsdCB3aXRoIHRoZSBzdW1tYXJ5KCkgZnVuY3Rpb24uDQpgYGB7cn0NCnBva2Vtb248LXJlYWQuY3N2KCJQb2tlbW9uLmNzdiIpDQpwb2tlbW9uX3ByIDwtIHBva2Vtb24gJT4lIHNlbGVjdChIUCwgQXR0YWNrLCBEZWZlbnNlLCBTcGVlZCkNCmdsaW1wc2UocG9rZW1vbl9wcikNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkocG9rZW1vbl9wcikNCmBgYA0KDQpgYGB7cn0NCnByLm91dCA8LSBwcmNvbXAoeCA9IHBva2Vtb25fcHIsIHNjYWxlID0gVFJVRSwgY2VudGVyID0gVFJVRSkNCnN1bW1hcnkocHIub3V0KQ0KYmlwbG90KHByLm91dCkNCmBgYA0KUmVtYXJrOiAgQXR0YWNrICYgSFAgdmFyaWFibGVzIGhhdmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBsb2FkaW5ncyBpbiB0aGUgZmlyc3QgdHdvIHByaW5jaXBhbCBjb21wb25lbnRzIChzaW1pbGFyIGRpcmVjdGlvbnMpDQoNCg0KIyAzLjI6IFZhcmlhbmNlIGV4cGxhaW5lZA0KDQpUaGUgc2Vjb25kIGNvbW1vbiBwbG90IHR5cGUgZm9yIHVuZGVyc3RhbmRpbmcgUENBIG1vZGVscyBpcyBhIHNjcmVlIHBsb3QuIEEgc2NyZWUgcGxvdCBzaG93cyB0aGUgdmFyaWFuY2UgZXhwbGFpbmVkIGFzIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgaW5jcmVhc2VzLiBTb21ldGltZXMgdGhlIGN1bXVsYXRpdmUgdmFyaWFuY2UgZXhwbGFpbmVkIGlzIHBsb3R0ZWQgYXMgd2VsbC4NCg0KSW4gdGhpcyBhbmQgdGhlIG5leHQgZXhlcmNpc2UsIHlvdSB3aWxsIHByZXBhcmUgZGF0YSBmcm9tIHRoZSBwci5vdXQgbW9kZWwgeW91IGNyZWF0ZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgY2hhcHRlciBmb3IgdXNlIGluIGEgc2NyZWUgcGxvdC4gUHJlcGFyaW5nIHRoZSBkYXRhIGZvciBwbG90dGluZyBpcyByZXF1aXJlZCBiZWNhdXNlIHRoZXJlIGlzIG5vdCBhIGJ1aWx0LWluIGZ1bmN0aW9uIGluIFIgdG8gY3JlYXRlIHRoaXMgdHlwZSBvZiBwbG90Lg0KDQpJbnN0cnVjdGlvbnMNCg0KMTAwIFhQDQoNCi0gcHIub3V0IGFuZCB0aGUgcG9rZW1vbiBkYXRhIGFyZSBzdGlsbCBhdmFpbGFibGUgaW4geW91ciB3b3Jrc3BhY2UuDQoNCg0KLSBBc3NpZ24gdG8gdGhlIHZhcmlhYmxlIHByLnZhciB0aGUgc3F1YXJlIG9mIHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIG9mIHRoZSBwcmluY2lwYWwgY29tcG9uZW50cyAoaS5lLiB0aGUgdmFyaWFuY2UpLiBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBwcmluY2lwYWwgY29tcG9uZW50cyBpcyBhdmFpbGFibGUgaW4gdGhlIHNkZXYgY29tcG9uZW50IG9mIHRoZSBQQ0EgbW9kZWwgb2JqZWN0Lg0KDQotIEFzc2lnbiB0byB0aGUgdmFyaWFibGUgcHZlIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpYW5jZSBleHBsYWluZWQsIGNhbGN1bGF0ZWQgYnkgZGl2aWRpbmcgcHIudmFyIGJ5IHRoZSB0b3RhbCB2YXJpYW5jZSBleHBsYWluZWQgYnkgYWxsIHByaW5jaXBhbCBjb21wb25lbnRzLg0KDQpgYGB7cn0NCiMgVmFyaWFiaWxpdHkgb2YgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50OiBwci52YXINCnByLnZhciA8LSBwci5vdXQkc2Rldl4yDQoNCiMgVmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudDogcHZlDQpwdmUgPC0gcHIudmFyIC8gc3VtKHByLnZhcikNCnB2ZQ0KYGBgDQoNCiMgMy4zOiBWaXN1YWxpemUgdmFyaWFuY2UgZXhwbGFpbmVkDQoNCk5vdyB5b3Ugd2lsbCBjcmVhdGUgYSBzY3JlZSBwbG90IHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudCwgYXMgd2VsbCBhcyB0aGUgY3VtdWxhdGl2ZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZC4NCg0KUmVjYWxsIGZyb20gdGhlIHZpZGVvIHRoYXQgdGhlc2UgcGxvdHMgY2FuIGhlbHAgdG8gZGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gcmV0YWluLiBPbmUgd2F5IHRvIGRldGVybWluZSB0aGUgbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIHRvIHJldGFpbiBpcyBieSBsb29raW5nIGZvciBhbiBlbGJvdyBpbiB0aGUgc2NyZWUgcGxvdCBzaG93aW5nIHRoYXQgYXMgdGhlIG51bWJlciBvZiBwcmluY2lwYWwgY29tcG9uZW50cyBpbmNyZWFzZXMsIHRoZSByYXRlIGF0IHdoaWNoIHZhcmlhbmNlIGlzIGV4cGxhaW5lZCBkZWNyZWFzZXMgc3Vic3RhbnRpYWxseS4gSW4gdGhlIGFic2VuY2Ugb2YgYSBjbGVhciBlbGJvdywgeW91IGNhbiB1c2UgdGhlIHNjcmVlIHBsb3QgYXMgYSBndWlkZSBmb3Igc2V0dGluZyBhIHRocmVzaG9sZC4NCg0KSW5zdHJ1Y3Rpb25zDQoNCjEwMCBYUA0KDQpUaGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgaXMgc3RpbGwgYXZhaWxhYmxlIGluIHRoZSBwdmUgb2JqZWN0IHlvdSBjcmVhdGVkIGluIHRoZSBsYXN0IGV4ZXJjaXNlLg0KDQpVc2UgcGxvdCgpIHRvIHBsb3QgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudC4NCg0KVXNlIHBsb3QoKSBhbmQgY3Vtc3VtKCkgKGN1bXVsYXRpdmUgc3VtKSB0byBwbG90IHRoZSBjdW11bGF0aXZlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGFzIGEgZnVuY3Rpb24gb2YgdGhlIG51bWJlciBwcmluY2lwYWwgY29tcG9uZW50cy4NCg0KYGBge3J9DQojIFBsb3QgdmFyaWFuY2UgZXhwbGFpbmVkIGZvciBlYWNoIHByaW5jaXBhbCBjb21wb25lbnQNCnBsb3QocHZlLCB4bGFiID0gIlByaW5jaXBhbCBDb21wb25lbnQiLA0KICAgICB5bGFiID0gIlByb3BvcnRpb24gb2YgVmFyaWFuY2UgRXhwbGFpbmVkIiwNCiAgICAgeWxpbSA9IGMoMCwgMSksIHR5cGUgPSAiYiIpDQoNCiMgUGxvdCBjdW11bGF0aXZlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkDQpwbG90KGN1bXN1bShwdmUpLCB4bGFiID0gIlByaW5jaXBhbCBDb21wb25lbnQiLA0KICAgICB5bGFiID0gIkN1bXVsYXRpdmUgUHJvcG9ydGlvbiBvZiBWYXJpYW5jZSBFeHBsYWluZWQiLA0KICAgICB5bGltID0gYygwLCAxKSwgdHlwZSA9ICJiIikNCmBgYA0KDQojIDMuNDogUHJhY3RpY2FsIGlzc3Vlczogc2NhbGluZw0KDQpZb3Ugc2F3IGluIHRoZSB2aWRlbyB0aGF0IHNjYWxpbmcgeW91ciBkYXRhIGJlZm9yZSBkb2luZyBQQ0EgY2hhbmdlcyB0aGUgcmVzdWx0cyBvZiB0aGUgUENBIG1vZGVsaW5nLiBIZXJlLCB5b3Ugd2lsbCBwZXJmb3JtIFBDQSB3aXRoIGFuZCB3aXRob3V0IHNjYWxpbmcsIHRoZW4gdmlzdWFsaXplIHRoZSByZXN1bHRzIHVzaW5nIGJpcGxvdHMuDQoNClNvbWV0aW1lcyBzY2FsaW5nIGlzIGFwcHJvcHJpYXRlIHdoZW4gdGhlIHZhcmlhbmNlcyBvZiB0aGUgdmFyaWFibGVzIGFyZSBzdWJzdGFudGlhbGx5IGRpZmZlcmVudC4gVGhpcyBpcyBjb21tb25seSB0aGUgY2FzZSB3aGVuIHZhcmlhYmxlcyBoYXZlIGRpZmZlcmVudCB1bml0cyBvZiBtZWFzdXJlbWVudCwgZm9yIGV4YW1wbGUsIGRlZ3JlZXMgRmFocmVuaGVpdCAodGVtcGVyYXR1cmUpIGFuZCBtaWxlcyAoZGlzdGFuY2UpLiBNYWtpbmcgdGhlIGRlY2lzaW9uIHRvIHVzZSBzY2FsaW5nIGlzIGFuIGltcG9ydGFudCBzdGVwIGluIHBlcmZvcm1pbmcgYSBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzLg0KDQpJbnN0cnVjdGlvbnMNCg0KMTAwIFhQDQoNCi0gVGhlIHNhbWUgUG9rZW1vbiBkYXRhc2V0IGlzIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZSBhcyBwb2tlbW9uLCBidXQgb25lIG5ldyB2YXJpYWJsZSBoYXMgYmVlbiBhZGRlZDogVG90YWwuDQoNCi0gVGhlcmUgaXMgc29tZSBjb2RlIGF0IHRoZSB0b3Agb2YgdGhlIGVkaXRvciB0byBjYWxjdWxhdGUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBlYWNoIHZhcmlhYmxlIGluIHRoZSBtb2RlbC4gUnVuIHRoaXMgY29kZSB0byBzZWUgaG93IHRoZSBzY2FsZSBvZiB0aGUgdmFyaWFibGVzIGRpZmZlcnMgaW4gdGhlIG9yaWdpbmFsIGRhdGEuDQoNCi0gQ3JlYXRlIGEgUENBIG1vZGVsIG9mIHBva2Vtb24gd2l0aCBzY2FsaW5nLCBhc3NpZ25pbmcgdGhlIHJlc3VsdCB0byBwci53aXRoLnNjYWxpbmcuDQoNCi0gQ3JlYXRlIGEgUENBIG1vZGVsIG9mIHBva2Vtb24gd2l0aG91dCBzY2FsaW5nLCBhc3NpZ25pbmcgdGhlIHJlc3VsdCB0byBwci53aXRob3V0LnNjYWxpbmcuDQoNCi0gVXNlIGJpcGxvdCgpIHRvIHBsb3QgYm90aCBtb2RlbHMgKG9uZSBhdCBhIHRpbWUpIGFuZCBjb21wYXJlIHRoZWlyIG91dHB1dHMuDQpgYGB7cn0NCiMgTWVhbiBvZiBlYWNoIHZhcmlhYmxlDQpwb2tlbW9uX25ldzwtcmVhZC5jc3YoIm5ld19wb2tlbW9uLmNzdiIpDQpjb2xNZWFucyhwb2tlbW9uX25ld1ssMjo2XSkNCg0KIyBTdGFuZGFyZCBkZXZpYXRpb24gb2YgZWFjaCB2YXJpYWJsZQ0KYXBwbHkocG9rZW1vbl9uZXdbLDI6Nl0sIDIsIHNkKQ0KDQojIFBDQSBtb2RlbCB3aXRoIHNjYWxpbmc6IHByLndpdGguc2NhbGluZw0KcHIud2l0aC5zY2FsaW5nIDwtIHByY29tcCh4ID0gcG9rZW1vbl9uZXdbLDI6Nl0sIHNjYWxlID0gVCwgY2VudGVyID1UKQ0KDQoNCiMgUENBIG1vZGVsIHdpdGhvdXQgc2NhbGluZzogcHIud2l0aG91dC5zY2FsaW5nDQpwci53aXRob3V0LnNjYWxpbmcgPC0gcHJjb21wKHggPSBwb2tlbW9uX25ld1ssMjo2XSwgc2NhbGUgPSBGLCBjZW50ZXIgPSBUKQ0KDQojIENyZWF0ZSBiaXBsb3RzIG9mIGJvdGggZm9yIGNvbXBhcmlzb24NCmJpcGxvdChwci53aXRoLnNjYWxpbmcpDQpiaXBsb3QocHIud2l0aG91dC5zY2FsaW5nKQ0KYGBgDQoNClJlbWFyazogVGhlIG5ldyBUb3RhbCBjb2x1bW4gY29udGFpbnMgbXVjaCBtb3JlIHZhcmlhdGlvbiwgb24gYXZlcmFnZSwgdGhhbiB0aGUgb3RoZXIgZm91ciBjb2x1bW5zLCBzbyBpdCBoYXMgYSBkaXNwcm9wb3J0aW9uYXRlIGVmZmVjdCBvbiB0aGUgUENBIG1vZGVsIHdoZW4gc2NhbGluZyBpcyBub3QgcGVyZm9ybWVkLiBBZnRlciBzY2FsaW5nIHRoZSBkYXRhLCB0aGVyZSdzIGEgbXVjaCBtb3JlIGV2ZW4gZGlzdHJpYnV0aW9uIG9mIHRoZSBsb2FkaW5nIHZlY3RvcnMu