Unsupervised Methods:
- Principal Components
- K-means Clustering
- Hierarchical Clustering
1. Principal Component Analysis
We will use the USArrests data to illustrate the implementation of Principal Component method
glimpse(USArrests)
Observations: 50
Variables: 4
$ Murder [3m[38;5;246m<dbl>[39m[23m 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, 2.6, 10.4, 7.2, 2....
$ Assault [3m[38;5;246m<int>[39m[23m 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, 249, 113, 56, 115,...
$ UrbanPop [3m[38;5;246m<int>[39m[23m 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57, 66, 52, 66, 51, 6...
$ Rape [3m[38;5;246m<dbl>[39m[23m 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8, 20.2, 14.2, 24.0,...
We will now check for the means and variances of the variables and decide if standarization is required or not
apply(USArrests, 2, var)
Murder Assault UrbanPop Rape
18.97047 6945.16571 209.51878 87.72916
We notice that the means and variances are quite different. And since in Principal Component method we aim to identify the linear combination of variables that maximizes the variance, the result will be dominated by the variable that has the greatest variance.
So, we will standardize the variables (i.e. bring the variance of all variables to 1 unit) before implementing the method.
This can be achieved by setting the scale
argument of the prcomp
function to TRUE
pca_res
Standard deviations (1, .., p=4):
[1] 1.5748783 0.9948694 0.5971291 0.4164494
Rotation (n x k) = (4 x 4):
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
The standard deviation displayed in the result is the standard deviation of each of the 4 principal components. (Remember that the total number of Principal Components for a dataset = MIN[n-1, p])
Notice that the standard deviations always decreases.
The Rotation in the above summary is nothing but the loadings.
The first principal component is loaded equally on all the 3 kinds of crime. And it has got a lower loading on UrbanPop
So the first principal component esentially measure the average of the 3 crimes in any state
The second principal component is heavily loaded on UrbanPop
Visualizing the Principal Components

Interpretation Since the loadings were negative for the first principal component, states with a negative values have high crime rate (like Michigan, Nevada, California)
Similarly, the second principal component had a negative loading corresponding to UrbanPop. Hence states like New Jersey, Hawaii has high percentage of urban population.
2. K-means clustering
We will work with a simulated 2-dimensional data to illustrate the application of k-means clustering method.

Now, the cluster_assign store the true cluster numbers for each data point.
We will now run k-means algorithm on this dataset. The true clsuter assignment will be hidden from the algorithm.
Determining the optimal value of k - * Elbow Curve Method *

Based on the plot above, we will select k = 4
kmeans_out
K-means clustering with 4 clusters of sizes 29, 22, 28, 21
Cluster means:
[,1] [,2]
1 -1.208942 -3.512880
2 3.062712 1.015205
3 -8.447148 -3.005280
4 -2.368405 1.643897
Clustering vector:
[1] 1 4 2 3 3 1 4 4 3 4 3 2 3 2 3 2 2 4 1 1 2 3 3 1 3 3 2 3 1 1 4 1 3 3 2 1 2 3 1 2 3 1 1 2 2 4
[47] 1 2 1 4 4 4 2 1 3 1 3 1 4 4 1 4 3 1 3 2 1 4 2 3 1 1 3 1 2 4 4 2 3 3 1 1 3 1 1 3 1 2 3 4 2 2
[93] 2 1 4 3 4 4 4 3
Within cluster sum of squares by cluster:
[1] 40.73619 51.11144 72.60169 41.22388
(between_SS / total_SS = 91.6 %)
Available components:
[1] "cluster" "centers" "totss" "withinss" "tot.withinss" "betweenss"
[7] "size" "iter" "ifault"
The output of k-means provides us with a number of metrics.
- It displays the cluster centers
- Cluster assignment for the input dataset
- Within sum of squares for each cluster: smaller the value more homogeneous the cluster is
Visualizing the output of k-means We will compare the cluster results from k-means with the the true cluster assignments

We can see that k-means did a pretty good job in correctly assigning points to the clusters.
3. Hierarchical Clustering
We will use the same simulated dataset used to perform k-means clustering.
We use the function hclust()
that accepts 2 parameters, one is the distance matrix
and the other is the linkage method
.

Since we know that there are 4 clusters in the data, the dendogram above infact shows the presence of 4 major cluster (if we cut the dendogram at height between 5 and 10)
Recall that complete linkage uses the maximum pairwise-distance between points in 2 clusters.
We will now use other linkage methods:
- Single: minimum pairwise distance
- Average: Averages the pairwise-distances between 2 clsuters

As expected, single linkage produced long, stringy trees. The 4 clsuters are not really prominent in the above dendogram.

Average linkage, like complete method, produces balanced trees. The 4 clusters are quite visible from the above dendogram.
Comparing the result from complete
linkage method with the true clsuter assignments
table(hclust_complete_cut, cluster_assign)
cluster_assign
hclust_complete_cut 1 2 3 4
1 29 0 0 0
2 0 20 0 0
3 0 0 22 0
4 1 0 0 28
The table above shows that only 1 observation has been assigned to a wrong cluster.
Comparing the result from complete
linkage method with the k-means clsuter assignments
table(hclust_complete_cut, kmeans_out$cluster)
hclust_complete_cut 1 2 3 4
1 29 0 0 0
2 0 0 0 20
3 0 22 0 0
4 0 0 28 1
LS0tDQp0aXRsZTogIklTTFIgLSBDaGFwdGVyIDEwIg0Kc3VidGl0bGU6ICJVbnN1cGVydmlzZWQgTGVhcm5pbmciDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoqKlVuc3VwZXJ2aXNlZCBNZXRob2RzOioqDQoNCiogKipQcmluY2lwYWwgQ29tcG9uZW50cyoqDQoqICoqSy1tZWFucyBDbHVzdGVyaW5nKioNCiogKipIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyoqDQoNCioqKg0KDQojIyMjICoqMS4gUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyoqDQoNCioqKg0KDQpgYGB7ciwgZXJyb3I9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpyZXF1aXJlKGRwbHlyKQ0KYGBgDQoNCldlIHdpbGwgdXNlIHRoZSBVU0FycmVzdHMgZGF0YSB0byBpbGx1c3RyYXRlIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiBQcmluY2lwYWwgQ29tcG9uZW50IG1ldGhvZA0KYGBge3J9DQpkYXRhKCJVU0FycmVzdHMiKQ0KZ2xpbXBzZShVU0FycmVzdHMpDQpgYGANCg0KV2Ugd2lsbCBub3cgY2hlY2sgZm9yIHRoZSBtZWFucyBhbmQgdmFyaWFuY2VzIG9mIHRoZSB2YXJpYWJsZXMgYW5kIGRlY2lkZSBpZiBzdGFuZGFyaXphdGlvbiBpcyByZXF1aXJlZCBvciBub3QNCmBgYHtyfQ0KYXBwbHkoVVNBcnJlc3RzLCAyLCBtZWFuKQ0KYXBwbHkoVVNBcnJlc3RzLCAyLCB2YXIpDQpgYGANCldlIG5vdGljZSB0aGF0IHRoZSBtZWFucyBhbmQgdmFyaWFuY2VzIGFyZSBxdWl0ZSBkaWZmZXJlbnQuIEFuZCBzaW5jZSBpbiBQcmluY2lwYWwgQ29tcG9uZW50IG1ldGhvZCB3ZSBhaW0gdG8gaWRlbnRpZnkgdGhlIGxpbmVhciBjb21iaW5hdGlvbiBvZiB2YXJpYWJsZXMgdGhhdCBtYXhpbWl6ZXMgdGhlIHZhcmlhbmNlLCB0aGUgcmVzdWx0IHdpbGwgYmUgZG9taW5hdGVkIGJ5IHRoZSB2YXJpYWJsZSB0aGF0IGhhcyB0aGUgZ3JlYXRlc3QgdmFyaWFuY2UuDQoNClNvLCB3ZSB3aWxsIHN0YW5kYXJkaXplIHRoZSB2YXJpYWJsZXMgKGkuZS4gYnJpbmcgdGhlIHZhcmlhbmNlIG9mIGFsbCB2YXJpYWJsZXMgdG8gMSB1bml0KSBiZWZvcmUgaW1wbGVtZW50aW5nIHRoZSBtZXRob2QuDQoNClRoaXMgY2FuIGJlIGFjaGlldmVkIGJ5IHNldHRpbmcgdGhlIGBzY2FsZWAgYXJndW1lbnQgb2YgdGhlIGBwcmNvbXBgIGZ1bmN0aW9uIHRvICoqVFJVRSoqDQoNCmBgYHtyfQ0KcGNhX3JlcyA8LSBwcmNvbXAoVVNBcnJlc3RzLCBzY2FsZSA9IFRSVUUpDQpwY2FfcmVzDQpgYGANClRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZGlzcGxheWVkIGluIHRoZSByZXN1bHQgaXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBlYWNoIG9mIHRoZSA0IHByaW5jaXBhbCBjb21wb25lbnRzLiAoUmVtZW1iZXIgdGhhdCB0aGUgdG90YWwgbnVtYmVyIG9mIFByaW5jaXBhbCBDb21wb25lbnRzIGZvciBhIGRhdGFzZXQgPSBNSU5bbi0xLCBwXSkNCg0KTm90aWNlIHRoYXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbnMgYWx3YXlzIGRlY3JlYXNlcy4NCg0KVGhlICoqUm90YXRpb24qKiBpbiB0aGUgYWJvdmUgc3VtbWFyeSBpcyBub3RoaW5nIGJ1dCB0aGUgbG9hZGluZ3MuDQoNClRoZSAqKmZpcnN0IHByaW5jaXBhbCBjb21wb25lbnQqKiBpcyBsb2FkZWQgZXF1YWxseSBvbiBhbGwgdGhlIDMga2luZHMgb2YgY3JpbWUuIEFuZCBpdCBoYXMgZ290IGEgbG93ZXIgbG9hZGluZyBvbiBgVXJiYW5Qb3BgDQoNCipTbyB0aGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCBlc2VudGlhbGx5IG1lYXN1cmUgdGhlIGF2ZXJhZ2Ugb2YgdGhlIDMgY3JpbWVzIGluIGFueSBzdGF0ZSoNCg0KVGhlICoqc2Vjb25kIHByaW5jaXBhbCBjb21wb25lbnQqKiBpcyBoZWF2aWx5IGxvYWRlZCBvbiBgVXJiYW5Qb3BgDQoNCioqVmlzdWFsaXppbmcgdGhlIFByaW5jaXBhbCBDb21wb25lbnRzKioNCmBgYHtyfQ0KYmlwbG90KHBjYV9yZXMsIHNjYWxlID0gMCwgY2V4ID0gMC42KQ0KYGBgDQoNCipJbnRlcnByZXRhdGlvbioNClNpbmNlIHRoZSBsb2FkaW5ncyB3ZXJlIG5lZ2F0aXZlIGZvciB0aGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCwgc3RhdGVzIHdpdGggYSBuZWdhdGl2ZSB2YWx1ZXMgaGF2ZSBoaWdoIGNyaW1lIHJhdGUgKGxpa2UgTWljaGlnYW4sIE5ldmFkYSwgQ2FsaWZvcm5pYSkNCg0KU2ltaWxhcmx5LCB0aGUgc2Vjb25kIHByaW5jaXBhbCBjb21wb25lbnQgaGFkIGEgbmVnYXRpdmUgbG9hZGluZyBjb3JyZXNwb25kaW5nIHRvIFVyYmFuUG9wLiBIZW5jZSBzdGF0ZXMgbGlrZSBOZXcgSmVyc2V5LCBIYXdhaWkgaGFzIGhpZ2ggcGVyY2VudGFnZSBvZiB1cmJhbiBwb3B1bGF0aW9uLg0KDQoNCioqKg0KDQoqKioNCg0KIyMjIyAqKjIuIEstbWVhbnMgY2x1c3RlcmluZyoqDQoNCioqKg0KV2Ugd2lsbCB3b3JrIHdpdGggYSBzaW11bGF0ZWQgMi1kaW1lbnNpb25hbCBkYXRhIHRvIGlsbHVzdHJhdGUgdGhlIGFwcGxpY2F0aW9uIG9mIGstbWVhbnMgY2x1c3RlcmluZyBtZXRob2QuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTExKQ0KZGF0YV9wb2ludHMgPC0gbWF0cml4KHJub3JtKDEwMCoyKSwgMTAwLCAyKSAjVG8gZ2VuZXJhdGUgMTAwIHBhaXJzIG9mIGRhdGEgcG9pbnRzDQoNCiNXZSB3aWxsIG5vdyBnZW5lcmF0ZSA0IHBhaXJzIG9mIG1lYW5zIHRvIHJlcHJlc2VudCA0IGNsdXN0ZXJzDQptZWFucyA8LSBtYXRyaXgocm5vcm0oOCwgc2QgPSA0KSwgNCwgMikNCg0KI0Fzc2lnbmluZyBlYWNoIHBhaXIgdG8gYSBjbHVzdGVyIGFuZCB0aGVuIHNoaWZ0aW5nIHRoZSBwb2ludCBieSB0aGUgY29ycmVzcG9uZGluZyBjbHVzdGVyIG1lYW4gdmFsdWUNCmNsdXN0ZXJfYXNzaWduIDwtIHNhbXBsZSgxOjQsIDEwMCwgcmVwbGFjZSA9IFQpDQoNCmRhdGFfcG9pbnRzIDwtIGRhdGFfcG9pbnRzICsgbWVhbnNbY2x1c3Rlcl9hc3NpZ24sIF0NCg0KI1Zpc3VhbGl6aW5nIHRoZSBkYXRhDQpwbG90KGRhdGFfcG9pbnRzLCBjb2wgPSBjbHVzdGVyX2Fzc2lnbiwgcGNoID0gMTkpDQpgYGANCg0KTm93LCB0aGUgY2x1c3Rlcl9hc3NpZ24gc3RvcmUgdGhlIHRydWUgY2x1c3RlciBudW1iZXJzIGZvciBlYWNoIGRhdGEgcG9pbnQuDQoNCldlIHdpbGwgbm93IHJ1biBrLW1lYW5zIGFsZ29yaXRobSBvbiB0aGlzIGRhdGFzZXQuIFRoZSB0cnVlIGNsc3V0ZXIgYXNzaWdubWVudCB3aWxsIGJlIGhpZGRlbiBmcm9tIHRoZSBhbGdvcml0aG0uDQoNCipEZXRlcm1pbmluZyB0aGUgb3B0aW1hbCB2YWx1ZSBvZiBrIC0qICogKipFbGJvdyBDdXJ2ZSBNZXRob2QqKiAqDQpgYGB7cn0NCnRvdF93aXRoaW5zcyA8LSByZXAoMCwxMCkNCmZvcihrIGluIDE6MTApDQp7DQogIGttZWFuc19yZXMgPC0ga21lYW5zKGRhdGFfcG9pbnRzLCBjZW50ZXJzID0gaywgbnN0YXJ0ID0gMjUpDQogIHRvdF93aXRoaW5zc1trXSA8LSBrbWVhbnNfcmVzJHRvdC53aXRoaW5zcw0KfQ0KDQpwbG90KHggPSBzZXEoMSwxMCwgYnkgPSAxKSwgeSA9IHRvdF93aXRoaW5zcywgdHlwZSA9ICdiJywgcGNoID0gMTksIGNvbCA9ICJkYXJrYmx1ZSIsIHhsYWIgPSAiTnVtYmVyIG9mIGNsdXN0ZXJzIikNCmBgYA0KDQpCYXNlZCBvbiB0aGUgcGxvdCBhYm92ZSwgd2Ugd2lsbCBzZWxlY3QgayA9IDQNCg0KYGBge3J9DQprbWVhbnNfb3V0IDwtIGttZWFucyhkYXRhX3BvaW50cywgY2VudGVycyA9IDQsIG5zdGFydCA9IDIwKQ0Ka21lYW5zX291dA0KYGBgDQoNClRoZSBvdXRwdXQgb2Ygay1tZWFucyBwcm92aWRlcyB1cyB3aXRoIGEgbnVtYmVyIG9mIG1ldHJpY3MuIA0KDQoqIC0gSXQgZGlzcGxheXMgdGhlIGNsdXN0ZXIgY2VudGVycw0KKiAtIENsdXN0ZXIgYXNzaWdubWVudCBmb3IgdGhlIGlucHV0IGRhdGFzZXQNCiogLSBXaXRoaW4gc3VtIG9mIHNxdWFyZXMgZm9yIGVhY2ggY2x1c3Rlcjogc21hbGxlciB0aGUgdmFsdWUgbW9yZSBob21vZ2VuZW91cyB0aGUgY2x1c3RlciBpcw0KDQoqVmlzdWFsaXppbmcgdGhlIG91dHB1dCBvZiBrLW1lYW5zKg0KV2Ugd2lsbCBjb21wYXJlIHRoZSBjbHVzdGVyIHJlc3VsdHMgZnJvbSBrLW1lYW5zIHdpdGggdGhlIHRoZSB0cnVlIGNsdXN0ZXIgYXNzaWdubWVudHMNCmBgYHtyfQ0KcGxvdChkYXRhX3BvaW50cywgY29sID0ga21lYW5zX291dCRjbHVzdGVyLCBwY2ggPSAxLCBjZXggPSAzKSAjI0hvbGxvdyBjaXJjbGVzDQpwb2ludHMoZGF0YV9wb2ludHMsIGNvbCA9IGNsdXN0ZXJfYXNzaWduLCBwY2ggPSAxOSkNCnBvaW50cyhkYXRhX3BvaW50cywgY29sID0gYyg0LDMsMiwxKVtjbHVzdGVyX2Fzc2lnbl0sIHBjaCA9IDE5KQ0KYGBgDQpXZSBjYW4gc2VlIHRoYXQgay1tZWFucyBkaWQgYSBwcmV0dHkgZ29vZCBqb2IgaW4gY29ycmVjdGx5IGFzc2lnbmluZyBwb2ludHMgdG8gdGhlIGNsdXN0ZXJzLg0KDQoNCg0KKioqDQoNCioqKg0KDQojIyMjICoqMy4gSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgKioNCg0KKioqDQpXZSB3aWxsIHVzZSB0aGUgc2FtZSBzaW11bGF0ZWQgZGF0YXNldCB1c2VkIHRvIHBlcmZvcm0gay1tZWFucyBjbHVzdGVyaW5nLg0KDQpXZSB1c2UgdGhlIGZ1bmN0aW9uIGBoY2x1c3QoKWAgdGhhdCBhY2NlcHRzIDIgcGFyYW1ldGVycywgb25lIGlzIHRoZSBgZGlzdGFuY2UgbWF0cml4YCBhbmQgdGhlIG90aGVyIGlzIHRoZSBsaW5rYWdlIGBtZXRob2RgLg0KDQpgYGB7cn0NCmhjbHVzdF9jb21wbGV0ZSA8LSBoY2x1c3QoZGlzdChkYXRhX3BvaW50cyksIG1ldGhvZCA9ICJjb21wbGV0ZSIpDQojZGlzdChkYXRhX3BvaW50cykgd2lsbCBnZW5lcmF0ZSAxMDAqMTAwIG1hdHJpeCB0byBzdG9yZSB0aGUgcGFpcndpc2UgZGlzdGFuY2UgdmFsdWVzDQoNCiNMZXRzIHZpc3VhbGl6ZSB0aGUgb3V0cHV0IGRlbmRvZ3JhbQ0KcGxvdChoY2x1c3RfY29tcGxldGUsIGxhYmVscyA9IGNsdXN0ZXJfYXNzaWduKQ0KYGBgDQoNClNpbmNlIHdlIGtub3cgdGhhdCB0aGVyZSBhcmUgNCBjbHVzdGVycyBpbiB0aGUgZGF0YSwgdGhlIGRlbmRvZ3JhbSBhYm92ZSBpbmZhY3Qgc2hvd3MgdGhlIHByZXNlbmNlIG9mIDQgbWFqb3IgY2x1c3RlciAoaWYgd2UgY3V0IHRoZSBkZW5kb2dyYW0gYXQgaGVpZ2h0IGJldHdlZW4gNSBhbmQgMTApDQoNClJlY2FsbCB0aGF0ICoqY29tcGxldGUqKiBsaW5rYWdlIHVzZXMgdGhlIG1heGltdW0gcGFpcndpc2UtZGlzdGFuY2UgYmV0d2VlbiBwb2ludHMgaW4gMiBjbHVzdGVycy4NCg0KV2Ugd2lsbCBub3cgdXNlIG90aGVyIGxpbmthZ2UgbWV0aG9kczoNCg0KKiBTaW5nbGU6IG1pbmltdW0gcGFpcndpc2UgZGlzdGFuY2UNCiogQXZlcmFnZTogQXZlcmFnZXMgdGhlIHBhaXJ3aXNlLWRpc3RhbmNlcyBiZXR3ZWVuIDIgY2xzdXRlcnMNCiogDQoNCmBgYHtyfQ0KaGNsdXN0X3NpbmdsZSA8LSBoY2x1c3QoZGlzdChkYXRhX3BvaW50cyksIG1ldGhvZCA9ICJzaW5nbGUiKQ0KcGxvdChoY2x1c3Rfc2luZ2xlKQ0KDQpgYGANCg0KQXMgZXhwZWN0ZWQsIHNpbmdsZSBsaW5rYWdlIHByb2R1Y2VkIGxvbmcsIHN0cmluZ3kgdHJlZXMuIFRoZSA0IGNsc3V0ZXJzIGFyZSBub3QgcmVhbGx5IHByb21pbmVudCBpbiB0aGUgYWJvdmUgZGVuZG9ncmFtLg0KDQpgYGB7cn0NCmhjbHVzdF9hdmVyYWdlIDwtIGhjbHVzdChkaXN0KGRhdGFfcG9pbnRzKSwgbWV0aG9kID0gImF2ZXJhZ2UiKQ0KcGxvdChoY2x1c3RfYXZlcmFnZSkNCmBgYA0KQXZlcmFnZSBsaW5rYWdlLCBsaWtlIGNvbXBsZXRlIG1ldGhvZCwgcHJvZHVjZXMgYmFsYW5jZWQgdHJlZXMuIFRoZSA0IGNsdXN0ZXJzIGFyZSBxdWl0ZSB2aXNpYmxlIGZyb20gdGhlIGFib3ZlIGRlbmRvZ3JhbS4NCg0KDQoqQ29tcGFyaW5nIHRoZSByZXN1bHQgZnJvbSogYGNvbXBsZXRlYCAqbGlua2FnZSBtZXRob2Qgd2l0aCB0aGUqICoqdHJ1ZSBjbHN1dGVyKiogKmFzc2lnbm1lbnRzKg0KYGBge3J9DQpoY2x1c3RfY29tcGxldGVfY3V0IDwtIGN1dHJlZShoY2x1c3RfY29tcGxldGUsIGsgPSA0KQ0KdGFibGUoaGNsdXN0X2NvbXBsZXRlX2N1dCwgY2x1c3Rlcl9hc3NpZ24pDQpgYGANCg0KVGhlIHRhYmxlIGFib3ZlIHNob3dzIHRoYXQgb25seSAxIG9ic2VydmF0aW9uIGhhcyBiZWVuIGFzc2lnbmVkIHRvIGEgd3JvbmcgY2x1c3Rlci4NCg0KKkNvbXBhcmluZyB0aGUgcmVzdWx0IGZyb20qIGBjb21wbGV0ZWAgKmxpbmthZ2UgbWV0aG9kIHdpdGggdGhlKiAqKmstbWVhbnMgY2xzdXRlciBhc3NpZ25tZW50cyoqDQpgYGB7cn0NCnRhYmxlKGhjbHVzdF9jb21wbGV0ZV9jdXQsIGttZWFuc19vdXQkY2x1c3RlcikNCmBgYA0KDQoNCg==