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=