This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
8. Proportion of Variance Explained (PVE) in two ways for the
USArrests dataset
(a) Using the sdev Output of prcomp()
To calculate the Proportion of Variance Explained (PVE) using the
built-in PCA function, I applied prcomp() to the USArrests dataset with
both centering and scaling enabled. I then used the squared standard
deviations (sdev^2) to compute the PVE for each principal component.
# Load data
data("USArrests")
# Perform PCA with centering and scaling
pca_out <- prcomp(USArrests, scale. = TRUE)
# Calculate the proportion of variance explained
eigenvalues <- pca_out$sdev^2
pve_a <- eigenvalues / sum(eigenvalues)
# Display the PVE
pve_a
[1] 0.62006039 0.24744129 0.08914080 0.04335752
Interpretation:
The first principal component explains 62.0% of the total variance.
The second explains 24.7%, The third explains 8.9%, and The fourth
explains 4.3%.
(b) Using Equation 12.10 Directly
To calculate the Proportion of Variance Explained (PVE) manually
using Equation 12.10, I first scaled the USArrests dataset so that all
variables have mean zero and standard deviation one, just like I did in
part (a). Then I used the principal component loadings obtained from the
prcomp() function and followed these steps:
I calculated the principal component scores manually by multiplying
the scaled data matrix with the loading matrix. I computed the numerator
of Equation 12.10 as the sum of squared scores for each principal
component. I computed the denominator as the total sum of squared values
from the scaled dataset. I divided the numerator by the denominator to
get the PVE for each principal component.
# Scale the data
scaled_data <- scale(USArrests)
# Perform PCA
pca_out <- prcomp(scaled_data)
# Extract loadings
loadings <- pca_out$rotation
# Calculate scores manually
scores <- scaled_data %*% loadings
# Compute numerator and denominator
numerator <- colSums(scores^2)
denominator <- sum(scaled_data^2)
# Calculate PVE
pve_b <- numerator / denominator
pve_b
PC1 PC2 PC3 PC4
0.62006039 0.24744129 0.08914080 0.04335752
This result matches exactly with the output from part (a), confirming
that both methods give the same PVE values when the data is properly
centered and scaled.
9(a) Hierarchical Clustering Using Complete Linkage and Euclidean
Distance
I performed hierarchical clustering on the USArrests dataset using
complete linkage and Euclidean distance. I did not scale the variables
in this part.
# Load data
data("USArrests")
# Compute the distance matrix
dist_matrix <- dist(USArrests)
# Perform hierarchical clustering with complete linkage
hc_complete <- hclust(dist_matrix, method = "complete")
# Plot the dendrogram
plot(hc_complete, main = "Dendrogram - Complete Linkage (Unscaled)")

# Dendrogram with clear labels
plot(hc_complete,
main = "Dendrogram - Complete Linkage (Unscaled)",
xlab = "",
sub = "",
cex = 0.6, # Shrink label size
las = 2) # Rotate labels for better spacing

(b) Cut the Dendrogram to Get 3 Clusters
I cut the dendrogram at a height that gives three clusters using
cutree(), and then listed which states belong to each cluster.
# Cut tree into 3 clusters
clusters_unscaled <- cutree(hc_complete, k = 3)
# Group states by clusters
split(names(clusters_unscaled), clusters_unscaled)
$`1`
[1] "Alabama" "Alaska" "Arizona" "California" "Delaware" "Florida" "Illinois" "Louisiana"
[9] "Maryland" "Michigan" "Mississippi" "Nevada" "New Mexico" "New York" "North Carolina" "South Carolina"
$`2`
[1] "Arkansas" "Colorado" "Georgia" "Massachusetts" "Missouri" "New Jersey" "Oklahoma" "Oregon" "Rhode Island"
[10] "Tennessee" "Texas" "Virginia" "Washington" "Wyoming"
$`3`
[1] "Connecticut" "Hawaii" "Idaho" "Indiana" "Iowa" "Kansas" "Kentucky" "Maine" "Minnesota"
[10] "Montana" "Nebraska" "New Hampshire" "North Dakota" "Ohio" "Pennsylvania" "South Dakota" "Utah" "Vermont"
[19] "West Virginia" "Wisconsin"
(c) Hierarchical Clustering After Scaling the Variables
I repeated the clustering after scaling all variables to have
standard deviation one.
# Scale the variables
scaled_data <- scale(USArrests)
# Compute new distance matrix
dist_scaled <- dist(scaled_data)
# Perform clustering
hc_scaled <- hclust(dist_scaled, method = "complete")
# Plot the scaled dendrogram
plot(hc_scaled, main = "Dendrogram - Complete Linkage (Scaled)")

