2. Extending nTARP to form multiple clusters
In most cases, it is desirable to form more than two clusters for a
dataset. To support this, the nTARP package includes a function called
nTARP_bisecting, which applies nTARP in a
recursive bisecting fashion. This function repeatedly splits clusters
until a minimum cluster size is reached.
The arguments are the same as for the standard nTARP
function, with the addition of a new argument:
minimum_cluster_size_percent. This argument provides a
stopping rule to prevent clusters from being broken down into very small
groups. The function will stop splitting a cluster if its size is
smaller than the percentage specified. By default, this threshold is set
to 20%.
set.seed(123532) #random seed for reproducibility
cluster_solution_bisecting <- nTARP_bisecting(data = iris[,1:4],
number_of_projections = 1000,
withinss_threshold = 0.36,
minimum_cluster_size_percent = 20 #default value
)
After running the nTARP_bisecting function, you will
obtain three main outputs:
-A list of the individual nTARP solutions (as described in Section
1). -The best clusters at each step, based on the within-cluster sum of
squares. -All within-cluster sum of squares values for each solution at
each step.
The most useful output for users is the BestClusters
entry. Examining this output provides information on cluster sizes,
cluster labels, and the within-cluster sum of squares for each selected
solution.
cluster_solution_bisecting$BestClusters
Ultimately, we want to obtain the final cluster labels for each
observation. This can be done using the
build_solution_from_labeled_clusters function, which
returns a data frame detailing how each datapoint was clustered.
The function requires two inputs: -The BestClusters
output from the nTARP_bisecting function. -A vector of IDs
to identify each observation.
If you don’t have specific IDs to track observations, you can simply
use 1:nrow(x), where x is your dataset. This
assigns sequential numeric labels to each row.
labeled_clusters <- build_solution_from_labeled_clusters(nTARP_best_clusters= cluster_solution_bisecting$BestClusters, ids = 1:nrow(iris))
labeled_clusters[sample(1:150,10,replace = FALSE),] #We'll take a sampling of the observations
When we inspect the result of
build_solution_from_labeled_clusters, we can see that the
data frame keeps track of which solutions each observation participated
in using a numeric coding system.
- Each solution starts with Cluster 0, representing the first split of
the dataset into two clusters.
- Subsequent numbers in the code indicate which cluster from the
previous split was further subdivided.
For example, a code like Cluster 012 means: - The observation was in
cluster 1 during the first split. - Then, when cluster 1 was subdivided,
the observation ended up in cluster 2 of the next split.
Finally, these cluster path codes are translated into a single
integer to record the final cluster assignment for each observation.
#2.1 Trimming clusters If you think that the resulting clusters are
too small after reviewing the output of
build_solution_from_labeled_clusters, we have a simple function called
consolidate_clusters that can be used. Let’s see what we
have here relative to the class labels we expected from this
dataset:
table(labeled_clusters$FinalClusterID,iris$Species)
It appears that nTARP was able to cluster the three
flower types reasonably well, but it split clusters too finely. To
reconcile this, we can use the consolidate_clusters
function.
The only inputs required are: - The output from
build_solution_from_labeled_clusters - The two clusters you
want to combine.
The function returns a data frame with the clusters merged, and we
can reassign the labeled_clusters variable with this
updated result:
labeled_clusters <- consolidate_clusters(cluster_path_matrix = labeled_clusters,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters$FinalClusterID,iris$Species)
From the second line, we can see that we lost one cluster as a result
of the merging. We can keep doing this two more times.
#Merge clusters two more times
labeled_clusters <- consolidate_clusters(cluster_path_matrix = labeled_clusters,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
labeled_clusters <- consolidate_clusters(cluster_path_matrix = labeled_clusters,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters$FinalClusterID,iris$Species)
After this pruning step, we find that the clustering split the flower
types with 97% accuracy.
#2.2 Using a contextual variable to support clustering Because of how
nTARP operates, we are effectively taking multiple random
“slices” of the same dataset and obtaining different candidate
clusterings. At its core, cluster analysis is descriptive—we are
building a useful representation of the structure in our data so that we
can ultimately act on what we learn about subgroups.
But what if there is a variable you would like to use to guide the
clustering process?
Instead of selecting the best solution based solely on the
within-cluster sum of squares, we can modify the objective function to
evaluate how well candidate clusterings separate observations with
respect to a contextual variable. In other words, we can allow
nTARP to search for structure that is meaningful relative
to some external criterion.
More specifically, we can approach clustering in a way similar to a
decision tree.
In the traditional CART algorithm, splits are chosen to maximize
separation of predefined class labels by minimizing node “impurity”
(e.g., Gini index). Similarly, in nTARP, we can evaluate
candidate clusterings based on how well they separate observations
according to a contextual variable, such as a known class label.
To evaluate the internal validity of a clustering solution and
examine how well clusters differ on a given variable, we use an impurity
metric known as the Gini index.
Originally developed to measure income inequality, the Gini index has
since been widely adopted in machine learning, particularly in training
decision tree models. In clustering contexts, it provides a measure of
how homogeneous each cluster is with respect to a categorical
variable.
The Gini index for a cluster \(t\),
denoted as \(\text{Gini}(t)\), is
defined as:
\[
\text{Gini}(t) = 1 - \sum_{i=1}^{c} p(i \mid t)^2
\] where:
- \(c\) is the number of class
labels,
- \(p(i \mid t)\) is the proportion
of observations belonging to class \(i\) within cluster \(t\).
Lower Gini values indicate greater purity (i.e., more homogeneous
clusters), while higher values indicate greater impurity.
To assess how well a clustering solution separates observations based
on a particular variable, we compute the gain, defined as
the reduction in impurity from the full dataset (parent node) to the set
of clusters.
The gain is calculated as:
\[
\text{Gain} = \text{Gini}(\text{Parent}) - \sum_{t=1}^{g} \frac{n_t}{n}
\, \text{Gini}(t)
\]
where:
- \(\text{Gini}(\text{Parent})\) is
the Gini index of the entire dataset prior to clustering,
- \(g\) is the number of
clusters,
- \(n_t\) is the number of
observations in cluster \(t\),
- \(n\) is the total number of
observations.
The gain represents the weighted reduction in impurity
achieved by the clustering solution. Larger gain values
indicate that the clusters more effectively separate observations on the
chosen variable.
The maximum possible gain is equal to \(\text{Gini}(\text{Parent})\), which would
occur if each cluster were perfectly pure with respect to the variable
(i.e., all \(\text{Gini}(t) = 0\)).
To illustrate the process, Figure 3 presents a simplified flowchart
of the bisecting nTARP algorithm, highlighting its general workflow
without delving into the more nitpicky details.
Figure 3: How the nTARP process works when
iteratively breaking down clusters with and without a contextual
variable

Let’s see how this works for the iris dataset, where the
goal is to cluster observations with respect to the Species
variable. We use the exact same function as before, but now we add the
contextual variable:
set.seed(123532) #random seed for reproducibility
cluster_solution_bisecting_contextual <- nTARP_bisecting(data = iris[,1:4],
number_of_projections = 1000,
withinss_threshold = 0.36,
minimum_cluster_size_percent = 20,
contextual_variable = iris$Species
)
labeled_clusters <- build_solution_from_labeled_clusters(nTARP_best_clusters= cluster_solution_bisecting_contextual$BestClusters, ids = 1:nrow(iris))
If it’s desirable to do so, you can append the contextual data to the
output of build_solution_from_labled_clusters using the
optional argument contextual_variables_df. Here, we can
just append the iris data as an example.
labeled_clusters_with_context <- build_solution_from_labeled_clusters(nTARP_best_clusters= cluster_solution_bisecting_contextual$BestClusters, ids = 1:nrow(iris), contextual_variables_df = iris)
head(labeled_clusters_with_context)
Let’s take a look at the results…
table(labeled_clusters$FinalClusterID,iris$Species)
First, when using a contextual variable, you may notice that the
nTARP function is less aggressive in splitting clusters
unnecessarily. In fact, for the first split in both cases, it already
identified a cluster containing only a single class. With the contextual
variable, the algorithm recognizes that further splitting is unnecessary
and stops appropriately.
Without a contextual variable, the function may continue splitting,
potentially creating clusters that are too fine. In the author’s
experience, over-splitting is generally safer than under-splitting, as
the resulting clusters can always be merged later.
To clean up the solution, we can use the
consolidate_clusters function. For example, we can merge
clusters 1 and 2 to ensure that all virginica observations are grouped
together:
labeled_clusters <- consolidate_clusters(cluster_path_matrix = labeled_clusters,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters$FinalClusterID,iris$Species)
You’ll notice that this contextual variable made our clustering even
better, with 99% accuracy.
By recursively bisecting clusters and assessing cluster “quality”
through metrics like normalized within-cluster sum of squares or
Gini-based purity gains, nTARP can uncover structure in
high-dimensional data while controlling for minimum cluster size. The
approach is flexible, allowing post-hoc merging of clusters, and is
particularly well-suited for applications where standard clustering
algorithms struggle with sparse, high-dimensional, or noisy data.
#3. Another high dimensional example To close out the demonstration,
we can try to apply nTARP to one more dataset, the wine
dataset from the HDclassif package. The wine
dataset from the HDclassif package contains 178
observations of wines derived from three different cultivars grown in
the same region of Italy. Each wine is described by 13 continuous
chemical measurements, such as alcohol content, flavanoids, magnesium,
color intensity, and proline, along with a class label indicating
cultivar membership.
library(HDclassif)
data(wine)
head(wine)
wine[,2:14] <- scale(wine[,2:14])
Like the iris dataset, the wine dataset
contains three distinct classes. However, unlike the iris
data—where the classes are perfectly balanced—the wine
dataset is moderately imbalanced. The imbalance is not extreme, but it
is worth noting, as class imbalance can influence both clustering
behavior and how we interpret separation quality.
table(wine$class)
We’ll try the bisecting nTARP approach without a contextual variable
first. We’ll also use more projections.
set.seed(123532) #random seed for reproducibility
cluster_solution_bisecting_wine <- nTARP_bisecting(data = wine[,2:14],
number_of_projections = 100^2,
withinss_threshold = 0.36,
minimum_cluster_size_percent = 20 #default value
)
labeled_clusters_wine <- build_solution_from_labeled_clusters(nTARP_best_clusters= cluster_solution_bisecting_wine$BestClusters, ids = 1:nrow(wine))
table(labeled_clusters_wine$FinalClusterID,wine$class)
Processing the clusters, we see that 1+2, 3+4, and 5+6 appear to be
reasonable combinations of clusters.
#Merge clusters two more times
print("This is the result of combining clusters 1 and 2, during which 3-6 were relabled to be 1-4 with the merged cluster being labeled 5.")
labeled_clusters_wine <- consolidate_clusters(cluster_path_matrix = labeled_clusters_wine,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters_wine$FinalClusterID,wine$class)
#Merge 1 and 2 again
print("This is the result of combining clusters 3 and 4 (that were relabeled 1 and 2 in the last step). Now there are 4 clusters left.")
labeled_clusters_wine <- consolidate_clusters(cluster_path_matrix = labeled_clusters_wine,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters_wine$FinalClusterID,wine$class)
#Merge 1 and 2 again
print("We combine that last two clusters, giving us 3 clusters at the end.")
labeled_clusters_wine <- consolidate_clusters(cluster_path_matrix = labeled_clusters_wine,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters_wine$FinalClusterID,wine$class)
Now that we’ve reduced the clusters to three, we can see we get an
accuracy of 92%. Let’s see if this improves with the contextual
variable.
set.seed(123532) #random seed for reproducibility
cluster_solution_bisecting_wine <- nTARP_bisecting(data = wine[,2:14],
number_of_projections = 100^2,
withinss_threshold = 0.36,
minimum_cluster_size_percent = 20,
contextual_variable = wine$class
)
labeled_clusters_wine <- build_solution_from_labeled_clusters(nTARP_best_clusters= cluster_solution_bisecting_wine$BestClusters, ids = 1:nrow(wine))
table(labeled_clusters_wine$FinalClusterID,wine$class)
Processing the clusters, we see that 1+2 and 3+4 appear to be
reasonable combinations of clusters.
#Merge clusters two more times
print("This is the result of combining clusters 1 and 2, during which 3-5 were relabled to be 1-3 with the merged cluster being labeled 4.")
labeled_clusters_wine <- consolidate_clusters(cluster_path_matrix = labeled_clusters_wine,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters_wine$FinalClusterID,wine$class)
#Merge 1 and 2 again
print("We combine that last two clusters, giving us 3 clusters at the end.")
labeled_clusters_wine <- consolidate_clusters(cluster_path_matrix = labeled_clusters_wine,
first_cluster_to_combine = 1,
second_cluster_to_combine = 2)
table(labeled_clusters_wine$FinalClusterID,wine$class)
Now that we’ve reduced the solution to three clusters, the clustering
aligns closely with the true wine cultivars, yielding an accuracy of
98%. This demonstrates that nTARP, especially when combined
with post-processing (e.g., consolidate_clusters), can recover
meaningful structure even in moderately imbalanced datasets.
Importantly, the contextual variable does not have to be a class
label; it can be any categorical variable of interest. Using a
contextual variable allows nTARP to guide the clustering toward patterns
that are most relevant for a particular analytical or predictive goal,
much like how decision trees split nodes to maximize purity with respect
to a target variable.
LS0tDQp0aXRsZTogIlRoZSBuVEFSUCBQYWNrYWdlIg0KYXV0aG9yOiBEYXZpZCBSZWVwaW5nDQpvdXRwdXQ6IHJtYXJrZG93bjo6aHRtbF92aWduZXR0ZQ0KdmlnbmV0dGU6ID4NCiAgJVxWaWduZXR0ZUluZGV4RW50cnl7blRBUlAgRG9jdW1lbnRhdGlvbn0NCiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQ0KICAlXFZpZ25ldHRlRW5jb2Rpbmd7VVRGLTh9DQotLS0NCg0KIyAxLiBJbnRyb2R1Y3Rpb24gdG8gdGhlIG4tVEFSUCBjbHVzdGVyaW5nIG1ldGhvZA0KVGhpcyBSIE5vdGVib29rIGRvY3VtZW50cyB0aGUgZnVuY3Rpb25hbGl0eSBvZiB0aGUgblRBUlAgcGFja2FnZS4gQXQgaXRzIGNvcmUsIHRoZSBwYWNrYWdlIGltcGxlbWVudHMgYSBoaWdoLWRpbWVuc2lvbmFsIGNsdXN0ZXJpbmcgdGVjaG5pcXVlIGNhbGxlZCBUaHJlc2hvbGRpbmcgQWZ0ZXIgUmFuZG9tIFByb2plY3Rpb25zIChuLVRBUlApLiBJbiBtYW55IGRhdGFzZXRzLCB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyAoZGltZW5zaW9uYWxpdHkpIGNhbiBiZSBtdWNoIGxhcmdlciB0aGFuIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zLCB3aGljaCBjYW4gbWFrZSB0cmFkaXRpb25hbCBkaXN0YW5jZS1iYXNlZCBjbHVzdGVyaW5nIGFwcHJvYWNoZXMgdW5yZWxpYWJsZSBvciBwcm9uZSB0byBub24tY29udmVyZ2VuY2UuIFRvIGFkZHJlc3MgdGhpcywgbi1UQVJQIHByb2plY3RzIHRoZSBoaWdoLWRpbWVuc2lvbmFsIGRhdGEgKGluIFwoIEQgXCkpIGludG8gb25lLWRpbWVuc2lvbmFsIHNwYWNlcyAoaW4gXCggRCcgXCkpIHJlcGVhdGVkbHkgYW5kIGFwcGxpZXMgay1tZWFucyBpbiBlYWNoIHByb2plY3Rpb24gdG8gaWRlbnRpZnkgY2x1c3RlcnMgKHR5cGljYWxseSBzcGxpdHRpbmcgdGhlIGRhdGEgaW50byB0d28gY2x1c3RlcnMgYXQgZWFjaCBzdGVwKS4gDQoNCioqRmlndXJlIDE6KiogVGhlIHByZW1pc2Ugb2Ygbi1UQVJQLCBwcm9qZWN0aW5nIGRhdGEgZnJvbSBoaWdoZXIgZGltZW5zaW9ucyBpbnRvIDEtRCB1c2luZyByYW5kb20gcHJvamVjdGlvbnMgdG8gZmluZCB0aGUgYmVzdCBjbHVzdGVyaW5nIA0KDQohW10oLi4vaW5zdC9maWd1cmVzL25UQVJQX2lsbHVzdHJhdGlvbi5wbmcpe3dpZHRoPTgwJX0NCg0KVGhlIGFsZ29yaXRobSBmbG93cyBsaWtlIHNvOg0KDQpMZXQgXCggeF8xLCBcZG90cywgeF9tIFxpbiBcbWF0aGJie1J9XnAgXCkgZGVub3RlIHRoZSBvYnNlcnZhdGlvbnMgaW4gdGhlIGRhdGFzZXQsIFwoIEQgXCkuIEFuZCBpbml0aWFsaXplIGxpc3RzLCBcKCBDIFwpICh0byBzdG9yZSBpbmRpdmlkdWFsIGNhbmRpZGF0ZSBjbHVzdGVyIHNvbHV0aW9ucyksIFwoIE0gXCkgKHRvIHN0b3JlIHRoZSBjbHVzdGVyIG1lbWJlcnNoaXAgZm9yIGVhY2ggXCggeF9pIFwpKSwgYW5kIFwoIFdfTCBcKSAodG8gc3RvcmUgdGhlIHdpdGhpbiBzdW0gb2Ygc3F1YXJlcyBmb3IgZWFjaCBjYW5kaWRhdGUgc29sdXRpb24pLg0KDQoxLiBGb3IgZWFjaCBwcm9qZWN0aW9uLCBcKCBpID0gMSwgXGRvdHMsIG4gXCk6DQoNCiAgIGEuIEdlbmVyYXRlIGEgcmFuZG9tIHZlY3RvciBcKCByX2kgXGluIFxtYXRoYmJ7Un1ecCBcKS4NCg0KICAgYi4gUHJvamVjdCBlYWNoIG9ic2VydmF0aW9uIFwoIHhfaiBcKSBvbnRvIFwoIHJfaSBcKSB1c2luZyB0aGUgZG90IHByb2R1Y3QgdG8gZm9ybSB0aGUgcHJvamVjdGVkIGRhdGFzZXQgXCggRF9pJyBcKToNCiAgICQkDQogICB4X2peXHRvcCByX2kNCiAgICQkDQogICBjLiBBcHBseSAyLW1lYW5zIGNsdXN0ZXJpbmcgdG8gdGhlIHByb2plY3RlZCB2YWx1ZXMgaW4gXCggRF9pJyBcKSB0byBvYnRhaW4gdHdvIGNsdXN0ZXJzLiBTdG9yZSB0aGUgY2x1c3RlciBtZW1iZXJzaGlwIGZvdW5kIGluIFwoIE0gXCkgYW5kIHRoZSBrbWVhbnMgb2JqZWN0IGluIFwoIEMgXCkuDQoNCiAgIGQuIENvbXB1dGUgdGhlIG5vcm1hbGl6ZWQgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMgXCggV19pIFwpIGZvciB0aGlzIGNsdXN0ZXJpbmcgYW5kIGFkZCBpdCB0byB0aGUgbGlzdCBcKCBXX0wgXCkuDQoNCjIuIEVuZCBsb29wLg0KDQozLiBJZGVudGlmeSBhbmQgc3RvcmUgdGhlIG9wdGltYWwgcmFuZG9tIHZlY3RvciBcKCByX2kqIFwpIGFzc29jaWF0ZWQgd2l0aCB0aGUgc21hbGxlc3Qgd2l0aGluIHN1bSBvZiBzcXVhcmVzIHZhbHVlIFwoIFdfaSogXCkuIFNldCB0aGUgb3B0aW1hbCBjbHVzdGVyIHNvbHV0aW9uIFwoIEMqIFwpIGFzIHRoZSBrbWVhbnMgb2JqZWN0IGFzc29jaWF0ZWQgd2l0aCBcKCByX2kqIFwpIGFuZCBcKCBXX2kqIFwpLg0KDQo0LiBTZXQgXCggbV8xIFwpIHRvIGJlIHRoZSBtZWFuIG9mIGNsdXN0ZXIgMSBhbmQgXCggbV8yIFwpIHRvIGJlIHRoZSBtZWFuIG9mIGNsdXN0ZXIgMiBmcm9tIHRoZSBvcHRpbWFsIHNvbHV0aW9uLiBJZiB0aGUgXCggbV8xID4gbV8yIFwpLCBzZXQgdGhlIGRpcmVjdGlvbiB2ZWN0b3IgXCggZCBcKSB0byBiZSAxLiBFbHNlLCBzZXQgXCggZCBcKSBhcyAyLiAgDQoNCjUuIENvbXB1dGUgYW5kIHN0b3JlIHRoZSB0aHJlc2hvbGQgXCggdCBcKSB0aGF0IHNlcGFyYXRlcyB0aGUgdHdvIGNsdXN0ZXJzIGFsb25nIHRoZSBzZWxlY3RlZCBwcm9qZWN0aW9uLiBUaGUgdGhyZXNob2xkIGlzIGVzc2VudGlhbGx5IHRoZSBoYWxmd2F5IHBvaW50IGJldHdlZW4gdGhlIGV4dHJlbWUgdmFsdWVzIG9mIHRoZSB0d28gY2x1c3RlcnMuIExldCBcKCBEX2leeygxKX0gXCkgYmUgdGhlIHByb2plY3RlZCBwb2ludHMgYmVsb25naW5nIHRvIGNsdXN0ZXIgMSBhbmQgXCggRF9pXnsoMil9IFwpIGJlIHRoZSBwcm9qZWN0ZWQgcG9pbnRzIGJlbG9uZ2luZyB0byBjbHVzdGVyIDIsIHRoZW46DQoNCiQkDQpcdGV4dHtJZiB9IGQgPSAxOiBccXVhZCANClxmcmFje1xtaW4oRF9pXnsoMSl9KSAtIFxtYXgoRF9pXnsoMil9KX17Mn0gKyBcbWF4KERfaV57KDIpfSkgXFxbMWVtXQ0KXHRleHR7SWYgfSBkID0gMjogXHF1YWQgDQpcZnJhY3tcbWluKERfaV57KDIpfSkgLSBcbWF4KERfaV57KDEpfSl9ezJ9ICsgXG1heChEX2leeygxKX0pDQokJA0KDQpBIGZsb3djaGFydCBjYW4gc3VtbWFyaXppbmcgdGhlIHByb2Nlc3MgY2FuIGJlIHNlZW4gYmVsb3cgaW4gRmlndXJlIDIuDQoNCioqRmlndXJlIDI6KiogSG93IHRoZSBuVEFSUCBwcm9jZXNzIHdvcmtzDQoNCiFbXSguLi9pbnN0L2ZpZ3VyZXMvblRBUlBfZ2VuZXJpYy5wbmcpDQoNCkFzIHlvdSBtaWdodCBnYXRoZXIgZnJvbSB0aGUgbG9vcCBhdCB0aGUgY29yZSBvZiB0aGUgYWxnb3JpdGhtLCBzZXZlcmFsIGNhbmRpZGF0ZSBzb2x1dGlvbnMgYXJlIGdlbmVyYXRlZCBhbmQgb25lIGlzIGNob3NlbiBiYXNlZCBvbiB0aGUgd2l0aGluIHN1bSBvZiBzcXVhcmVzLiBBbHRob3VnaCBuLVRBUlAgaGFzIGJlZW4gdXNlZCBzcGFyaW5nbHksIGl0cyBhcHBsaWNhdGlvbnMgaGF2ZSBiZWVuIG5vdGFibHkgZGl2ZXJzZS4gSW4gc29tZSBjYXNlcywgcmVzZWFyY2hlcnMgaGF2ZSBhZGRyZXNzZWQgdGhlIHJhbmRvbW5lc3Mgb2YgdGhlIGFsZ29yaXRobSBieSB0cmFja2luZyBjbHVzdGVyIG1lbWJlcnNoaXAgYWNyb3NzIGl0ZXJhdGlvbnMgYW5kIGFnZ3JlZ2F0aW5nIHJlc3VsdHMgaW50byBjb21wb3NpdGUgcHJvZmlsZXMuIEluIG90aGVycywgbi1UQVJQIGhhcyBiZWVuIGFwcGxpZWQgYXMgYSBjb252ZW50aW9uYWwgY2x1c3RlcmluZyB0b29sIHRvIGlkZW50aWZ5IG1lYW5pbmdmdWwgc3BsaXRzIGJldHdlZW4gcGFydGljaXBhbnQgZ3JvdXBzLg0KDQpBIGNvbmNlcHR1YWxseSBkaXN0aW5jdCB1c2Ugb2Ygbi1UQVJQIGlzIGFzIGEgY2xhc3NpZmllci4gQWZ0ZXIgdHJhaW5pbmcsIHRoZSBhbGdvcml0aG0geWllbGRzIHR3byBrZXkgcGFyYW1ldGVyczogKDEpIHRoZSBvcHRpbWFsIHJhbmRvbSBwcm9qZWN0aW9uIGFzc29jaWF0ZWQgd2l0aCB0aGUgc21hbGxlc3Qgbm9ybWFsaXplZCB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyBhbmQgKDIpIHRoZSB0aHJlc2hvbGQgc2VwYXJhdGluZyBjbHVzdGVycyBhbG9uZyB0aGF0IHByb2plY3Rpb24uIEluIHNvbWUgYXBwbGljYXRpb25zLCByZXNlYXJjaGVycyBoYXZlIHVzZWQgbi1UQVJQIHRvIGNsYXNzaWZ5IGluZGl2aWR1YWxzIGFuZCB0aGVuIGV4YW1pbmUgaG93IHRoZSByZXN1bHRpbmcgcGF0dGVybnMgcmVsYXRlIHRvIGV4dGVybmFsIG91dGNvbWVzLCBleHRlbmRpbmcgdGhlIG1ldGhvZCBiZXlvbmQgZGVzY3JpcHRpb24gaW50byBpbmZlcmVudGlhbCBhbmFseXNpcy4NCg0KVG9nZXRoZXIsIHRoZXNlIGV4YW1wbGVzIGlsbHVzdHJhdGUgdGhlIGZsZXhpYmlsaXR5IG9mIG4tVEFSUCwgd2hpY2ggYXJlIG5vdyBhY2Nlc3NpYmxlIHRocm91Z2ggdGhpcyBwYWNrYWdlLg0KDQojIDEuMSBJbnN0YWxsaW5nIHRoZSBwYWNrYWdlIGFuZCBydW5uaW5nIHRoZSBjb3JlIG4tVEFSUCBmdW5jdGlvbg0KDQpMZXQncyBsb2FkIHRoZSBwYWNrYWdlLg0KDQpgYGB7cn0NCmxpYnJhcnkoblRBUlApDQpgYGANCg0KVG8gaWxsdXN0cmF0ZSBob3cgdGhlIG1ldGhvZCB3b3Jrcywgd2Ugd2lsbCB1c2UgdGhlIGNsYXNzaWMgYGlyaXNgIGRhdGFzZXQsIHdoaWNoIGNvbnRhaW5zIHRocmVlIHR5cGVzIG9mIGZsb3dlcnMuIE91ciBnb2FsIGlzIHRvIGNsdXN0ZXIgdGhlIG9ic2VydmF0aW9ucyBiYXNlZCBvbiB0aGUgZm91ciBtZWFzdXJlZCB2YXJpYWJsZXMuIA0KDQpgYGB7cn0NCmRhdGEoaXJpcykNCmhlYWQoaXJpcykNCmBgYA0KDQpOb3RlIHRoYXQgdGhlcmUgYXJlIDE1MCBvYnNlcnZhdGlvbnMgd2l0aCB0aHJlZSBjbGFzc2VzLCA1MCBvYnNlcnZhdGlvbnMgZWFjaC4gDQoNCmBgYHtyfQ0KdGFibGUoaXJpcyRTcGVjaWVzKQ0KYGBgDQoNClRoZSBwcmltYXJ5IGZ1bmN0aW9uIGluIHRoZSBwYWNrYWdlIGlzIGBuVEFSUGAuIFRvIHVzZSBpdCwgdGhlIG1haW4gaW5wdXQgaXMgdGhlIGRhdGFzZXQgdG8gYmUgY2x1c3RlcmVkLg0KDQpZb3UgbXVzdCB0aGVuIHNwZWNpZnkgdGhlIG51bWJlciBvZiBwcm9qZWN0aW9ucywgd2hpY2ggZGV0ZXJtaW5lcyBob3cgbWFueSByYW5kb20gdmVjdG9ycyBhcmUgdXNlZCB0byBwcm9qZWN0IHRoZSBkYXRhIGludG8gb25lLWRpbWVuc2lvbmFsIHNwYWNlcyBmb3IgY2x1c3RlcmluZy4gQSBjb21tb24gc3RhcnRpbmcgdmFsdWUgaXMgMSwwMDAgcHJvamVjdGlvbnMsIGluY3JlYXNpbmcgdG8gMTAsMDAwIG9yIG1vcmUgZm9yIGRhdGFzZXRzIHdpdGggbGFyZ2VyIHNhbXBsZSBzaXplcyBvciBoaWdoZXIgZGltZW5zaW9uYWxpdHkuIFRoZXJlIGlzIGdlbmVyYWxseSBubyBzdGF0aXN0aWNhbCBkaXNhZHZhbnRhZ2UgdG8gaW5jcmVhc2luZyB0aGUgbnVtYmVyIG9mIHByb2plY3Rpb25z4oCUb25seSBhZGRpdGlvbmFsIGNvbXB1dGF0aW9uYWwgdGltZSBhbmQgcmVzb3VyY2UgdXNlLg0KDQpGaW5hbGx5LCB0aGUgYHdpdGhpbnNzX3RocmVzaG9sZGAgYXJndW1lbnQgc2V0cyB0aGUgbWF4aW11bSBub3JtYWxpemVkIHdpdGhpbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmVzIHRoYXQgYSBjYW5kaWRhdGUgc29sdXRpb24gY2FuIGhhdmUgdG8gYmUgY29uc2lkZXJlZCBhY2NlcHRhYmxlLiBCYXNlZCBvbiBwcmlvciB3b3JrIChZZWxsYW1yYWp1ICYgQm91dGluLCAyMDE4LCBJRUVFIFRyYW5zYWN0aW9ucyBvbiBJbWFnZSBQcm9jZXNzaW5nLCAyNyg0KSwgMTkyN+KAkzE5MzgpLCBhIHZhbHVlIG9mIDAuMzYgb3IgbG93ZXIgaXMgb2Z0ZW4gYSByZWFzb25hYmxlIGJlbmNobWFyayBmb3IgZGV0ZXJtaW5pbmcgd2hldGhlciBhIHNvbHV0aW9uIGNvbnRhaW5zIHN1ZmZpY2llbnQgc3RydWN0dXJlLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMzUzMikgI3JhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkNCmNsdXN0ZXJfc29sdXRpb24gPC0gblRBUlAoZGF0YSA9IGlyaXNbLDE6NF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9vZl9wcm9qZWN0aW9ucyA9IDEwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhpbnNzX3RocmVzaG9sZCA9IDAuMzYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCiMgMS4xIEdldHRpbmcgdGhlIG9wdGltYWwgc29sdXRpb24gZnJvbSB0aGUgblRBUlAgZnVuY3Rpb24NCg0KRnJvbSBoZXJlLCB0aGVyZSBhcmUgc2V2ZXJhbCB3YXlzIHRvIGV4cGxvcmUgdGhlIHJlc3VsdHMuIFdlIGNhbiBleGFtaW5lIHRoZSBvdXRwdXRzIG9uZSBieSBvbmUuDQoNClRoZSBmaXJzdCBvdXRwdXQgaXMgdGhlIHJlc3VsdCBvZiB0aGUgYGttZWFuc2AgZnVuY3Rpb24gY29ycmVzcG9uZGluZyB0byB0aGUgYmVzdCBjbHVzdGVyaW5nIHNvbHV0aW9uIGlkZW50aWZpZWQgYWNjb3JkaW5nIHRvIHRoZSB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyBjcml0ZXJpb24uIFRoaXMgb2JqZWN0IGNvbnRhaW5zOg0KDQotIFRoZSBjbHVzdGVyIGNlbnRlcnMNCi0gVGhlIGNsdXN0ZXJpbmcgdmVjdG9yIChmaW5hbCBjbHVzdGVyIGxhYmVscyBmb3IgZWFjaCBvYnNlcnZhdGlvbikNCi0gVGhlIHdpdGhpbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmVzDQotIFRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZA0KDQpJZiB5b3Ugd291bGQgbGlrZSB0byBpbnNwZWN0IHRoaXMgc29sdXRpb24gZGlyZWN0bHksIHlvdSBjYW4gYWNjZXNzIGl0IGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KY2x1c3Rlcl9zb2x1dGlvbiRPcHRpbWFsU29sdXRpb24NCnBhc3RlKCJUaGUgb3B0aW1hbCB3aXRoaW4gc3VtIG9mIHNxdWFyZXMgd2FzIiwgcm91bmQoY2x1c3Rlcl9zb2x1dGlvbiRPcHRpbWFsV2l0aGluc3MsMikpDQpgYGANCg0KIyAxLjIgVXNpbmcgdGhlIHJlc3VsdHMgb2YgblRBUlAgYXMgYSBjbGFzc2lmaWVyDQoNClRoZSBuZXh0IG91dHB1dHMgb2YgdGhlIG5UQVJQIGZ1bmN0aW9uIGFyZSBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciB0aG9zZSB3aG8gd2FudCB0byB1c2UgblRBUlAgYXMgYSBjbGFzc2lmaWVyIOKAlCB0aGF0IGlzLCB0byBjbGFzc2lmeSBuZXcgZGF0YSBwb2ludHMgdXNpbmcgdGhlIGJlc3QgcmFuZG9tIHByb2plY3Rpb24uIFRoZSB0aHJlZSByZWxldmFudCBvdXRwdXRzIGFyZSBgT3B0aW1hbFByb2plY3Rpb25gLCBgVGhyZXNob2xkYCwgYW5kIGBEaXJlY3Rpb25gLg0KDQotYE9wdGltYWxQcm9qZWN0aW9uYCBpcyB0aGUgcmFuZG9tIHZlY3RvciBhc3NvY2lhdGVkIHdpdGggdGhlIHNvbHV0aW9uIHRoYXQgaGFzIHRoZSBzbWFsbGVzdCB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcy4NCi1gVGhyZXNob2xkYCBzcGVjaWZpZXMgdGhlIGJvdW5kYXJ5IHRoYXQgc2VwYXJhdGVzIGNsdXN0ZXIgMSBmcm9tIGNsdXN0ZXIgMiBpbiB0aGUgb25lLWRpbWVuc2lvbmFsIHByb2plY3RlZCBzcGFjZS4NCi1gRGlyZWN0aW9uYCBpbmRpY2F0ZXMgd2hpY2ggY2x1c3RlciBoYXMgdGhlIGxhcmdlciBtZWFuIGFsb25nIHRoZSBvcHRpbWFsIHByb2plY3Rpb24uDQoNClRvIGNsYXNzaWZ5IGEgbmV3IGRhdGEgcG9pbnQsIHlvdSBtdWx0aXBseSBpdCBieSB0aGUgYE9wdGltYWxQcm9qZWN0aW9uYCB1c2luZyB0aGUgZG90IHByb2R1Y3QgdG8gZ2V0IGl0cyAxLUQgcHJvamVjdGlvbi4gVGhlbiBjb21wYXJlIHRoaXMgdmFsdWUgdG8gdGhlIFRocmVzaG9sZDoNCg0KLUlmIHRoZSBwcm9qZWN0ZWQgdmFsdWUgaXMgZ3JlYXRlciB0aGFuIHRoZSB0aHJlc2hvbGQsIGFzc2lnbiBpdCB0byB0aGUgY2x1c3RlciBpbmRpY2F0ZWQgYnkgRGlyZWN0aW9uLg0KLUlmIGl0IGlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byB0aGUgdGhyZXNob2xkLCBhc3NpZ24gaXQgdG8gdGhlIG90aGVyIGNsdXN0ZXIuDQoNClRoaXMgbWVjaGFuaXNtIGFsbG93cyBgblRBUlBgIHRvIGJlIHVzZWQgYXMgYSBzaW1wbGUgbGluZWFyIGNsYXNzaWZpZXIgYmFzZWQgb24gdGhlIGhpZ2gtZGltZW5zaW9uYWwgcHJvamVjdGlvbnMuDQoNCmBgYHtyfQ0KcHJpbnQoIlRoaXMgaXMgdGhlIHJhbmRvbSB2ZWN0b3IgYXNzb2NpYXRlZCB3aXRoIHRoZSBiZXN0IGNsdXN0ZXIuIikNCmNsdXN0ZXJfc29sdXRpb24kT3B0aW1hbFByb2plY3Rpb24NCnByaW50KCJUaGlzIGlzIHRoZSBib3VuZGFyeSB3aGVyZSB0aGUgY2x1c3RlcnMgdHJhbnNpdGlvbi4iKQ0KY2x1c3Rlcl9zb2x1dGlvbiRUaHJlc2hvbGQNCnByaW50KCJUaGUgKmRpcmVjdGlvbiogdGVsbHMgdXMgd2hpY2ggY2x1c3RlciBoYXMgdGhlIGxhcmdlciBtZWFuLCBzbyBpbiB0aGlzIGNhc2UsIHBvaW50cyB3aXRoIHZhbHVlcyBsYXJnZXIgdGhhbiB0aGUgdGhyZXNob2xkIHNob3VsZCBiZSBhc3NpZ25lZCB0byBjbHVzdGVyIDIuIikNCmNsdXN0ZXJfc29sdXRpb24kRGlyZWN0aW9uDQpgYGANCg0KRm9yIGV4YW1wbGUsIHdlIGNhbiB0YWtlIHRoZSBmaXJzdCByb3cgb2YgdGhlIGBpcmlzYCBkYXRhc2V0IGFuZCBzZWUgaG93IGl0IHdvdWxkIGJlIGFzc2lnbmVkIHRvIGEgY2x1c3RlciB1c2luZyB0aGUgblRBUlAgY2xhc3NpZmllci4gQnkgYXBwbHlpbmcgdGhlIGBPcHRpbWFsUHJvamVjdGlvbmAgYW5kIGNvbXBhcmluZyB0aGUgcHJvamVjdGVkIHZhbHVlIHRvIHRoZSBgVGhyZXNob2xkYCwgd2UgZmluZCB0aGF0IHRoZSBmaXJzdCBvYnNlcnZhdGlvbiBzaG91bGQgYmUgYXNzaWduZWQgdG8gY2x1c3RlciAyLiBXZSBjYW4gY29uZmlybSB0aGlzIGJ5IGNoZWNraW5nIHRoZSBvcHRpbWFsIHNvbHV0aW9uIGluIGBuVEFSUF9yZXN1bHQkT3B0aW1hbFNvbHV0aW9uYCDigJRpbmRlZWQsIHRoZSBmaXJzdCBvYnNlcnZhdGlvbiB3YXMgYXNzaWduZWQgdG8gY2x1c3RlciAyIQ0KDQpgYGB7cn0NCm9ic2VydmF0aW9uX3RvX2NsYXNzaWZ5IDwtIGlyaXNbMSwxOjRdDQpvYnNlcnZhdGlvbl9hZnRlcl9wcm9qZWN0aW9uIDwtIHN1bShvYnNlcnZhdGlvbl90b19jbGFzc2lmeSAqIGNsdXN0ZXJfc29sdXRpb24kT3B0aW1hbFByb2plY3Rpb24pDQpwcmludCgiVGhlIHJlc3VsdGluZyAxLUQgcHJvamVjdGlvbiBpcy4uLiIpDQpvYnNlcnZhdGlvbl9hZnRlcl9wcm9qZWN0aW9uIA0KcGFzdGUoIk91ciBkaXJlY3Rpb24sICIsIGNsdXN0ZXJfc29sdXRpb24kRGlyZWN0aW9uLCIsIHRlbGxzIHVzIHRoYXQgY2x1c3RlciAyIGhhcyBhIG1lYW4gYmlnZ2VyIHRoYW4gdGhlIHRocmVzaG9sZCwgc28gc2luY2UgdGhlIHByb2plY3RlZCB2YWx1ZSAiLCByb3VuZChvYnNlcnZhdGlvbl9hZnRlcl9wcm9qZWN0aW9uLDIpLCIgaXMgbGFyZ2VyIHRoYW4gdGhlIHRocmVzaG9sZCAiLHJvdW5kKGNsdXN0ZXJfc29sdXRpb24kVGhyZXNob2xkLDIpLCIgd2Ugc2hvdWxkIGFzc2lnbiBpdCB0byBjbHVzdGVyIDIuIiwgc2VwPSIiKQ0KYGBgDQoNCiMgMS4zIENoZWNraW5nIHRoZSBjbHVzdGVyYWJpbGl0eSBvZiB0aGUgZGF0YXNldA0KVGhlIG5leHQgb3V0cHV0IGFsbG93cyB1cyB0byBhc3Nlc3MgdGhlIG92ZXJhbGwgY2x1c3RlcmFiaWxpdHkgb2YgdGhlIGRhdGFzZXQuIFNpbmNlIGBuVEFSUGAgdXNlcyBtdWx0aXBsZSByYW5kb20gcHJvamVjdGlvbnMsIHlvdSBjYW4gZXhhbWluZSB0aGUgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMgKGB3aXRoaW5zc2ApIGZvciBlYWNoIGNhbmRpZGF0ZSBzb2x1dGlvbiBpdCBhdHRlbXB0ZWQuIEFzIHRoZSBudW1iZXIgb2YgcHJvamVjdGlvbnMgaW5jcmVhc2VzLCB0aGUgZGlzdHJpYnV0aW9uIG9mIGB3aXRoaW5zc2AgdmFsdWVzIHR5cGljYWxseSBhcHByb2FjaGVzIGEgbm9ybWFsIG9yIGFwcHJveGltYXRlbHkgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gV2hhdCB5b3Ugd2FudCB0byBsb29rIGZvciBpcyB0aGUgcHJvcG9ydGlvbiBvZiBzb2x1dGlvbnMgd2l0aCBgd2l0aGluc3NgIGJlbG93IHRoZSB0aHJlc2hvbGQgKGNvbW1vbmx5IDAuMzYpLiBUaGUgbGFyZ2VyIHRoaXMgcHJvcG9ydGlvbiwgdGhlIG1vcmUgZXZpZGVuY2UgdGhhdCB0aGUgZGF0YXNldCBjb250YWlucyBtZWFuaW5nZnVsIGNsdXN0ZXJzLg0KDQpgYGB7cn0NCmhpc3QoY2x1c3Rlcl9zb2x1dGlvbiRBbGxXaXRoaW5zcykNCmBgYA0KDQojIDEuNCBUaGUgbGFzdCBvdXRwdXRzIG9mIHRoZSBuVEFSUCBmdW5jdGlvbg0KVGhlIGZpbmFsIG91dHB1dHMgcHJvdmlkZSBhIGxpc3Qgb2YgYWxsIHRoZSBjbHVzdGVycywgdGhlIG9yaWdpbmFsIGRhdGEsIGFuZCBhbnkgSUQgbnVtYmVycyB1c2VkIHRvIGtlZXAgdHJhY2sgb2Ygb2JzZXJ2YXRpb25zIC0gdGhlIGxhdHRlciB0d28gb2Ygd2hpY2ggYXJlIHVzZWQgZm9yIGZ1bmN0aW9ucyBleHBhbmRpbmcgb24gdGhlIGJpY2x1c3RlcmluZyBuYXR1cmUgb2YgYG5UQVJQYC4gU28sIGlmIHlvdSB3YW50IHRvIHB1bGwgb3V0IGEgc3BlY2lmaWMgY2x1c3RlciBzb2x1dGlvbiwgeW91IGNhbiBkbyBzbyB1c2luZyB0aGUgYENsdXN0ZXJpbmdzYCBvdXRwdXQuIE5vdGUgdGhhdCB0aGUgc29sdXRpb25zIG5lZWQgdG8gYmUgdHJlYXRlZCBhcyBwYWlycywgc28gdGhlIGZpcnN0IGFuZCBzZWNvbmQgZW50cmllcyBhcmUgb25lIHNvbHV0aW9uIChhcyBzaG93biBpbiB0aGUgbmV4dCBjaHVuaykuIFRoZSBmdW5jdGlvbiBpcyB3cml0dGVuIHRoaXMgd2F5IGZvciB0aGUgcHVycG9zZXMgb2YgbWFraW5nIHRoZSBvdGhlciBmdW5jdGlvbmFsaXR5IGEgYml0IGVhc2llciB0byBydW4uIEl0J3Mgbm90IGFudGljaXBhdGVkIHRoYXQgdXNlcnMgd291bGQgYmUgaW50ZXJhY3Rpbmcgd2l0aCB0aGVzZSBvdXRwdXRzLCBhbmQgaXMgbW9yZSBzbyBmb3IgaW50ZXJuYWwgY2FsY3VsYXRpb25zLg0KDQpgYGB7cn0NCm9uZV9mZWFzaWJsZV9zb2x1dGlvbiA8LSBsaXN0KGNsdXN0ZXJfc29sdXRpb24kQ2x1c3RlcmluZ3NbWzFdXSxjbHVzdGVyX3NvbHV0aW9uJENsdXN0ZXJpbmdzW1syXV0pDQpvbmVfZmVhc2libGVfc29sdXRpb24gDQpgYGANCg0KSXQgc2hvdWxkIGFsc28gYmUgbm90ZWQgdGhhdCBgblRBUlBgIG9ubHkga2VlcHMgdGhlIHNvbHV0aW9ucyBtZWV0aW5nIHRoZSB3aXRoaW4gc3VtIG9mIHNxdWFyZXMgdGhyZXNob2xkIGVzdGFibGlzaGVkIGJ5IHRoZSB1c2VyLiBBcyBjYW4gYmUgc2VlbiBieSBkaXZpZGluZyB0aGUgbGVuZ3RoIG9mIHRoZSBsaXN0IHRyYWNraW5nIHRoZSBjbHVzdGVyIHNvbHV0aW9ucyBieSB0d28sIHRoZXJlIGFyZSBmZXdlciBzb2x1dGlvbnMgdGhhbiB0aGUgbnVtYmVyIG9mIHByb2plY3Rpb25zLg0KDQpgYGB7cn0NCmxlbmd0aChjbHVzdGVyX3NvbHV0aW9uJENsdXN0ZXJpbmdzKS8yDQpgYGANCg0KIyAyLiBFeHRlbmRpbmcgblRBUlAgdG8gZm9ybSBtdWx0aXBsZSBjbHVzdGVycw0KSW4gbW9zdCBjYXNlcywgaXQgaXMgZGVzaXJhYmxlIHRvIGZvcm0gbW9yZSB0aGFuIHR3byBjbHVzdGVycyBmb3IgYSBkYXRhc2V0LiBUbyBzdXBwb3J0IHRoaXMsIHRoZSBuVEFSUCBwYWNrYWdlIGluY2x1ZGVzIGEgZnVuY3Rpb24gY2FsbGVkIGBuVEFSUF9iaXNlY3RpbmdgLCB3aGljaCBhcHBsaWVzIGBuVEFSUGAgaW4gYSByZWN1cnNpdmUgYmlzZWN0aW5nIGZhc2hpb24uIFRoaXMgZnVuY3Rpb24gcmVwZWF0ZWRseSBzcGxpdHMgY2x1c3RlcnMgdW50aWwgYSBtaW5pbXVtIGNsdXN0ZXIgc2l6ZSBpcyByZWFjaGVkLiANCg0KVGhlIGFyZ3VtZW50cyBhcmUgdGhlIHNhbWUgYXMgZm9yIHRoZSBzdGFuZGFyZCBgblRBUlBgIGZ1bmN0aW9uLCB3aXRoIHRoZSBhZGRpdGlvbiBvZiBhIG5ldyBhcmd1bWVudDogYG1pbmltdW1fY2x1c3Rlcl9zaXplX3BlcmNlbnRgLiBUaGlzIGFyZ3VtZW50IHByb3ZpZGVzIGEgc3RvcHBpbmcgcnVsZSB0byBwcmV2ZW50IGNsdXN0ZXJzIGZyb20gYmVpbmcgYnJva2VuIGRvd24gaW50byB2ZXJ5IHNtYWxsIGdyb3Vwcy4gVGhlIGZ1bmN0aW9uIHdpbGwgc3RvcCBzcGxpdHRpbmcgYSBjbHVzdGVyIGlmIGl0cyBzaXplIGlzIHNtYWxsZXIgdGhhbiB0aGUgcGVyY2VudGFnZSBzcGVjaWZpZWQuIEJ5IGRlZmF1bHQsIHRoaXMgdGhyZXNob2xkIGlzIHNldCB0byAyMCUuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzNTMyKSAjcmFuZG9tIHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0KY2x1c3Rlcl9zb2x1dGlvbl9iaXNlY3RpbmcgPC0gblRBUlBfYmlzZWN0aW5nKGRhdGEgPSBpcmlzWywxOjRdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyX29mX3Byb2plY3Rpb25zID0gMTAwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhpbnNzX3RocmVzaG9sZCA9IDAuMzYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtX2NsdXN0ZXJfc2l6ZV9wZXJjZW50ID0gMjAgI2RlZmF1bHQgdmFsdWUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQpBZnRlciBydW5uaW5nIHRoZSBgblRBUlBfYmlzZWN0aW5nYCBmdW5jdGlvbiwgeW91IHdpbGwgb2J0YWluIHRocmVlIG1haW4gb3V0cHV0czoNCg0KLUEgbGlzdCBvZiB0aGUgaW5kaXZpZHVhbCBuVEFSUCBzb2x1dGlvbnMgKGFzIGRlc2NyaWJlZCBpbiBTZWN0aW9uIDEpLg0KLVRoZSBiZXN0IGNsdXN0ZXJzIGF0IGVhY2ggc3RlcCwgYmFzZWQgb24gdGhlIHdpdGhpbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmVzLg0KLUFsbCB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyB2YWx1ZXMgZm9yIGVhY2ggc29sdXRpb24gYXQgZWFjaCBzdGVwLg0KDQpUaGUgbW9zdCB1c2VmdWwgb3V0cHV0IGZvciB1c2VycyBpcyB0aGUgYEJlc3RDbHVzdGVyc2AgZW50cnkuIEV4YW1pbmluZyB0aGlzIG91dHB1dCBwcm92aWRlcyBpbmZvcm1hdGlvbiBvbiBjbHVzdGVyIHNpemVzLCBjbHVzdGVyIGxhYmVscywgYW5kIHRoZSB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyBmb3IgZWFjaCBzZWxlY3RlZCBzb2x1dGlvbi4gDQoNCmBgYHtyfQ0KY2x1c3Rlcl9zb2x1dGlvbl9iaXNlY3RpbmckQmVzdENsdXN0ZXJzDQpgYGANCg0KVWx0aW1hdGVseSwgd2Ugd2FudCB0byBvYnRhaW4gdGhlIGZpbmFsIGNsdXN0ZXIgbGFiZWxzIGZvciBlYWNoIG9ic2VydmF0aW9uLiBUaGlzIGNhbiBiZSBkb25lIHVzaW5nIHRoZSBgYnVpbGRfc29sdXRpb25fZnJvbV9sYWJlbGVkX2NsdXN0ZXJzYCBmdW5jdGlvbiwgd2hpY2ggcmV0dXJucyBhIGRhdGEgZnJhbWUgZGV0YWlsaW5nIGhvdyBlYWNoIGRhdGFwb2ludCB3YXMgY2x1c3RlcmVkLg0KDQpUaGUgZnVuY3Rpb24gcmVxdWlyZXMgdHdvIGlucHV0czoNCi1UaGUgYEJlc3RDbHVzdGVyc2Agb3V0cHV0IGZyb20gdGhlIGBuVEFSUF9iaXNlY3RpbmdgIGZ1bmN0aW9uLg0KLUEgdmVjdG9yIG9mIElEcyB0byBpZGVudGlmeSBlYWNoIG9ic2VydmF0aW9uLg0KDQpJZiB5b3UgZG9u4oCZdCBoYXZlIHNwZWNpZmljIElEcyB0byB0cmFjayBvYnNlcnZhdGlvbnMsIHlvdSBjYW4gc2ltcGx5IHVzZSBgMTpucm93KHgpYCwgd2hlcmUgYHhgIGlzIHlvdXIgZGF0YXNldC4gVGhpcyBhc3NpZ25zIHNlcXVlbnRpYWwgbnVtZXJpYyBsYWJlbHMgdG8gZWFjaCByb3cuDQoNCmBgYHtyfQ0KbGFiZWxlZF9jbHVzdGVycyA8LSBidWlsZF9zb2x1dGlvbl9mcm9tX2xhYmVsZWRfY2x1c3RlcnMoblRBUlBfYmVzdF9jbHVzdGVycz0gY2x1c3Rlcl9zb2x1dGlvbl9iaXNlY3RpbmckQmVzdENsdXN0ZXJzLCBpZHMgPSAxOm5yb3coaXJpcykpDQpsYWJlbGVkX2NsdXN0ZXJzW3NhbXBsZSgxOjE1MCwxMCxyZXBsYWNlID0gRkFMU0UpLF0gI1dlJ2xsIHRha2UgYSBzYW1wbGluZyBvZiB0aGUgb2JzZXJ2YXRpb25zDQpgYGANCg0KV2hlbiB3ZSBpbnNwZWN0IHRoZSByZXN1bHQgb2YgYGJ1aWxkX3NvbHV0aW9uX2Zyb21fbGFiZWxlZF9jbHVzdGVyc2AsIHdlIGNhbiBzZWUgdGhhdCB0aGUgZGF0YSBmcmFtZSBrZWVwcyB0cmFjayBvZiB3aGljaCBzb2x1dGlvbnMgZWFjaCBvYnNlcnZhdGlvbiBwYXJ0aWNpcGF0ZWQgaW4gdXNpbmcgYSBudW1lcmljIGNvZGluZyBzeXN0ZW0uDQoNCi0gRWFjaCBzb2x1dGlvbiBzdGFydHMgd2l0aCBDbHVzdGVyIDAsIHJlcHJlc2VudGluZyB0aGUgZmlyc3Qgc3BsaXQgb2YgdGhlIGRhdGFzZXQgaW50byB0d28gY2x1c3RlcnMuDQotIFN1YnNlcXVlbnQgbnVtYmVycyBpbiB0aGUgY29kZSBpbmRpY2F0ZSB3aGljaCBjbHVzdGVyIGZyb20gdGhlIHByZXZpb3VzIHNwbGl0IHdhcyBmdXJ0aGVyIHN1YmRpdmlkZWQuDQoNCkZvciBleGFtcGxlLCBhIGNvZGUgbGlrZSBDbHVzdGVyIDAxMiBtZWFuczoNCi0gVGhlIG9ic2VydmF0aW9uIHdhcyBpbiBjbHVzdGVyIDEgZHVyaW5nIHRoZSBmaXJzdCBzcGxpdC4NCi0gVGhlbiwgd2hlbiBjbHVzdGVyIDEgd2FzIHN1YmRpdmlkZWQsIHRoZSBvYnNlcnZhdGlvbiBlbmRlZCB1cCBpbiBjbHVzdGVyIDIgb2YgdGhlIG5leHQgc3BsaXQuDQoNCkZpbmFsbHksIHRoZXNlIGNsdXN0ZXIgcGF0aCBjb2RlcyBhcmUgdHJhbnNsYXRlZCBpbnRvIGEgc2luZ2xlIGludGVnZXIgdG8gcmVjb3JkIHRoZSBmaW5hbCBjbHVzdGVyIGFzc2lnbm1lbnQgZm9yIGVhY2ggb2JzZXJ2YXRpb24uDQoNCiMyLjEgVHJpbW1pbmcgY2x1c3RlcnMNCklmIHlvdSB0aGluayB0aGF0IHRoZSByZXN1bHRpbmcgY2x1c3RlcnMgYXJlIHRvbyBzbWFsbCBhZnRlciByZXZpZXdpbmcgdGhlIG91dHB1dCBvZiBidWlsZF9zb2x1dGlvbl9mcm9tX2xhYmVsZWRfY2x1c3RlcnMsIHdlIGhhdmUgYSBzaW1wbGUgZnVuY3Rpb24gY2FsbGVkIGBjb25zb2xpZGF0ZV9jbHVzdGVyc2AgdGhhdCBjYW4gYmUgdXNlZC4gTGV0J3Mgc2VlIHdoYXQgd2UgaGF2ZSBoZXJlIHJlbGF0aXZlIHRvIHRoZSBjbGFzcyBsYWJlbHMgd2UgZXhwZWN0ZWQgZnJvbSB0aGlzIGRhdGFzZXQ6DQoNCmBgYHtyfQ0KdGFibGUobGFiZWxlZF9jbHVzdGVycyRGaW5hbENsdXN0ZXJJRCxpcmlzJFNwZWNpZXMpDQpgYGANCg0KSXQgYXBwZWFycyB0aGF0IGBuVEFSUGAgd2FzIGFibGUgdG8gY2x1c3RlciB0aGUgdGhyZWUgZmxvd2VyIHR5cGVzIHJlYXNvbmFibHkgd2VsbCwgYnV0IGl0IHNwbGl0IGNsdXN0ZXJzIHRvbyBmaW5lbHkuIFRvIHJlY29uY2lsZSB0aGlzLCB3ZSBjYW4gdXNlIHRoZSBgY29uc29saWRhdGVfY2x1c3RlcnNgIGZ1bmN0aW9uLg0KDQpUaGUgb25seSBpbnB1dHMgcmVxdWlyZWQgYXJlOg0KLSBUaGUgb3V0cHV0IGZyb20gYGJ1aWxkX3NvbHV0aW9uX2Zyb21fbGFiZWxlZF9jbHVzdGVyc2AgDQotIFRoZSB0d28gY2x1c3RlcnMgeW91IHdhbnQgdG8gY29tYmluZS4NCg0KVGhlIGZ1bmN0aW9uIHJldHVybnMgYSBkYXRhIGZyYW1lIHdpdGggdGhlIGNsdXN0ZXJzIG1lcmdlZCwgYW5kIHdlIGNhbiByZWFzc2lnbiB0aGUgYGxhYmVsZWRfY2x1c3RlcnNgIHZhcmlhYmxlIHdpdGggdGhpcyB1cGRhdGVkIHJlc3VsdDoNCg0KYGBge3J9DQpsYWJlbGVkX2NsdXN0ZXJzIDwtIGNvbnNvbGlkYXRlX2NsdXN0ZXJzKGNsdXN0ZXJfcGF0aF9tYXRyaXggPSBsYWJlbGVkX2NsdXN0ZXJzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdF9jbHVzdGVyX3RvX2NvbWJpbmUgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWNvbmRfY2x1c3Rlcl90b19jb21iaW5lID0gMikNCnRhYmxlKGxhYmVsZWRfY2x1c3RlcnMkRmluYWxDbHVzdGVySUQsaXJpcyRTcGVjaWVzKQ0KYGBgDQoNCkZyb20gdGhlIHNlY29uZCBsaW5lLCB3ZSBjYW4gc2VlIHRoYXQgd2UgbG9zdCBvbmUgY2x1c3RlciBhcyBhIHJlc3VsdCBvZiB0aGUgbWVyZ2luZy4gV2UgY2FuIGtlZXAgZG9pbmcgdGhpcyB0d28gbW9yZSB0aW1lcy4NCg0KYGBge3J9DQojTWVyZ2UgY2x1c3RlcnMgdHdvIG1vcmUgdGltZXMNCmxhYmVsZWRfY2x1c3RlcnMgPC0gY29uc29saWRhdGVfY2x1c3RlcnMoY2x1c3Rlcl9wYXRoX21hdHJpeCA9IGxhYmVsZWRfY2x1c3RlcnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X2NsdXN0ZXJfdG9fY29tYmluZSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY29uZF9jbHVzdGVyX3RvX2NvbWJpbmUgPSAyKQ0KbGFiZWxlZF9jbHVzdGVycyA8LSBjb25zb2xpZGF0ZV9jbHVzdGVycyhjbHVzdGVyX3BhdGhfbWF0cml4ID0gbGFiZWxlZF9jbHVzdGVycywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfY2x1c3Rlcl90b19jb21iaW5lID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vjb25kX2NsdXN0ZXJfdG9fY29tYmluZSA9IDIpDQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzJEZpbmFsQ2x1c3RlcklELGlyaXMkU3BlY2llcykNCmBgYA0KDQpBZnRlciB0aGlzIHBydW5pbmcgc3RlcCwgd2UgZmluZCB0aGF0IHRoZSBjbHVzdGVyaW5nIHNwbGl0IHRoZSBmbG93ZXIgdHlwZXMgd2l0aCA5NyUgYWNjdXJhY3kuIA0KDQojMi4yIFVzaW5nIGEgY29udGV4dHVhbCB2YXJpYWJsZSB0byBzdXBwb3J0IGNsdXN0ZXJpbmcNCkJlY2F1c2Ugb2YgaG93IGBuVEFSUGAgb3BlcmF0ZXMsIHdlIGFyZSBlZmZlY3RpdmVseSB0YWtpbmcgbXVsdGlwbGUgcmFuZG9tIOKAnHNsaWNlc+KAnSBvZiB0aGUgc2FtZSBkYXRhc2V0IGFuZCBvYnRhaW5pbmcgZGlmZmVyZW50IGNhbmRpZGF0ZSBjbHVzdGVyaW5ncy4gQXQgaXRzIGNvcmUsIGNsdXN0ZXIgYW5hbHlzaXMgaXMgZGVzY3JpcHRpdmXigJR3ZSBhcmUgYnVpbGRpbmcgYSB1c2VmdWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIHN0cnVjdHVyZSBpbiBvdXIgZGF0YSBzbyB0aGF0IHdlIGNhbiB1bHRpbWF0ZWx5IGFjdCBvbiB3aGF0IHdlIGxlYXJuIGFib3V0IHN1Ymdyb3Vwcy4NCg0KQnV0IHdoYXQgaWYgdGhlcmUgaXMgYSB2YXJpYWJsZSB5b3Ugd291bGQgbGlrZSB0byB1c2UgdG8gZ3VpZGUgdGhlIGNsdXN0ZXJpbmcgcHJvY2Vzcz8NCg0KSW5zdGVhZCBvZiBzZWxlY3RpbmcgdGhlIGJlc3Qgc29sdXRpb24gYmFzZWQgc29sZWx5IG9uIHRoZSB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcywgd2UgY2FuIG1vZGlmeSB0aGUgb2JqZWN0aXZlIGZ1bmN0aW9uIHRvIGV2YWx1YXRlIGhvdyB3ZWxsIGNhbmRpZGF0ZSBjbHVzdGVyaW5ncyBzZXBhcmF0ZSBvYnNlcnZhdGlvbnMgd2l0aCByZXNwZWN0IHRvIGEgY29udGV4dHVhbCB2YXJpYWJsZS4gSW4gb3RoZXIgd29yZHMsIHdlIGNhbiBhbGxvdyBgblRBUlBgIHRvIHNlYXJjaCBmb3Igc3RydWN0dXJlIHRoYXQgaXMgbWVhbmluZ2Z1bCByZWxhdGl2ZSB0byBzb21lIGV4dGVybmFsIGNyaXRlcmlvbi4NCg0KTW9yZSBzcGVjaWZpY2FsbHksIHdlIGNhbiBhcHByb2FjaCBjbHVzdGVyaW5nIGluIGEgd2F5IHNpbWlsYXIgdG8gYSBkZWNpc2lvbiB0cmVlLg0KDQpJbiB0aGUgdHJhZGl0aW9uYWwgQ0FSVCBhbGdvcml0aG0sIHNwbGl0cyBhcmUgY2hvc2VuIHRvIG1heGltaXplIHNlcGFyYXRpb24gb2YgcHJlZGVmaW5lZCBjbGFzcyBsYWJlbHMgYnkgbWluaW1pemluZyBub2RlIOKAnGltcHVyaXR54oCdIChlLmcuLCBHaW5pIGluZGV4KS4gU2ltaWxhcmx5LCBpbiBgblRBUlBgLCB3ZSBjYW4gZXZhbHVhdGUgY2FuZGlkYXRlIGNsdXN0ZXJpbmdzIGJhc2VkIG9uIGhvdyB3ZWxsIHRoZXkgc2VwYXJhdGUgb2JzZXJ2YXRpb25zIGFjY29yZGluZyB0byBhIGNvbnRleHR1YWwgdmFyaWFibGUsIHN1Y2ggYXMgYSBrbm93biBjbGFzcyBsYWJlbC4NCg0KVG8gZXZhbHVhdGUgdGhlIGludGVybmFsIHZhbGlkaXR5IG9mIGEgY2x1c3RlcmluZyBzb2x1dGlvbiBhbmQgZXhhbWluZSBob3cgd2VsbCBjbHVzdGVycyBkaWZmZXIgb24gYSBnaXZlbiB2YXJpYWJsZSwgd2UgdXNlIGFuIGltcHVyaXR5IG1ldHJpYyBrbm93biBhcyB0aGUgKipHaW5pIGluZGV4KiouIA0KDQpPcmlnaW5hbGx5IGRldmVsb3BlZCB0byBtZWFzdXJlIGluY29tZSBpbmVxdWFsaXR5LCB0aGUgR2luaSBpbmRleCBoYXMgc2luY2UgYmVlbiB3aWRlbHkgYWRvcHRlZCBpbiBtYWNoaW5lIGxlYXJuaW5nLCBwYXJ0aWN1bGFybHkgaW4gdHJhaW5pbmcgZGVjaXNpb24gdHJlZSBtb2RlbHMuIEluIGNsdXN0ZXJpbmcgY29udGV4dHMsIGl0IHByb3ZpZGVzIGEgbWVhc3VyZSBvZiBob3cgaG9tb2dlbmVvdXMgZWFjaCBjbHVzdGVyIGlzIHdpdGggcmVzcGVjdCB0byBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLg0KDQpUaGUgR2luaSBpbmRleCBmb3IgYSBjbHVzdGVyIFwoIHQgXCksIGRlbm90ZWQgYXMgXCggXHRleHR7R2luaX0odCkgXCksIGlzIGRlZmluZWQgYXM6DQoNCiQkDQpcdGV4dHtHaW5pfSh0KSA9IDEgLSBcc3VtX3tpPTF9XntjfSBwKGkgXG1pZCB0KV4yDQokJA0Kd2hlcmU6DQoNCi0gXCggYyBcKSBpcyB0aGUgbnVtYmVyIG9mIGNsYXNzIGxhYmVscywNCi0gXCggcChpIFxtaWQgdCkgXCkgaXMgdGhlIHByb3BvcnRpb24gb2Ygb2JzZXJ2YXRpb25zIGJlbG9uZ2luZyB0byBjbGFzcyBcKCBpIFwpIHdpdGhpbiBjbHVzdGVyIFwoIHQgXCkuDQoNCkxvd2VyIEdpbmkgdmFsdWVzIGluZGljYXRlIGdyZWF0ZXIgcHVyaXR5IChpLmUuLCBtb3JlIGhvbW9nZW5lb3VzIGNsdXN0ZXJzKSwgd2hpbGUgaGlnaGVyIHZhbHVlcyBpbmRpY2F0ZSBncmVhdGVyIGltcHVyaXR5Lg0KDQpUbyBhc3Nlc3MgaG93IHdlbGwgYSBjbHVzdGVyaW5nIHNvbHV0aW9uIHNlcGFyYXRlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlLCB3ZSBjb21wdXRlIHRoZSBgZ2FpbmAsIGRlZmluZWQgYXMgdGhlIHJlZHVjdGlvbiBpbiBpbXB1cml0eSBmcm9tIHRoZSBmdWxsIGRhdGFzZXQgKHBhcmVudCBub2RlKSB0byB0aGUgc2V0IG9mIGNsdXN0ZXJzLg0KDQpUaGUgZ2FpbiBpcyBjYWxjdWxhdGVkIGFzOg0KDQokJA0KXHRleHR7R2Fpbn0gPSBcdGV4dHtHaW5pfShcdGV4dHtQYXJlbnR9KSAtIFxzdW1fe3Q9MX1ee2d9IFxmcmFje25fdH17bn0gXCwgXHRleHR7R2luaX0odCkNCiQkDQoNCndoZXJlOg0KDQotIFwoIFx0ZXh0e0dpbml9KFx0ZXh0e1BhcmVudH0pIFwpIGlzIHRoZSBHaW5pIGluZGV4IG9mIHRoZSBlbnRpcmUgZGF0YXNldCBwcmlvciB0byBjbHVzdGVyaW5nLA0KLSBcKCBnIFwpIGlzIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMsDQotIFwoIG5fdCBcKSBpcyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBjbHVzdGVyIFwoIHQgXCksDQotIFwoIG4gXCkgaXMgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQoNClRoZSBgZ2FpbmAgcmVwcmVzZW50cyB0aGUgd2VpZ2h0ZWQgcmVkdWN0aW9uIGluIGltcHVyaXR5IGFjaGlldmVkIGJ5IHRoZSBjbHVzdGVyaW5nIHNvbHV0aW9uLiBMYXJnZXIgYGdhaW5gIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IHRoZSBjbHVzdGVycyBtb3JlIGVmZmVjdGl2ZWx5IHNlcGFyYXRlIG9ic2VydmF0aW9ucyBvbiB0aGUgY2hvc2VuIHZhcmlhYmxlLg0KDQpUaGUgbWF4aW11bSBwb3NzaWJsZSBgZ2FpbmAgaXMgZXF1YWwgdG8gXCggXHRleHR7R2luaX0oXHRleHR7UGFyZW50fSkgXCksIHdoaWNoIHdvdWxkIG9jY3VyIGlmIGVhY2ggY2x1c3RlciB3ZXJlIHBlcmZlY3RseSBwdXJlIHdpdGggcmVzcGVjdCB0byB0aGUgdmFyaWFibGUgKGkuZS4sIGFsbCBcKCBcdGV4dHtHaW5pfSh0KSA9IDAgXCkpLg0KDQpUbyBpbGx1c3RyYXRlIHRoZSBwcm9jZXNzLCBGaWd1cmUgMyBwcmVzZW50cyBhIHNpbXBsaWZpZWQgZmxvd2NoYXJ0IG9mIHRoZSBiaXNlY3RpbmcgblRBUlAgYWxnb3JpdGhtLCBoaWdobGlnaHRpbmcgaXRzIGdlbmVyYWwgd29ya2Zsb3cgd2l0aG91dCBkZWx2aW5nIGludG8gdGhlIG1vcmUgbml0cGlja3kgZGV0YWlscy4NCg0KKipGaWd1cmUgMzoqKiBIb3cgdGhlIG5UQVJQIHByb2Nlc3Mgd29ya3Mgd2hlbiBpdGVyYXRpdmVseSBicmVha2luZyBkb3duIGNsdXN0ZXJzIHdpdGggYW5kIHdpdGhvdXQgYSBjb250ZXh0dWFsIHZhcmlhYmxlDQoNCiFbXSguLi9pbnN0L2ZpZ3VyZXMvblRBUlBfYmlzZWN0aW5nLnBuZykNCg0KTGV04oCZcyBzZWUgaG93IHRoaXMgd29ya3MgZm9yIHRoZSBgaXJpc2AgZGF0YXNldCwgd2hlcmUgdGhlIGdvYWwgaXMgdG8gY2x1c3RlciBvYnNlcnZhdGlvbnMgd2l0aCByZXNwZWN0IHRvIHRoZSBgU3BlY2llc2AgdmFyaWFibGUuIFdlIHVzZSB0aGUgZXhhY3Qgc2FtZSBmdW5jdGlvbiBhcyBiZWZvcmUsIGJ1dCBub3cgd2UgYWRkIHRoZSBjb250ZXh0dWFsIHZhcmlhYmxlOg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMzUzMikgI3JhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkNCmNsdXN0ZXJfc29sdXRpb25fYmlzZWN0aW5nX2NvbnRleHR1YWwgPC0gblRBUlBfYmlzZWN0aW5nKGRhdGEgPSBpcmlzWywxOjRdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyX29mX3Byb2plY3Rpb25zID0gMTAwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhpbnNzX3RocmVzaG9sZCA9IDAuMzYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtX2NsdXN0ZXJfc2l6ZV9wZXJjZW50ID0gMjAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0dWFsX3ZhcmlhYmxlID0gaXJpcyRTcGVjaWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpsYWJlbGVkX2NsdXN0ZXJzIDwtIGJ1aWxkX3NvbHV0aW9uX2Zyb21fbGFiZWxlZF9jbHVzdGVycyhuVEFSUF9iZXN0X2NsdXN0ZXJzPSBjbHVzdGVyX3NvbHV0aW9uX2Jpc2VjdGluZ19jb250ZXh0dWFsJEJlc3RDbHVzdGVycywgaWRzID0gMTpucm93KGlyaXMpKQ0KYGBgDQoNCklmIGl0J3MgZGVzaXJhYmxlIHRvIGRvIHNvLCB5b3UgY2FuIGFwcGVuZCB0aGUgY29udGV4dHVhbCBkYXRhIHRvIHRoZSBvdXRwdXQgb2YgYGJ1aWxkX3NvbHV0aW9uX2Zyb21fbGFibGVkX2NsdXN0ZXJzYCB1c2luZyB0aGUgb3B0aW9uYWwgYXJndW1lbnQgYGNvbnRleHR1YWxfdmFyaWFibGVzX2RmYC4gSGVyZSwgd2UgY2FuIGp1c3QgYXBwZW5kIHRoZSBpcmlzIGRhdGEgYXMgYW4gZXhhbXBsZS4gDQoNCmBgYHtyfQ0KbGFiZWxlZF9jbHVzdGVyc193aXRoX2NvbnRleHQgPC0gYnVpbGRfc29sdXRpb25fZnJvbV9sYWJlbGVkX2NsdXN0ZXJzKG5UQVJQX2Jlc3RfY2x1c3RlcnM9IGNsdXN0ZXJfc29sdXRpb25fYmlzZWN0aW5nX2NvbnRleHR1YWwkQmVzdENsdXN0ZXJzLCBpZHMgPSAxOm5yb3coaXJpcyksIGNvbnRleHR1YWxfdmFyaWFibGVzX2RmID0gaXJpcykNCmhlYWQobGFiZWxlZF9jbHVzdGVyc193aXRoX2NvbnRleHQpDQpgYGANCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIHJlc3VsdHMuLi4NCg0KYGBge3J9DQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzJEZpbmFsQ2x1c3RlcklELGlyaXMkU3BlY2llcykNCmBgYA0KDQpGaXJzdCwgd2hlbiB1c2luZyBhIGNvbnRleHR1YWwgdmFyaWFibGUsIHlvdSBtYXkgbm90aWNlIHRoYXQgdGhlIGBuVEFSUGAgZnVuY3Rpb24gaXMgbGVzcyBhZ2dyZXNzaXZlIGluIHNwbGl0dGluZyBjbHVzdGVycyB1bm5lY2Vzc2FyaWx5LiBJbiBmYWN0LCBmb3IgdGhlIGZpcnN0IHNwbGl0IGluIGJvdGggY2FzZXMsIGl0IGFscmVhZHkgaWRlbnRpZmllZCBhIGNsdXN0ZXIgY29udGFpbmluZyBvbmx5IGEgc2luZ2xlIGNsYXNzLiBXaXRoIHRoZSBjb250ZXh0dWFsIHZhcmlhYmxlLCB0aGUgYWxnb3JpdGhtIHJlY29nbml6ZXMgdGhhdCBmdXJ0aGVyIHNwbGl0dGluZyBpcyB1bm5lY2Vzc2FyeSBhbmQgc3RvcHMgYXBwcm9wcmlhdGVseS4NCg0KV2l0aG91dCBhIGNvbnRleHR1YWwgdmFyaWFibGUsIHRoZSBmdW5jdGlvbiBtYXkgY29udGludWUgc3BsaXR0aW5nLCBwb3RlbnRpYWxseSBjcmVhdGluZyBjbHVzdGVycyB0aGF0IGFyZSB0b28gZmluZS4gSW4gdGhlIGF1dGhvcuKAmXMgZXhwZXJpZW5jZSwgb3Zlci1zcGxpdHRpbmcgaXMgZ2VuZXJhbGx5IHNhZmVyIHRoYW4gdW5kZXItc3BsaXR0aW5nLCBhcyB0aGUgcmVzdWx0aW5nIGNsdXN0ZXJzIGNhbiBhbHdheXMgYmUgbWVyZ2VkIGxhdGVyLg0KDQpUbyBjbGVhbiB1cCB0aGUgc29sdXRpb24sIHdlIGNhbiB1c2UgdGhlIGBjb25zb2xpZGF0ZV9jbHVzdGVyc2AgZnVuY3Rpb24uIEZvciBleGFtcGxlLCB3ZSBjYW4gbWVyZ2UgY2x1c3RlcnMgMSBhbmQgMiB0byBlbnN1cmUgdGhhdCBhbGwgdmlyZ2luaWNhIG9ic2VydmF0aW9ucyBhcmUgZ3JvdXBlZCB0b2dldGhlcjoNCg0KYGBge3J9DQpsYWJlbGVkX2NsdXN0ZXJzIDwtIGNvbnNvbGlkYXRlX2NsdXN0ZXJzKGNsdXN0ZXJfcGF0aF9tYXRyaXggPSBsYWJlbGVkX2NsdXN0ZXJzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdF9jbHVzdGVyX3RvX2NvbWJpbmUgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWNvbmRfY2x1c3Rlcl90b19jb21iaW5lID0gMikNCnRhYmxlKGxhYmVsZWRfY2x1c3RlcnMkRmluYWxDbHVzdGVySUQsaXJpcyRTcGVjaWVzKQ0KYGBgDQoNCllvdSdsbCBub3RpY2UgdGhhdCB0aGlzIGNvbnRleHR1YWwgdmFyaWFibGUgbWFkZSBvdXIgY2x1c3RlcmluZyBldmVuIGJldHRlciwgd2l0aCA5OSUgYWNjdXJhY3kuIA0KDQpCeSByZWN1cnNpdmVseSBiaXNlY3RpbmcgY2x1c3RlcnMgYW5kIGFzc2Vzc2luZyBjbHVzdGVyIOKAnHF1YWxpdHnigJ0gdGhyb3VnaCBtZXRyaWNzIGxpa2Ugbm9ybWFsaXplZCB3aXRoaW4tY2x1c3RlciBzdW0gb2Ygc3F1YXJlcyBvciBHaW5pLWJhc2VkIHB1cml0eSBnYWlucywgYG5UQVJQYCBjYW4gdW5jb3ZlciBzdHJ1Y3R1cmUgaW4gaGlnaC1kaW1lbnNpb25hbCBkYXRhIHdoaWxlIGNvbnRyb2xsaW5nIGZvciBtaW5pbXVtIGNsdXN0ZXIgc2l6ZS4gVGhlIGFwcHJvYWNoIGlzIGZsZXhpYmxlLCBhbGxvd2luZyBwb3N0LWhvYyBtZXJnaW5nIG9mIGNsdXN0ZXJzLCBhbmQgaXMgcGFydGljdWxhcmx5IHdlbGwtc3VpdGVkIGZvciBhcHBsaWNhdGlvbnMgd2hlcmUgc3RhbmRhcmQgY2x1c3RlcmluZyBhbGdvcml0aG1zIHN0cnVnZ2xlIHdpdGggc3BhcnNlLCBoaWdoLWRpbWVuc2lvbmFsLCBvciBub2lzeSBkYXRhLg0KDQojMy4gQW5vdGhlciBoaWdoIGRpbWVuc2lvbmFsIGV4YW1wbGUNClRvIGNsb3NlIG91dCB0aGUgZGVtb25zdHJhdGlvbiwgd2UgY2FuIHRyeSB0byBhcHBseSBgblRBUlBgIHRvIG9uZSBtb3JlIGRhdGFzZXQsIHRoZSB3aW5lIGRhdGFzZXQgZnJvbSB0aGUgYEhEY2xhc3NpZmAgcGFja2FnZS4gVGhlIGB3aW5lYCBkYXRhc2V0IGZyb20gdGhlIGBIRGNsYXNzaWZgIHBhY2thZ2UgY29udGFpbnMgMTc4IG9ic2VydmF0aW9ucyBvZiB3aW5lcyBkZXJpdmVkIGZyb20gdGhyZWUgZGlmZmVyZW50IGN1bHRpdmFycyBncm93biBpbiB0aGUgc2FtZSByZWdpb24gb2YgSXRhbHkuIEVhY2ggd2luZSBpcyBkZXNjcmliZWQgYnkgMTMgY29udGludW91cyBjaGVtaWNhbCBtZWFzdXJlbWVudHMsIHN1Y2ggYXMgYWxjb2hvbCBjb250ZW50LCBmbGF2YW5vaWRzLCBtYWduZXNpdW0sIGNvbG9yIGludGVuc2l0eSwgYW5kIHByb2xpbmUsIGFsb25nIHdpdGggYSBjbGFzcyBsYWJlbCBpbmRpY2F0aW5nIGN1bHRpdmFyIG1lbWJlcnNoaXAuDQoNCmBgYHtyfQ0KbGlicmFyeShIRGNsYXNzaWYpDQpkYXRhKHdpbmUpDQpoZWFkKHdpbmUpDQp3aW5lWywyOjE0XSA8LSBzY2FsZSh3aW5lWywyOjE0XSkNCmBgYA0KDQpMaWtlIHRoZSBgaXJpc2AgZGF0YXNldCwgdGhlIGB3aW5lYCBkYXRhc2V0IGNvbnRhaW5zIHRocmVlIGRpc3RpbmN0IGNsYXNzZXMuIEhvd2V2ZXIsIHVubGlrZSB0aGUgYGlyaXNgIGRhdGHigJR3aGVyZSB0aGUgY2xhc3NlcyBhcmUgcGVyZmVjdGx5IGJhbGFuY2Vk4oCUdGhlIGB3aW5lYCBkYXRhc2V0IGlzIG1vZGVyYXRlbHkgaW1iYWxhbmNlZC4gVGhlIGltYmFsYW5jZSBpcyBub3QgZXh0cmVtZSwgYnV0IGl0IGlzIHdvcnRoIG5vdGluZywgYXMgY2xhc3MgaW1iYWxhbmNlIGNhbiBpbmZsdWVuY2UgYm90aCBjbHVzdGVyaW5nIGJlaGF2aW9yIGFuZCBob3cgd2UgaW50ZXJwcmV0IHNlcGFyYXRpb24gcXVhbGl0eS4NCg0KYGBge3J9DQp0YWJsZSh3aW5lJGNsYXNzKQ0KYGBgDQoNCldlJ2xsIHRyeSB0aGUgYmlzZWN0aW5nIG5UQVJQIGFwcHJvYWNoIHdpdGhvdXQgYSBjb250ZXh0dWFsIHZhcmlhYmxlIGZpcnN0LiBXZSdsbCBhbHNvIHVzZSBtb3JlIHByb2plY3Rpb25zLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMzUzMikgI3JhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkNCmNsdXN0ZXJfc29sdXRpb25fYmlzZWN0aW5nX3dpbmUgPC0gblRBUlBfYmlzZWN0aW5nKGRhdGEgPSB3aW5lWywyOjE0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9vZl9wcm9qZWN0aW9ucyA9IDEwMF4yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aGluc3NfdGhyZXNob2xkID0gMC4zNiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW1fY2x1c3Rlcl9zaXplX3BlcmNlbnQgPSAyMCAjZGVmYXVsdCB2YWx1ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KbGFiZWxlZF9jbHVzdGVyc193aW5lIDwtIGJ1aWxkX3NvbHV0aW9uX2Zyb21fbGFiZWxlZF9jbHVzdGVycyhuVEFSUF9iZXN0X2NsdXN0ZXJzPSBjbHVzdGVyX3NvbHV0aW9uX2Jpc2VjdGluZ193aW5lJEJlc3RDbHVzdGVycywgaWRzID0gMTpucm93KHdpbmUpKQ0KdGFibGUobGFiZWxlZF9jbHVzdGVyc193aW5lJEZpbmFsQ2x1c3RlcklELHdpbmUkY2xhc3MpDQpgYGANCg0KUHJvY2Vzc2luZyB0aGUgY2x1c3RlcnMsIHdlIHNlZSB0aGF0IDErMiwgMys0LCBhbmQgNSs2IGFwcGVhciB0byBiZSByZWFzb25hYmxlIGNvbWJpbmF0aW9ucyBvZiBjbHVzdGVycy4gDQoNCmBgYHtyfQ0KI01lcmdlIGNsdXN0ZXJzIHR3byBtb3JlIHRpbWVzDQpwcmludCgiVGhpcyBpcyB0aGUgcmVzdWx0IG9mIGNvbWJpbmluZyBjbHVzdGVycyAxIGFuZCAyLCBkdXJpbmcgd2hpY2ggMy02IHdlcmUgcmVsYWJsZWQgdG8gYmUgMS00IHdpdGggdGhlIG1lcmdlZCBjbHVzdGVyIGJlaW5nIGxhYmVsZWQgNS4iKQ0KbGFiZWxlZF9jbHVzdGVyc193aW5lIDwtIGNvbnNvbGlkYXRlX2NsdXN0ZXJzKGNsdXN0ZXJfcGF0aF9tYXRyaXggPSBsYWJlbGVkX2NsdXN0ZXJzX3dpbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X2NsdXN0ZXJfdG9fY29tYmluZSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY29uZF9jbHVzdGVyX3RvX2NvbWJpbmUgPSAyKQ0KdGFibGUobGFiZWxlZF9jbHVzdGVyc193aW5lJEZpbmFsQ2x1c3RlcklELHdpbmUkY2xhc3MpDQojTWVyZ2UgMSBhbmQgMiBhZ2Fpbg0KcHJpbnQoIlRoaXMgaXMgdGhlIHJlc3VsdCBvZiBjb21iaW5pbmcgY2x1c3RlcnMgMyBhbmQgNCAodGhhdCB3ZXJlIHJlbGFiZWxlZCAxIGFuZCAyIGluIHRoZSBsYXN0IHN0ZXApLiBOb3cgdGhlcmUgYXJlIDQgY2x1c3RlcnMgbGVmdC4iKQ0KbGFiZWxlZF9jbHVzdGVyc193aW5lIDwtIGNvbnNvbGlkYXRlX2NsdXN0ZXJzKGNsdXN0ZXJfcGF0aF9tYXRyaXggPSBsYWJlbGVkX2NsdXN0ZXJzX3dpbmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X2NsdXN0ZXJfdG9fY29tYmluZSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY29uZF9jbHVzdGVyX3RvX2NvbWJpbmUgPSAyKQ0KdGFibGUobGFiZWxlZF9jbHVzdGVyc193aW5lJEZpbmFsQ2x1c3RlcklELHdpbmUkY2xhc3MpDQojTWVyZ2UgMSBhbmQgMiBhZ2Fpbg0KDQpwcmludCgiV2UgY29tYmluZSB0aGF0IGxhc3QgdHdvIGNsdXN0ZXJzLCBnaXZpbmcgdXMgMyBjbHVzdGVycyBhdCB0aGUgZW5kLiIpDQpsYWJlbGVkX2NsdXN0ZXJzX3dpbmUgPC0gY29uc29saWRhdGVfY2x1c3RlcnMoY2x1c3Rlcl9wYXRoX21hdHJpeCA9IGxhYmVsZWRfY2x1c3RlcnNfd2luZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfY2x1c3Rlcl90b19jb21iaW5lID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vjb25kX2NsdXN0ZXJfdG9fY29tYmluZSA9IDIpDQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzX3dpbmUkRmluYWxDbHVzdGVySUQsd2luZSRjbGFzcykNCmBgYA0KDQpOb3cgdGhhdCB3ZSd2ZSByZWR1Y2VkIHRoZSBjbHVzdGVycyB0byB0aHJlZSwgd2UgY2FuIHNlZSB3ZSBnZXQgYW4gYWNjdXJhY3kgb2YgOTIlLiBMZXQncyBzZWUgaWYgdGhpcyBpbXByb3ZlcyB3aXRoIHRoZSBjb250ZXh0dWFsIHZhcmlhYmxlLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMzUzMikgI3JhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkNCmNsdXN0ZXJfc29sdXRpb25fYmlzZWN0aW5nX3dpbmUgPC0gblRBUlBfYmlzZWN0aW5nKGRhdGEgPSB3aW5lWywyOjE0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9vZl9wcm9qZWN0aW9ucyA9IDEwMF4yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aGluc3NfdGhyZXNob2xkID0gMC4zNiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW1fY2x1c3Rlcl9zaXplX3BlcmNlbnQgPSAyMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHR1YWxfdmFyaWFibGUgPSB3aW5lJGNsYXNzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpsYWJlbGVkX2NsdXN0ZXJzX3dpbmUgPC0gYnVpbGRfc29sdXRpb25fZnJvbV9sYWJlbGVkX2NsdXN0ZXJzKG5UQVJQX2Jlc3RfY2x1c3RlcnM9IGNsdXN0ZXJfc29sdXRpb25fYmlzZWN0aW5nX3dpbmUkQmVzdENsdXN0ZXJzLCBpZHMgPSAxOm5yb3cod2luZSkpDQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzX3dpbmUkRmluYWxDbHVzdGVySUQsd2luZSRjbGFzcykNCmBgYA0KDQpQcm9jZXNzaW5nIHRoZSBjbHVzdGVycywgd2Ugc2VlIHRoYXQgMSsyIGFuZCAzKzQgYXBwZWFyIHRvIGJlIHJlYXNvbmFibGUgY29tYmluYXRpb25zIG9mIGNsdXN0ZXJzLiANCg0KYGBge3J9DQojTWVyZ2UgY2x1c3RlcnMgdHdvIG1vcmUgdGltZXMNCnByaW50KCJUaGlzIGlzIHRoZSByZXN1bHQgb2YgY29tYmluaW5nIGNsdXN0ZXJzIDEgYW5kIDIsIGR1cmluZyB3aGljaCAzLTUgd2VyZSByZWxhYmxlZCB0byBiZSAxLTMgd2l0aCB0aGUgbWVyZ2VkIGNsdXN0ZXIgYmVpbmcgbGFiZWxlZCA0LiIpDQpsYWJlbGVkX2NsdXN0ZXJzX3dpbmUgPC0gY29uc29saWRhdGVfY2x1c3RlcnMoY2x1c3Rlcl9wYXRoX21hdHJpeCA9IGxhYmVsZWRfY2x1c3RlcnNfd2luZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfY2x1c3Rlcl90b19jb21iaW5lID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vjb25kX2NsdXN0ZXJfdG9fY29tYmluZSA9IDIpDQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzX3dpbmUkRmluYWxDbHVzdGVySUQsd2luZSRjbGFzcykNCiNNZXJnZSAxIGFuZCAyIGFnYWluDQpwcmludCgiV2UgY29tYmluZSB0aGF0IGxhc3QgdHdvIGNsdXN0ZXJzLCBnaXZpbmcgdXMgMyBjbHVzdGVycyBhdCB0aGUgZW5kLiIpDQpsYWJlbGVkX2NsdXN0ZXJzX3dpbmUgPC0gY29uc29saWRhdGVfY2x1c3RlcnMoY2x1c3Rlcl9wYXRoX21hdHJpeCA9IGxhYmVsZWRfY2x1c3RlcnNfd2luZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfY2x1c3Rlcl90b19jb21iaW5lID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vjb25kX2NsdXN0ZXJfdG9fY29tYmluZSA9IDIpDQp0YWJsZShsYWJlbGVkX2NsdXN0ZXJzX3dpbmUkRmluYWxDbHVzdGVySUQsd2luZSRjbGFzcykNCmBgYA0KDQpOb3cgdGhhdCB3ZeKAmXZlIHJlZHVjZWQgdGhlIHNvbHV0aW9uIHRvIHRocmVlIGNsdXN0ZXJzLCB0aGUgY2x1c3RlcmluZyBhbGlnbnMgY2xvc2VseSB3aXRoIHRoZSB0cnVlIHdpbmUgY3VsdGl2YXJzLCB5aWVsZGluZyBhbiBhY2N1cmFjeSBvZiA5OCUuIFRoaXMgZGVtb25zdHJhdGVzIHRoYXQgYG5UQVJQYCwgZXNwZWNpYWxseSB3aGVuIGNvbWJpbmVkIHdpdGggcG9zdC1wcm9jZXNzaW5nIChlLmcuLCBjb25zb2xpZGF0ZV9jbHVzdGVycyksIGNhbiByZWNvdmVyIG1lYW5pbmdmdWwgc3RydWN0dXJlIGV2ZW4gaW4gbW9kZXJhdGVseSBpbWJhbGFuY2VkIGRhdGFzZXRzLg0KDQpJbXBvcnRhbnRseSwgdGhlIGNvbnRleHR1YWwgdmFyaWFibGUgZG9lcyBub3QgaGF2ZSB0byBiZSBhIGNsYXNzIGxhYmVsOyBpdCBjYW4gYmUgYW55IGNhdGVnb3JpY2FsIHZhcmlhYmxlIG9mIGludGVyZXN0LiBVc2luZyBhIGNvbnRleHR1YWwgdmFyaWFibGUgYWxsb3dzIG5UQVJQIHRvIGd1aWRlIHRoZSBjbHVzdGVyaW5nIHRvd2FyZCBwYXR0ZXJucyB0aGF0IGFyZSBtb3N0IHJlbGV2YW50IGZvciBhIHBhcnRpY3VsYXIgYW5hbHl0aWNhbCBvciBwcmVkaWN0aXZlIGdvYWwsIG11Y2ggbGlrZSBob3cgZGVjaXNpb24gdHJlZXMgc3BsaXQgbm9kZXMgdG8gbWF4aW1pemUgcHVyaXR5IHdpdGggcmVzcGVjdCB0byBhIHRhcmdldCB2YXJpYWJsZS4NCg==