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.


2. Hierarchical Clustering Analysis Using Dissimilarity Matrix

We have 4 observations: A, B, C, D (label them as 1, 2, 3, 4).

Matrix:

 1    2    3    4

1 0 0.3 0.4 0.7
2 0.3 0 0.5 0.8
3 0.4 0.5 0 0.45
4 0.7 0.8 0.45 0

(a) Complete Linkage Dendrogram

Complete linkage: distance between two clusters = maximum pairwise distance between elements in the clusters.

Step-by-step:

Closest pair: (1,2) → 0.3 → merge (1,2) Compute distances from (1,2) to other observations: (1,2)–3: max(0.4, 0.5) = 0.5 (1,2)–4: max(0.7, 0.8) = 0.8 (3,4): 0.45 → merge (3,4) at 0.45 Remaining clusters: (1,2) and (3,4) Distance between them = max(0.5, 0.7, 0.45, 0.8) = 0.8

Final merges:

Merge (1,2) at height 0.3 Merge (3,4) at height 0.45 Merge ((1,2), (3,4)) at height 0.8

Dendrogram sketch:

# Define the dissimilarity matrix
d <- matrix(c(
  0,   0.3, 0.4, 0.7,
  0.3, 0,   0.5, 0.8,
  0.4, 0.5, 0,   0.45,
  0.7, 0.8, 0.45, 0
), nrow = 4, byrow = TRUE)

# Assign names to the observations
rownames(d) <- colnames(d) <- c("1", "2", "3", "4")

# Convert to a dist object
dist_matrix <- as.dist(d)

# Perform hierarchical clustering using complete linkage
hc_complete <- hclust(dist_matrix, method = "complete")

# Plot the dendrogram
plot(hc_complete, main = "Complete Linkage Dendrogram", xlab = "", sub = "", ylab = "Height")

# Optional: flip branches to match visual layout (e.g., 3-4 on left, 1-2 on right)
# Use the `ape` package to reorder (install if not already installed)
# install.packages("ape")
library(ape)
plot(as.phylo(hc_complete), type = "cladogram", tip.order = c(3, 4, 1, 2), main = "Reordered Dendrogram")

(b) Single Linkage Dendrogram

Single linkage: distance between two clusters = minimum pairwise distance between elements in the clusters.

Step-by-step:

Closest pair: (1,2) = 0.3 → merge (1,2) (1,2)–3: min(0.4, 0.5) = 0.4 (3,4) = 0.45 → merge (1,2) and 3 at 0.4 ((1,2,3),4): min(0.7, 0.8, 0.45) = 0.45 → merge all

Final merges:

Merge (1,2) at height 0.3 Merge (1,2,3) at height 0.4 Merge (1,2,3,4) at height 0.45

# Define the dissimilarity matrix
d <- matrix(c(
  0,   0.3, 0.4, 0.7,
  0.3, 0,   0.5, 0.8,
  0.4, 0.5, 0,   0.45,
  0.7, 0.8, 0.45, 0
), nrow = 4, byrow = TRUE)

# Assign names to the observations
rownames(d) <- colnames(d) <- c("1", "2", "3", "4")

# Convert to dist object
dist_matrix <- as.dist(d)

# Perform hierarchical clustering using single linkage
hc_single <- hclust(dist_matrix, method = "single")

# Plot the dendrogram
plot(hc_single, main = "Single Linkage Dendrogram", xlab = "", sub = "", ylab = "Height")

# Optional: reorder tips to match your drawing using ape
# install.packages("ape") # if not installed
library(ape)
plot(as.phylo(hc_single), type = "cladogram", tip.order = c(1, 2, 3, 4), main = "Reordered Single Linkage")

(c) Two clusters from (a) [Complete linkage]

Cut at height just below 0.8:

Cluster 1: (1,2) Cluster 2: (3,4)

(d) Two clusters from (b) [Single linkage]

Cut at height just below 0.45:

Cluster 1: (1,2,3) Cluster 2: (4)

(e) Equivalent dendrogram to (a) with different leaf positions

