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))

(b) Perform PCA and Plot First Two Principal Components

Principal component analysis (PCA) was applied to the dataset, and the first two principal components were visualized. Each class was represented using a different color.

# Perform PCA
pca_out <- prcomp(x)

# Plot the first two principal component score vectors
plot(pca_out$x[, 1:2], col = labels, pch = 19,
     xlab = "PC1", ylab = "PC2", main = "PCA - First Two PCs")

Interpretation:

The three classes appeared well-separated in the PCA plot, confirming that the mean shifts were sufficient for visual class distinction.

(c) Perform K-means Clustering with K = 3

K-means clustering was performed with 3 clusters, and the resulting cluster assignments were compared to the true labels using a contingency table.

set.seed(1)
km_out <- kmeans(x, centers = 3, nstart = 20)

# Compare clustering with true labels
table(labels, km_out$cluster)
      
labels  1  2  3
     1  0  0 20
     2  0 20  0
     3 20  0  0

Interpretation:

The clustering closely aligned with the actual class labels, with only minor discrepancies due to arbitrary cluster numbering by K-means.

(d) Perform K-means Clustering with K = 2

K-means clustering was repeated with 2 clusters instead of 3.

set.seed(1)
km2 <- kmeans(x, centers = 2, nstart = 20)
table(labels, km2$cluster)
      
labels  1  2
     1  0 20
     2  0 20
     3 20  0

Interpretation:

Two clusters resulted in the merging of two actual classes, reducing clustering accuracy and underrepresenting the data’s true structure.

(e) Perform K-means Clustering with K = 4

K-means clustering was also performed with 4 clusters.

set.seed(1)
km4 <- kmeans(x, centers = 4, nstart = 20)
table(labels, km4$cluster)
      
labels  1  2  3  4
     1  0 11  0  9
     2  0  0 20  0
     3 20  0  0  0

Interpretation:

Using four clusters led to overfitting, as one of the original classes was split into two clusters unnecessarily.

(f) Perform K-means Clustering on First Two Principal Components

Clustering was applied to the 2D PCA-reduced dataset instead of the full 50-dimensional dataset.

pc_data <- pca_out$x[, 1:2]

set.seed(1)
km_pca <- kmeans(pc_data, centers = 3, nstart = 20)
table(labels, km_pca$cluster)
      
labels  1  2  3
     1  0 20  0
     2  0  0 20
     3 20  0  0

Interpretation:

Clustering on the first two principal components preserved much of the structure and yielded results similar to those obtained on the original dataset.

  1. 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==