# Dendrogram with clear labels
plot(hc_complete,
main = "Dendrogram - Complete Linkage (Unscaled)",
xlab = "",
sub = "",
cex = 0.6, # Shrink label size
las = 2) # Rotate labels for better spacing

Then I again cut the dendrogram into 3 clusters:
clusters_scaled <- cutree(hc_scaled, k = 3)
split(names(clusters_scaled), clusters_scaled)
$`1`
[1] "Alabama" "Alaska" "Georgia" "Louisiana" "Mississippi" "North Carolina" "South Carolina" "Tennessee"
$`2`
[1] "Arizona" "California" "Colorado" "Florida" "Illinois" "Maryland" "Michigan" "Nevada" "New Mexico" "New York" "Texas"
$`3`
[1] "Arkansas" "Connecticut" "Delaware" "Hawaii" "Idaho" "Indiana" "Iowa" "Kansas" "Kentucky"
[10] "Maine" "Massachusetts" "Minnesota" "Missouri" "Montana" "Nebraska" "New Hampshire" "New Jersey" "North Dakota"
[19] "Ohio" "Oklahoma" "Oregon" "Pennsylvania" "Rhode Island" "South Dakota" "Utah" "Vermont" "Virginia"
[28] "Washington" "West Virginia" "Wisconsin" "Wyoming"
(d) Effect of Scaling and Justification
Scaling had a significant effect on the clustering results.
Before scaling, variables like ‘Assault’ (which has a larger
variance) dominated the distance calculations. As a result, the
clustering was heavily influenced by the raw magnitude of certain crime
types.
After scaling, all variables contributed equally to the distance
calculation. This gave a more balanced view, and the cluster assignments
changed accordingly.
In my opinion, the variables should be scaled before computing
inter-observation dissimilarities, especially when the variables are
measured on different scales (e.g., ‘Murder’ and ‘UrbanPop’). Without
scaling, clustering reflects the influence of high-variance variables
rather than all features equally.
10 (a) Generate Simulated Data for 3 Classes
A simulated dataset was generated with 60 observations (20 in each of
3 distinct classes) and 50 variables. A mean shift was added to each
class to ensure clear separation between them.
set.seed(1)
# Generate 20 observations for each class
x1 <- matrix(rnorm(20 * 50, mean = 0), nrow = 20)
x2 <- matrix(rnorm(20 * 50, mean = 3), nrow = 20)
x3 <- matrix(rnorm(20 * 50, mean = 6), nrow = 20)
# Combine all observations
x <- rbind(x1, x2, x3)
# Create true class labels
labels <- c(rep(1, 20), rep(2, 20), rep(3, 20))
Interpretation:
The three classes appeared well-separated in the PCA plot, confirming
that the mean shifts were sufficient for visual class distinction.
Interpretation:
The clustering closely aligned with the actual class labels, with
only minor discrepancies due to arbitrary cluster numbering by
K-means.
Interpretation:
Two clusters resulted in the merging of two actual classes, reducing
clustering accuracy and underrepresenting the data’s true structure.
Interpretation:
Using four clusters led to overfitting, as one of the original
classes was split into two clusters unnecessarily.
Interpretation:
Clustering on the first two principal components preserved much of
the structure and yielded results similar to those obtained on the
original dataset.
- Perform K-means Clustering on Scaled Data The dataset was scaled
using scale(), and K-means clustering was performed again with 3
clusters.
x_scaled <- scale(x)
set.seed(1)
km_scaled <- kmeans(x_scaled, centers = 3, nstart = 20)
table(labels, km_scaled$cluster)
labels 1 2 3
1 0 0 20
2 0 20 0
3 20 0 0
Interpretation:
Scaling the data before clustering helped standardize variable
influence, although in this simulated case the improvement was minimal.
In real-world datasets where variables differ in scale, scaling is
essential to prevent dominance by high-variance features.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgotLS0tLS0KCiMgOC4gUHJvcG9ydGlvbiBvZiBWYXJpYW5jZSBFeHBsYWluZWQgKFBWRSkgaW4gdHdvIHdheXMgZm9yIHRoZSBVU0FycmVzdHMgZGF0YXNldAoKIyAoYSkgVXNpbmcgdGhlIHNkZXYgT3V0cHV0IG9mIHByY29tcCgpCgpUbyBjYWxjdWxhdGUgdGhlIFByb3BvcnRpb24gb2YgVmFyaWFuY2UgRXhwbGFpbmVkIChQVkUpIHVzaW5nIHRoZSBidWlsdC1pbiBQQ0EgZnVuY3Rpb24sIEkgYXBwbGllZCBwcmNvbXAoKSB0byB0aGUgVVNBcnJlc3RzIGRhdGFzZXQgd2l0aCBib3RoIGNlbnRlcmluZyBhbmQgc2NhbGluZyBlbmFibGVkLiBJIHRoZW4gdXNlZCB0aGUgc3F1YXJlZCBzdGFuZGFyZCBkZXZpYXRpb25zIChzZGV2XjIpIHRvIGNvbXB1dGUgdGhlIFBWRSBmb3IgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50LgoKYGBge3J9CiMgTG9hZCBkYXRhCmRhdGEoIlVTQXJyZXN0cyIpCgojIFBlcmZvcm0gUENBIHdpdGggY2VudGVyaW5nIGFuZCBzY2FsaW5nCnBjYV9vdXQgPC0gcHJjb21wKFVTQXJyZXN0cywgc2NhbGUuID0gVFJVRSkKCiMgQ2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZAplaWdlbnZhbHVlcyA8LSBwY2Ffb3V0JHNkZXZeMgpwdmVfYSA8LSBlaWdlbnZhbHVlcyAvIHN1bShlaWdlbnZhbHVlcykKCiMgRGlzcGxheSB0aGUgUFZFCnB2ZV9hCmBgYAoKIyAgSW50ZXJwcmV0YXRpb246CgpUaGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCBleHBsYWlucyA2Mi4wJSBvZiB0aGUgdG90YWwgdmFyaWFuY2UuClRoZSBzZWNvbmQgZXhwbGFpbnMgMjQuNyUsClRoZSB0aGlyZCBleHBsYWlucyA4LjklLCBhbmQKVGhlIGZvdXJ0aCBleHBsYWlucyA0LjMlLgoKIyAoYikgVXNpbmcgRXF1YXRpb24gMTIuMTAgRGlyZWN0bHkKClRvIGNhbGN1bGF0ZSB0aGUgUHJvcG9ydGlvbiBvZiBWYXJpYW5jZSBFeHBsYWluZWQgKFBWRSkgbWFudWFsbHkgdXNpbmcgRXF1YXRpb24gMTIuMTAsIEkgZmlyc3Qgc2NhbGVkIHRoZSBVU0FycmVzdHMgZGF0YXNldCBzbyB0aGF0IGFsbCB2YXJpYWJsZXMgaGF2ZSBtZWFuIHplcm8gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvbmUsIGp1c3QgbGlrZSBJIGRpZCBpbiBwYXJ0IChhKS4gVGhlbiBJIHVzZWQgdGhlIHByaW5jaXBhbCBjb21wb25lbnQgbG9hZGluZ3Mgb2J0YWluZWQgZnJvbSB0aGUgcHJjb21wKCkgZnVuY3Rpb24gYW5kIGZvbGxvd2VkIHRoZXNlIHN0ZXBzOgoKSSBjYWxjdWxhdGVkIHRoZSBwcmluY2lwYWwgY29tcG9uZW50IHNjb3JlcyBtYW51YWxseSBieSBtdWx0aXBseWluZyB0aGUgc2NhbGVkIGRhdGEgbWF0cml4IHdpdGggdGhlIGxvYWRpbmcgbWF0cml4LgpJIGNvbXB1dGVkIHRoZSBudW1lcmF0b3Igb2YgRXF1YXRpb24gMTIuMTAgYXMgdGhlIHN1bSBvZiBzcXVhcmVkIHNjb3JlcyBmb3IgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50LgpJIGNvbXB1dGVkIHRoZSBkZW5vbWluYXRvciBhcyB0aGUgdG90YWwgc3VtIG9mIHNxdWFyZWQgdmFsdWVzIGZyb20gdGhlIHNjYWxlZCBkYXRhc2V0LgpJIGRpdmlkZWQgdGhlIG51bWVyYXRvciBieSB0aGUgZGVub21pbmF0b3IgdG8gZ2V0IHRoZSBQVkUgZm9yIGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudC4KCmBgYHtyfQojIFNjYWxlIHRoZSBkYXRhCnNjYWxlZF9kYXRhIDwtIHNjYWxlKFVTQXJyZXN0cykKCiMgUGVyZm9ybSBQQ0EKcGNhX291dCA8LSBwcmNvbXAoc2NhbGVkX2RhdGEpCgojIEV4dHJhY3QgbG9hZGluZ3MKbG9hZGluZ3MgPC0gcGNhX291dCRyb3RhdGlvbgoKIyBDYWxjdWxhdGUgc2NvcmVzIG1hbnVhbGx5CnNjb3JlcyA8LSBzY2FsZWRfZGF0YSAlKiUgbG9hZGluZ3MKCiMgQ29tcHV0ZSBudW1lcmF0b3IgYW5kIGRlbm9taW5hdG9yCm51bWVyYXRvciA8LSBjb2xTdW1zKHNjb3Jlc14yKQpkZW5vbWluYXRvciA8LSBzdW0oc2NhbGVkX2RhdGFeMikKCiMgQ2FsY3VsYXRlIFBWRQpwdmVfYiA8LSBudW1lcmF0b3IgLyBkZW5vbWluYXRvcgpwdmVfYgpgYGAKCgpUaGlzIHJlc3VsdCBtYXRjaGVzIGV4YWN0bHkgd2l0aCB0aGUgb3V0cHV0IGZyb20gcGFydCAoYSksIGNvbmZpcm1pbmcgdGhhdCBib3RoIG1ldGhvZHMgZ2l2ZSB0aGUgc2FtZSBQVkUgdmFsdWVzIHdoZW4gdGhlIGRhdGEgaXMgcHJvcGVybHkgY2VudGVyZWQgYW5kIHNjYWxlZC4KCiMgOShhKSBIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyBVc2luZyBDb21wbGV0ZSBMaW5rYWdlIGFuZCBFdWNsaWRlYW4gRGlzdGFuY2UKSSBwZXJmb3JtZWQgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb24gdGhlIFVTQXJyZXN0cyBkYXRhc2V0IHVzaW5nIGNvbXBsZXRlIGxpbmthZ2UgYW5kIEV1Y2xpZGVhbiBkaXN0YW5jZS4gSSBkaWQgbm90IHNjYWxlIHRoZSB2YXJpYWJsZXMgaW4gdGhpcyBwYXJ0LgoKYGBge3J9CiMgTG9hZCBkYXRhCmRhdGEoIlVTQXJyZXN0cyIpCgojIENvbXB1dGUgdGhlIGRpc3RhbmNlIG1hdHJpeApkaXN0X21hdHJpeCA8LSBkaXN0KFVTQXJyZXN0cykKCiMgUGVyZm9ybSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyB3aXRoIGNvbXBsZXRlIGxpbmthZ2UKaGNfY29tcGxldGUgPC0gaGNsdXN0KGRpc3RfbWF0cml4LCBtZXRob2QgPSAiY29tcGxldGUiKQoKIyBQbG90IHRoZSBkZW5kcm9ncmFtCnBsb3QoaGNfY29tcGxldGUsIG1haW4gPSAiRGVuZHJvZ3JhbSAtIENvbXBsZXRlIExpbmthZ2UgKFVuc2NhbGVkKSIpCgojIERlbmRyb2dyYW0gd2l0aCBjbGVhciBsYWJlbHMKcGxvdChoY19jb21wbGV0ZSwKICAgICBtYWluID0gIkRlbmRyb2dyYW0gLSBDb21wbGV0ZSBMaW5rYWdlIChVbnNjYWxlZCkiLAogICAgIHhsYWIgPSAiIiwgCiAgICAgc3ViID0gIiIsCiAgICAgY2V4ID0gMC42LCAgICAgICAgIyBTaHJpbmsgbGFiZWwgc2l6ZQogICAgIGxhcyA9IDIpICAgICAgICAgICMgUm90YXRlIGxhYmVscyBmb3IgYmV0dGVyIHNwYWNpbmcKYGBgCgojIChiKSBDdXQgdGhlIERlbmRyb2dyYW0gdG8gR2V0IDMgQ2x1c3RlcnMKSSBjdXQgdGhlIGRlbmRyb2dyYW0gYXQgYSBoZWlnaHQgdGhhdCBnaXZlcyB0aHJlZSBjbHVzdGVycyB1c2luZyBjdXRyZWUoKSwgYW5kIHRoZW4gbGlzdGVkIHdoaWNoIHN0YXRlcyBiZWxvbmcgdG8gZWFjaCBjbHVzdGVyLgoKYGBge3J9CiMgQ3V0IHRyZWUgaW50byAzIGNsdXN0ZXJzCmNsdXN0ZXJzX3Vuc2NhbGVkIDwtIGN1dHJlZShoY19jb21wbGV0ZSwgayA9IDMpCgojIEdyb3VwIHN0YXRlcyBieSBjbHVzdGVycwpzcGxpdChuYW1lcyhjbHVzdGVyc191bnNjYWxlZCksIGNsdXN0ZXJzX3Vuc2NhbGVkKQpgYGAKCiMgKGMpIEhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nIEFmdGVyIFNjYWxpbmcgdGhlIFZhcmlhYmxlcwpJIHJlcGVhdGVkIHRoZSBjbHVzdGVyaW5nIGFmdGVyIHNjYWxpbmcgYWxsIHZhcmlhYmxlcyB0byBoYXZlIHN0YW5kYXJkIGRldmlhdGlvbiBvbmUuCgpgYGB7cn0KIyBTY2FsZSB0aGUgdmFyaWFibGVzCnNjYWxlZF9kYXRhIDwtIHNjYWxlKFVTQXJyZXN0cykKCiMgQ29tcHV0ZSBuZXcgZGlzdGFuY2UgbWF0cml4CmRpc3Rfc2NhbGVkIDwtIGRpc3Qoc2NhbGVkX2RhdGEpCgojIFBlcmZvcm0gY2x1c3RlcmluZwpoY19zY2FsZWQgPC0gaGNsdXN0KGRpc3Rfc2NhbGVkLCBtZXRob2QgPSAiY29tcGxldGUiKQoKIyBQbG90IHRoZSBzY2FsZWQgZGVuZHJvZ3JhbQpwbG90KGhjX3NjYWxlZCwgbWFpbiA9ICJEZW5kcm9ncmFtIC0gQ29tcGxldGUgTGlua2FnZSAoU2NhbGVkKSIpCgojIERlbmRyb2dyYW0gd2l0aCBjbGVhciBsYWJlbHMKcGxvdChoY19jb21wbGV0ZSwKICAgICBtYWluID0gIkRlbmRyb2dyYW0gLSBDb21wbGV0ZSBMaW5rYWdlIChVbnNjYWxlZCkiLAogICAgIHhsYWIgPSAiIiwgCiAgICAgc3ViID0gIiIsCiAgICAgY2V4ID0gMC42LCAgICAgICAgIyBTaHJpbmsgbGFiZWwgc2l6ZQogICAgIGxhcyA9IDIpICAgICAgICAgICMgUm90YXRlIGxhYmVscyBmb3IgYmV0dGVyIHNwYWNpbmcKYGBgCgpUaGVuIEkgYWdhaW4gY3V0IHRoZSBkZW5kcm9ncmFtIGludG8gMyBjbHVzdGVyczoKCmBgYHtyfQpjbHVzdGVyc19zY2FsZWQgPC0gY3V0cmVlKGhjX3NjYWxlZCwgayA9IDMpCnNwbGl0KG5hbWVzKGNsdXN0ZXJzX3NjYWxlZCksIGNsdXN0ZXJzX3NjYWxlZCkKYGBgCgojIChkKSBFZmZlY3Qgb2YgU2NhbGluZyBhbmQgSnVzdGlmaWNhdGlvbgpTY2FsaW5nIGhhZCBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgY2x1c3RlcmluZyByZXN1bHRzLgoKQmVmb3JlIHNjYWxpbmcsIHZhcmlhYmxlcyBsaWtlICdBc3NhdWx0JyAod2hpY2ggaGFzIGEgbGFyZ2VyIHZhcmlhbmNlKSBkb21pbmF0ZWQgdGhlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucy4gQXMgYSByZXN1bHQsIHRoZSBjbHVzdGVyaW5nIHdhcyBoZWF2aWx5IGluZmx1ZW5jZWQgYnkgdGhlIHJhdyBtYWduaXR1ZGUgb2YgY2VydGFpbiBjcmltZSB0eXBlcy4KCkFmdGVyIHNjYWxpbmcsIGFsbCB2YXJpYWJsZXMgY29udHJpYnV0ZWQgZXF1YWxseSB0byB0aGUgZGlzdGFuY2UgY2FsY3VsYXRpb24uIFRoaXMgZ2F2ZSBhIG1vcmUgYmFsYW5jZWQgdmlldywgYW5kIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIGNoYW5nZWQgYWNjb3JkaW5nbHkuCgpJbiBteSBvcGluaW9uLCB0aGUgdmFyaWFibGVzIHNob3VsZCBiZSBzY2FsZWQgYmVmb3JlIGNvbXB1dGluZyBpbnRlci1vYnNlcnZhdGlvbiBkaXNzaW1pbGFyaXRpZXMsIGVzcGVjaWFsbHkgd2hlbiB0aGUgdmFyaWFibGVzIGFyZSBtZWFzdXJlZCBvbiBkaWZmZXJlbnQgc2NhbGVzIChlLmcuLCAnTXVyZGVyJyBhbmQgJ1VyYmFuUG9wJykuIFdpdGhvdXQgc2NhbGluZywgY2x1c3RlcmluZyByZWZsZWN0cyB0aGUgaW5mbHVlbmNlIG9mIGhpZ2gtdmFyaWFuY2UgdmFyaWFibGVzIHJhdGhlciB0aGFuIGFsbCBmZWF0dXJlcyBlcXVhbGx5LgoKCiMgMTAgKGEpIEdlbmVyYXRlIFNpbXVsYXRlZCBEYXRhIGZvciAzIENsYXNzZXMKQSBzaW11bGF0ZWQgZGF0YXNldCB3YXMgZ2VuZXJhdGVkIHdpdGggNjAgb2JzZXJ2YXRpb25zICgyMCBpbiBlYWNoIG9mIDMgZGlzdGluY3QgY2xhc3NlcykgYW5kIDUwIHZhcmlhYmxlcy4gQSBtZWFuIHNoaWZ0IHdhcyBhZGRlZCB0byBlYWNoIGNsYXNzIHRvIGVuc3VyZSBjbGVhciBzZXBhcmF0aW9uIGJldHdlZW4gdGhlbS4KCmBgYHtyfQpzZXQuc2VlZCgxKQoKIyBHZW5lcmF0ZSAyMCBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggY2xhc3MKeDEgPC0gbWF0cml4KHJub3JtKDIwICogNTAsIG1lYW4gPSAwKSwgbnJvdyA9IDIwKQp4MiA8LSBtYXRyaXgocm5vcm0oMjAgKiA1MCwgbWVhbiA9IDMpLCBucm93ID0gMjApCngzIDwtIG1hdHJpeChybm9ybSgyMCAqIDUwLCBtZWFuID0gNiksIG5yb3cgPSAyMCkKCiMgQ29tYmluZSBhbGwgb2JzZXJ2YXRpb25zCnggPC0gcmJpbmQoeDEsIHgyLCB4MykKCiMgQ3JlYXRlIHRydWUgY2xhc3MgbGFiZWxzCmxhYmVscyA8LSBjKHJlcCgxLCAyMCksIHJlcCgyLCAyMCksIHJlcCgzLCAyMCkpCmBgYAoKIyAoYikgUGVyZm9ybSBQQ0EgYW5kIFBsb3QgRmlyc3QgVHdvIFByaW5jaXBhbCBDb21wb25lbnRzClByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSkgd2FzIGFwcGxpZWQgdG8gdGhlIGRhdGFzZXQsIGFuZCB0aGUgZmlyc3QgdHdvIHByaW5jaXBhbCBjb21wb25lbnRzIHdlcmUgdmlzdWFsaXplZC4gRWFjaCBjbGFzcyB3YXMgcmVwcmVzZW50ZWQgdXNpbmcgYSBkaWZmZXJlbnQgY29sb3IuCgpgYGB7cn0KIyBQZXJmb3JtIFBDQQpwY2Ffb3V0IDwtIHByY29tcCh4KQoKIyBQbG90IHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudCBzY29yZSB2ZWN0b3JzCnBsb3QocGNhX291dCR4WywgMToyXSwgY29sID0gbGFiZWxzLCBwY2ggPSAxOSwKICAgICB4bGFiID0gIlBDMSIsIHlsYWIgPSAiUEMyIiwgbWFpbiA9ICJQQ0EgLSBGaXJzdCBUd28gUENzIikKYGBgCgojIEludGVycHJldGF0aW9uOgpUaGUgdGhyZWUgY2xhc3NlcyBhcHBlYXJlZCB3ZWxsLXNlcGFyYXRlZCBpbiB0aGUgUENBIHBsb3QsIGNvbmZpcm1pbmcgdGhhdCB0aGUgbWVhbiBzaGlmdHMgd2VyZSBzdWZmaWNpZW50IGZvciB2aXN1YWwgY2xhc3MgZGlzdGluY3Rpb24uCgojIChjKSBQZXJmb3JtIEstbWVhbnMgQ2x1c3RlcmluZyB3aXRoIEsgPSAzCkstbWVhbnMgY2x1c3RlcmluZyB3YXMgcGVyZm9ybWVkIHdpdGggMyBjbHVzdGVycywgYW5kIHRoZSByZXN1bHRpbmcgY2x1c3RlciBhc3NpZ25tZW50cyB3ZXJlIGNvbXBhcmVkIHRvIHRoZSB0cnVlIGxhYmVscyB1c2luZyBhIGNvbnRpbmdlbmN5IHRhYmxlLgoKYGBge3J9CnNldC5zZWVkKDEpCmttX291dCA8LSBrbWVhbnMoeCwgY2VudGVycyA9IDMsIG5zdGFydCA9IDIwKQoKIyBDb21wYXJlIGNsdXN0ZXJpbmcgd2l0aCB0cnVlIGxhYmVscwp0YWJsZShsYWJlbHMsIGttX291dCRjbHVzdGVyKQpgYGAKCiMgSW50ZXJwcmV0YXRpb246ClRoZSBjbHVzdGVyaW5nIGNsb3NlbHkgYWxpZ25lZCB3aXRoIHRoZSBhY3R1YWwgY2xhc3MgbGFiZWxzLCB3aXRoIG9ubHkgbWlub3IgZGlzY3JlcGFuY2llcyBkdWUgdG8gYXJiaXRyYXJ5IGNsdXN0ZXIgbnVtYmVyaW5nIGJ5IEstbWVhbnMuCgojIChkKSBQZXJmb3JtIEstbWVhbnMgQ2x1c3RlcmluZyB3aXRoIEsgPSAyCkstbWVhbnMgY2x1c3RlcmluZyB3YXMgcmVwZWF0ZWQgd2l0aCAyIGNsdXN0ZXJzIGluc3RlYWQgb2YgMy4KCmBgYHtyfQpzZXQuc2VlZCgxKQprbTIgPC0ga21lYW5zKHgsIGNlbnRlcnMgPSAyLCBuc3RhcnQgPSAyMCkKdGFibGUobGFiZWxzLCBrbTIkY2x1c3RlcikKYGBgCgojIEludGVycHJldGF0aW9uOgpUd28gY2x1c3RlcnMgcmVzdWx0ZWQgaW4gdGhlIG1lcmdpbmcgb2YgdHdvIGFjdHVhbCBjbGFzc2VzLCByZWR1Y2luZyBjbHVzdGVyaW5nIGFjY3VyYWN5IGFuZCB1bmRlcnJlcHJlc2VudGluZyB0aGUgZGF0YSdzIHRydWUgc3RydWN0dXJlLgoKIyAoZSkgUGVyZm9ybSBLLW1lYW5zIENsdXN0ZXJpbmcgd2l0aCBLID0gNApLLW1lYW5zIGNsdXN0ZXJpbmcgd2FzIGFsc28gcGVyZm9ybWVkIHdpdGggNCBjbHVzdGVycy4KCmBgYHtyfQpzZXQuc2VlZCgxKQprbTQgPC0ga21lYW5zKHgsIGNlbnRlcnMgPSA0LCBuc3RhcnQgPSAyMCkKdGFibGUobGFiZWxzLCBrbTQkY2x1c3RlcikKYGBgCgojIEludGVycHJldGF0aW9uOgpVc2luZyBmb3VyIGNsdXN0ZXJzIGxlZCB0byBvdmVyZml0dGluZywgYXMgb25lIG9mIHRoZSBvcmlnaW5hbCBjbGFzc2VzIHdhcyBzcGxpdCBpbnRvIHR3byBjbHVzdGVycyB1bm5lY2Vzc2FyaWx5LgoKIyAoZikgUGVyZm9ybSBLLW1lYW5zIENsdXN0ZXJpbmcgb24gRmlyc3QgVHdvIFByaW5jaXBhbCBDb21wb25lbnRzCkNsdXN0ZXJpbmcgd2FzIGFwcGxpZWQgdG8gdGhlIDJEIFBDQS1yZWR1Y2VkIGRhdGFzZXQgaW5zdGVhZCBvZiB0aGUgZnVsbCA1MC1kaW1lbnNpb25hbCBkYXRhc2V0LgoKCmBgYHtyfQpwY19kYXRhIDwtIHBjYV9vdXQkeFssIDE6Ml0KCnNldC5zZWVkKDEpCmttX3BjYSA8LSBrbWVhbnMocGNfZGF0YSwgY2VudGVycyA9IDMsIG5zdGFydCA9IDIwKQp0YWJsZShsYWJlbHMsIGttX3BjYSRjbHVzdGVyKQpgYGAKCiMgSW50ZXJwcmV0YXRpb246CkNsdXN0ZXJpbmcgb24gdGhlIGZpcnN0IHR3byBwcmluY2lwYWwgY29tcG9uZW50cyBwcmVzZXJ2ZWQgbXVjaCBvZiB0aGUgc3RydWN0dXJlIGFuZCB5aWVsZGVkIHJlc3VsdHMgc2ltaWxhciB0byB0aG9zZSBvYnRhaW5lZCBvbiB0aGUgb3JpZ2luYWwgZGF0YXNldC4KCihnKSBQZXJmb3JtIEstbWVhbnMgQ2x1c3RlcmluZyBvbiBTY2FsZWQgRGF0YQpUaGUgZGF0YXNldCB3YXMgc2NhbGVkIHVzaW5nIHNjYWxlKCksIGFuZCBLLW1lYW5zIGNsdXN0ZXJpbmcgd2FzIHBlcmZvcm1lZCBhZ2FpbiB3aXRoIDMgY2x1c3RlcnMuCgpgYGB7cn0KeF9zY2FsZWQgPC0gc2NhbGUoeCkKCnNldC5zZWVkKDEpCmttX3NjYWxlZCA8LSBrbWVhbnMoeF9zY2FsZWQsIGNlbnRlcnMgPSAzLCBuc3RhcnQgPSAyMCkKdGFibGUobGFiZWxzLCBrbV9zY2FsZWQkY2x1c3RlcikKYGBgCgojIEludGVycHJldGF0aW9uOgpTY2FsaW5nIHRoZSBkYXRhIGJlZm9yZSBjbHVzdGVyaW5nIGhlbHBlZCBzdGFuZGFyZGl6ZSB2YXJpYWJsZSBpbmZsdWVuY2UsIGFsdGhvdWdoIGluIHRoaXMgc2ltdWxhdGVkIGNhc2UgdGhlIGltcHJvdmVtZW50IHdhcyBtaW5pbWFsLiBJbiByZWFsLXdvcmxkIGRhdGFzZXRzIHdoZXJlIHZhcmlhYmxlcyBkaWZmZXIgaW4gc2NhbGUsIHNjYWxpbmcgaXMgZXNzZW50aWFsIHRvIHByZXZlbnQgZG9taW5hbmNlIGJ5IGhpZ2gtdmFyaWFuY2UgZmVhdHVyZXMuCg==