We can swap subtrees or reorder leaves, e.g., place (2) before (1), or (4) before (3):

# Load required library
# install.packages("ape")  # Uncomment if not already installed
library(ape)

# Define the dissimilarity matrix
d <- matrix(c(
  0,   0.3, 0.4, 0.7,
  0.3, 0,   0.5, 0.8,
  0.4, 0.5, 0,   0.45,
  0.7, 0.8, 0.45, 0
), nrow = 4, byrow = TRUE)

# Assign names to the observations
rownames(d) <- colnames(d) <- c("1", "2", "3", "4")

# Convert to dist object
dist_matrix <- as.dist(d)

# Perform complete linkage hierarchical clustering
hc_complete <- hclust(dist_matrix, method = "complete")

# Convert to phylo object and plot with custom tip order
phylo_tree <- as.phylo(hc_complete)

# Reorder tips: 4, 3, 2, 1
tip_order <- c("4", "3", "2", "1")
plot(phylo_tree, type = "cladogram", tip.order = tip_order,
     main = "Complete Linkage (4, 3, 2, 1)", cex = 1.2)

# Optional: Add height labels manually

This code ensures:

Observations 4 and 3 are on the left side of the dendrogram. Observations 2 and 1 are on the right. Merge heights will match the complete linkage steps.

3. Manual K-Means Clustering on a Small 2D Dataset (K = 2, n = 6)

Given Data Table

Obs X1 X2 1 1 4 2 2 3 3 3 0 4 4 5 5 6 2 6 6 4

(a) Plot the observations

data <- data.frame(
  Obs = 1:6,
  X1 = c(1, 2, 3, 4, 6, 6),
  X2 = c(4, 3, 0, 5, 2, 4)
)

plot(data$X1, data$X2, pch = 19, xlab = "X1", ylab = "X2", main = "Observations")
text(data$X1, data$X2, labels = data$Obs, pos = 3)

We plotted the 6 observations on a 2D scatterplot using X1 and X2 as coordinates. Each point is labeled with its observation number for easy identification.

(b) Randomly assign a cluster label

set.seed(123)  # for reproducibility
data$Cluster <- sample(c(1, 2), size = 6, replace = TRUE)
data[, c("Obs", "Cluster")]

(c) Compute centroid for each cluster

Using the cluster labels above:

Cluster 1: Obs 1 and 4 → Points (1,4) and (4,5) Centroid = ((1+4)/2, (4+5)/2) = (2.5, 4.5) Cluster 2: Obs 2,3,5,6 → Points (2,3), (3,0), (6,2), (6,4) Centroid = ((2+3+6+6)/4, (3+0+2+4)/4) = (4.25, 2.25)

(d) Reassign Each Observation

Obs | Coordinates (X1, X2) | Distance to C1 | Distance to C2 | Assigned Cluster

1 | (1, 4) | 1.58 | 3.61 | 1 2 | (2, 3) | 1.58 | 2.42 | 1 3 | (3, 0) | 4.53 | 2.54 | 2 4 | (4, 5) | 1.58 | 2.76 | 1 5 | (6, 2) | 4.30 | 1.76 | 2 6 | (6, 4) | 3.54 | 2.49 | 2

Final Reassigned Clusters:

Cluster 1: Obs 1, 2, 4 Cluster 2: Obs 3, 5, 6

(e) Repeat (c) and (d) until convergence

You keep recalculating centroids and reassigning until the cluster labels stop changing.

Final cluster assignment (after convergence):

Obs Cluster 1 1 2 2 3 2 4 1 5 2 6 1

(f) Plot with final cluster coloring

plot(data$X1, data$X2, col = data$Cluster, pch = 19,
     xlab = "X1", ylab = "X2", main = "Final Clusters")
text(data$X1, data$X2, labels = data$Obs, pos = 3)
legend("topright", legend = c("Cluster 1", "Cluster 2"), col = 1:2, pch = 19)

Hierarchical Clustering Comparisons

(a) Fusion of {1,2,3} and {4,5}

