1 Unsupervised learning in R

1.1 Introduction

1.1.1 Identify clustering problems

Example of clustering problems:

  • Determining the natural groupings of houses for sale based on size, number of bedrooms, etc.
  • Determining if there are common patterns in the demographics of people at a commerce site

1.2 Introduction to k-means clustering

1.2.1 k-means clustering

We have created some two-dimensional data and stored it in a variable called x.

plot(x)

Our task is to create a k-means model of the x data using 3 clusters, then to look at the structure of the resulting model using the summary() function.

# Create the k-means model: km.out
km.out <- kmeans(x, centers = 3, nstart = 20 )

# Inspect the result
summary(km.out)
             Length Class  Mode   
cluster      300    -none- numeric
centers        6    -none- numeric
totss          1    -none- numeric
withinss       3    -none- numeric
tot.withinss   1    -none- numeric
betweenss      1    -none- numeric
size           3    -none- numeric
iter           1    -none- numeric
ifault         1    -none- numeric

1.2.2 Results of kmeans()

The kmeans() function produces several outputs.

We will access the cluster component directly. This is useful anytime we need the cluster membership for each observation of the data used to build the clustering model.

k-means models also have a print method to give a human friendly output of basic modeling results. This is available by using print() or simply typing the name of the model.

# Print the cluster membership component of the model
km.out$cluster
  [1] 3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 3 3 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
 [35] 3 3 2 2 2 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3
 [69] 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1
[103] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[137] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[171] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[205] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[239] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[273] 2 2 2 3 3 2 2 3 2 2 2 2 2 2 3 2 2 2 2 2 2 3 2 2 2 3 2 2
# Print the km.out object
print(km.out)
K-means clustering with 3 clusters of sizes 150, 52, 98

Cluster means:
        [,1]        [,2]
1 -5.0556758  1.96991743
2  0.6642455 -0.09132968
3  2.2171113  2.05110690

Clustering vector:
  [1] 3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 3 3 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
 [35] 3 3 2 2 2 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3
 [69] 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1
[103] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[137] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[171] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[205] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[239] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[273] 2 2 2 3 3 2 2 3 2 2 2 2 2 2 3 2 2 2 2 2 2 3 2 2 2 3 2 2