In single linkage, the distance between two clusters is defined as the minimum distance between any pair of points (one from each cluster). In complete linkage, it’s the maximum distance between such pairs.

So, for the same two clusters {1,2,3} and {4,5}:

Single linkage fuses them at the smallest distance between any point in {1,2,3} and any point in {4,5} Complete linkage fuses them at the largest such distance

Therefore, the fusion in complete linkage will occur at a higher height than in single linkage.

Answer: The fusion occurs higher in the complete linkage dendrogram.

(b) Fusion of {5} and {6}

Since these are single-element clusters, the distance between them is simply the Euclidean distance (or whatever metric is used) between point 5 and point 6.

That value is fixed and the same for both single and complete linkage, because both use the actual pairwise distance when merging two individual points.

Answer: They will fuse at the same height in both dendrograms.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgotLS0tLS0tLS0KCiMgMi4gSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgQW5hbHlzaXMgVXNpbmcgRGlzc2ltaWxhcml0eSBNYXRyaXgKCldlIGhhdmUgNCBvYnNlcnZhdGlvbnM6IEEsIEIsIEMsIEQgKGxhYmVsIHRoZW0gYXMgMSwgMiwgMywgNCkuCgpNYXRyaXg6CgogICAgIDEgICAgMiAgICAzICAgIDQKMSAgIDAgICAwLjMgIDAuNCAgMC43ICAKMiAgMC4zICAgMCAgIDAuNSAgMC44ICAKMyAgMC40ICAwLjUgICAwICAgMC40NSAgCjQgIDAuNyAgMC44IDAuNDUgICAwCgoKIyAoYSkgQ29tcGxldGUgTGlua2FnZSBEZW5kcm9ncmFtCgpDb21wbGV0ZSBsaW5rYWdlOiBkaXN0YW5jZSBiZXR3ZWVuIHR3byBjbHVzdGVycyA9IG1heGltdW0gcGFpcndpc2UgZGlzdGFuY2UgYmV0d2VlbiBlbGVtZW50cyBpbiB0aGUgY2x1c3RlcnMuCgpTdGVwLWJ5LXN0ZXA6CgpDbG9zZXN0IHBhaXI6ICgxLDIpIOKGkiAwLjMg4oaSIG1lcmdlICgxLDIpCkNvbXB1dGUgZGlzdGFuY2VzIGZyb20gKDEsMikgdG8gb3RoZXIgb2JzZXJ2YXRpb25zOgooMSwyKeKAkzM6IG1heCgwLjQsIDAuNSkgPSAwLjUKKDEsMinigJM0OiBtYXgoMC43LCAwLjgpID0gMC44CigzLDQpOiAwLjQ1IOKGkiBtZXJnZSAoMyw0KSBhdCAwLjQ1ClJlbWFpbmluZyBjbHVzdGVyczogKDEsMikgYW5kICgzLDQpCkRpc3RhbmNlIGJldHdlZW4gdGhlbSA9IG1heCgwLjUsIDAuNywgMC40NSwgMC44KSA9IDAuOAoKRmluYWwgbWVyZ2VzOgoKTWVyZ2UgKDEsMikgYXQgaGVpZ2h0IDAuMwpNZXJnZSAoMyw0KSBhdCBoZWlnaHQgMC40NQpNZXJnZSAoKDEsMiksICgzLDQpKSBhdCBoZWlnaHQgMC44CiAKIyBEZW5kcm9ncmFtIHNrZXRjaDoKCmBgYHtyfQojIERlZmluZSB0aGUgZGlzc2ltaWxhcml0eSBtYXRyaXgKZCA8LSBtYXRyaXgoYygKICAwLCAgIDAuMywgMC40LCAwLjcsCiAgMC4zLCAwLCAgIDAuNSwgMC44LAogIDAuNCwgMC41LCAwLCAgIDAuNDUsCiAgMC43LCAwLjgsIDAuNDUsIDAKKSwgbnJvdyA9IDQsIGJ5cm93ID0gVFJVRSkKCiMgQXNzaWduIG5hbWVzIHRvIHRoZSBvYnNlcnZhdGlvbnMKcm93bmFtZXMoZCkgPC0gY29sbmFtZXMoZCkgPC0gYygiMSIsICIyIiwgIjMiLCAiNCIpCgojIENvbnZlcnQgdG8gYSBkaXN0IG9iamVjdApkaXN0X21hdHJpeCA8LSBhcy5kaXN0KGQpCgojIFBlcmZvcm0gaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgdXNpbmcgY29tcGxldGUgbGlua2FnZQpoY19jb21wbGV0ZSA8LSBoY2x1c3QoZGlzdF9tYXRyaXgsIG1ldGhvZCA9ICJjb21wbGV0ZSIpCgojIFBsb3QgdGhlIGRlbmRyb2dyYW0KcGxvdChoY19jb21wbGV0ZSwgbWFpbiA9ICJDb21wbGV0ZSBMaW5rYWdlIERlbmRyb2dyYW0iLCB4bGFiID0gIiIsIHN1YiA9ICIiLCB5bGFiID0gIkhlaWdodCIpCgojIE9wdGlvbmFsOiBmbGlwIGJyYW5jaGVzIHRvIG1hdGNoIHZpc3VhbCBsYXlvdXQgKGUuZy4sIDMtNCBvbiBsZWZ0LCAxLTIgb24gcmlnaHQpCiMgVXNlIHRoZSBgYXBlYCBwYWNrYWdlIHRvIHJlb3JkZXIgKGluc3RhbGwgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkKQojIGluc3RhbGwucGFja2FnZXMoImFwZSIpCmxpYnJhcnkoYXBlKQpwbG90KGFzLnBoeWxvKGhjX2NvbXBsZXRlKSwgdHlwZSA9ICJjbGFkb2dyYW0iLCB0aXAub3JkZXIgPSBjKDMsIDQsIDEsIDIpLCBtYWluID0gIlJlb3JkZXJlZCBEZW5kcm9ncmFtIikKYGBgCgoKIyAoYikgU2luZ2xlIExpbmthZ2UgRGVuZHJvZ3JhbQpTaW5nbGUgbGlua2FnZTogZGlzdGFuY2UgYmV0d2VlbiB0d28gY2x1c3RlcnMgPSBtaW5pbXVtIHBhaXJ3aXNlIGRpc3RhbmNlIGJldHdlZW4gZWxlbWVudHMgaW4gdGhlIGNsdXN0ZXJzLgoKU3RlcC1ieS1zdGVwOgoKQ2xvc2VzdCBwYWlyOiAoMSwyKSA9IDAuMyDihpIgbWVyZ2UgKDEsMikKKDEsMinigJMzOiBtaW4oMC40LCAwLjUpID0gMC40CigzLDQpID0gMC40NSDihpIgbWVyZ2UgKDEsMikgYW5kIDMgYXQgMC40CigoMSwyLDMpLDQpOiBtaW4oMC43LCAwLjgsIDAuNDUpID0gMC40NSDihpIgbWVyZ2UgYWxsCgpGaW5hbCBtZXJnZXM6CgpNZXJnZSAoMSwyKSBhdCBoZWlnaHQgMC4zCk1lcmdlICgxLDIsMykgYXQgaGVpZ2h0IDAuNApNZXJnZSAoMSwyLDMsNCkgYXQgaGVpZ2h0IDAuNDUKCmBgYHtyfQojIERlZmluZSB0aGUgZGlzc2ltaWxhcml0eSBtYXRyaXgKZCA8LSBtYXRyaXgoYygKICAwLCAgIDAuMywgMC40LCAwLjcsCiAgMC4zLCAwLCAgIDAuNSwgMC44LAogIDAuNCwgMC41LCAwLCAgIDAuNDUsCiAgMC43LCAwLjgsIDAuNDUsIDAKKSwgbnJvdyA9IDQsIGJ5cm93ID0gVFJVRSkKCiMgQXNzaWduIG5hbWVzIHRvIHRoZSBvYnNlcnZhdGlvbnMKcm93bmFtZXMoZCkgPC0gY29sbmFtZXMoZCkgPC0gYygiMSIsICIyIiwgIjMiLCAiNCIpCgojIENvbnZlcnQgdG8gZGlzdCBvYmplY3QKZGlzdF9tYXRyaXggPC0gYXMuZGlzdChkKQoKIyBQZXJmb3JtIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIHVzaW5nIHNpbmdsZSBsaW5rYWdlCmhjX3NpbmdsZSA8LSBoY2x1c3QoZGlzdF9tYXRyaXgsIG1ldGhvZCA9ICJzaW5nbGUiKQoKIyBQbG90IHRoZSBkZW5kcm9ncmFtCnBsb3QoaGNfc2luZ2xlLCBtYWluID0gIlNpbmdsZSBMaW5rYWdlIERlbmRyb2dyYW0iLCB4bGFiID0gIiIsIHN1YiA9ICIiLCB5bGFiID0gIkhlaWdodCIpCgojIE9wdGlvbmFsOiByZW9yZGVyIHRpcHMgdG8gbWF0Y2ggeW91ciBkcmF3aW5nIHVzaW5nIGFwZQojIGluc3RhbGwucGFja2FnZXMoImFwZSIpICMgaWYgbm90IGluc3RhbGxlZApsaWJyYXJ5KGFwZSkKcGxvdChhcy5waHlsbyhoY19zaW5nbGUpLCB0eXBlID0gImNsYWRvZ3JhbSIsIHRpcC5vcmRlciA9IGMoMSwgMiwgMywgNCksIG1haW4gPSAiUmVvcmRlcmVkIFNpbmdsZSBMaW5rYWdlIikKYGBgCgoKIyAoYykgVHdvIGNsdXN0ZXJzIGZyb20gKGEpIFtDb21wbGV0ZSBsaW5rYWdlXQpDdXQgYXQgaGVpZ2h0IGp1c3QgYmVsb3cgMC44OgoKQ2x1c3RlciAxOiAoMSwyKQpDbHVzdGVyIDI6ICgzLDQpCgojIChkKSBUd28gY2x1c3RlcnMgZnJvbSAoYikgW1NpbmdsZSBsaW5rYWdlXQpDdXQgYXQgaGVpZ2h0IGp1c3QgYmVsb3cgMC40NToKCkNsdXN0ZXIgMTogKDEsMiwzKQpDbHVzdGVyIDI6ICg0KQoKIyAoZSkgRXF1aXZhbGVudCBkZW5kcm9ncmFtIHRvIChhKSB3aXRoIGRpZmZlcmVudCBsZWFmIHBvc2l0aW9ucwpXZSBjYW4gc3dhcCBzdWJ0cmVlcyBvciByZW9yZGVyIGxlYXZlcywgZS5nLiwgcGxhY2UgKDIpIGJlZm9yZSAoMSksIG9yICg0KSBiZWZvcmUgKDMpOgoKYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJ5CiMgaW5zdGFsbC5wYWNrYWdlcygiYXBlIikgICMgVW5jb21tZW50IGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZApsaWJyYXJ5KGFwZSkKCiMgRGVmaW5lIHRoZSBkaXNzaW1pbGFyaXR5IG1hdHJpeApkIDwtIG1hdHJpeChjKAogIDAsICAgMC4zLCAwLjQsIDAuNywKICAwLjMsIDAsICAgMC41LCAwLjgsCiAgMC40LCAwLjUsIDAsICAgMC40NSwKICAwLjcsIDAuOCwgMC40NSwgMAopLCBucm93ID0gNCwgYnlyb3cgPSBUUlVFKQoKIyBBc3NpZ24gbmFtZXMgdG8gdGhlIG9ic2VydmF0aW9ucwpyb3duYW1lcyhkKSA8LSBjb2xuYW1lcyhkKSA8LSBjKCIxIiwgIjIiLCAiMyIsICI0IikKCiMgQ29udmVydCB0byBkaXN0IG9iamVjdApkaXN0X21hdHJpeCA8LSBhcy5kaXN0KGQpCgojIFBlcmZvcm0gY29tcGxldGUgbGlua2FnZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZwpoY19jb21wbGV0ZSA8LSBoY2x1c3QoZGlzdF9tYXRyaXgsIG1ldGhvZCA9ICJjb21wbGV0ZSIpCgojIENvbnZlcnQgdG8gcGh5bG8gb2JqZWN0IGFuZCBwbG90IHdpdGggY3VzdG9tIHRpcCBvcmRlcgpwaHlsb190cmVlIDwtIGFzLnBoeWxvKGhjX2NvbXBsZXRlKQoKIyBSZW9yZGVyIHRpcHM6IDQsIDMsIDIsIDEKdGlwX29yZGVyIDwtIGMoIjQiLCAiMyIsICIyIiwgIjEiKQpwbG90KHBoeWxvX3RyZWUsIHR5cGUgPSAiY2xhZG9ncmFtIiwgdGlwLm9yZGVyID0gdGlwX29yZGVyLAogICAgIG1haW4gPSAiQ29tcGxldGUgTGlua2FnZSAoNCwgMywgMiwgMSkiLCBjZXggPSAxLjIpCgojIE9wdGlvbmFsOiBBZGQgaGVpZ2h0IGxhYmVscyBtYW51YWxseQpgYGAKClRoaXMgY29kZSBlbnN1cmVzOgoKT2JzZXJ2YXRpb25zIDQgYW5kIDMgYXJlIG9uIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIGRlbmRyb2dyYW0uCk9ic2VydmF0aW9ucyAyIGFuZCAxIGFyZSBvbiB0aGUgcmlnaHQuCk1lcmdlIGhlaWdodHMgd2lsbCBtYXRjaCB0aGUgY29tcGxldGUgbGlua2FnZSBzdGVwcy4KCiMgMy4gTWFudWFsIEstTWVhbnMgQ2x1c3RlcmluZyBvbiBhIFNtYWxsIDJEIERhdGFzZXQgKEsgPSAyLCBuID0gNikKCkdpdmVuIERhdGEgVGFibGUKCk9icyAgIFgxICAgWDIKMSAgICAgMSAgICA0CjIgICAgIDIgICAgMwozICAgICAzICAgIDAKNCAgICAgNCAgICA1CjUgICAgIDYgICAgMgo2ICAgICA2ICAgIDQKCiMgKGEpIFBsb3QgdGhlIG9ic2VydmF0aW9ucwoKYGBge3J9CmRhdGEgPC0gZGF0YS5mcmFtZSgKICBPYnMgPSAxOjYsCiAgWDEgPSBjKDEsIDIsIDMsIDQsIDYsIDYpLAogIFgyID0gYyg0LCAzLCAwLCA1LCAyLCA0KQopCgpwbG90KGRhdGEkWDEsIGRhdGEkWDIsIHBjaCA9IDE5LCB4bGFiID0gIlgxIiwgeWxhYiA9ICJYMiIsIG1haW4gPSAiT2JzZXJ2YXRpb25zIikKdGV4dChkYXRhJFgxLCBkYXRhJFgyLCBsYWJlbHMgPSBkYXRhJE9icywgcG9zID0gMykKYGBgCgpXZSBwbG90dGVkIHRoZSA2IG9ic2VydmF0aW9ucyBvbiBhIDJEIHNjYXR0ZXJwbG90IHVzaW5nIFgxIGFuZCBYMiBhcyBjb29yZGluYXRlcy4gRWFjaCBwb2ludCBpcyBsYWJlbGVkIHdpdGggaXRzIG9ic2VydmF0aW9uIG51bWJlciBmb3IgZWFzeSBpZGVudGlmaWNhdGlvbi4KCiMgKGIpIFJhbmRvbWx5IGFzc2lnbiBhIGNsdXN0ZXIgbGFiZWwKCmBgYHtyfQpzZXQuc2VlZCgxMjMpICAjIGZvciByZXByb2R1Y2liaWxpdHkKZGF0YSRDbHVzdGVyIDwtIHNhbXBsZShjKDEsIDIpLCBzaXplID0gNiwgcmVwbGFjZSA9IFRSVUUpCmRhdGFbLCBjKCJPYnMiLCAiQ2x1c3RlciIpXQpgYGAKCiMgKGMpIENvbXB1dGUgY2VudHJvaWQgZm9yIGVhY2ggY2x1c3RlcgpVc2luZyB0aGUgY2x1c3RlciBsYWJlbHMgYWJvdmU6CgpDbHVzdGVyIDE6IE9icyAxIGFuZCA0IOKGkiBQb2ludHMgKDEsNCkgYW5kICg0LDUpCkNlbnRyb2lkID0gKCgxKzQpLzIsICg0KzUpLzIpID0gKDIuNSwgNC41KQpDbHVzdGVyIDI6IE9icyAyLDMsNSw2IOKGkiBQb2ludHMgKDIsMyksICgzLDApLCAoNiwyKSwgKDYsNCkKQ2VudHJvaWQgPSAoKDIrMys2KzYpLzQsICgzKzArMis0KS80KSA9ICg0LjI1LCAyLjI1KQoKIyAoZCkgUmVhc3NpZ24gRWFjaCBPYnNlcnZhdGlvbgoKT2JzIHwgQ29vcmRpbmF0ZXMgKFgxLCBYMikgfCBEaXN0YW5jZSB0byBDMSB8IERpc3RhbmNlIHRvIEMyIHwgQXNzaWduZWQgQ2x1c3RlcgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAxICB8ICAgICAgICgxLCA0KSAgICAgICAgIHwgICAgIDEuNTggICAgICAgfCAgICAgMy42MSAgICAgICB8ICAgICAgICAxCiAyICB8ICAgICAgICgyLCAzKSAgICAgICAgIHwgICAgIDEuNTggICAgICAgfCAgICAgMi40MiAgICAgICB8ICAgICAgICAxCiAzICB8ICAgICAgICgzLCAwKSAgICAgICAgIHwgICAgIDQuNTMgICAgICAgfCAgICAgMi41NCAgICAgICB8ICAgICAgICAyCiA0ICB8ICAgICAgICg0LCA1KSAgICAgICAgIHwgICAgIDEuNTggICAgICAgfCAgICAgMi43NiAgICAgICB8ICAgICAgICAxCiA1ICB8ICAgICAgICg2LCAyKSAgICAgICAgIHwgICAgIDQuMzAgICAgICAgfCAgICAgMS43NiAgICAgICB8ICAgICAgICAyCiA2ICB8ICAgICAgICg2LCA0KSAgICAgICAgIHwgICAgIDMuNTQgICAgICAgfCAgICAgMi40OSAgICAgICB8ICAgICAgICAyCiAKCkZpbmFsIFJlYXNzaWduZWQgQ2x1c3RlcnM6CgpDbHVzdGVyIDE6IE9icyAxLCAyLCA0CkNsdXN0ZXIgMjogT2JzIDMsIDUsIDYKCiMgKGUpIFJlcGVhdCAoYykgYW5kIChkKSB1bnRpbCBjb252ZXJnZW5jZQpZb3Uga2VlcCByZWNhbGN1bGF0aW5nIGNlbnRyb2lkcyBhbmQgcmVhc3NpZ25pbmcgdW50aWwgdGhlIGNsdXN0ZXIgbGFiZWxzIHN0b3AgY2hhbmdpbmcuCgpGaW5hbCBjbHVzdGVyIGFzc2lnbm1lbnQgKGFmdGVyIGNvbnZlcmdlbmNlKToKCk9icyBDbHVzdGVyCjEgICAgIDEKMiAgICAgMgozICAgICAyCjQgICAgIDEKNSAgICAgMgo2ICAgICAxCgojIChmKSBQbG90IHdpdGggZmluYWwgY2x1c3RlciBjb2xvcmluZwoKYGBge3J9CnBsb3QoZGF0YSRYMSwgZGF0YSRYMiwgY29sID0gZGF0YSRDbHVzdGVyLCBwY2ggPSAxOSwKICAgICB4bGFiID0gIlgxIiwgeWxhYiA9ICJYMiIsIG1haW4gPSAiRmluYWwgQ2x1c3RlcnMiKQp0ZXh0KGRhdGEkWDEsIGRhdGEkWDIsIGxhYmVscyA9IGRhdGEkT2JzLCBwb3MgPSAzKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiQ2x1c3RlciAxIiwgIkNsdXN0ZXIgMiIpLCBjb2wgPSAxOjIsIHBjaCA9IDE5KQpgYGAKCiMgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgQ29tcGFyaXNvbnMKCiMgKGEpIEZ1c2lvbiBvZiB7MSwyLDN9IGFuZCB7NCw1fQpJbiBzaW5nbGUgbGlua2FnZSwgdGhlIGRpc3RhbmNlIGJldHdlZW4gdHdvIGNsdXN0ZXJzIGlzIGRlZmluZWQgYXMgdGhlIG1pbmltdW0gZGlzdGFuY2UgYmV0d2VlbiBhbnkgcGFpciBvZiBwb2ludHMgKG9uZSBmcm9tIGVhY2ggY2x1c3RlcikuCkluIGNvbXBsZXRlIGxpbmthZ2UsIGl0J3MgdGhlIG1heGltdW0gZGlzdGFuY2UgYmV0d2VlbiBzdWNoIHBhaXJzLgoKU28sIGZvciB0aGUgc2FtZSB0d28gY2x1c3RlcnMgezEsMiwzfSBhbmQgezQsNX06CgpTaW5nbGUgbGlua2FnZSBmdXNlcyB0aGVtIGF0IHRoZSBzbWFsbGVzdCBkaXN0YW5jZSBiZXR3ZWVuIGFueSBwb2ludCBpbiB7MSwyLDN9IGFuZCBhbnkgcG9pbnQgaW4gezQsNX0KQ29tcGxldGUgbGlua2FnZSBmdXNlcyB0aGVtIGF0IHRoZSBsYXJnZXN0IHN1Y2ggZGlzdGFuY2UKCiBUaGVyZWZvcmUsIHRoZSBmdXNpb24gaW4gY29tcGxldGUgbGlua2FnZSB3aWxsIG9jY3VyIGF0IGEgaGlnaGVyIGhlaWdodCB0aGFuIGluIHNpbmdsZSBsaW5rYWdlLgoKQW5zd2VyOiBUaGUgZnVzaW9uIG9jY3VycyBoaWdoZXIgaW4gdGhlIGNvbXBsZXRlIGxpbmthZ2UgZGVuZHJvZ3JhbS4KCiMgKGIpIEZ1c2lvbiBvZiB7NX0gYW5kIHs2fQoKU2luY2UgdGhlc2UgYXJlIHNpbmdsZS1lbGVtZW50IGNsdXN0ZXJzLCB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGVtIGlzIHNpbXBseSB0aGUgRXVjbGlkZWFuIGRpc3RhbmNlIChvciB3aGF0ZXZlciBtZXRyaWMgaXMgdXNlZCkgYmV0d2VlbiBwb2ludCA1IGFuZCBwb2ludCA2LgoKVGhhdCB2YWx1ZSBpcyBmaXhlZCBhbmQgdGhlIHNhbWUgZm9yIGJvdGggc2luZ2xlIGFuZCBjb21wbGV0ZSBsaW5rYWdlLCBiZWNhdXNlIGJvdGggdXNlIHRoZSBhY3R1YWwgcGFpcndpc2UgZGlzdGFuY2Ugd2hlbiBtZXJnaW5nIHR3byBpbmRpdmlkdWFsIHBvaW50cy4KCkFuc3dlcjogVGhleSB3aWxsIGZ1c2UgYXQgdGhlIHNhbWUgaGVpZ2h0IGluIGJvdGggZGVuZHJvZ3JhbXMuCgo=