Within cluster sum of squares by cluster:
[1] 295.16925  95.50625 148.64781
 (between_SS / total_SS =  87.2 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"    
[5] "tot.withinss" "betweenss"    "size"         "iter"        
[9] "ifault"      

Because printing the whole model object to the console outputs many different things, we may wish to instead print a specific component of the model object using the $ operator.

1.2.3 Visualizing and interpreting results of kmeans()

One of the more intuitive ways to interpret the results of k-means models is by plotting the data as a scatter plot and using color to label the samples’ cluster membership. We will use the standard plot() function to accomplish this.

To create a scatter plot, we can pass data with two features (i.e. columns) to plot() with an extra argument col = km.out$cluster, which sets the color of each point in the scatter plot according to its cluster membership.

# Scatter plot of x
plot(x, col = km.out$cluster, main = "k-means with 3 clusters",
xlab = "", ylab = "" )

1.3 How k-means works and practical matters

1.3.1 Handling random algorithms

We saw how kmeans() randomly initializes the centers of clusters. This random initialization can result in assigning observations to different cluster labels. Also, the random initialization can result in finding different local minima for the k-means algorithm. This example will demonstrate both results.

At the top of each plot, the measure of model quality—total within cluster sum of squares error—will be plotted. Look for the model(s) with the lowest error to find models with the better model results.

Because kmeans() initializes observations to random clusters, it is important to set the random number generator seed for reproducibility.

# Set up 2 x 3 plotting grid
par(mfrow = c(2, 3))

# Set seed
set.seed(1)

for(i in 1:6) {
  # Run kmeans() on x with three clusters and one start
  km.out <- kmeans(x, centers = 3, nstart = 1)
  
  # Plot clusters
  plot(x, col = km.out$cluster, 
       main = km.out$tot.withinss, 
       xlab = "", ylab = "")
}

Because of the random initialization of the k-means algorithm, there’s quite some variation in cluster assignments among the six models.

1.3.2 Selecting number of clusters

The k-means algorithm assumes the number of clusters as part of the input. If we know the number of clusters in advance (e.g. due to certain business constraints) this makes setting the number of clusters easy. However, if we do not know the number of clusters and need to determine it, we will need to run the algorithm multiple times, each time with a different number of clusters. From this, we can observe how a measure of model quality changes with the number of clusters.

We will run kmeans() multiple times to see how model quality changes as the number of clusters changes. Plots displaying this information help to determine the number of clusters and are often referred to as scree plots.

The ideal plot will have an elbow where the quality measure improves more slowly as the number of clusters increases. This indicates that the quality of the model is no longer improving substantially as the model complexity (i.e. number of clusters) increases. In other words, the elbow indicates the number of clusters inherent in the data.

# Initialize total within sum of squares error: wss
wss <- 0

# For 1 to 15 cluster centers
for (i in 1:15) {
  km.out <- kmeans(x, centers = i, nstart = 20)
  # Save total within sum of squares to wss variable
  wss[i] <- km.out$tot.withinss
}

# Plot total within sum of squares vs. number of clusters
plot(1:15, wss, type = "b", 
     xlab = "Number of Clusters", 
     ylab = "Within groups sum of squares")


# Set k equal to the number of clusters corresponding to the elbow location
k <- 2

Looking at the scree plot, it looks like there are inherently 2 or 3 clusters in the data.

1.4 Introduction to the Pokemon data

1.4.1 Practical matters: working with real data

Dealing with real data is often more challenging than dealing with synthetic data. Synthetic data helps with learning new concepts and techniques, but we will deal with data that is closer to the type of real data you might find in your professional or academic pursuits.

The first challenge with the Pokemon data is that there is no pre-determined number of clusters. We will determine the appropriate number of clusters, keeping in mind that in real data the elbow in the scree plot might be less of a sharp elbow than in synthetic data. Use your judgement on making the determination of the number of clusters.

This example includes plotting the outcomes of the clustering on two dimensions, or features, of the data. These features were chosen somewhat arbitrarily for this exercise. Think about how you would use plotting and clustering to communicate interesting groups of Pokemon to other people.

An additional note: this example utilizes the iter.max argument to kmeans(). As we’ve seen, kmeans() is an iterative algorithm, repeating over and over until some stopping criterion is reached. The default number of iterations for kmeans() is 10, which is not enough for the algorithm to converge and reach its stopping criterion, so we’ll set the number of iterations to 50 to overcome this issue. To see what happens when kmeans() does not converge, try running the example with a lower number of iterations (e.g. 3). This is another example of what might happen when we encounter real data and use real cases.

library(readr)
pokemon <- read_csv("Pokemon.csv") %>% 
  select(HitPoints, Attack, Defense, SpecialAttack, SpecialDefense, Speed)
Parsed with column specification:
cols(
  Number = col_double(),
  Name = col_character(),
  Type1 = col_character(),
  Type2 = col_character(),
  Total = col_double(),
  HitPoints = col_double(),
  Attack = col_double(),
  Defense = col_double(),
  SpecialAttack = col_double(),
  SpecialDefense = col_double(),
  Speed = col_double(),
  Generation = col_double(),
  Legendary = col_logical()
)
# Initialize total within sum of squares error: wss
wss <- 0

# Look over 1 to 15 possible clusters
for (i in 1:15) {
  # Fit the model: km.out
  km.out <- kmeans(pokemon, centers = i, nstart = 20, iter.max = 50)
  # Save the within cluster sum of squares
  wss[i] <- km.out$tot.withinss
}

# Produce a scree plot
plot(1:15, wss, type = "b", 
     xlab = "Number of Clusters", 
     ylab = "Within groups sum of squares")

# Select number of clusters
k <- 2

# Build model with k clusters: km.out
km.out <- kmeans(pokemon, centers = k, nstart = 20, iter.max = 50)

# View the resulting model
km.out
K-means clustering with 2 clusters of sizes 374, 426

Cluster means:
  HitPoints   Attack  Defense SpecialAttack SpecialDefense    Speed
1  54.87968 57.94118 55.49733      52.33155       53.44118 54.04278
2  81.88263 97.49061 89.94836      90.80751       88.11033 80.77465

Clustering vector:
  [1] 1 1 2 2 1 1 2 2 2 1 1 2 2 1 1 1 1 1 1 2 1 1 2 2 1 1 1 2 1 2 1 2 1 2
 [35] 1 1 2 1 1 2 1 2 1 2 1 1 1 2 1 1 2 1 1 1 2 1 1 1 1 1 2 1 2 1 2 1 1 2
 [69] 1 1 2 2 1 1 2 1 1 2 1 2 1 1 2 1 2 1 2 2 1 2 1 1 2 1 2 1 2 1 2 1 1 2
[103] 2 1 1 2 1 2 1 2 1 2 1 2 2 2 1 1 2 1 2 1 2 2 2 1 2 1 2 1 2 2 2 2 2 2
[137] 2 2 2 1 2 2 2 1 1 2 2 2 1 1 2 1 2 2 2 2 2 2 2 1 1 2 2 2 2 2 1 1 2 1
[171] 1 2 1 1 2 1 1 1 2 1 1 1 1 2 1 2 1 1 1 1 1 1 2 1 1 2 2 2 1 1 1 2 1 1
[205] 2 1 1 2 1 1 2 2 2 1 2 2 1 1 2 1 2 1 1 2 2 1 2 1 2 2 2 2 2 1 1 2 1 1
[239] 1 2 1 1 2 1 2 2 1 2 2 2 1 2 2 2 1 1 2 1 1 1 2 2 2 2 2 1 1 2 2 2 2 2
[273] 1 1 2 2 1 1 2 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 1 2 1 1 2
[307] 2 1 1 1 2 1 2 2 1 2 1 1 1 2 1 2 1 1 1 1 1 2 1 2 1 2 2 2 1 1 2 1 2 2
[341] 1 1 1 1 1 1 2 1 2 2 1 2 1 2 2 2 1 2 1 1 1 2 1 2 1 2 2 2 2 2 2 1 2 1
[375] 2 1 2 1 2 1 2 1 2 1 2 1 2 2 1 2 2 1 2 2 1 1 2 2 1 1 2 1 2 2 2 1 1 1
[409] 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 1 1 2 1 1 2 1
[443] 1 2 1 1 1 1 1 1 2 1 2 1 2 1 2 1 2 2 2 2 1 2 1 1 2 1 2 1 2 2 1 2 1 2
[477] 2 2 2 1 2 1 1 2 1 2 1 1 1 1 2 1 1 2 2 1 1 2 2 1 2 1 2 1 2 2 1 2 1 1
[511] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[545] 2 2 2 2 2 2 2 2 2 2 1 1 2 1 1 2 1 1 2 1 1 1 1 2 1 2 1 2 1 2 1 2 1 2
[579] 1 1 2 1 2 1 1 2 1 1 1 2 2 2 1 1 2 1 1 2 2 2 1 1 2 1 1 2 1 2 1 2 2 1
[613] 1 2 1 2 2 2 1 2 1 2 2 1 2 1 2 1 2 1 2 1 2 1 2 1 1 2 1 1 2 1 2 1 1 2
[647] 1 2 1 1 2 1 2 1 2 2 1 2 1 2 1 2 2 1 1 2 1 2 1 1 2 1 1 2 1 2 2 1 2 2
[681] 1 2 2 1 2 1 2 2 1 2 1 2 2 2 1 1 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[715] 2 2 2 2 1 1 2 1 1 2 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 2 1 2 1 2 2 1 2 2
[749] 1 2 2 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 2 2 1 2 1 2 2 2 1 2 1 1
[783] 1 1 2 2 2 2 1 2 1 2 2 2 2 2 2 2 2 2

Within cluster sum of squares by cluster:
[1]  911966.2 2007145.9
 (between_SS / total_SS =  31.9 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"    
[5] "tot.withinss" "betweenss"    "size"         "iter"        
[9] "ifault"      
# Plot of Defense vs. Speed by cluster membership
plot(pokemon[, c("Defense", "Speed")],
     col = km.out$cluster,
     main = paste("k-means clustering of Pokemon with", k, "clusters"),
     xlab = "Defense", ylab = "Speed")

# Select number of clusters
k <- 3

# Build model with k clusters: km.out
km.out <- kmeans(pokemon, centers = k, nstart = 20, iter.max = 50)
km.pokemon <- km.out
# View the resulting model
km.out
K-means clustering with 3 clusters of sizes 175, 270, 355

Cluster means:
  HitPoints   Attack   Defense SpecialAttack SpecialDefense    Speed
1  79.30857 97.29714 108.93143      66.71429       87.04571 57.29143
2  81.90370 96.15926  77.65556     104.12222       86.87778 94.71111
3  54.68732 56.93239  53.64507      52.02254       53.04789 53.58873

Clustering vector:
  [1] 3 3 2 2 3 3 2 2 2 3 3 1 2 3 3 3 3 3 3 2 3 3 2 2 3 3 3 2 3 2 3 2 3 1
 [35] 3 3 1 3 3 2 3 2 3 2 3 3 3 2 3 3 2 3 1 3 2 3 3 3 2 3 2 3 2 3 2 3 3 1
 [69] 3 2 2 2 3 1 1 3 3 2 3 2 3 1 1 3 2 3 1 1 3 2 3 3 2 3 1 3 1 3 1 3 2 2
[103] 2 1 3 1 3 1 3 2 3 2 3 1 1 1 3 3 1 3 1 3 1 1 1 3 2 3 1 3 2 2 2 2 2 2
[137] 1 1 1 3 1 1 1 3 3 2 2 2 3 3 1 3 1 2 2 1 2 2 2 3 3 2 2 2 2 2 3 3 1 3
[171] 3 2 3 3 1 3 3 3 2 3 3 3 3 2 3 2 3 3 3 3 3 3 2 3 3 2 2 1 3 3 1 2 3 3
[205] 2 3 3 3 3 3 1 2 1 3 1 2 3 3 2 3 1 3 1 1 1 3 1 3 1 1 1 1 1 3 3 1 3 1
[239] 3 1 3 3 2 3 2 1 3 2 2 2 3 1 2 2 3 3 1 3 3 3 1 2 2 2 1 3 3 1 1 2 2 2
[273] 3 3 2 2 3 3 2 2 3 3 1 1 3 3 3 3 3 3 3 3 3 3 3 2 3 3 2 3 3 3 1 3 3 2
[307] 2 3 3 3 1 3 3 2 3 2 3 3 3 2 3 1 3 1 3 3 3 1 3 1 3 1 1 1 3 3 2 3 2 2
[341] 3 3 3 3 3 3 1 3 2 2 3 2 3 2 1 1 3 2 3 3 3 2 3 2 3 1 2 2 2 2 1 3 1 3
[375] 1 3 1 3 1 3 1 3 2 3 1 3 2 2 3 1 1 3 2 2 3 3 2 2 3 3 2 3 1 1 1 3 3 1
[409] 2 2 3 1 1 2 1 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 3 1 1 3 3 2 3 3 2 3
[443] 3 2 3 3 3 3 3 3 2 3 2 3 1 3 1 3 1 1 1 2 3 1 3 3 2 3 2 3 1 2 3 2 3 2
[477] 2 2 2 3 2 3 3 2 3 1 3 3 3 3 1 3 3 2 2 3 3 2 2 3 1 3 1 3 2 1 3 2 3 3
[511] 2 1 2 2 1 1 1 2 2 2 2 1 2 1 2 2 2 2 1 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2
[545] 2 2 1 2 2 2 2 2 2 2 3 3 2 3 3 2 3 3 2 3 3 3 3 1 3 2 3 2 3 2 3 2 3 1
[579] 3 3 2 3 2 3 1 1 3 2 3 2 1 1 3 1 1 3 3 2 1 1 3 3 2 3 3 2 3 2 3 2 2 3
[613] 3 2 3 1 2 2 3 1 3 1 2 3 1 3 1 3 2 3 1 3 2 3 2 3 3 1 3 3 2 3 2 3 3 2
[647] 3 2 2 3 1 3 1 3 2 1 3 2 3 1 3 1 1 3 3 2 3 2 3 3 2 3 1 1 3 1 2 3 2 1
[681] 3 2 1 3 1 3 1 1 3 1 3 1 2 1 3 3 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[715] 2 2 2 2 3 1 1 3 3 2 3 3 2 3 3 3 3 2 3 3 3 3 2 3 3 2 3 2 3 1 2 3 2 2
[749] 3 1 2 1 3 1 3 2 3 1 3 1 3 1 3 2 3 2 3 1 3 2 2 2 2 1 3 2 2 1 3 1 3 3
[783] 3 3 1 1 1 1 3 1 3 2 2 2 1 1 2 2 2 2

Within cluster sum of squares by cluster:
[1]  709020.5 1018348.0  812079.9
 (between_SS / total_SS =  40.8 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"    
[5] "tot.withinss" "betweenss"    "size"         "iter"        
[9] "ifault"      
# Plot of Defense vs. Speed by cluster membership
plot(pokemon[, c("Defense", "Speed")],
     col = km.out$cluster,
     main = paste("k-means clustering of Pokemon with", k, "clusters"),
     xlab = "Defense", ylab = "Speed")

2 Hierarchical clustering

2.1 Introduction

2.1.1 Hierarchical clustering with results

We will create your first hierarchical clustering model using the hclust() function.

We will create a hierarchical clustering model of x. The first step to hierarchical clustering is determining the similarity between observations, which you will do with the dist() function.

# Create hierarchical clustering model: hclust.out
hclust.out <- hclust(dist(x))

# Inspect the result
summary(hclust.out)
            Length Class  Mode     
merge       598    -none- numeric  
height      299    -none- numeric  
order       300    -none- numeric  
labels        0    -none- NULL     
method        1    -none- character
call          2    -none- call     
dist.method   1    -none- character

Now that we’ve made your first hierarchical clustering model, let’s learn how to use it to solve problems.

2.2 Selecting number of clusters

plot(hclust.out)
abline(h = c(3.5,4.5, 6.9, 9.0), col = "red")

If we cut the tree at a height of 6.9, we’re left with 3 branches representing 3 distinct clusters.

2.2.1 Cutting the tree

cutree() is the R function that cuts a hierarchical model. The h and k arguments to cutree() allow you to cut the tree based on a certain height h or a certain number of clusters k.

# Cut by height
cutree(hclust.out, h = 7)
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 2 2 1 1 2 1 1 1 2 1 2 1 2 1 1 1 2
 [35] 1 2 2 2 2 1 1 1 1 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 2 1 2 1 1 1 2 1 1 1
 [69] 1 1 1 1 1 2 1 1 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 2 1 1 2 1 2 2 1 1 3 3
[103] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[137] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[171] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[205] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[239] 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 2 2 2 2 2 1 1 2 2 2 2 1 2 2 2 2 2
[273] 2 2 2 1 2 2 1 1 1 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 1 2 2
# Cut by number of clusters
cutree(hclust.out, k = 3)
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 2 2 1 1 2 1 1 1 2 1 2 1 2 1 1 1 2
 [35] 1 2 2 2 2 1 1 1 1 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 2 1 2 1 1 1 2 1 1 1
 [69] 1 1 1 1 1 2 1 1 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 2 1 1 2 1 2 2 1 1 3 3
[103] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[137] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[171] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[205] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[239] 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 2 2 2 2 2 1 1 2 2 2 2 1 2 2 2 2 2
[273] 2 2 2 1 2 2 1 1 1 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 1 2 2

The output of each cutree() call represents the cluster assignments for each observation in the original dataset.

2.3 Clustering linkage and practical matters

2.3.1 Linkage methods

We will produce hierarchical clustering models using different linkages and plot the dendrogram for each, observing the overall structure of the trees.

# Cluster using complete linkage: hclust.complete
hclust.complete <- hclust(dist(x), method = "complete")

# Cluster using average linkage: hclust.average
hclust.average <- hclust(dist(x), method = "average")

# Cluster using single linkage: hclust.single
hclust.single <- hclust(dist(x), method = "single")

# Plot dendrogram of hclust.complete
plot(hclust.complete, main = "Complete")


# Plot dendrogram of hclust.average
plot(hclust.average, main = "Average")


# Plot dendrogram of hclust.single
plot(hclust.single, main = "Single")

Whether we want balanced or unbalanced trees for our hierarchical clustering model depends on the context of the problem we’re trying to solve. Balanced trees are essential if we want an even number of observations assigned to each cluster. On the other hand, if we want to detect outliers, for example, an unbalanced tree is more desirable because pruning an unbalanced tree can result in most observations assigned to one cluster and only a few observations assigned to other clusters.

2.3.2 Practical matters: scaling

Clustering real data may require scaling the features if they have different distributions.

We will go back to working with “real” data, the pokemon dataset introduced in the first chapter. We will observe the distribution (mean and standard deviation) of each feature, scale the data accordingly, then produce a hierarchical clustering model using the complete linkage method.

# View column means
colMeans(pokemon)
     HitPoints         Attack        Defense  SpecialAttack 
      69.25875       79.00125       73.84250       72.82000 
SpecialDefense          Speed 
      71.90250       68.27750 
# View column standard deviations
apply(pokemon, 2, sd)
     HitPoints         Attack        Defense  SpecialAttack 
      25.53467       32.45737       31.18350       32.72229 
SpecialDefense          Speed 
      27.82892       29.06047 
# Scale the data
pokemon.scaled = scale(pokemon)

# Create hierarchical clustering model: hclust.pokemon
hclust.pokemon = hclust(dist(pokemon.scaled), method = "complete")

We first checked to see if the column means and standard deviations vary. Because they do, we scaled the data, converted the scaled data to a similarity matrix and passed it into the hclust() function.

2.3.3 Comparing kmeans() and hclust()

Comparing k-means and hierarchical clustering, we’ll see the two methods produce different cluster memberships. This is because the two algorithms make different assumptions about how the data is generated.

# Apply cutree() to hclust.pokemon: cut.pokemon
cut.pokemon <- cutree(hclust.pokemon, k = 3)

# Compare methods
table(km.pokemon$cluster, cut.pokemon)
   cut.pokemon
      1   2   3
  1 171   3   1
  2 267   3   0
  3 350   5   0

Looking at the table, it looks like the hierarchical clustering model assigns most of the observations to cluster 1, while the k-means algorithm distributes the observations relatively evenly among all clusters. It’s important to note that there’s no consensus on which method produces better clusters. The job of the analyst in unsupervised clustering is to observe the cluster assignments and make a judgment call as to which method provides more insights into the data.

3 Dimensionality reduction with PCA

3.1 Introduction

3.1.1 PCA using prcomp()

We will create a s principal component analysis (PCA) model and observe the diagnostic results.

pokemon_pca is a 4 dimensions version of our pokemon dataset.

head(pokemon_pca)
           HitPoints Attack Defense Speed
Quilava           58     64      58    80
Goodra            90    100      70    80
Mothim            70     94      50    66
Marowak           60     80     110    45
Chandelure        60     55      90    80
Helioptile        44     38      33    70
# Perform scaled PCA: pr.out
pr.out <- prcomp(x = pokemon_pca,
scale = TRUE)

# Inspect model output
summary(pr.out)
Importance of components:
                          PC1    PC2    PC3     PC4
Standard deviation     1.4420 1.0013 0.7941 0.53595
Proportion of Variance 0.5199 0.2507 0.1577 0.07181
Cumulative Proportion  0.5199 0.7705 0.9282 1.00000

What is the minimum number of principal components that are required to describe at least 75% of the cumulative variance in this dataset? 2. The first two principal components describe around 77% of the variance.

3.1.2 Additional results of PCA

PCA models in R produce additional diagnostic and output components:

  • center: the column means used to center to the data, or FALSE if the data weren’t centered
  • scale: the column standard deviations used to scale the data, or FALSE if the data weren’t scaled
  • rotation: the directions of the principal component vectors in terms of the original features/variables. This information allows you to define new data in terms of the original principal components
  • x: the value of each observation in the original dataset projected to the principal components

We can access these the same as other model components. For example, use pr.out$rotation to access the rotation component.

The x component is a table with the same dimensions as the original data.

dim(pr.out$x)
[1] 50  4
dim(pokemon_pca)
[1] 50  4

The data were centered prior to performing PCA.

pr.out$center
HitPoints    Attack   Defense     Speed 
    71.08     81.22     78.44     66.58 

The data were scaled prior to performing PCA.

pr.out$scale
HitPoints    Attack   Defense     Speed 
 25.62193  33.03078  32.05809  27.51036 

The directions of the principal component vectors are presented in a table with different dimensions as the original data.

dim(pr.out$rotation)
[1] 4 4
dim(pokemon_pca)
[1] 50  4

3.2 Visualizing and interpreting PCA results

3.2.1 Interpreting biplots

The biplot() function plots both the principal components loadings and the mapping of the observations to their first two principal component values.

biplot(pr.out)

which two original variables have approximately the same loadings in the first two principal components? Attack and HitPoints

which two Pokemon are the least similar in terms of the second principal component? Kadabra and Torkoal

3.2.2 Variance explained

The second common plot type for understanding PCA models is a scree plot. A scree plot shows the variance explained as the number of principal components increases. Sometimes the cumulative variance explained is plotted as well.

# Variability of each principal component: pr.var
pr.var <- pr.out$sdev^2

# Variance explained by each principal component: pve
pve <- pr.var / sum(pr.var)

3.2.3 Visualize variance explained

Now we will create a scree plot showing the proportion of variance explained by each principal component, as well as the cumulative proportion of variance explained.

These plots can help to determine the number of principal components to retain. One way to determine the number of principal components to retain is by looking for an elbow in the scree plot showing that as the number of principal components increases, the rate at which variance is explained decreases substantially. In the absence of a clear elbow, you can use the scree plot as a guide for setting a threshold.

# Plot variance explained for each principal component
plot(pve, xlab = "Principal Component",
     ylab = "Proportion of Variance Explained",
     ylim = c(0, 1), type = "b")


# Plot cumulative proportion of variance explained
plot(cumsum(pve), xlab = "Principal Component",
     ylab = "Cumulative Proportion of Variance Explained",
     ylim = c(0, 1), type = "b")

Notice that when the number of principal components is equal to the number of original features in the data, the cumulative proportion of variance explained is 1.

3.3 Practical issues

3.3.1 Scaling

Scaling your data before doing PCA changes the results of the PCA modeling. Here, we will perform PCA with and without scaling, then visualize the results using biplots.

Sometimes scaling is appropriate when the variances of the variables are substantially different. This is commonly the case when variables have different units of measurement, for example, degrees Fahrenheit (temperature) and miles (distance). Making the decision to use scaling is an important step in performing a principal component analysis.

# Mean of each variable
colMeans(pokemon)
     HitPoints         Attack        Defense  SpecialAttack 
      69.25875       79.00125       73.84250       72.82000 
SpecialDefense          Speed 
      71.90250       68.27750 
# Standard deviation of each variable
apply(pokemon, 2, sd)
     HitPoints         Attack        Defense  SpecialAttack 
      25.53467       32.45737       31.18350       32.72229 
SpecialDefense          Speed 
      27.82892       29.06047 
# PCA model with scaling: pr.with.scaling
pr.with.scaling <- prcomp(x = pokemon_pca, scale = TRUE)

# PCA model without scaling: pr.without.scaling
pr.without.scaling <- prcomp(x = pokemon_pca, scale = FALSE)

# Create biplots of both for comparison
biplot(pr.with.scaling)

biplot(pr.without.scaling)

The new Total column contains much more variation, on average, than the other four columns, so it has a disproportionate effect on the PCA model when scaling is not performed. After scaling the data, there’s a much more even distribution of the loading vectors.

LS0tCnRpdGxlOiAiVW5zdXBlcnZpc2VkIExlYXJuaW5nIGluIFIiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIAp0b2NfZGVwdGg6IDMKLS0tCiMgVW5zdXBlcnZpc2VkIGxlYXJuaW5nIGluIFIKCiMjIEludHJvZHVjdGlvbgoKIyMjIElkZW50aWZ5IGNsdXN0ZXJpbmcgcHJvYmxlbXMKCkV4YW1wbGUgb2YgY2x1c3RlcmluZyBwcm9ibGVtczoKCi0gRGV0ZXJtaW5pbmcgdGhlIG5hdHVyYWwgZ3JvdXBpbmdzIG9mIGhvdXNlcyBmb3Igc2FsZSBiYXNlZCBvbiBzaXplLCBudW1iZXIgb2YgYmVkcm9vbXMsIGV0Yy4KLSBEZXRlcm1pbmluZyBpZiB0aGVyZSBhcmUgY29tbW9uIHBhdHRlcm5zIGluIHRoZSBkZW1vZ3JhcGhpY3Mgb2YgcGVvcGxlIGF0IGEgY29tbWVyY2Ugc2l0ZQoKIyMgSW50cm9kdWN0aW9uIHRvIGstbWVhbnMgY2x1c3RlcmluZwoKIyMjIGstbWVhbnMgY2x1c3RlcmluZwoKV2UgaGF2ZSBjcmVhdGVkIHNvbWUgdHdvLWRpbWVuc2lvbmFsIGRhdGEgYW5kIHN0b3JlZCBpdCBpbiBhIHZhcmlhYmxlIGNhbGxlZCB4LgpgYGB7ciBlY2hvPUZBTFNFfQp4ID0gcmJpbmQoc3RydWN0dXJlKGMoMy4zNzA5NTg0NDcxNDY2NywgMS40MzUzMDE4Mjg2MDM5MSwgMi4zNjMxMjg0MTEzMzczNCwgCjIuNjMyODYyNjA0OTYxMDQsIDIuNDA0MjY4MzIzMTQxLCAxLjg5Mzg3NTQ4MzkwODUyLCAzLjUxMTUyMTk5NzQzODk0LCAKMS45MDUzNDA5NjE1ODY5LCA0LjAxODQyMzcxMzg3NzA0LCAxLjkzNzI4NTkwMDk0NzU4LCAzLjMwNDg2OTY1NDIyMzQ5LCAKNC4yODY2NDUzOTI3MDExMSwgMC42MTExMzkyOTg4ODc2NjEsIDEuNzIxMjExMjMzMTgyNjMsIDEuODY2Njc4NjYzNjA2MzQsIAoyLjYzNTk1MDM5ODA3MDA3LCAxLjcxNTc0NzA3ODU4MzkzLCAtMC42NTY0NTU0MjA5MDQ3NzYsIC0wLjQ0MDQ2NjkyODU3NTUxOSwgCjMuMzIwMTEzMzQ1NzMwMTksIDEuNjkzMzYxNDA1OTIxNTMsIDAuMjE4NjkxNTY2MDIsIDEuODI4MDgyNjQ0MjQwMzgsIAozLjIxNDY3NDY5OTE3MjYsIDMuODk1MTkzNDYxMjY0OTcsIDEuNTY5NTMwODY4MzkzOCwgMS43NDI3MzA2MTcyMzEwNywgCjAuMjM2ODM2OTE0ODA1MjIsIDIuNDYwMDk3MzU0ODMxMjcsIDEuMzYwMDA1MTI0MDM5ODgsIDIuNDU1NDUwMTIzMjQxMjIsIAoyLjcwNDgzNzMzNzIyODgyLCAzLjAzNTEwMzUyMTk2OTkyLCAxLjM5MTA3MzYyNDU5Mjc5LCAyLjUwNDk1NTEyMzI5Nzk3LCAKMC4yODI5OTEzMjA5MjY2NTcsIDEuMjE1NTQwOTkxNjIwNSwgMS4xNDkwOTI0MDU4MjM0OCwgLTAuNDE0MjA3NjQ5OTQ2NjMyLCAKMi4wMzYxMjI2MDY4OTIyNiwgMi4yMDU5OTg2MDAyMDAyNSwgMS42Mzg5NDI3MDE0NTEzMywgMi43NTgxNjMyMzU2OTk1MiwgCjEuMjczMjk1MTcyOTIzNDIsIDAuNjMxNzE4OTU1NTgwNzA1LCAyLjQzMjgxODAyNTg4ODcyLCAxLjE4ODYwNjgyMzgxMzMzLCAKMy40NDQxMDEyNjE3MjEyNSwgMS41Njg1NTM3OTczODY2NSwgMi42NTU2NDc4ODM0MDIyMSwgMi4zMjE5MjUyNjUyMDM5NSwgCjEuMjE2MTYxMDU5MTE5NjIsIDMuNTc1NzI3NTE5NzkxOTgsIDIuNjQyODk5MzA1NzE3MzIsIDIuMDg5NzYwNjQ2NTk5NjEsIAoyLjI3NjU1MDc0NzI5MTQ2LCAyLjY3OTI4ODgxNjA1NTI3LCAyLjA4OTgzMjg4NjU3OTA4LCAtMC45OTMwOTAwODMxNTI5MzUsIAoyLjI4NDg4Mjk1MzUzMDY2LCAxLjYzMjc2NTM1NzI1OTAyLCAyLjE4NTIzMDU2NDg2NTYxLCAyLjU4MTgyMzcyNzM2NTUxLCAKMy4zOTk3MzY4MjcyOTI2OCwgMS4yNzI3MDc5NDA1MjU1MywgMy4zMDI1NDI2MzIwNDQxNCwgMi4zMzU4NDgxMTk3NTIwNywgCjMuMDM4NTA2MDk4Njk3NjIsIDIuOTIwNzI4NTY4MjkwNjUsIDIuNzIwODc4MTYyODY2ODYsIDAuOTU2ODgxMDYxNDMyMTQ1LCAKMS45MDk4MTM2MTMzODkyOSwgMi42MjM1MTgxNjE5OTk1NCwgMS4wNDY0NzY2NDIyMjc2NiwgMS40NTcxNzExODU0MjYxNCwgCjIuNTgwOTk2NDk3NjgxNjgsIDIuNzY4MTc4NzM3ODM0NTksIDIuNDYzNzY3NTg4NTQwMTcsIDEuMTE0MjIzNzAyNTkwMzIsIAowLjkwMDIxOTEwMTM1MjE0NCwgMy41MTI3MDcwMDk4MDQ5MywgMi4yNTc5MjE0Mzc1MzIwMywgMi4wODg0NDAyMjkxNTk1OSwgCjEuODc5MTAzNDYyNDYwOTEsIDAuODA1NjcxMTA0ODM5NDcyLCAyLjYxMTk5Njg5ODA0MDM5LCAxLjc4Mjg2MDE1NDI1MzQ4LCAKMS44MTcyNDMyOTM2NjgwOCwgMi45MzMzNDYzMjg1NzExNiwgMi44MjE3NzMxMTA1MDgyNSwgMy4zOTIxMTYzNzU5MzQyNywgCjEuNTIzODI2MDc2OTQ1MzMsIDIuNjUwMzQ4NTYwNzI2MzEsIDMuMzkxMTEwNDU2MzksIDAuODg5MjExMTIwNTUyMTAxLCAKMS4xMzkyMDc0MTMxMjIxNiwgMC44NjgyNjEzMTkxNDYyMywgMC41NDA3ODYwMDA0OTc2MDQsIDIuMDc5OTgyNTUzMjQxMTYsIAoyLjY1MzIwNDMzOTY0OTE5LCAtMy43OTkwMzQ2MjQ0MDE1MSwgLTMuOTU1MjQ4OTEyODMyMjcsIC02LjAwMzIwODY0NjgzOTg1LCAKLTMuMTUxNTE4MDk4MzI3MjUsIC01LjY2Njc3MzQwODc1NzgyLCAtNC44OTQ0ODYxODc1NDM5MywgLTUuNDIyMjU1ODgxODY4ODYsIAotNS4xMjIzNTAxNzE5NTQ5NywgLTQuODExODA2OTY1NDk4NSwgLTQuODgwODM5MDQyMDAyOTksIC01LjAyNTA5MjU1MDg2NzQsIAotNC44OTE5MjcyNzIwNTc5NywgLTUuNDg1NDM1MjM1ODQ2NjcsIC01LjUwNDIxNzEzMDY4NzksIC02LjY2MTA5OTA3OTkxNDgxLCAKLTUuMzgyMzMzNzI2ODczODIsIC01LjUxMjY1MDI1Nzg3NzgsIC0yLjI5ODEwODk5OTY1NTIsIC02LjM2MjExNjIzMTE4OTcyLCAKLTQuODYyNzQzNzgxNDQxMzksIC02LjQ5MzYyNTA2NzMxNjI5LCAtNi40NzA0MzU3NDE0MzY4LCAtNC44NzUyOTc2MTM4MDI5OSwgCi01Ljk5NjYzOTEzNDg4NDA0LCAtNS4wMDE4MjI2MTQzMDQ3MSwgLTUuNDI4MjU4ODgxNDI1ODIsIC01LjYxMzY3MTYwNjQ0OTUsIAotNy4wMjQ2Nzc4NDU0MTkxMSwgLTYuMjI0NzQ3OTUwMzU5OTksIC00LjgyMDQ4MzU1ODg4MjA2LCAtNC40MzIzNzk0MDU1NzY0NiwgCi01LjQ5Mjg3NzM1MzU1MzQ3LCAtNC45OTk5MzcxMTU5MzQ2NSwgLTMuODc3MTEwMzU2NjIwMDMsIC0zLjU2MDE0NDI1NzAyMzgxLCAKLTYuMDk3MTEzNzY4NDA1ODIsIC01LjExNzMxOTU2MDI1MDE4LCAtMy43OTg1MDE1OTkwODAzLCAtNS40Njk3Mjk1ODA1NjYzLCAKLTUuMDUyNDY5NDg0OTM5LCAtNS4wODYxMDcyOTgyMzcwOSwgLTUuODg3Njc5MDE3OTA2NDMsIC01LjQ0NDY4NDAwNDg4NDc0LCAKLTUuMDI5NDQ0ODc5MDg4MjQsIC01LjQxMzg2ODg0OTA1NzkyLCAtMy44ODY2MTM5NzY2MzE4LCAtNS40ODA5OTI4NDE2NTM5OCwgCi01LjQzMzE2OTAzMjYwMDczLCAtNC4zMDMxMzc0MjM0NDc5LCAtNi4wNTYzNjg0MTMxNzA5MSwgLTUuMDQwNjk4NDc1MTUxMjIsIAotNi41NTE1NDQ4MjIzNDc1OSwgLTMuODMyODMwNDUwNzY0MzIsIC01LjI3MzY0NTcwMTM3NDA4LCAtNS40Njc4NDUzMjQ2NzIyNSwgCi02LjIzODI1MjMyNzk4NjIxLCAtNS4wMDc3NjIwMzM3NzczMywgLTUuODAwMjgyMTc3OTUxNjYsIC01LjUzMzQ5MjMyOTk1MDQ0LCAKLTMuNzEyMzI0NzU0NDE1NDEsIC01LjE3NTUyNTg3MDI0MjEzLCAtNi4wNzE3ODIzODQxNTA2OCwgLTQuODM2NzkzMTE3NTMyNjIsIAotNS4zNjI3Mzg0MTU2Mjc5NSwgLTQuNDA5OTg2NDUyMDEyNjYsIC0zLjU2NzU3ODA3MjI2OTAxLCAtNS45OTI2OTI1MTExMDk0OSwgCi00LjU0NTM0OTcwMjQxOTcyLCAtNC45MTUxMDE5NDEzMjE1MSwgLTQuMTA0NDM0NDE3NzM1NDYsIC01LjIyOTc3ODEzODk0NjI3LCAKLTQuMTYzMzgwOTMxNTM5MzksIC02Ljc0NTA1NTg2MTMzNjY5LCAtMy4zMTA1NDEwNzg2ODY2MywgLTQuMTM1MjIyMDIxNDgxNDIsIAotNS4xNTA3NzU5ODg4ODU3NSwgLTYuNDQ5MDA3MTMwMTM5MTcsIC00LjM1Njk5MTI5OTk1ODAyLCAtNC41MTY4MDYxMzYxODUyMywgCi01LjAwNjM1NTYyNjQyMTM5LCAtNC44NDg1NDQxMDcxMzc1OCwgLTUuNTg0MTA4OTcwMzQ5OCwgLTQuNjMxMTkzMjY3MzY5NzYsIAotNC43MDUzNDU2NjAyODA0OCwgLTUuMjc5MjU5MzczMzQyNTgsIC02LjMzNjIzNjY1NDg5MzE1LCAtNC4yOTkyNTExODE1NTk5NywgCi00LjQ0NTgwMzM3NzcyNTk3LCAtNS44MzYzMDY1OTI4MDE0MiwgLTYuNTk0NTg4MTYyMDA2MjQsIC00Ljc5NTA0MTQxOTQxMjM3LCAKLTUuMzQ1MDg3OTc3OTcyODksIC00Ljc0NzM4ODI5NjYzNTU1LCAtNi4yOTQwMDI0NjU0ODQ1NSwgLTUuOTU5MTcwNDQ0MzgwMzYsIAotMy45MTQyMjUxNDYzMjAxLCAtNC41OTYyMjUwOTUyODQyOSwgLTQuNDEzNTEyNDYzMjgwNywgLTMuMTg0NzcxNTUzODQ2MDUsIAotNC44NzExNzg1NzEzOTc2MiwgLTcuMDAwOTI5MjM3NzMxNTEsIC00LjY2NjIyMjgwMjU2NjQzLCAtMy44Mjg2NzQ4NzI2NDEyMSwgCi0yLjk0MDQ2MDc1NzcwMDcsIC02LjM3Njg2MTU5ODI0MDUyLCAtNi4xNTA4NTU1NjU2MjcxMSwgLTUuNzA1ODIxMzk0NzYwMTIsIAotNi4wNTQwNTU3ODIwNzcxOSwgLTUuNjQ1NzQzNzIzMTQyNDksIC01LjE4NTM3Nzk2NzY3NjUsIC02LjIwMTIyMjA1MDczOTk5LCAKLTIuOTYzMDI3ODMzMDE2ODUsIC00Ljg5MjIyNTI1NTExNDQ1LCAtNS4wODQxMDgxMDA1MDU1OCwgLTQuNTA0MzgwMzU4Mzk1NDEsIAotNC45NjI1ODQ4MTM4ODIwMywgLTUuMTMyMDg4MDM2OTU1OTEsIC0zLjUyMzIxMjU3NjQ0NzksIC01LjIxNzAzMDIxMDA5MjEsIAotNi4yODM2MDIyMDQwOTIyMywgLTQuNjE0MzMyMTA5NTU2NiwgLTUuMzUxNTEyODczNTI5MDksIC01LjUyMTc5NjA5MzM1NjI3LCAKLTYuMDY4MTMxMjAwNjg3MTcsIC00LjU3MTYzNDA5NjczMzMxLCAtNS4xNzQwMTgyMzQ0MjcsIC00LjQ4NDMzMjI3MTM1MTk3LCAKLTUuMjM0MzY1Mjc3MzA1OTIsIC01LjY1ODUwMzQyNTgyMTc3LCAtMy43NDk3NjMzOTU5MjEyOCwgLTUuMjcxNzYzNzE1MTExNCwgCi00LjA1MjA0ODAwNDEyNDgsIC02LjIwMTU4MjQzMDEwODk0LCAtNS40NjYxMTYwOTYzNzU1LCAtNS4yNjkzNTEzOTUxNTMxOCwgCi01LjM5MDk2NTQwODEzMDg2LCAtMy42NTEyOTI5ODgwMDgyOSwgLTUuMDIyNzY0NzAxMjk4NDEsIC00Ljc1NTc3NDE0ODg5NjU1LCAKLTUuOTQyMzcxNzA3ODYzOTIsIC01LjcyOTIxNzI3NjUwOTU3LCAtNC4wMDE5MzEwOTE0NDUxNSwgLTMuNzQxNTE4MzM1NDA0NDQsIAotMy43NTExMzYzMTExODk5LCAtNi4zODA2MzcwNDk1MjUzMywgLTIuOTUwMDM5MzA2MzYzNjEsIC0zLjk4MzEyNzE3MDIwMDQ2LCAKLTUuMDI2NzE3NDY0MTM4MjYsIC00LjI5NjM5MjIyMTIwMTc0LCAtNS45NzEzODUyMjkxNTE4NiwgLTAuMDk2MTU2MjQxNTU4ODU3MywgCjEuMDQ5MDUwNDUwOTM3NiwgLTAuMTk4NDk1ODU2NTU3NzgsIDEuMTkwMDE4OTk4NTU5NzUsIDIuMjk3NzA1ODk5NjA0NjcsIAotMC4wMzM4NzM3MjI5NjQ3NTEsIDAuMjYxNTU5MjQ1Nzg2OTM2LCAxLjA0NjU2MzkzOTQ1MDg2LCAtMC4wMTc1OTYxMTk4MjYxMDU5LCAKMC42MTY3MTYwNDAxMTM3MjIsIDEuODcyNzU1NDExNjcxNCwgMS45Njk1NDUwMTM5NzAxMiwgMS4zODM4NDY2NjUwMjcwOSwgCi0wLjg1MTU1NTY2MzA2NzQ2NSwgMC45NDYwMDMyNjMxNzM4MzQsIDIuMDY0NzczMjE0MzM4MjgsIDEuODEzMTk1MDM3NDExNiwgCjAuODA5MTgzNTI1ODk1NzE4LCAtMS42OTk5Mjk4MDg1NjM3LCAxLjA2MDk2NjYzODgwMTEyLCAxLjU3Mzc1MTY5NzQ4MzU4LCAKMS4wNDU4MDM1Nzk3MjUxLCAxLjE1NzQxMjU0MDE3NTg4LCAxLjQzMTU2NTM3Mjg2ODc3LCAwLjYwMzQ1MDI2Mzk0OTc4OCwgCjIuMzA5OTc4MjI1NzUxNTUsIDEuNDcwMzkzMzk5ODczOTQsIC0wLjI0MjY3MDI3MDU3NDYwMiwgMi4zODE1NzU0NTYzODU1MywgCjIuMjA0NDU4OTM3MDA5ODIsIDEuODI0MDczOTYzNjgxODgsIC0wLjY2MjYyOTQwMjE4NTU5NSwgMC40MzA2OTM2NTYzOTQ1MTksIAoxLjYzNTUxMzgxNzI4OTUzLCAxLjA0MzcyMjAwNzU3Nzg2LCAxLjM0ODAxMjMwMzY2MTMxLCAzLjQ1OTU5MzU0ODg3MDQxLCAKMC4xODE2MTk2NzU2MDAzMzEsIC0xLjExMzIwMDExNDkyOTE0LCAxLjI3MzY5NTI3MjQzMDQxLCAwLjMxMjQwMzE1ODc1NjU4OCwgCjEuNDQ2MDQxMDUyOTYxODcsIDAuMTg3NjE1Mjc2MjA5NDAzLCAzLjIxMjA1NTQ4MDMzNTE0LCAwLjg3NjI5NDAyODQyMjU3LCAKMC41MjI2NjQ0OTM5Njk5NDgsIDAuODMzNzM4NTA4NTEzMzkyLCAxLjg2MjU2MzM4MzYyNjQzLCAxLjA5NzM0MDQ4NTIwMjgyLCAKLTAuNjI1NjE2NzM5MjExMjg4LCAxLjk5NTM3OTIzMjE3MzU0LCAyLjc2MDI0MjE2NzY2MjA1LCAyLjAzODk5MDkxMjg3MjU2LCAKMi43MzUwNzIxNDE2MTQ0NCwgMS44NTM1MjczNzMwMDExMywgMS45NDIxMTI2NjQ2MTg3MiwgMi40ODIzNjk0NjYxMDQ1MywgCjIuOTkyOTQzNjM2Nzc1NzMsIDAuNzUzNjA0NTAxOTY3OTU4LCAxLjk2NjUxMjQ3NTE1NDM5LCAxLjkyOTAzNzgxODc1LCAKMS4yNDEwNzkzNDYyNjkwNSwgMC45NjU2NDA2MzkwNjA4NDcsIDEuMzY5MjY4MDQ2MDI5MTgsIDIuNTg2ODA3NzIwMDEzLCAKMS41ODM2NzczNDM4MTYzNSwgMS4yMTUxMTIxOTA0OTQ2OCwgMi4xNjM0MTYzMTk0ODYxLCAwLjc2MzI4NTc2NDg5MDY1LCAKMy4wNDU4NzM3NzYyMzY2NywgMS41MTU0MDQ1ODM3ODEyOSwgMi4xODkxMjg4MTE2ODA2NywgMi4wNTEwMDYzMzE1NzQ5NywgCjEuOTk5NzU5MzMxMTEzNTYsIDMuODA5MzgyMDQyNDQyODcsIDEuMTc0NjcyMDQyODkwMDYsIDMuMTQ1NDcwNDUyMjI3OTksIAoyLjAzMTU3MzE4NzU1MzI0LCAxLjE2NDc5NDE5NDY5MzI4LCAxLjkzMTIzNjM1MDk4MzQ5LCAyLjc0Njc3MTY4NzAxMjQ3LCAKMS41NzQ0ODEyNjU2MDU0LCAxLjIyNzkxNzc2NDgwNjU0LCAyLjE1Mjc2NDEwNjc0Nzg5LCAyLjk4ODU5Njg0NTE3ODgsIAoxLjkyNjU0MTY2NTMyNzgzLCAwLjYxMjk3MzQ0NjQ0MDI1OCwgMC42OTMzMjQwOTU2MjQ2MzcsIDEuMjMxNjA0Njc0OTIyMDYsIAoxLjQ3Mjg5MTg3NDYyNTU0LCAxLjk3ODU3MjkzNDk1ODM4LCAyLjY3MDQ5ODA3MDk5NjI4LCAxLjU2NTM4Mjk2MTQyNzU5LCAKMC44ODYxMjAyMTY2ODcxNTMsIDIuNjA3MTA1OTk0ODc4NSwgMi4yNzU0NTY5Njg3Mzk1OSwgMy4xNTczNDcwNjk0MTQ3NCwgCjAuMzE3NTE5MTQwNTIxNzQ0LCAyLjA4NzMxOTA4ODg5NDg3LCAzLjM1MzM2MTg5Mzk0MjY3LCAyLjcyNDE3MzgwMDY4MzM3LCAKMS4xNjc0NDcxNzQyMzU3OSwgMi43MzI1Mjg0ODY3Njg0MSwgMS4xMjgwNzMxMzAwMDI3OSwgMS41NDY2MDI0ODg3NzAyMSwgCjMuMTg3NTM0Mjc4NjI5MDgsIDEuNzA5ODU0Njg4MjA5OTIsIDIuODI4NTQ2MTQ0OTY1NDQsIDEuNzA4NzcyMjkxMjIwODMsIAowLjQyMzYzNzU5NTI1MjA5NCwgMS4xNTExODQzMDMwNTEwOCwgMC45MTE0ODAxMzgwNDI4MDUsIDEuNTE1NzA5NDI4ODgyODMsIAoxLjY2MzY4ODc5MDk5MDQzLCAxLjg0NjY0MjEwOTMzODM2LCAxLjc1Njc1Mjc3MTQyNTE1LCAzLjg5MjIwMjA0MTYwMDExLCAKMC42MTQwMDE2NjI3MTQ1OCwgMS41ODUxNzU2OTkyOTIyMiwgMi4zNDkwODE1MjgxMDY4MywgMy42Mjg0NDIyNjU4MTU0MSwgCjIuMDg4NTIxODk1NzEzNjIsIDMuMjM5MTUwNzA4NDAwNTYsIDAuMzU1NDQ0NDY0MjQ2MjkzLCAzLjQ0NjM1NjUyNTM3ODQ4LCAKMS4zMDk0Mzk4MjgzMzQ4MiwgMS43MjM1Njg5MTQ1NDYxNSwgMC44OTA1ODEyNDAxMDA1NjMsIDIuMTMzODY5MzE2NDI5NDUsIAozLjc4NTMzOTA1MTczMTU1LCA0LjQyMjE2MzM1NTI1MTU5LCAwLjkyMzE3MTA5Nzg4MTU4OCwgMi40ODU5NDExMTA0MDMxLCAKMy4zODg1MjE3Mzg3NDQyOSwgMS44MDQzNDMxODI3MTU0NiwgMS43ODE4MjUyMDIyOTM3OSwgMS42OTUyMjIwNDU0NTM1NSwgCjIuNTk3ODMyNzI0MTExNDQsIDMuMzk3NDI5NDEwODE1NzYsIDIuNjg3NjE5NzYxMjM5OTYsIDIuMzIwMTg4MDE0Mjk2OTcsIAoxLjY5ODEzMDA3NDIyMjc0LCAyLjQ5ODM0ODY4NTU1Nzk1LCAxLjQ1MDQ2MzA4MjA4MzI0LCAxLjcyMDc0MzQ5NjM2Mjc2LCAKMy4wOTY1MTM0NDMxMTE3MywgMi40NDIwMTMwODgxNzg4MSwgMi4yNDEwMTYyOTQwMjYxMSwgMS43NDQzOTIzNDQ2NDQ0OCwgCjIuOTMxMDMyOTAxNDg0ODgsIDMuMzM0OTEyNTg1Mzc1NDcsIDEuMTMwNzI4MjM2MTI0NTYsIDIuMDU1NDg2OTU0NjY1MSwgCjIuMDQ5MDY2OTEzMTkxOTIsIDEuNDIxNjQ0MjcxNjM5MSwgMS4wMDEyNjEzNDQwMDQsIDEuOTk3NTY3MjE5OTkzNCwgCjIuNjU1NTExODgyODEyOTcsIDMuNDc2ODQyMjc4OTc2NTUsIDAuMDkwODQ3MjExNzIwNzg2NCwgMS4yOTc1NjA1MjY2ODc1OSwgCjEuNjg4NTY5NzgxOTg4MDgsIDAuMzM2ODQyOTY5MzMyNjI0LCAxLjI0OTQ2NjU1ODIwNzcxLCAxLjIyMjY0ODI0MDgxODQ5LCAKMS4yNzc0MzAzMDAxNDA0LCAtMC4xODg4MzQ1OTkxNDcwNjgsIDIuMjEzNDE4NTUwMjg2NTUsIDEuMzY4MDc3MDYzNzQ1MTcsIAozLjUyMDQ5MTE5MzgzMjE2LCAyLjc5NTk1NTk0OTQxNTA4LCAwLjU0NjQ3MDQzNDg2NzIwMSwgMi4wOTgzOTU0MjEwMDU4NCwgCjEuNDA2MjI5MDE1NzY2ODUsIDIuODg4MjgxMTY4NjM0NTEsIDIuMDUzMDcwNDE1NDk4NjcsIDEuNDQyOTc2Mzc0MTU1MzQsIAoyLjQzODM5NzAzNjE3MjcyLCAyLjE1MjYwODE1ODY0MjQyLCAxLjgzNTM4MjQxODI1MDQ0LCA0LjAxOTg5MDYyMTQ3NTk3LCAKMS40NzA2MTQxMTM2ODI3NCwgMS41MjkyMTMwMjcwMTU5NiwgMC40NTQwNjMwNzU5ODI0NzcsIDEuOTU5NDczMjc2NzA0ODIsIAoyLjg5MDM1NjMwNTQ3MDY4LCAtMC4wNzEzODc4NTA5MjkyMTM4LCAxLjc0OTkzNDg3OTkyNjk4LCAwLjgxODM0OTU3MzM0NjY4MiwgCjMuNDQxOTM3MjY1MDE2OTEsIDMuMzU3ODk1NTM4ODc4ODYsIDIuMzM0NTAyODQ3MzQwNjUsIDMuNDI5MzM4MDgwNDAwMjMsIAoxLjEzMjY4MjE0OTEyMTMyLCAyLjk1MDY1MTcyNDk3MTg5LCAxLjQxNDk4ODQ5MTM2Njc3LCAyLjMyMDk1NzUyMjUyNTYzLCAKMS43MDA2MDM5ODMzMzUwOSwgMS43MjE0NTY5MTY3MDY5MywgMi41NDYxMTUxNTgzMjk1MywgMC42OTYxNzg4NDYzNTUxMjgsIAoxLjc0OTA4NTUzNDk1NzU0LCAyLjE3MTAwNzM3MzcxNzkxLCAxLjU5NjUzMjUyMTI1MjQ5LCAyLjEwNDY1OTQ0MDgzNTczLCAKMS42ODExMTkyMTMyNjU5OSwgMy42MTgzNDM5MzU4ODM0MywgMi43MTQxODg2MDE0ODg2MiwgNC45NjU4NjUzNjk4MzMyNCwgCjEuMjA0OTIyMzk1NDQwNzksIDIuODE0MzY1OTE0Njc5OTEsIDQuMDk4MDMwODEwMTMwMzcsIDIuMzAwOTgwMDU1MTUyNTcsIAowLjkxNjkyNDg1ODE2MDc2OSwgMC45OTM2Nzc0OTgxOTY3MTUsIDEuOTY0NTg1NDM1MDgyMzksIDMuMzA5MTI0MzYwODUzNDEsIAoyLjc1MDQwMDQ4NjY0NjcyLCAtMC4xMzgzNjgzMjc2MTI0MiwgMS4yOTk2NDU4OTExMzMzNywgMS45OTA5NDM1MjQ3MDcwMSwgCjAuNTQxODY2NTEyNzU1MjMyLCAyLjY5NDUyOTY0NjQ5NDg3LCAtMC40NjEzMzU0NzUxODY0ODgsIDIuMTQzMjg5NzY0MDQwNDYsIAoxLjYwODc3Nzg4MDg3Mjk0LCAxLjUwODgzNTkxNDM4NTkyLCAxLjcxNjM1MjU0NzU0Nzk1LCAyLjMxNDc5NDgwNDcwNzg0LCAKMi4zOTYzMjY1Nzc5Mzg5OSwgMS43NzQzOTYyODg5NjQwNCwgMC4wNzUwNDk1Njk2NTk0NDA0LCAwLjU2MDc3MDcwMTY3ODAyMSwgCjAuNTMwMzQyMjI2MDI3NTk4LCAyLjc2MTg2MzQ0Njg5MTkzLCAxLjc1NjM4NTAxODEyODcyLCAyLjI2OTY3NjYwNzQxODAxLCAKMC40NDEwNzI0NzkwNDQxODQsIDEuNDY0NDExOTkzMzAzNjksIDIuNTYyNDUxOTczMTczNSwgMS44MjE2NzM4NzY1ODAwOCwgCjEuODg0ODY0MDEzNzk3MzUsIDEuOTI3OTM4NTI3ODkzNjMsIDMuMjEwOTA5ODA2OTI2MywgMS4zODUxMDMwOTkyMDAzLCAKMi42NzYxMjY0NTgzMTQ3LCAyLjg5ODU5OTYwNTUzNzU1LCAwLjgxMDY4MjA5NjQ3ODk4LCAyLjEyMTI1ODg0OTgxOTAxLCAKMS45ODg3NzgzMTM4Njk1OSwgMy4wMjkxNDA3MTkzMTM3NiwgMi45MTQ3NzQ4Njc3MTk2MSwgMS45OTc1NDM3MzMzMjA0NCwgCjIuMTM2MDA5NTUyNDEzNzMsIDEuMjc5ODQ2NDU1MDU2ODgsIDEuODAxODc1NjY5OTQ4NzgsIDAuOTcwNzkxMTkzOTUxNzI3LCAKMS4wMzMwNDQxMDQxNDczOCwgMC43NzkxODY5MTEwODA5MDUsIDIuODM2MjA3NzAzOTQ0ODQsIDMuMTE0OTcxNzk4NDk1NCwgCjEuNTg3MDU1MTQ3MDcyOTEsIDAuODcxMDIyNjAxOTkzMTY5LCAxLjkxMjA2ODY2ODIyMjk1LCA0LjI0MTkwMzY5MzMxMjYyLCAKNC4wNDEzMTMxNzA3NTA0OSwgMC4yODAxOTk2NjMyNzg1NDgsIDEuNjQzMDkzMzQzODc3NjEsIDMuNTMzMjgwNDkyMTYyMjksIAoxLjk2MTc1NTkwMzM4OTc2LCAzLjU5NzQxMzI0MjMyNjQzLCAxLjY2NjQxNDYwNjY5MDEyLCAyLjYwNDk4NTkyMzkxNTM4LCAKMi4yMjQyNDEyMzkyNTAyNSwgNS4yMjkwNjk0OTU0ODAwNiwgMi45MjA0NTI1NjY3NzI1MiwgMC43OTM0NjA5MzA3ODQwNzksIAoxLjM5NjExODgzMDgzNjczLCAyLjM3MDIzNTI4NDYyMjA2LCAwLjA5ODk5OTM1MzMyMDM5MzQsIDAuMTk1NTkwMDU1MDM2NzU4LCAKMC44NzgxNzczOTM2NDQ3ODEsIDEuNjUyMDcwMzkzNDQwODYsIDMuMjM4OTAyMTQ4NjMxOTgsIDEuNzI1ODAyNDM1MTQ3NzIsIAoyLjE2MjM4MDcxNTU1ODE5LCAxLjkzNTM5MzA5MDI0Njk0LCAxLjI5NDc2MjkwMjk3NDg2LCAzLjM2MjE5NzI2ODc1MDk5LCAKMC45MDM0ODY4MTE5MTY2ODMsIDEuNzcxNTY2NDgxNDUzMTEsIDEuNjUyMTcxOTE5Mzg5NzMsIDIuNTMyMTI4NjE5NTA2NzMsIAozLjYwNzIzNDU2MjI2MTE5LCAyLjUxMzgxNDUyNjExNjU5LCAzLjM4MjM3MzE2MDU3MzAzLCAyLjc2MzA5NzA0ODU0OTksIAoxLjM3NTQxNTQ1NTM2NTg5LCAyLjA4MTU0MzgwMDQyODk5LCAzLjM3NjA3OTExMTM2NDc3LCAtMS41NjEyNjU3ODYxNTcwNCwgCjAuMzI0NzcwNjYwNTk0Njk5LCAtMC4xNTY3OTAzMTY5NTIyMzgsIDAuODc3NzgzODYwNzM0MzUyLCAwLjc1MDE2NjU3NTE4MDYzOCwgCjAuMzAxMDUzNDAzODQyODMsIDEuNDkyODExMTE3MjI5MzEsIC0xLjUyNTQ5MzgwMDE2OTcsIDAuOTEwNzE3NTU4NDg2MDIyLCAKLTEuNTc5NTMyMDI3ODU3NTQsIDAuNTg3NzE2MjU3MTE4NTgxLCAwLjA4OTY0MjI5NjAwMDcyNDQsIDAuOTY3MjYxNjU2OTQ5ODQsIAowLjA3ODgxMjM1MjkxNDgyMzQsIC0xLjU2ODY5OTgzNjQ4NjA5LCAtMi4wMDc4MjMxODQwMTYwOSwgMC41NDA5NzM1MjQyMzg3NjMsIAotMC4wNzMzNzY1OTgxMDg0MjU1LCAtMC41NzEwMTgzOTM1NTgwODEsIC0wLjMxMTA2ODQ1OTg1MzY0MSwgCi0wLjY3MTQxNTA2NzEwMTM2NSwgLTAuMTU3MzQwNDUyMDgwOTc5LCAtMC45MzEzMDUwNzA5OTk4NjksIC0xLjk4MzAwOTQ3OTQ3MDEzLCAKLTAuMjE5NTk5ODA0MjQ5Mzc4LCAxLjA0NTI3NTg2OTQ2MjM5LCAxLjg3NzMyOTU2NjI5OTY3LCAwLjAwMjYwNjE5NTk1NzE2NjM3LCAKLTAuMDgwNjY5OTM0NzA5MTY1NSwgMC45NjI5ODIyODEyMzk4NywgMC4wNTM1NzEwMTY1NDY1MTc0LCAtMC40MzQ4OTg0MDg5MTAwMzcsIAotMS43MzcyOTcyNTUzNDIzMSwgLTEuMjYzNjk1NTk5NzgyNDMsIDAuNDA2MzA4NTEyMDY5MjczLCAtMS40NTk2NTM5Njc3Nzk3NiwgCjEuMDQ4NDU3MzcwMTU0NywgLTEuMzQ2NDMwNTM5NDUwMiwgLTAuMTkzNTcwNTU4MTEzNDk0LCAtMC4wMDIzMzU5NTcxMTM2NzYwNSwgCi0wLjAxMjgyOTczMzg2NzE4ODEsIDAuMTUxOTQ3MzIxOTg0Mzk4LCAwLjU5ODUxMTEzMTQwMTA3OSwgLTAuMTI2MjEyNDM3Mjk4Mjc5LCAKLTAuMjQ4NTM1NTY1ODQ2Nzc2LCAwLjE2MDMyNzM5NDkwNDYyMiwgLTAuNDMzNjQxOTQxNTk3MjY5LCAxLjUzNzQxMjQxOTEwMDI3LCAKLTIuMTcwMjQ2NTc2NjE2MDgsIDEuMDI3MDA0NjE5MjkxNDMpLCAuRGltID0gYygzMDBMLCAyTCkpKQpgYGAKYGBge3J9CnBsb3QoeCkKYGBgCk91ciB0YXNrIGlzIHRvIGNyZWF0ZSBhIGstbWVhbnMgbW9kZWwgb2YgdGhlIHggZGF0YSB1c2luZyAzIGNsdXN0ZXJzLCB0aGVuIHRvIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgcmVzdWx0aW5nIG1vZGVsIHVzaW5nIHRoZSBzdW1tYXJ5KCkgZnVuY3Rpb24uCmBgYHtyfQojIENyZWF0ZSB0aGUgay1tZWFucyBtb2RlbDoga20ub3V0CmttLm91dCA8LSBrbWVhbnMoeCwgY2VudGVycyA9IDMsIG5zdGFydCA9IDIwICkKCiMgSW5zcGVjdCB0aGUgcmVzdWx0CnN1bW1hcnkoa20ub3V0KQpgYGAKIyMjIFJlc3VsdHMgb2Yga21lYW5zKCkKClRoZSBrbWVhbnMoKSBmdW5jdGlvbiBwcm9kdWNlcyBzZXZlcmFsIG91dHB1dHMuCgpXZSB3aWxsIGFjY2VzcyB0aGUgY2x1c3RlciBjb21wb25lbnQgZGlyZWN0bHkuIFRoaXMgaXMgdXNlZnVsIGFueXRpbWUgd2UgbmVlZCB0aGUgY2x1c3RlciBtZW1iZXJzaGlwIGZvciBlYWNoIG9ic2VydmF0aW9uIG9mIHRoZSBkYXRhIHVzZWQgdG8gYnVpbGQgdGhlIGNsdXN0ZXJpbmcgbW9kZWwuCgprLW1lYW5zIG1vZGVscyBhbHNvIGhhdmUgYSBwcmludCBtZXRob2QgdG8gZ2l2ZSBhIGh1bWFuIGZyaWVuZGx5IG91dHB1dCBvZiBiYXNpYyBtb2RlbGluZyByZXN1bHRzLiBUaGlzIGlzIGF2YWlsYWJsZSBieSB1c2luZyBwcmludCgpIG9yIHNpbXBseSB0eXBpbmcgdGhlIG5hbWUgb2YgdGhlIG1vZGVsLgpgYGB7cn0KIyBQcmludCB0aGUgY2x1c3RlciBtZW1iZXJzaGlwIGNvbXBvbmVudCBvZiB0aGUgbW9kZWwKa20ub3V0JGNsdXN0ZXIKCiMgUHJpbnQgdGhlIGttLm91dCBvYmplY3QKcHJpbnQoa20ub3V0KQpgYGAKQmVjYXVzZSBwcmludGluZyB0aGUgd2hvbGUgbW9kZWwgb2JqZWN0IHRvIHRoZSBjb25zb2xlIG91dHB1dHMgbWFueSBkaWZmZXJlbnQgdGhpbmdzLCB3ZSBtYXkgd2lzaCB0byBpbnN0ZWFkIHByaW50IGEgc3BlY2lmaWMgY29tcG9uZW50IG9mIHRoZSBtb2RlbCBvYmplY3QgdXNpbmcgdGhlICQgb3BlcmF0b3IuIAoKIyMjIFZpc3VhbGl6aW5nIGFuZCBpbnRlcnByZXRpbmcgcmVzdWx0cyBvZiBrbWVhbnMoKQoKT25lIG9mIHRoZSBtb3JlIGludHVpdGl2ZSB3YXlzIHRvIGludGVycHJldCB0aGUgcmVzdWx0cyBvZiBrLW1lYW5zIG1vZGVscyBpcyBieSBwbG90dGluZyB0aGUgZGF0YSBhcyBhIHNjYXR0ZXIgcGxvdCBhbmQgdXNpbmcgY29sb3IgdG8gbGFiZWwgdGhlIHNhbXBsZXMnIGNsdXN0ZXIgbWVtYmVyc2hpcC4gV2Ugd2lsbCB1c2UgdGhlIHN0YW5kYXJkIHBsb3QoKSBmdW5jdGlvbiB0byBhY2NvbXBsaXNoIHRoaXMuCgpUbyBjcmVhdGUgYSBzY2F0dGVyIHBsb3QsIHdlIGNhbiBwYXNzIGRhdGEgd2l0aCB0d28gZmVhdHVyZXMgKGkuZS4gY29sdW1ucykgdG8gcGxvdCgpIHdpdGggYW4gZXh0cmEgYXJndW1lbnQgY29sID0ga20ub3V0JGNsdXN0ZXIsIHdoaWNoIHNldHMgdGhlIGNvbG9yIG9mIGVhY2ggcG9pbnQgaW4gdGhlIHNjYXR0ZXIgcGxvdCBhY2NvcmRpbmcgdG8gaXRzIGNsdXN0ZXIgbWVtYmVyc2hpcC4KCmBgYHtyfQojIFNjYXR0ZXIgcGxvdCBvZiB4CnBsb3QoeCwgY29sID0ga20ub3V0JGNsdXN0ZXIsIG1haW4gPSAiay1tZWFucyB3aXRoIDMgY2x1c3RlcnMiLAp4bGFiID0gIiIsIHlsYWIgPSAiIiApCmBgYAojIyBIb3cgay1tZWFucyB3b3JrcyBhbmQgcHJhY3RpY2FsIG1hdHRlcnMKCiMjIyBIYW5kbGluZyByYW5kb20gYWxnb3JpdGhtcwoKV2Ugc2F3IGhvdyBrbWVhbnMoKSByYW5kb21seSBpbml0aWFsaXplcyB0aGUgY2VudGVycyBvZiBjbHVzdGVycy4gVGhpcyByYW5kb20gaW5pdGlhbGl6YXRpb24gY2FuIHJlc3VsdCBpbiBhc3NpZ25pbmcgb2JzZXJ2YXRpb25zIHRvIGRpZmZlcmVudCBjbHVzdGVyIGxhYmVscy4gQWxzbywgdGhlIHJhbmRvbSBpbml0aWFsaXphdGlvbiBjYW4gcmVzdWx0IGluIGZpbmRpbmcgZGlmZmVyZW50IGxvY2FsIG1pbmltYSBmb3IgdGhlIGstbWVhbnMgYWxnb3JpdGhtLiBUaGlzIGV4YW1wbGUgd2lsbCBkZW1vbnN0cmF0ZSBib3RoIHJlc3VsdHMuCgpBdCB0aGUgdG9wIG9mIGVhY2ggcGxvdCwgdGhlIG1lYXN1cmUgb2YgbW9kZWwgcXVhbGl0eeKAlHRvdGFsIHdpdGhpbiBjbHVzdGVyIHN1bSBvZiBzcXVhcmVzIGVycm9y4oCUd2lsbCBiZSBwbG90dGVkLiBMb29rIGZvciB0aGUgbW9kZWwocykgd2l0aCB0aGUgbG93ZXN0IGVycm9yIHRvIGZpbmQgbW9kZWxzIHdpdGggdGhlIGJldHRlciBtb2RlbCByZXN1bHRzLgoKQmVjYXVzZSBrbWVhbnMoKSBpbml0aWFsaXplcyBvYnNlcnZhdGlvbnMgdG8gcmFuZG9tIGNsdXN0ZXJzLCBpdCBpcyBpbXBvcnRhbnQgdG8gc2V0IHRoZSByYW5kb20gbnVtYmVyIGdlbmVyYXRvciBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkuCmBgYHtyfQojIFNldCB1cCAyIHggMyBwbG90dGluZyBncmlkCnBhcihtZnJvdyA9IGMoMiwgMykpCgojIFNldCBzZWVkCnNldC5zZWVkKDEpCgpmb3IoaSBpbiAxOjYpIHsKICAjIFJ1biBrbWVhbnMoKSBvbiB4IHdpdGggdGhyZWUgY2x1c3RlcnMgYW5kIG9uZSBzdGFydAogIGttLm91dCA8LSBrbWVhbnMoeCwgY2VudGVycyA9IDMsIG5zdGFydCA9IDEpCiAgCiAgIyBQbG90IGNsdXN0ZXJzCiAgcGxvdCh4LCBjb2wgPSBrbS5vdXQkY2x1c3RlciwgCiAgICAgICBtYWluID0ga20ub3V0JHRvdC53aXRoaW5zcywgCiAgICAgICB4bGFiID0gIiIsIHlsYWIgPSAiIikKfQpgYGAKQmVjYXVzZSBvZiB0aGUgcmFuZG9tIGluaXRpYWxpemF0aW9uIG9mIHRoZSBrLW1lYW5zIGFsZ29yaXRobSwgdGhlcmUncyBxdWl0ZSBzb21lIHZhcmlhdGlvbiBpbiBjbHVzdGVyIGFzc2lnbm1lbnRzIGFtb25nIHRoZSBzaXggbW9kZWxzLgoKIyMjIFNlbGVjdGluZyBudW1iZXIgb2YgY2x1c3RlcnMKClRoZSBrLW1lYW5zIGFsZ29yaXRobSBhc3N1bWVzIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMgYXMgcGFydCBvZiB0aGUgaW5wdXQuIElmIHdlIGtub3cgdGhlIG51bWJlciBvZiBjbHVzdGVycyBpbiBhZHZhbmNlIChlLmcuIGR1ZSB0byBjZXJ0YWluIGJ1c2luZXNzIGNvbnN0cmFpbnRzKSB0aGlzIG1ha2VzIHNldHRpbmcgdGhlIG51bWJlciBvZiBjbHVzdGVycyBlYXN5LiBIb3dldmVyLCBpZiB3ZSBkbyBub3Qga25vdyB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIGFuZCBuZWVkIHRvIGRldGVybWluZSBpdCwgd2Ugd2lsbCBuZWVkIHRvIHJ1biB0aGUgYWxnb3JpdGhtIG11bHRpcGxlIHRpbWVzLCBlYWNoIHRpbWUgd2l0aCBhIGRpZmZlcmVudCBudW1iZXIgb2YgY2x1c3RlcnMuIEZyb20gdGhpcywgd2UgY2FuIG9ic2VydmUgaG93IGEgbWVhc3VyZSBvZiBtb2RlbCBxdWFsaXR5IGNoYW5nZXMgd2l0aCB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzLgoKV2Ugd2lsbCBydW4ga21lYW5zKCkgbXVsdGlwbGUgdGltZXMgdG8gc2VlIGhvdyBtb2RlbCBxdWFsaXR5IGNoYW5nZXMgYXMgdGhlIG51bWJlciBvZiBjbHVzdGVycyBjaGFuZ2VzLiBQbG90cyBkaXNwbGF5aW5nIHRoaXMgaW5mb3JtYXRpb24gaGVscCB0byBkZXRlcm1pbmUgdGhlIG51bWJlciBvZiBjbHVzdGVycyBhbmQgYXJlIG9mdGVuIHJlZmVycmVkIHRvIGFzIHNjcmVlIHBsb3RzLgoKVGhlIGlkZWFsIHBsb3Qgd2lsbCBoYXZlIGFuIGVsYm93IHdoZXJlIHRoZSBxdWFsaXR5IG1lYXN1cmUgaW1wcm92ZXMgbW9yZSBzbG93bHkgYXMgdGhlIG51bWJlciBvZiBjbHVzdGVycyBpbmNyZWFzZXMuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIHF1YWxpdHkgb2YgdGhlIG1vZGVsIGlzIG5vIGxvbmdlciBpbXByb3Zpbmcgc3Vic3RhbnRpYWxseSBhcyB0aGUgbW9kZWwgY29tcGxleGl0eSAoaS5lLiBudW1iZXIgb2YgY2x1c3RlcnMpIGluY3JlYXNlcy4gSW4gb3RoZXIgd29yZHMsIHRoZSBlbGJvdyBpbmRpY2F0ZXMgdGhlIG51bWJlciBvZiBjbHVzdGVycyBpbmhlcmVudCBpbiB0aGUgZGF0YS4KCmBgYHtyfQojIEluaXRpYWxpemUgdG90YWwgd2l0aGluIHN1bSBvZiBzcXVhcmVzIGVycm9yOiB3c3MKd3NzIDwtIDAKCiMgRm9yIDEgdG8gMTUgY2x1c3RlciBjZW50ZXJzCmZvciAoaSBpbiAxOjE1KSB7CiAga20ub3V0IDwtIGttZWFucyh4LCBjZW50ZXJzID0gaSwgbnN0YXJ0ID0gMjApCiAgIyBTYXZlIHRvdGFsIHdpdGhpbiBzdW0gb2Ygc3F1YXJlcyB0byB3c3MgdmFyaWFibGUKICB3c3NbaV0gPC0ga20ub3V0JHRvdC53aXRoaW5zcwp9CgojIFBsb3QgdG90YWwgd2l0aGluIHN1bSBvZiBzcXVhcmVzIHZzLiBudW1iZXIgb2YgY2x1c3RlcnMKcGxvdCgxOjE1LCB3c3MsIHR5cGUgPSAiYiIsIAogICAgIHhsYWIgPSAiTnVtYmVyIG9mIENsdXN0ZXJzIiwgCiAgICAgeWxhYiA9ICJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikKCiMgU2V0IGsgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBjbHVzdGVycyBjb3JyZXNwb25kaW5nIHRvIHRoZSBlbGJvdyBsb2NhdGlvbgprIDwtIDIKYGBgCkxvb2tpbmcgYXQgdGhlIHNjcmVlIHBsb3QsIGl0IGxvb2tzIGxpa2UgdGhlcmUgYXJlIGluaGVyZW50bHkgMiBvciAzIGNsdXN0ZXJzIGluIHRoZSBkYXRhLgoKIyMgSW50cm9kdWN0aW9uIHRvIHRoZSBQb2tlbW9uIGRhdGEKCiMjIyBQcmFjdGljYWwgbWF0dGVyczogd29ya2luZyB3aXRoIHJlYWwgZGF0YQoKRGVhbGluZyB3aXRoIHJlYWwgZGF0YSBpcyBvZnRlbiBtb3JlIGNoYWxsZW5naW5nIHRoYW4gZGVhbGluZyB3aXRoIHN5bnRoZXRpYyBkYXRhLiBTeW50aGV0aWMgZGF0YSBoZWxwcyB3aXRoIGxlYXJuaW5nIG5ldyBjb25jZXB0cyBhbmQgdGVjaG5pcXVlcywgYnV0IHdlIHdpbGwgZGVhbCB3aXRoIGRhdGEgdGhhdCBpcyBjbG9zZXIgdG8gdGhlIHR5cGUgb2YgcmVhbCBkYXRhIHlvdSBtaWdodCBmaW5kIGluIHlvdXIgcHJvZmVzc2lvbmFsIG9yIGFjYWRlbWljIHB1cnN1aXRzLgoKVGhlIGZpcnN0IGNoYWxsZW5nZSB3aXRoIHRoZSBQb2tlbW9uIGRhdGEgaXMgdGhhdCB0aGVyZSBpcyBubyBwcmUtZGV0ZXJtaW5lZCBudW1iZXIgb2YgY2x1c3RlcnMuIFdlIHdpbGwgZGV0ZXJtaW5lIHRoZSBhcHByb3ByaWF0ZSBudW1iZXIgb2YgY2x1c3RlcnMsIGtlZXBpbmcgaW4gbWluZCB0aGF0IGluIHJlYWwgZGF0YSB0aGUgZWxib3cgaW4gdGhlIHNjcmVlIHBsb3QgbWlnaHQgYmUgbGVzcyBvZiBhIHNoYXJwIGVsYm93IHRoYW4gaW4gc3ludGhldGljIGRhdGEuIFVzZSB5b3VyIGp1ZGdlbWVudCBvbiBtYWtpbmcgdGhlIGRldGVybWluYXRpb24gb2YgdGhlIG51bWJlciBvZiBjbHVzdGVycy4KClRoaXMgZXhhbXBsZSBpbmNsdWRlcyBwbG90dGluZyB0aGUgb3V0Y29tZXMgb2YgdGhlIGNsdXN0ZXJpbmcgb24gdHdvIGRpbWVuc2lvbnMsIG9yIGZlYXR1cmVzLCBvZiB0aGUgZGF0YS4gVGhlc2UgZmVhdHVyZXMgd2VyZSBjaG9zZW4gc29tZXdoYXQgYXJiaXRyYXJpbHkgZm9yIHRoaXMgZXhlcmNpc2UuIFRoaW5rIGFib3V0IGhvdyB5b3Ugd291bGQgdXNlIHBsb3R0aW5nIGFuZCBjbHVzdGVyaW5nIHRvIGNvbW11bmljYXRlIGludGVyZXN0aW5nIGdyb3VwcyBvZiBQb2tlbW9uIHRvIG90aGVyIHBlb3BsZS4KCkFuIGFkZGl0aW9uYWwgbm90ZTogdGhpcyBleGFtcGxlIHV0aWxpemVzIHRoZSBpdGVyLm1heCBhcmd1bWVudCB0byBrbWVhbnMoKS4gQXMgd2UndmUgc2Vlbiwga21lYW5zKCkgaXMgYW4gaXRlcmF0aXZlIGFsZ29yaXRobSwgcmVwZWF0aW5nIG92ZXIgYW5kIG92ZXIgdW50aWwgc29tZSBzdG9wcGluZyBjcml0ZXJpb24gaXMgcmVhY2hlZC4gVGhlIGRlZmF1bHQgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIGttZWFucygpIGlzIDEwLCB3aGljaCBpcyBub3QgZW5vdWdoIGZvciB0aGUgYWxnb3JpdGhtIHRvIGNvbnZlcmdlIGFuZCByZWFjaCBpdHMgc3RvcHBpbmcgY3JpdGVyaW9uLCBzbyB3ZSdsbCBzZXQgdGhlIG51bWJlciBvZiBpdGVyYXRpb25zIHRvIDUwIHRvIG92ZXJjb21lIHRoaXMgaXNzdWUuIFRvIHNlZSB3aGF0IGhhcHBlbnMgd2hlbiBrbWVhbnMoKSBkb2VzIG5vdCBjb252ZXJnZSwgdHJ5IHJ1bm5pbmcgdGhlIGV4YW1wbGUgd2l0aCBhIGxvd2VyIG51bWJlciBvZiBpdGVyYXRpb25zIChlLmcuIDMpLiBUaGlzIGlzIGFub3RoZXIgZXhhbXBsZSBvZiB3aGF0IG1pZ2h0IGhhcHBlbiB3aGVuIHdlIGVuY291bnRlciByZWFsIGRhdGEgYW5kIHVzZSByZWFsIGNhc2VzLgoKYGBge3J9CmxpYnJhcnkocmVhZHIpCnBva2Vtb24gPC0gcmVhZF9jc3YoIlBva2Vtb24uY3N2IikgJT4lIAogIHNlbGVjdChIaXRQb2ludHMsIEF0dGFjaywgRGVmZW5zZSwgU3BlY2lhbEF0dGFjaywgU3BlY2lhbERlZmVuc2UsIFNwZWVkKQpgYGAKYGBge3J9CiMgSW5pdGlhbGl6ZSB0b3RhbCB3aXRoaW4gc3VtIG9mIHNxdWFyZXMgZXJyb3I6IHdzcwp3c3MgPC0gMAoKIyBMb29rIG92ZXIgMSB0byAxNSBwb3NzaWJsZSBjbHVzdGVycwpmb3IgKGkgaW4gMToxNSkgewogICMgRml0IHRoZSBtb2RlbDoga20ub3V0CiAga20ub3V0IDwtIGttZWFucyhwb2tlbW9uLCBjZW50ZXJzID0gaSwgbnN0YXJ0ID0gMjAsIGl0ZXIubWF4ID0gNTApCiAgIyBTYXZlIHRoZSB3aXRoaW4gY2x1c3RlciBzdW0gb2Ygc3F1YXJlcwogIHdzc1tpXSA8LSBrbS5vdXQkdG90LndpdGhpbnNzCn0KCiMgUHJvZHVjZSBhIHNjcmVlIHBsb3QKcGxvdCgxOjE1LCB3c3MsIHR5cGUgPSAiYiIsIAogICAgIHhsYWIgPSAiTnVtYmVyIG9mIENsdXN0ZXJzIiwgCiAgICAgeWxhYiA9ICJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikKYGBgCmBgYHtyfQojIFNlbGVjdCBudW1iZXIgb2YgY2x1c3RlcnMKayA8LSAyCgojIEJ1aWxkIG1vZGVsIHdpdGggayBjbHVzdGVyczoga20ub3V0CmttLm91dCA8LSBrbWVhbnMocG9rZW1vbiwgY2VudGVycyA9IGssIG5zdGFydCA9IDIwLCBpdGVyLm1heCA9IDUwKQoKIyBWaWV3IHRoZSByZXN1bHRpbmcgbW9kZWwKa20ub3V0CgojIFBsb3Qgb2YgRGVmZW5zZSB2cy4gU3BlZWQgYnkgY2x1c3RlciBtZW1iZXJzaGlwCnBsb3QocG9rZW1vblssIGMoIkRlZmVuc2UiLCAiU3BlZWQiKV0sCiAgICAgY29sID0ga20ub3V0JGNsdXN0ZXIsCiAgICAgbWFpbiA9IHBhc3RlKCJrLW1lYW5zIGNsdXN0ZXJpbmcgb2YgUG9rZW1vbiB3aXRoIiwgaywgImNsdXN0ZXJzIiksCiAgICAgeGxhYiA9ICJEZWZlbnNlIiwgeWxhYiA9ICJTcGVlZCIpCmBgYApgYGB7cn0KIyBTZWxlY3QgbnVtYmVyIG9mIGNsdXN0ZXJzCmsgPC0gMwoKIyBCdWlsZCBtb2RlbCB3aXRoIGsgY2x1c3RlcnM6IGttLm91dAprbS5vdXQgPC0ga21lYW5zKHBva2Vtb24sIGNlbnRlcnMgPSBrLCBuc3RhcnQgPSAyMCwgaXRlci5tYXggPSA1MCkKa20ucG9rZW1vbiA8LSBrbS5vdXQKIyBWaWV3IHRoZSByZXN1bHRpbmcgbW9kZWwKa20ub3V0CgojIFBsb3Qgb2YgRGVmZW5zZSB2cy4gU3BlZWQgYnkgY2x1c3RlciBtZW1iZXJzaGlwCnBsb3QocG9rZW1vblssIGMoIkRlZmVuc2UiLCAiU3BlZWQiKV0sCiAgICAgY29sID0ga20ub3V0JGNsdXN0ZXIsCiAgICAgbWFpbiA9IHBhc3RlKCJrLW1lYW5zIGNsdXN0ZXJpbmcgb2YgUG9rZW1vbiB3aXRoIiwgaywgImNsdXN0ZXJzIiksCiAgICAgeGxhYiA9ICJEZWZlbnNlIiwgeWxhYiA9ICJTcGVlZCIpCmBgYAojIEhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nCgojIyBJbnRyb2R1Y3Rpb24KCiMjIyBIaWVyYXJjaGljYWwgY2x1c3RlcmluZyB3aXRoIHJlc3VsdHMKCldlIHdpbGwgY3JlYXRlIHlvdXIgZmlyc3QgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgbW9kZWwgdXNpbmcgdGhlIGhjbHVzdCgpIGZ1bmN0aW9uLgoKV2Ugd2lsbCBjcmVhdGUgYSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBtb2RlbCBvZiB4LiBUaGUgZmlyc3Qgc3RlcCB0byBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBpcyBkZXRlcm1pbmluZyB0aGUgc2ltaWxhcml0eSBiZXR3ZWVuIG9ic2VydmF0aW9ucywgd2hpY2ggeW91IHdpbGwgZG8gd2l0aCB0aGUgZGlzdCgpIGZ1bmN0aW9uLgoKYGBge3J9CiMgQ3JlYXRlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG1vZGVsOiBoY2x1c3Qub3V0CmhjbHVzdC5vdXQgPC0gaGNsdXN0KGRpc3QoeCkpCgojIEluc3BlY3QgdGhlIHJlc3VsdApzdW1tYXJ5KGhjbHVzdC5vdXQpCmBgYApOb3cgdGhhdCB3ZSd2ZSBtYWRlIHlvdXIgZmlyc3QgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgbW9kZWwsIGxldCdzIGxlYXJuIGhvdyB0byB1c2UgaXQgdG8gc29sdmUgcHJvYmxlbXMuCgojIyBTZWxlY3RpbmcgbnVtYmVyIG9mIGNsdXN0ZXJzCmBgYHtyfQpwbG90KGhjbHVzdC5vdXQpCmFibGluZShoID0gYygzLjUsNC41LCA2LjksIDkuMCksIGNvbCA9ICJyZWQiKQpgYGAKSWYgd2UgY3V0IHRoZSB0cmVlIGF0IGEgaGVpZ2h0IG9mIDYuOSwgd2UncmUgbGVmdCB3aXRoIDMgYnJhbmNoZXMgcmVwcmVzZW50aW5nIDMgZGlzdGluY3QgY2x1c3RlcnMuCgojIyMgQ3V0dGluZyB0aGUgdHJlZQoKY3V0cmVlKCkgaXMgdGhlIFIgZnVuY3Rpb24gdGhhdCBjdXRzIGEgaGllcmFyY2hpY2FsIG1vZGVsLiBUaGUgaCBhbmQgayBhcmd1bWVudHMgdG8gY3V0cmVlKCkgYWxsb3cgeW91IHRvIGN1dCB0aGUgdHJlZSBiYXNlZCBvbiBhIGNlcnRhaW4gaGVpZ2h0IGggb3IgYSBjZXJ0YWluIG51bWJlciBvZiBjbHVzdGVycyBrLgpgYGB7cn0KIyBDdXQgYnkgaGVpZ2h0CmN1dHJlZShoY2x1c3Qub3V0LCBoID0gNykKCiMgQ3V0IGJ5IG51bWJlciBvZiBjbHVzdGVycwpjdXRyZWUoaGNsdXN0Lm91dCwgayA9IDMpCmBgYApUaGUgb3V0cHV0IG9mIGVhY2ggY3V0cmVlKCkgY2FsbCByZXByZXNlbnRzIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIGZvciBlYWNoIG9ic2VydmF0aW9uIGluIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiAKCiMjIENsdXN0ZXJpbmcgbGlua2FnZSBhbmQgcHJhY3RpY2FsIG1hdHRlcnMKCiMjIyBMaW5rYWdlIG1ldGhvZHMKCldlIHdpbGwgcHJvZHVjZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBtb2RlbHMgdXNpbmcgZGlmZmVyZW50IGxpbmthZ2VzIGFuZCBwbG90IHRoZSBkZW5kcm9ncmFtIGZvciBlYWNoLCBvYnNlcnZpbmcgdGhlIG92ZXJhbGwgc3RydWN0dXJlIG9mIHRoZSB0cmVlcy4KCmBgYHtyfQojIENsdXN0ZXIgdXNpbmcgY29tcGxldGUgbGlua2FnZTogaGNsdXN0LmNvbXBsZXRlCmhjbHVzdC5jb21wbGV0ZSA8LSBoY2x1c3QoZGlzdCh4KSwgbWV0aG9kID0gImNvbXBsZXRlIikKCiMgQ2x1c3RlciB1c2luZyBhdmVyYWdlIGxpbmthZ2U6IGhjbHVzdC5hdmVyYWdlCmhjbHVzdC5hdmVyYWdlIDwtIGhjbHVzdChkaXN0KHgpLCBtZXRob2QgPSAiYXZlcmFnZSIpCgojIENsdXN0ZXIgdXNpbmcgc2luZ2xlIGxpbmthZ2U6IGhjbHVzdC5zaW5nbGUKaGNsdXN0LnNpbmdsZSA8LSBoY2x1c3QoZGlzdCh4KSwgbWV0aG9kID0gInNpbmdsZSIpCgojIFBsb3QgZGVuZHJvZ3JhbSBvZiBoY2x1c3QuY29tcGxldGUKcGxvdChoY2x1c3QuY29tcGxldGUsIG1haW4gPSAiQ29tcGxldGUiKQoKIyBQbG90IGRlbmRyb2dyYW0gb2YgaGNsdXN0LmF2ZXJhZ2UKcGxvdChoY2x1c3QuYXZlcmFnZSwgbWFpbiA9ICJBdmVyYWdlIikKCiMgUGxvdCBkZW5kcm9ncmFtIG9mIGhjbHVzdC5zaW5nbGUKcGxvdChoY2x1c3Quc2luZ2xlLCBtYWluID0gIlNpbmdsZSIpCmBgYApXaGV0aGVyIHdlIHdhbnQgYmFsYW5jZWQgb3IgdW5iYWxhbmNlZCB0cmVlcyBmb3Igb3VyIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG1vZGVsIGRlcGVuZHMgb24gdGhlIGNvbnRleHQgb2YgdGhlIHByb2JsZW0gd2UncmUgdHJ5aW5nIHRvIHNvbHZlLiBCYWxhbmNlZCB0cmVlcyBhcmUgZXNzZW50aWFsIGlmIHdlIHdhbnQgYW4gZXZlbiBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGFzc2lnbmVkIHRvIGVhY2ggY2x1c3Rlci4gT24gdGhlIG90aGVyIGhhbmQsIGlmIHdlIHdhbnQgdG8gZGV0ZWN0IG91dGxpZXJzLCBmb3IgZXhhbXBsZSwgYW4gdW5iYWxhbmNlZCB0cmVlIGlzIG1vcmUgZGVzaXJhYmxlIGJlY2F1c2UgcHJ1bmluZyBhbiB1bmJhbGFuY2VkIHRyZWUgY2FuIHJlc3VsdCBpbiBtb3N0IG9ic2VydmF0aW9ucyBhc3NpZ25lZCB0byBvbmUgY2x1c3RlciBhbmQgb25seSBhIGZldyBvYnNlcnZhdGlvbnMgYXNzaWduZWQgdG8gb3RoZXIgY2x1c3RlcnMuCgojIyMgUHJhY3RpY2FsIG1hdHRlcnM6IHNjYWxpbmcKCkNsdXN0ZXJpbmcgcmVhbCBkYXRhIG1heSByZXF1aXJlIHNjYWxpbmcgdGhlIGZlYXR1cmVzIGlmIHRoZXkgaGF2ZSBkaWZmZXJlbnQgZGlzdHJpYnV0aW9ucy4gCgpXZSB3aWxsIGdvIGJhY2sgdG8gd29ya2luZyB3aXRoICJyZWFsIiBkYXRhLCB0aGUgcG9rZW1vbiBkYXRhc2V0IGludHJvZHVjZWQgaW4gdGhlIGZpcnN0IGNoYXB0ZXIuIFdlIHdpbGwgb2JzZXJ2ZSB0aGUgZGlzdHJpYnV0aW9uIChtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24pIG9mIGVhY2ggZmVhdHVyZSwgc2NhbGUgdGhlIGRhdGEgYWNjb3JkaW5nbHksIHRoZW4gcHJvZHVjZSBhIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG1vZGVsIHVzaW5nIHRoZSBjb21wbGV0ZSBsaW5rYWdlIG1ldGhvZC4KYGBge3J9CiMgVmlldyBjb2x1bW4gbWVhbnMKY29sTWVhbnMocG9rZW1vbikKCiMgVmlldyBjb2x1bW4gc3RhbmRhcmQgZGV2aWF0aW9ucwphcHBseShwb2tlbW9uLCAyLCBzZCkKCiMgU2NhbGUgdGhlIGRhdGEKcG9rZW1vbi5zY2FsZWQgPSBzY2FsZShwb2tlbW9uKQoKIyBDcmVhdGUgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgbW9kZWw6IGhjbHVzdC5wb2tlbW9uCmhjbHVzdC5wb2tlbW9uID0gaGNsdXN0KGRpc3QocG9rZW1vbi5zY2FsZWQpLCBtZXRob2QgPSAiY29tcGxldGUiKQpgYGAKV2UgZmlyc3QgY2hlY2tlZCB0byBzZWUgaWYgdGhlIGNvbHVtbiBtZWFucyBhbmQgc3RhbmRhcmQgZGV2aWF0aW9ucyB2YXJ5LiBCZWNhdXNlIHRoZXkgZG8sIHdlIHNjYWxlZCB0aGUgZGF0YSwgY29udmVydGVkIHRoZSBzY2FsZWQgZGF0YSB0byBhIHNpbWlsYXJpdHkgbWF0cml4IGFuZCBwYXNzZWQgaXQgaW50byB0aGUgaGNsdXN0KCkgZnVuY3Rpb24uCgojIyMgQ29tcGFyaW5nIGttZWFucygpIGFuZCBoY2x1c3QoKQoKQ29tcGFyaW5nIGstbWVhbnMgYW5kIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nLCB3ZSdsbCBzZWUgdGhlIHR3byBtZXRob2RzIHByb2R1Y2UgZGlmZmVyZW50IGNsdXN0ZXIgbWVtYmVyc2hpcHMuIFRoaXMgaXMgYmVjYXVzZSB0aGUgdHdvIGFsZ29yaXRobXMgbWFrZSBkaWZmZXJlbnQgYXNzdW1wdGlvbnMgYWJvdXQgaG93IHRoZSBkYXRhIGlzIGdlbmVyYXRlZC4gCmBgYHtyfQojIEFwcGx5IGN1dHJlZSgpIHRvIGhjbHVzdC5wb2tlbW9uOiBjdXQucG9rZW1vbgpjdXQucG9rZW1vbiA8LSBjdXRyZWUoaGNsdXN0LnBva2Vtb24sIGsgPSAzKQoKIyBDb21wYXJlIG1ldGhvZHMKdGFibGUoa20ucG9rZW1vbiRjbHVzdGVyLCBjdXQucG9rZW1vbikKYGBgCkxvb2tpbmcgYXQgdGhlIHRhYmxlLCBpdCBsb29rcyBsaWtlIHRoZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBtb2RlbCBhc3NpZ25zIG1vc3Qgb2YgdGhlIG9ic2VydmF0aW9ucyB0byBjbHVzdGVyIDEsIHdoaWxlIHRoZSBrLW1lYW5zIGFsZ29yaXRobSBkaXN0cmlidXRlcyB0aGUgb2JzZXJ2YXRpb25zIHJlbGF0aXZlbHkgZXZlbmx5IGFtb25nIGFsbCBjbHVzdGVycy4gSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHRoZXJlJ3Mgbm8gY29uc2Vuc3VzIG9uIHdoaWNoIG1ldGhvZCBwcm9kdWNlcyBiZXR0ZXIgY2x1c3RlcnMuIFRoZSBqb2Igb2YgdGhlIGFuYWx5c3QgaW4gdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgaXMgdG8gb2JzZXJ2ZSB0aGUgY2x1c3RlciBhc3NpZ25tZW50cyBhbmQgbWFrZSBhIGp1ZGdtZW50IGNhbGwgYXMgdG8gd2hpY2ggbWV0aG9kIHByb3ZpZGVzIG1vcmUgaW5zaWdodHMgaW50byB0aGUgZGF0YS4gCgojIERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB3aXRoIFBDQQoKIyMgSW50cm9kdWN0aW9uCgojIyMgUENBIHVzaW5nIHByY29tcCgpCgpXZSB3aWxsIGNyZWF0ZSBhIHMgcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyAoUENBKSBtb2RlbCBhbmQgb2JzZXJ2ZSB0aGUgZGlhZ25vc3RpYyByZXN1bHRzLgoKcG9rZW1vbl9wY2EgaXMgYSA0IGRpbWVuc2lvbnMgdmVyc2lvbiBvZiBvdXIgcG9rZW1vbiBkYXRhc2V0LgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpwb2tlbW9uX3BjYSA8LSBkcHV0KHN0cnVjdHVyZShjKDU4TCwgOTBMLCA3MEwsIDYwTCwgNjBMLCA0NEwsIDEwMEwsIDgwTCwgODBMLCA2MEwsIAoxNTBMLCA2MkwsIDc1TCwgNzBMLCAxMTVMLCA3NEwsIDc0TCwgNDBMLCA5NUwsIDgwTCwgMjVMLCA1MUwsIAo0OEwsIDQ1TCwgMzVMLCAyMEwsIDYwTCwgNzBMLCA3MEwsIDgwTCwgNTdMLCA2NEwsIDc1TCwgMTAxTCwgCjUwTCwgNjBMLCA4NUwsIDk1TCwgNThMLCAxMDBMLCA5NUwsIDkxTCwgNjJMLCA3MEwsIDYwTCwgNzBMLCAKNTBMLCA1MEwsIDcwTCwgMTUwTCwgNjRMLCAxMDBMLCA5NEwsIDgwTCwgNTVMLCAzOEwsIDc3TCwgMTQ1TCwgCjEwMEwsIDU1TCwgMTAwTCwgNzdMLCA5OEwsIDEzMEwsIDQ1TCwgMTA4TCwgOTRMLCAzNUwsIDY1TCwgMTIwTCwgCjM1TCwgNjVMLCA3MkwsIDQ1TCwgNTVMLCA0MEwsIDcwTCwgMjBMLCA1NUwsIDEwMEwsIDI0TCwgNzhMLCAKOThMLCA3MkwsIDc1TCwgMTAwTCwgMTIwTCwgMTU1TCwgODlMLCAxNTBMLCAxMjVMLCA5MEwsIDQ4TCwgNDBMLCAKMTEwTCwgODVMLCA4NUwsIDUwTCwgMTEwTCwgMTIwTCwgNThMLCA3MEwsIDUwTCwgMTEwTCwgOTBMLCAzM0wsIAo3N0wsIDE1MEwsIDcwTCwgMTQ1TCwgMTIwTCwgNjJMLCA2M0wsIDEwMEwsIDIwTCwgMTMzTCwgMTMxTCwgCjMwTCwgNjVMLCAxMzBMLCA3MEwsIDY1TCwgNDhMLCA1NUwsIDQwTCwgOTBMLCA1MEwsIDUwTCwgNjVMLCAKODBMLCA4NkwsIDUyTCwgNjNMLCA3MkwsIDcwTCwgODlMLCA3MEwsIDEwOUwsIDc3TCwgMTIwTCwgNzlMLCAKMTI5TCwgNTRMLCA1MEwsIDcwTCwgMTQwTCwgNDBMLCA2MkwsIDcwTCwgMTAwTCwgODBMLCA4MEwsIDY2TCwgCjQ1TCwgODBMLCA3MEwsIDkwTCwgMTEwTCwgOTVMLCA0MEwsIDkwTCwgNjVMLCAxMDFMLCA2NUwsIDIwTCwgCjMyTCwgMjBMLCAxMDVMLCA2MEwsIDQ1TCwgNDVMLCA1OUwsIDQ4TCwgNjNMLCA2MEwsIDI1TCwgNjVMLCAKNDBMLCA3MEwsIDEwMEwsIDIzTCwgODFMLCAxMDFMLCAyOUwsIDQ4TCwgMTEyTCwgMTAwTCwgODFMLCA0OEwsIAo5MEwsIDgxTCwgMTA4TCwgNjhMLCAyNUwsIDEwMEwsIDIwTCwgMzVMLCA2NUwsIDkwTCwgOTBMKSwgLkRpbSA9IGMoNTBMLCAKNEwpLCAuRGltbmFtZXMgPSBsaXN0KGMoIlF1aWxhdmEiLCAiR29vZHJhIiwgIk1vdGhpbSIsICJNYXJvd2FrIiwgCiJDaGFuZGVsdXJlIiwgIkhlbGlvcHRpbGUiLCAiTWVsb2V0dGFBcmlhIEZvcm1lIiwgIk1ldGFncm9zc01lZ2EgTWV0YWdyb3NzIiwgCiJTYXdzYnVjayIsICJQcm9ib3Bhc3MiLCAiR2lyYXRpbmFBbHRlcmVkIEZvcm1lIiwgIlRyYW5xdWlsbCIsIAoiU2ltaXNhZ2UiLCAiU2Npem9yIiwgIkppZ2dseXB1ZmYiLCAiQ2FycmFjb3N0YSIsICJGZXJyb3Rob3JuIiwgCiJLYWRhYnJhIiwgIlN5bHZlb24iLCAiR29sZW0iLCAiTWFnbmVtaXRlIiwgIlZhbmlsbGlzaCIsICJVbm93biIsIAoiU25pdnkiLCAiVHluYW1vIiwgIkR1c2t1bGwiLCAiQmVhdXRpZmx5IiwgIk1hcmlsbCIsICJMdW5hdG9uZSIsIAoiRmx5Z29uIiwgIkJyb256b3IiLCAiTW9uZmVybm8iLCAiU2ltaXNlYXIiLCAiQXJvbWF0aXNzZSIsICJTY3JhZ2d5IiwgCiJTY29saXBlZGUiLCAiU3RhcmFwdG9yIiwgIkd5YXJhZG9zTWVnYSBHeWFyYWRvcyIsICJUeXJ1bnQiLCAKIlpla3JvbSIsICJHeWFyYWRvcyIsICJDb2JhbGlvbiIsICJFc3B1cnIiLCAiU3BoZWFsIiwgIkRvZHJpbyIsIAoiVG9ya29hbCIsICJDYWNuZWEiLCAiVHJ1YmJpc2giLCAiTHVjYXJpbyIsICJHaXJhdGluYU9yaWdpbiBGb3JtZSIKKSwgYygiSGl0UG9pbnRzIiwgIkF0dGFjayIsICJEZWZlbnNlIiwgIlNwZWVkIikpKSkKYGBgCgpgYGB7cn0KaGVhZChwb2tlbW9uX3BjYSkKYGBgCgpgYGB7cn0KIyBQZXJmb3JtIHNjYWxlZCBQQ0E6IHByLm91dApwci5vdXQgPC0gcHJjb21wKHggPSBwb2tlbW9uX3BjYSwKc2NhbGUgPSBUUlVFKQoKIyBJbnNwZWN0IG1vZGVsIG91dHB1dApzdW1tYXJ5KHByLm91dCkKYGBgCldoYXQgaXMgdGhlIG1pbmltdW0gbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIHRoYXQgYXJlIHJlcXVpcmVkIHRvIGRlc2NyaWJlIGF0IGxlYXN0IDc1JSBvZiB0aGUgY3VtdWxhdGl2ZSB2YXJpYW5jZSBpbiB0aGlzIGRhdGFzZXQ/IDIuIFRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMgZGVzY3JpYmUgYXJvdW5kIDc3JSBvZiB0aGUgdmFyaWFuY2UuCgojIyMgQWRkaXRpb25hbCByZXN1bHRzIG9mIFBDQQoKUENBIG1vZGVscyBpbiBSIHByb2R1Y2UgYWRkaXRpb25hbCBkaWFnbm9zdGljIGFuZCBvdXRwdXQgY29tcG9uZW50czoKCi0gY2VudGVyOiB0aGUgY29sdW1uIG1lYW5zIHVzZWQgdG8gY2VudGVyIHRvIHRoZSBkYXRhLCBvciBGQUxTRSBpZiB0aGUgZGF0YSB3ZXJlbid0IGNlbnRlcmVkCi0gc2NhbGU6IHRoZSBjb2x1bW4gc3RhbmRhcmQgZGV2aWF0aW9ucyB1c2VkIHRvIHNjYWxlIHRoZSBkYXRhLCBvciBGQUxTRSBpZiB0aGUgZGF0YSB3ZXJlbid0IHNjYWxlZAotIHJvdGF0aW9uOiB0aGUgZGlyZWN0aW9ucyBvZiB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudCB2ZWN0b3JzIGluIHRlcm1zIG9mIHRoZSBvcmlnaW5hbCBmZWF0dXJlcy92YXJpYWJsZXMuIFRoaXMgaW5mb3JtYXRpb24gYWxsb3dzIHlvdSB0byBkZWZpbmUgbmV3IGRhdGEgaW4gdGVybXMgb2YgdGhlIG9yaWdpbmFsIHByaW5jaXBhbCBjb21wb25lbnRzCi0geDogdGhlIHZhbHVlIG9mIGVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIG9yaWdpbmFsIGRhdGFzZXQgcHJvamVjdGVkIHRvIHRoZSBwcmluY2lwYWwgY29tcG9uZW50cwoKV2UgY2FuIGFjY2VzcyB0aGVzZSB0aGUgc2FtZSBhcyBvdGhlciBtb2RlbCBjb21wb25lbnRzLiBGb3IgZXhhbXBsZSwgdXNlIHByLm91dCRyb3RhdGlvbiB0byBhY2Nlc3MgdGhlIHJvdGF0aW9uIGNvbXBvbmVudC4KClRoZSB4IGNvbXBvbmVudCBpcyBhIHRhYmxlIHdpdGggdGhlIHNhbWUgZGltZW5zaW9ucyBhcyB0aGUgb3JpZ2luYWwgZGF0YS4KYGBge3J9CmRpbShwci5vdXQkeCkKZGltKHBva2Vtb25fcGNhKQpgYGAKClRoZSBkYXRhIHdlcmUgY2VudGVyZWQgcHJpb3IgdG8gcGVyZm9ybWluZyBQQ0EuCmBgYHtyfQpwci5vdXQkY2VudGVyCmBgYAoKVGhlIGRhdGEgd2VyZSBzY2FsZWQgcHJpb3IgdG8gcGVyZm9ybWluZyBQQ0EuCmBgYHtyfQpwci5vdXQkc2NhbGUKYGBgCgpUaGUgZGlyZWN0aW9ucyBvZiB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudCB2ZWN0b3JzIGFyZSBwcmVzZW50ZWQgaW4gYSB0YWJsZSB3aXRoIGRpZmZlcmVudCBkaW1lbnNpb25zIGFzIHRoZSBvcmlnaW5hbCBkYXRhLgpgYGB7cn0KZGltKHByLm91dCRyb3RhdGlvbikKZGltKHBva2Vtb25fcGNhKQpgYGAKIyMgVmlzdWFsaXppbmcgYW5kIGludGVycHJldGluZyBQQ0EgcmVzdWx0cwoKIyMjIEludGVycHJldGluZyBiaXBsb3RzCgpUaGUgYmlwbG90KCkgZnVuY3Rpb24gcGxvdHMgYm90aCB0aGUgcHJpbmNpcGFsIGNvbXBvbmVudHMgbG9hZGluZ3MgYW5kIHRoZSBtYXBwaW5nIG9mIHRoZSBvYnNlcnZhdGlvbnMgdG8gdGhlaXIgZmlyc3QgdHdvIHByaW5jaXBhbCBjb21wb25lbnQgdmFsdWVzLgpgYGB7cn0KYmlwbG90KHByLm91dCkKYGBgCndoaWNoIHR3byBvcmlnaW5hbCB2YXJpYWJsZXMgaGF2ZSBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGxvYWRpbmdzIGluIHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHM/IEF0dGFjayBhbmQgSGl0UG9pbnRzCgp3aGljaCB0d28gUG9rZW1vbiBhcmUgdGhlIGxlYXN0IHNpbWlsYXIgaW4gdGVybXMgb2YgdGhlIHNlY29uZCBwcmluY2lwYWwgY29tcG9uZW50PyBLYWRhYnJhIGFuZCBUb3Jrb2FsCgojIyMgVmFyaWFuY2UgZXhwbGFpbmVkCgpUaGUgc2Vjb25kIGNvbW1vbiBwbG90IHR5cGUgZm9yIHVuZGVyc3RhbmRpbmcgUENBIG1vZGVscyBpcyBhIHNjcmVlIHBsb3QuIEEgc2NyZWUgcGxvdCBzaG93cyB0aGUgdmFyaWFuY2UgZXhwbGFpbmVkIGFzIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgaW5jcmVhc2VzLiBTb21ldGltZXMgdGhlIGN1bXVsYXRpdmUgdmFyaWFuY2UgZXhwbGFpbmVkIGlzIHBsb3R0ZWQgYXMgd2VsbC4KYGBge3J9CiMgVmFyaWFiaWxpdHkgb2YgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50OiBwci52YXIKcHIudmFyIDwtIHByLm91dCRzZGV2XjIKCiMgVmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudDogcHZlCnB2ZSA8LSBwci52YXIgLyBzdW0ocHIudmFyKQpgYGAKIyMjIFZpc3VhbGl6ZSB2YXJpYW5jZSBleHBsYWluZWQKCk5vdyB3ZSB3aWxsIGNyZWF0ZSBhIHNjcmVlIHBsb3Qgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50LCBhcyB3ZWxsIGFzIHRoZSBjdW11bGF0aXZlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkLgoKVGhlc2UgcGxvdHMgY2FuIGhlbHAgdG8gZGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gcmV0YWluLiBPbmUgd2F5IHRvIGRldGVybWluZSB0aGUgbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIHRvIHJldGFpbiBpcyBieSBsb29raW5nIGZvciBhbiBlbGJvdyBpbiB0aGUgc2NyZWUgcGxvdCBzaG93aW5nIHRoYXQgYXMgdGhlIG51bWJlciBvZiBwcmluY2lwYWwgY29tcG9uZW50cyBpbmNyZWFzZXMsIHRoZSByYXRlIGF0IHdoaWNoIHZhcmlhbmNlIGlzIGV4cGxhaW5lZCBkZWNyZWFzZXMgc3Vic3RhbnRpYWxseS4gSW4gdGhlIGFic2VuY2Ugb2YgYSBjbGVhciBlbGJvdywgeW91IGNhbiB1c2UgdGhlIHNjcmVlIHBsb3QgYXMgYSBndWlkZSBmb3Igc2V0dGluZyBhIHRocmVzaG9sZC4KYGBge3J9CiMgUGxvdCB2YXJpYW5jZSBleHBsYWluZWQgZm9yIGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudApwbG90KHB2ZSwgeGxhYiA9ICJQcmluY2lwYWwgQ29tcG9uZW50IiwKICAgICB5bGFiID0gIlByb3BvcnRpb24gb2YgVmFyaWFuY2UgRXhwbGFpbmVkIiwKICAgICB5bGltID0gYygwLCAxKSwgdHlwZSA9ICJiIikKCiMgUGxvdCBjdW11bGF0aXZlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkCnBsb3QoY3Vtc3VtKHB2ZSksIHhsYWIgPSAiUHJpbmNpcGFsIENvbXBvbmVudCIsCiAgICAgeWxhYiA9ICJDdW11bGF0aXZlIFByb3BvcnRpb24gb2YgVmFyaWFuY2UgRXhwbGFpbmVkIiwKICAgICB5bGltID0gYygwLCAxKSwgdHlwZSA9ICJiIikKYGBgCk5vdGljZSB0aGF0IHdoZW4gdGhlIG51bWJlciBvZiBwcmluY2lwYWwgY29tcG9uZW50cyBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIG9yaWdpbmFsIGZlYXR1cmVzIGluIHRoZSBkYXRhLCB0aGUgY3VtdWxhdGl2ZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZCBpcyAxLgoKIyMgUHJhY3RpY2FsIGlzc3VlcwoKIyMjIFNjYWxpbmcKClNjYWxpbmcgeW91ciBkYXRhIGJlZm9yZSBkb2luZyBQQ0EgY2hhbmdlcyB0aGUgcmVzdWx0cyBvZiB0aGUgUENBIG1vZGVsaW5nLiBIZXJlLCB3ZSB3aWxsIHBlcmZvcm0gUENBIHdpdGggYW5kIHdpdGhvdXQgc2NhbGluZywgdGhlbiB2aXN1YWxpemUgdGhlIHJlc3VsdHMgdXNpbmcgYmlwbG90cy4KClNvbWV0aW1lcyBzY2FsaW5nIGlzIGFwcHJvcHJpYXRlIHdoZW4gdGhlIHZhcmlhbmNlcyBvZiB0aGUgdmFyaWFibGVzIGFyZSBzdWJzdGFudGlhbGx5IGRpZmZlcmVudC4gVGhpcyBpcyBjb21tb25seSB0aGUgY2FzZSB3aGVuIHZhcmlhYmxlcyBoYXZlIGRpZmZlcmVudCB1bml0cyBvZiBtZWFzdXJlbWVudCwgZm9yIGV4YW1wbGUsIGRlZ3JlZXMgRmFocmVuaGVpdCAodGVtcGVyYXR1cmUpIGFuZCBtaWxlcyAoZGlzdGFuY2UpLiBNYWtpbmcgdGhlIGRlY2lzaW9uIHRvIHVzZSBzY2FsaW5nIGlzIGFuIGltcG9ydGFudCBzdGVwIGluIHBlcmZvcm1pbmcgYSBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzLgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpwb2tlbW9uX3BjYSA8LSByYmluZChzdHJ1Y3R1cmUoYyg0MDVMLCA2MDBMLCA0MjRMLCA0MjVMLCA1MjBMLCAyODlMLCA2MDBMLCA3MDBMLCA0NzVMLCAKNTI1TCwgNjgwTCwgMzU4TCwgNDk4TCwgNTAwTCwgMjcwTCwgNDk1TCwgNDg5TCwgNDAwTCwgNTI1TCwgNDk1TCwgCjMyNUwsIDM5NUwsIDMzNkwsIDMwOEwsIDI3NUwsIDI5NUwsIDM5NUwsIDI1MEwsIDQ0MEwsIDUyMEwsIDMwMEwsIAo0MDVMLCA0OThMLCA0NjJMLCAzNDhMLCA0ODVMLCA0ODVMLCA2NDBMLCAzNjJMLCA2ODBMLCA1NDBMLCA1ODBMLCAKMzU1TCwgMjkwTCwgNDYwTCwgNDcwTCwgMzM1TCwgMzI5TCwgNTI1TCwgNjgwTCwgNThMLCA5MEwsIDcwTCwgCjYwTCwgNjBMLCA0NEwsIDEwMEwsIDgwTCwgODBMLCA2MEwsIDE1MEwsIDYyTCwgNzVMLCA3MEwsIDExNUwsIAo3NEwsIDc0TCwgNDBMLCA5NUwsIDgwTCwgMjVMLCA1MUwsIDQ4TCwgNDVMLCAzNUwsIDIwTCwgNjBMLCA3MEwsIAo3MEwsIDgwTCwgNTdMLCA2NEwsIDc1TCwgMTAxTCwgNTBMLCA2MEwsIDg1TCwgOTVMLCA1OEwsIDEwMEwsIAo5NUwsIDkxTCwgNjJMLCA3MEwsIDYwTCwgNzBMLCA1MEwsIDUwTCwgNzBMLCAxNTBMLCA2NEwsIDEwMEwsIAo5NEwsIDgwTCwgNTVMLCAzOEwsIDc3TCwgMTQ1TCwgMTAwTCwgNTVMLCAxMDBMLCA3N0wsIDk4TCwgMTMwTCwgCjQ1TCwgMTA4TCwgOTRMLCAzNUwsIDY1TCwgMTIwTCwgMzVMLCA2NUwsIDcyTCwgNDVMLCA1NUwsIDQwTCwgCjcwTCwgMjBMLCA1NUwsIDEwMEwsIDI0TCwgNzhMLCA5OEwsIDcyTCwgNzVMLCAxMDBMLCAxMjBMLCAxNTVMLCAKODlMLCAxNTBMLCAxMjVMLCA5MEwsIDQ4TCwgNDBMLCAxMTBMLCA4NUwsIDg1TCwgNTBMLCAxMTBMLCAxMjBMLCAKNThMLCA3MEwsIDUwTCwgMTEwTCwgOTBMLCAzM0wsIDc3TCwgMTUwTCwgNzBMLCAxNDVMLCAxMjBMLCA2MkwsIAo2M0wsIDEwMEwsIDIwTCwgMTMzTCwgMTMxTCwgMzBMLCA2NUwsIDEzMEwsIDcwTCwgNjVMLCA0OEwsIDU1TCwgCjQwTCwgOTBMLCA1MEwsIDUwTCwgNjVMLCA4MEwsIDg2TCwgNTJMLCA2M0wsIDcyTCwgNzBMLCA4OUwsIDcwTCwgCjEwOUwsIDc3TCwgMTIwTCwgNzlMLCAxMjlMLCA1NEwsIDUwTCwgNzBMLCAxNDBMLCA0MEwsIDYyTCwgNzBMLCAKMTAwTCwgODBMLCA4MEwsIDY2TCwgNDVMLCA4MEwsIDcwTCwgOTBMLCAxMTBMLCA5NUwsIDQwTCwgOTBMLCAKNjVMLCAxMDFMLCA2NUwsIDIwTCwgMzJMLCAyMEwsIDEwNUwsIDYwTCwgNDVMLCA0NUwsIDU5TCwgNDhMLCAKNjNMLCA2MEwsIDI1TCwgNjVMLCA0MEwsIDcwTCwgMTAwTCwgMjNMLCA4MUwsIDEwMUwsIDI5TCwgNDhMLCAKMTEyTCwgMTAwTCwgODFMLCA0OEwsIDkwTCwgODFMLCAxMDhMLCA2OEwsIDI1TCwgMTAwTCwgMjBMLCAzNUwsIAo2NUwsIDkwTCwgOTBMKSwgLkRpbSA9IGMoNTBMLCA1TCksIC5EaW1uYW1lcyA9IGxpc3QoYygiUXVpbGF2YSIsIAoiR29vZHJhIiwgIk1vdGhpbSIsICJNYXJvd2FrIiwgIkNoYW5kZWx1cmUiLCAiSGVsaW9wdGlsZSIsICJNZWxvZXR0YUFyaWEgRm9ybWUiLCAKIk1ldGFncm9zc01lZ2EgTWV0YWdyb3NzIiwgIlNhd3NidWNrIiwgIlByb2JvcGFzcyIsICJHaXJhdGluYUFsdGVyZWQgRm9ybWUiLCAKIlRyYW5xdWlsbCIsICJTaW1pc2FnZSIsICJTY2l6b3IiLCAiSmlnZ2x5cHVmZiIsICJDYXJyYWNvc3RhIiwgCiJGZXJyb3Rob3JuIiwgIkthZGFicmEiLCAiU3lsdmVvbiIsICJHb2xlbSIsICJNYWduZW1pdGUiLCAiVmFuaWxsaXNoIiwgCiJVbm93biIsICJTbml2eSIsICJUeW5hbW8iLCAiRHVza3VsbCIsICJCZWF1dGlmbHkiLCAiTWFyaWxsIiwgCiJMdW5hdG9uZSIsICJGbHlnb24iLCAiQnJvbnpvciIsICJNb25mZXJubyIsICJTaW1pc2VhciIsICJBcm9tYXRpc3NlIiwgCiJTY3JhZ2d5IiwgIlNjb2xpcGVkZSIsICJTdGFyYXB0b3IiLCAiR3lhcmFkb3NNZWdhIEd5YXJhZG9zIiwgCiJUeXJ1bnQiLCAiWmVrcm9tIiwgIkd5YXJhZG9zIiwgIkNvYmFsaW9uIiwgIkVzcHVyciIsICJTcGhlYWwiLCAKIkRvZHJpbyIsICJUb3Jrb2FsIiwgIkNhY25lYSIsICJUcnViYmlzaCIsICJMdWNhcmlvIiwgIkdpcmF0aW5hT3JpZ2luIEZvcm1lIgopLCBjKCJUb3RhbCIsICJIaXRQb2ludHMiLCAiQXR0YWNrIiwgIkRlZmVuc2UiLCAiU3BlZWQiKSkpKQpgYGAKYGBge3J9CiMgTWVhbiBvZiBlYWNoIHZhcmlhYmxlCmNvbE1lYW5zKHBva2Vtb24pCgojIFN0YW5kYXJkIGRldmlhdGlvbiBvZiBlYWNoIHZhcmlhYmxlCmFwcGx5KHBva2Vtb24sIDIsIHNkKQoKIyBQQ0EgbW9kZWwgd2l0aCBzY2FsaW5nOiBwci53aXRoLnNjYWxpbmcKcHIud2l0aC5zY2FsaW5nIDwtIHByY29tcCh4ID0gcG9rZW1vbl9wY2EsIHNjYWxlID0gVFJVRSkKCiMgUENBIG1vZGVsIHdpdGhvdXQgc2NhbGluZzogcHIud2l0aG91dC5zY2FsaW5nCnByLndpdGhvdXQuc2NhbGluZyA8LSBwcmNvbXAoeCA9IHBva2Vtb25fcGNhLCBzY2FsZSA9IEZBTFNFKQoKIyBDcmVhdGUgYmlwbG90cyBvZiBib3RoIGZvciBjb21wYXJpc29uCmJpcGxvdChwci53aXRoLnNjYWxpbmcpCmJpcGxvdChwci53aXRob3V0LnNjYWxpbmcpCgpgYGAKVGhlIG5ldyBUb3RhbCBjb2x1bW4gY29udGFpbnMgbXVjaCBtb3JlIHZhcmlhdGlvbiwgb24gYXZlcmFnZSwgdGhhbiB0aGUgb3RoZXIgZm91ciBjb2x1bW5zLCBzbyBpdCBoYXMgYSBkaXNwcm9wb3J0aW9uYXRlIGVmZmVjdCBvbiB0aGUgUENBIG1vZGVsIHdoZW4gc2NhbGluZyBpcyBub3QgcGVyZm9ybWVkLiBBZnRlciBzY2FsaW5nIHRoZSBkYXRhLCB0aGVyZSdzIGEgbXVjaCBtb3JlIGV2ZW4gZGlzdHJpYnV0aW9uIG9mIHRoZSBsb2FkaW5nIHZlY3RvcnMu