Data

The Varieties of Democracy (V-Dem) dataset is a new approach to conceptualizing and measuring democracy. The data provides a multidimensional and disaggregated perspective that reflects the complexity of the concept of democracy as a system of rule that goes beyond the simple presence of elections. The V-Dem project distinguishes between five high-level principles of democracy: electoral, liberal, participatory, deliberative, and egalitarian, and collects data to measure these principles.

The data regularly surveys 3000 expert to construct each measure. Below I’ve selected all metrics concerning civil liberties in a country. Below the following outlines all the V-Dems variables in the data.

  • Freedom from torture (v2cltort)
  • Freedom from political killings (v2clkill)
  • Freedom from forced labor for men (v2clslavem)
  • Freedom from forced labor for women (v2clslavef)
  • Transparent laws with predictable enforcement (v2cltrnslw)
  • Rigorous and impartial public administration (v2clrspct)
  • Access to justice for men (v2clacjstm)
  • Access to justice for women (v2clacjstw)
  • Social class equality in respect for civil liberty (v2clacjust)
  • Social group equality in respect for civil liberties (v2clsocgrp)
  • Freedom of discussion for men (v2cldiscm)
  • Freedom of discussion for women (v2cldiscw)
  • Freedom of academic and cultural expression (v2clacfree)
  • Freedom of religion (v2clrelig)
  • Freedom of foreign movement (v2clfmove)
  • Freedom of domestic movement for men (v2cldmovem)
  • Freedom of domestic movement for women (v2cldmovew)
  • State ownership of economy (v2clstown)
  • Property rights for men (v2clprptym)
  • Property rights for women (v2clprptyw)

The data has been aggregated to the country level (in an effort to keep the file size small). To do this, I first subsetted the data to reflect the post-World War II period and then averaged the scores for the entire time series. In addition, I’ve included a country-average measure of polity, which offers an alternative measure of democracy generated by the Center for Systemic Peace. (More on this below).

Task

Let’s explore some of the clustering methods used in lecture to see if we can cluster countries into basic regime types — democracies/non-democracies — using the V-Dems data of a country’s civil liberties record. We’ll then compare our clustered categories to the averaged polity metric to see if our bins reflect the democracy scale reflected in that metric.

Summarize

Read in the data.

vdems <- read_csv("Data/vdems_civil_liberties.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  country = col_character()
)
See spec(...) for full column specifications.

Quick summary of the data distribution using skimr. Somethings to note:

  • There are 177 observations, meaning there are 177 countries represented in the data.
  • All the V-Dems variables are already scaled (this actually has to do with how the measures are generated from the expert surveys). Generally speaking, since we leverage the concept of “distance” to cluster, we need all the variables to exist in the same space. The only exception here is the polity variable, but we’ll be using that as confirmation of the clusters we draw out of the data rather than an input into the clustering algorithm.
  • There is no missingness in the data.
  • From the mini histograms in the skimr plot, there doesn’t appear to be any significant distributional issues.
skimr::skim(vdems)
── Data Summary ────────────────────────
                           Values
Name                       vdems 
Number of rows             177   
Number of columns          25    
_______________________          
Column type frequency:           
  character                1     
  numeric                  24    
________________________         
Group variables                  

── Variable type: character ──────────────────────────────────────────
  skim_variable n_missing complete_rate   min   max empty n_unique
1 country               0             1     4    32     0      177
  whitespace
1          0

── Variable type: numeric ────────────────────────────────────────────
   skim_variable n_missing complete_rate    mean    sd     p0    p25
 1 polity                0             1  0.980   5.88 -10    -3.75 
 2 v2cltort              0             1  0.215   1.28  -2.22 -0.794
 3 v2clkill              0             1  0.480   1.27  -2.47 -0.604
 4 v2clslavem            0             1  0.595   1.05  -2.19 -0.249
 5 v2clslavef            0             1  0.536   1.03  -1.99 -0.176
 6 v2cltrnslw            0             1  0.258   1.24  -1.79 -0.715
 7 v2clrspct             0             1  0.0599  1.25  -1.99 -0.904
 8 v2clacjstm            0             1  0.288   1.24  -2.32 -0.694
 9 v2clacjstw            0             1  0.260   1.23  -2.96 -0.699
10 v2clacjust            0             1  0.595   1.12  -2.17 -0.178
11 v2clsocgrp            0             1  0.332   1.14  -2.24 -0.568
12 v2cldiscm             0             1  0.200   1.23  -2.88 -0.666
13 v2cldiscw             0             1  0.169   1.19  -2.81 -0.743
14 v2clacfree            0             1  0.233   1.26  -2.80 -0.738
15 v2clrelig             0             1  0.428   1.17  -3.34 -0.388
16 v2clfmove             0             1  0.416   1.15  -3.55 -0.479
17 v2cldmovem            0             1  0.468   1.08  -4.22 -0.220
18 v2cldmovew            0             1  0.374   1.20  -4.24 -0.558
19 v2clstown             0             1 -0.0333  1.06  -3.51 -0.762
20 v2clprptym            0             1  0.479   1.14  -3.41 -0.509
21 v2clprptyw            0             1  0.491   1.22  -2.83 -0.461
22 v2clgencl             0             1  0.497   1.10  -2.80 -0.304
23 v2clgeocl             0             1  0.0856  1.08  -2.50 -0.828
24 v2clpolcl             0             1  0.299   1.16  -2.18 -0.556
       p50   p75  p100 hist 
 1  0.0959 6     10    ▃▇▇▅▇
 2 -0.0369 1.01   3.06 ▃▇▆▃▃
 3  0.476  1.40   2.95 ▂▇▆▇▅
 4  0.824  1.38   2.73 ▁▃▅▇▃
 5  0.652  1.40   2.69 ▂▅▇▇▂
 6  0.0656 1.05   3.29 ▆▇▇▃▂
 7 -0.239  0.826  3.56 ▆▇▅▂▁
 8  0.127  0.983  3.10 ▂▆▇▃▃
 9  0.217  1.05   3.04 ▁▅▇▃▃
10  0.722  1.35   2.93 ▂▅▇▇▃
11  0.381  1.22   2.80 ▂▇▇▇▃
12 -0.0185 1.18   2.86 ▁▆▇▅▃
13  0.0179 1.06   3.03 ▁▆▇▅▃
14  0.151  1.09   2.75 ▁▇▇▇▅
15  0.616  1.39   2.47 ▁▂▅▇▆
16  0.542  1.32   2.45 ▁▂▇▇▆
17  0.694  1.28   2.07 ▁▁▃▆▇
18  0.671  1.29   2.26 ▁▁▆▆▇
19  0.0998 0.818  2.11 ▁▃▆▇▃
20  0.812  1.43   2.18 ▁▂▆▆▇
21  0.708  1.37   2.52 ▁▃▆▇▆
22  0.476  1.42   2.68 ▁▂▇▆▅
23 -0.0766 1.19   2.36 ▁▇▇▆▅
24  0.0236 1.14   2.99 ▃▇▇▅▃

Let’s now explore the correlation of the variables. As you can see, all the variables are highly correlated with one another. This isn’t surprising since they all attempt to get at similar concepts. That is, when you infringe upon the civil liberties along one dimension, you usually also do so along another. Clustering in an of itself makes no parametric assumptions, so we don’t need to worry about lurking issues here, such as multicolinearity. That said, these data are likely prime candidates for a decomposition (see reading)!

vdems %>% 
  select(-country,-polity) %>%  
  GGally::ggcorr(.)
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2

K Means Clustering

The aim here is to see if we can leverage the V-Dems civil liberties data to generate ad-hoc categories containing democracies and non-democracies. What is the value of doing this? Well, say we didn’t have any information on which observations were democracies and which were not (or we didn’t trust existing measures). We’ll unsupervised learning techniques, like K-Means clustering, offers us a way to classify clusters (i.e. groups, structures, etc.) in the data. These groups can correspond with theoretically relevant concepts (like democracy), or they can simply offer useful ways of clustering the information in the dataset to (a) generate new features to be used in a supervised machine learning task, and/or (b) explore the data. The way variables clump together (or don’t clump together) can sometimes offer interesting insights.

# Subset the data to only include the variables we are clustering
c_dat  <- vdems %>%  select(-country,-polity)

# Set a seed to reproduce results, as where you randomly start matters 
set.seed(1988)

# run the K Means clustering algorithm. Here 'centers' == k. 
kmean_cluster <- kmeans(c_dat,centers=2)
kmean_cluster
K-means clustering with 2 clusters of sizes 100, 77

Cluster means:
    v2cltort   v2clkill  v2clslavem  v2clslavef v2cltrnslw  v2clrspct
1 -0.6472049 -0.3528492 -0.02498549 -0.08285085 -0.5356396 -0.6596279
2  1.3337045  1.5623754  1.39904041  1.34071630  1.2877663  0.9942734
  v2clacjstm v2clacjstw  v2clacjust v2clsocgrp  v2cldiscm  v2cldiscw
1 -0.4948829 -0.5436113 -0.03226539 -0.3071647 -0.6647442 -0.6700085
2  1.3057142  1.3043362  1.41023181  1.1620475  1.3225157  1.2578235
  v2clacfree  v2clrelig  v2clfmove v2cldmovem v2cldmovew  v2clstown
1 -0.5420559 -0.2199273 -0.3047384 -0.1358756 -0.3404345 -0.4994183
2  1.2400200  1.2702497  1.3518833  1.2514456  1.3019754  0.5721136
  v2clprptym v2clprptyw  v2clgencl  v2clgeocl  v2clpolcl
1 -0.1914482 -0.2430414 -0.1292365 -0.6098815 -0.4403644
2  1.3489253  1.4439545  1.3101084  0.9887677  1.2580801

Clustering vector:
  [1] 1 1 1 1 2 2 2 2 1 1 1 2 2 2 2 1 1 2 2 2 1 2 1 1 1 1 2 1 1 1 2 1
 [33] 1 1 2 2 1 2 2 1 2 1 1 2 1 1 1 1 2 1 1 2 2 2 1 2 1 2 2 2 1 1 1 2
 [65] 1 1 2 2 2 1 1 1 2 2 2 1 2 2 1 2 1 2 1 2 1 2 2 1 1 1 2 2 1 1 1 1
 [97] 1 2 1 2 1 2 1 2 1 1 1 1 2 2 1 1 1 1 2 2 1 1 2 1 1 1 1 2 2 1 1 1
[129] 1 1 1 1 1 2 2 1 2 2 2 2 1 1 2 1 1 2 2 1 2 2 2 1 2 1 2 1 2 1 1 2
[161] 1 1 1 1 2 1 2 2 2 1 2 2 1 1 1 1 1

Within cluster sum of squares by cluster:
[1] 1700.127 1116.362
 (between_SS / total_SS =  49.3 %)

Available components:

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

As we can see above, the k-means algorithm is quick to run and it spits out a lot of interesting material.

  1. we can see the Within Cluster Sum of Squares. This captures the degree to which the cluster is homogeneous. The smaller this value is, the more the data points contained within the cluster resemble one another.
kmean_cluster$tot.withinss
[1] 2816.489
  1. We can see the between cluster sum of squares. This tells us how different each cluster is from the other clusters. Put differently, it’s a measure of heterogeneity between clusters.
kmean_cluster$betweenss
[1] 2736.799

In practice, we want the within-ness to be small, and the between-ness to be large. That is, each data point in a cluster really resembles its neighbors while each cluster is distinct from the other clusters.

This is more of an art than a science, but there is a clear way of trying to optimize this arrangement (see below).

  1. We can see that the k means algorithm spits out class designations. We’ll use these as the categories that we’ll classify each event.
kmean_cluster$cluster
  [1] 1 1 1 1 2 2 2 2 1 1 1 2 2 2 2 1 1 2 2 2 1 2 1 1 1 1 2 1 1 1 2 1
 [33] 1 1 2 2 1 2 2 1 2 1 1 2 1 1 1 1 2 1 1 2 2 2 1 2 1 2 2 2 1 1 1 2
 [65] 1 1 2 2 2 1 1 1 2 2 2 1 2 2 1 2 1 2 1 2 1 2 2 1 1 1 2 2 1 1 1 1
 [97] 1 2 1 2 1 2 1 2 1 1 1 1 2 2 1 1 1 1 2 2 1 1 2 1 1 1 1 2 2 1 1 1
[129] 1 1 1 1 1 2 2 1 2 2 2 2 1 1 2 1 1 2 2 1 2 2 2 1 2 1 2 1 2 1 1 2
[161] 1 1 1 1 2 1 2 2 2 1 2 2 1 1 1 1 1

We can actually turn this classification into a variable that we can use in a visualization, model, or data summary. Note that we convert to a factor so that R treats it as a categorical variable and not an ordered one. It’s always important to keep in mind that there is no intrinsic ordering in these categorical levels — that is, going from 1 to 2 doesn’t mean you’re increasing or decreasing.

vdems$k_clusters <- as.factor(kmean_cluster$cluster)

Specifically, let’s examine the difference in means between the clusters. We can see there are distinct divergences in the mean levels between the values in each of the two clusters.

vdems %>% 
  select(-country,-polity) %>% 
  group_by(k_clusters) %>% 
  summarize_all(mean) 

A better way to look at this is to examine the univariate distributions of the two cluster categories.

vdems %>% 
  
  # Let's reshape the data so that the imputes are in a "long" format
  pivot_longer(cols=v2cltort:v2clpolcl) %>% 
  
  # Let's now plot as separate density plots using facet wrap
  ggplot(aes(value,fill=k_clusters)) +
  geom_density(alpha=.5) +
  
  # Break up each plot by variable.
  facet_wrap(~name,scale='free',ncol=4) +
  theme(legend.position = "top")

NA

As we can see from the above, the algorithm does a fairly good job shuffling the data into two piles. We can see this play out in a simple scatter plot. Note that the clusters aren’t perfect: there does appear to be some cross-over, but the clusters appear stable.

vdems %>% 
  ggplot(aes(v2clkill,v2cltort,color=k_clusters)) +
  geom_point()

But did we capture democracy?

The big question now is whether we were successful or not in capturing the concept of democracy by using these data to cluster into two categories. First, let’s outline a few things to keep in mind:

  • An important thing to note is that it’s really hard to classify countries as democracies and non-democracies. Much ink has been split on the undertaking and clustering methods aren’t going to offer a magic wand that will do this perfectly.
  • We’re going to compare how well our clustering algorithm binned countries by looking at how it performed relative to the popular polity scale (which measures democracy on a -10 to 10 rating system). But noted, we often don’t have such a scale to measure the validity of our results. Else, why would we need to cluster, we could just use that existing classification system! This gets to the heart of why we call these methods unsupervised: there is no right or wrong answer, just interpretation.
  • The cluster categories don’t always have to “make sense” to be useful. Remember, much of supervised machine learning can operate under the paradigm of “throw it all in and see what does best”.

Let’s now compare our cluster categories to the polity scale. As we can see, it looks like our clusters did in fact broadly categorize democracies from non-democracies. Cluster 2 clearly contains countries that have a higher polity score (i.e. more democratic) than countries Cluster 1.

vdems %>% 
  ggplot(aes(k_clusters,polity)) +
  geom_boxplot()

Let’s look at the country membership into each category. As we can see, in Cluster 2 we capture countries like the United States, Finland, Canada, etc. and in Cluster 1 we capture states like Saudi Arabia, Russia, and North Korea. Note also, that the clusters aren’t perfect. There are some countries that fall lower on the polity scale that we captured in cluster 2 (e.g. Kazakhstan). Likewise, there are countries that were relatively high on the polity scale that were in Cluster 1 (e.ge. Turkey, South Africa).

vdems %>% 
  ggplot(aes(k_clusters,polity,color=k_clusters)) +
  geom_jitter(width=.3,show.legend = F) +
  ggrepel::geom_text_repel(aes(label=country),show.legend = F) +
  ggthemes::scale_color_gdocs()

The method isn’t perfect, but for something that took less than a second to run, not bad.

Optimizing K-means?

As a side note: one thing that we can do is to look for an “optimal” value of k by running the algorithm many times and plotting the within-ness and between-ness. There should be a point — an “elbow” as the literature goes — where one additional cluster brings very little return.

The following plots simply plots the within sum of squares and the between sum of squares as we increase the number of clusters.

between_sum_squares <- numeric()
within_sum_squares <- numeric()

# Run the algorithm for different values of k 
set.seed(1988)

for(k in c(1:10)){
  
  # For each k, calculate betweenss and tot.withinss
  between_sum_squares[k] <- kmeans(c_dat, centers=k)$betweenss
  within_sum_squares[k] <- kmeans(c_dat, centers=k)$tot.withinss
  
}

# Between-cluster sum of squares vs Choice of k
bss_plot <- qplot(1:10, between_sum_squares, geom=c("point", "line"), 
                  xlab="Number of clusters", ylab="Between-cluster sum of squares") +
  scale_x_continuous(breaks=seq(1, 10, 1)) +
  theme_bw()

# Total within-cluster sum of squares vs Choice of k
wss_plot <- qplot(1:10, within_sum_squares, geom=c("point", "line"),
                  xlab="Number of clusters", ylab="Total within-cluster sum of squares") +
  scale_x_continuous(breaks=seq(1, 10, 1)) +
  theme_bw()

# Subplot
gridExtra::grid.arrange(bss_plot, wss_plot, ncol=2)

As we can see from the above, after 4 clusters, we get very little by way of a return from adding an additional cluster. What’s interesting is that there appears to be something closer to 4 clusters in the data, so the data is potentially more nuanced than the two categories we just showcased.

Hierarchical Clustering

As we discussed in lecture, hierarchical clustering takes a very different approach to clustering data points. Rather than pre-specifying a value for k, we build the clusters organically from the bottom-up, using a concept of distance and tree structure.

First, note that we’ll need to convert our data into a pair-wise distance matrix, which in a single square matrix captures the euclidean distance of every observation to every other observation. The below code does this for us.

distance_mat <- dist(c_dat)
class(distance_mat) 
[1] "dist"

Recall that the concept of dissimilarity between pairs of observations (“linkage”) can be conceptualized in very different ways. Let’s explore how the hierarchical trees look different as one changes the concept of linkage.

hc_complete <- hclust(distance_mat, method="complete")
plot(hc_complete,main="Hierarchical Cluster - Complete Linkage")

hc_average <- hclust(distance_mat, method="average")
plot(hc_average,main="Hierarchical Cluster - Average Linkage")

hc_centroid=hclust(distance_mat, method="centroid")
plot(hc_centroid,main="Hierarchical Cluster - Centroid Linkage")

hc_single <- hclust(distance_mat, method="single")
plot(hc_single,main="Hierarchical Cluster - Single Linkage")

As we can see, very different stories emerge from each one. This isn’t a cause for alarm, but rather a call to investigation. How does differences in linkages change the types of clusters that emerge? Does this do a better or worse job? Do these decisions appear to reveal anything interesting from the data?

For example, when using centroid, average, and single linkage method, as single observation (114) stands out from the pack. What’s up with that observation? Let’s look.

vdems %>% slice(114)

Ah-ha! It’s North Korea. A clear outlier on the international stage. The hierarchical clustering method clearly noted the stark difference between North Korea and all the other countries in the data and that “distance” is captured in how observations were clustered.

So how did it do capturing democracy?

To get categories from a hierarchical clustering algorithm, you can do one of two things:

  1. “Trim” the tree at a certain height.
cutree(hc_complete,h=20)
  [1] 1 1 1 1 2 2 2 2 1 1 1 2 2 2 2 2 1 2 2 1 2 2 1 1 1 1 2 2 1 1 2 1
 [33] 1 1 2 2 1 2 2 1 2 1 1 1 1 1 1 1 2 1 1 2 2 2 1 2 1 2 2 2 1 1 1 2
 [65] 1 1 2 2 2 1 1 1 2 2 2 1 2 2 2 2 1 2 1 2 1 2 2 2 1 1 2 2 1 1 2 1
 [97] 1 2 1 2 1 2 2 2 1 1 1 1 2 2 1 2 1 1 2 2 1 1 2 2 1 1 1 2 2 1 1 1
[129] 1 1 1 2 1 2 2 1 2 2 2 2 1 1 2 1 1 2 2 1 2 2 2 1 2 1 2 1 2 1 1 2
[161] 1 1 1 1 2 1 2 2 2 1 2 2 1 1 1 1 1
  1. Ask for k number of clusters back, and the software will find the right height to cut the tree to return that result.
cutree(hc_complete,k=2)
  [1] 1 1 1 1 2 2 2 2 1 1 1 2 2 2 2 2 1 2 2 1 2 2 1 1 1 1 2 2 1 1 2 1
 [33] 1 1 2 2 1 2 2 1 2 1 1 1 1 1 1 1 2 1 1 2 2 2 1 2 1 2 2 2 1 1 1 2
 [65] 1 1 2 2 2 1 1 1 2 2 2 1 2 2 2 2 1 2 1 2 1 2 2 2 1 1 2 2 1 1 2 1
 [97] 1 2 1 2 1 2 2 2 1 1 1 1 2 2 1 2 1 1 2 2 1 1 2 2 1 1 1 2 2 1 1 1
[129] 1 1 1 2 1 2 2 1 2 2 2 2 1 1 2 1 1 2 2 1 2 2 2 1 2 1 2 1 2 1 1 2
[161] 1 1 1 1 2 1 2 2 2 1 2 2 1 1 1 1 1

Let’s do the following:

  • As before, let’s split the data into two cluster categories. Again, we’ll convert these categories two factors so R doesn’t get confused.
  • Let’s then compare those categories to polity and see if they capture our “democracy”/“non-democracy” concepts.
  • Let’s do this for every linkage method to see if there are any noticeable differences.
vdems$h_clust_complete <- as.factor(cutree(hc_complete,k=2))
vdems$h_clust_average <- as.factor(cutree(hc_average,k=2))
vdems$h_clust_centroid <- as.factor(cutree(hc_centroid ,k=2))
vdems$h_clust_single <- as.factor(cutree(hc_single,k=2))

Let’s now let’s plot.

vdems %>% 
  # Select the data, and spread the cluster categories long
  select(country,polity,contains("h_clust")) %>% 
  pivot_longer(cols=contains("h_clust"))  %>% 
  
  # Generate the box plots
  ggplot(aes(value,polity,fill=value,color=value)) +
  geom_boxplot(alpha=.7) +
  facet_wrap(~name,scales="free")

Wait, what’s going on here? Why are some of the categories so squished for a few of the methods? Recall that for many of the clustering algorithms there was North Korea and then every other country. This was true for all clustering algorithms but the complete method.

We could re-run this to then include more clusters, but then, we’ll be doing something slightly different than getting a raw measure for dems/non-dems.

For the h-clustering method that relies on complete linkage, we can see that we get a distinction similar to what we recovered from the k means algorithm.

Just for the sake of it, let’s increase k to 4. When we do so, we can see that those outlier categories prevail. This should make us think about what outliers mean for different linkage methods (and eventual interpretation) when using hierarchical clustering.

vdems$h_clust_complete <- as.factor(cutree(hc_complete,k=4))
vdems$h_clust_average <- as.factor(cutree(hc_average,k=4))
vdems$h_clust_centroid <- as.factor(cutree(hc_centroid ,k=4))
vdems$h_clust_single <- as.factor(cutree(hc_single,k=4))

vdems %>% 
  # Select the data, and spread the cluster categories long
  select(country,polity,contains("h_clust")) %>% 
  pivot_longer(cols=contains("h_clust"))  %>% 
  
  # Generate the box plots
  ggplot(aes(value,polity,fill=value,color=value)) +
  geom_boxplot(alpha=.7) +
  facet_wrap(~name,scales="free")

LS0tCnRpdGxlOiAiUFBPTDY3MCB8IEFwcGxpY2F0aW9ucyBpbiBVbnN1cGVydmlzZWQgTWFjaGluZSBMZWFybmluZyIKc3VidGl0bGU6ICJDbHVzdGVyaW5nIFJlZ2ltZSBUeXBlcyIKZGF0ZTogV2VlayAxMwpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRoZW1lOiB1bml0ZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7ciBTZXR1cCwgaW5jbHVkZT1GfQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEYsZXJyb3IgPSBGLG1lc3NhZ2UgPSBGKQpyZXF1aXJlKHRpZHl2ZXJzZSkKYGBgCgojIERhdGEgCgpUaGUgW1ZhcmlldGllcyBvZiBEZW1vY3JhY3kgKFYtRGVtKSBkYXRhc2V0XShodHRwczovL3d3dy52LWRlbS5uZXQvZW4vKSAgaXMgYSBuZXcgYXBwcm9hY2ggdG8gY29uY2VwdHVhbGl6aW5nIGFuZCBtZWFzdXJpbmcgZGVtb2NyYWN5LiBUaGUgZGF0YSBwcm92aWRlcyBhIG11bHRpZGltZW5zaW9uYWwgYW5kIGRpc2FnZ3JlZ2F0ZWQgcGVyc3BlY3RpdmUgdGhhdCByZWZsZWN0cyB0aGUgY29tcGxleGl0eSBvZiB0aGUgY29uY2VwdCBvZiBkZW1vY3JhY3kgYXMgYSBzeXN0ZW0gb2YgcnVsZSB0aGF0IGdvZXMgYmV5b25kIHRoZSBzaW1wbGUgcHJlc2VuY2Ugb2YgZWxlY3Rpb25zLiBUaGUgVi1EZW0gcHJvamVjdCBkaXN0aW5ndWlzaGVzIGJldHdlZW4gZml2ZSBoaWdoLWxldmVsIHByaW5jaXBsZXMgb2YgZGVtb2NyYWN5OiBlbGVjdG9yYWwsIGxpYmVyYWwsIHBhcnRpY2lwYXRvcnksIGRlbGliZXJhdGl2ZSwgYW5kIGVnYWxpdGFyaWFuLCBhbmQgY29sbGVjdHMgZGF0YSB0byBtZWFzdXJlIHRoZXNlIHByaW5jaXBsZXMuIAoKVGhlIGRhdGEgcmVndWxhcmx5IHN1cnZleXMgMzAwMCBleHBlcnQgdG8gY29uc3RydWN0IGVhY2ggbWVhc3VyZS4gQmVsb3cgSSd2ZSBzZWxlY3RlZCBhbGwgbWV0cmljcyBjb25jZXJuaW5nICoqY2l2aWwgbGliZXJ0aWVzKiogaW4gYSBjb3VudHJ5LiBCZWxvdyB0aGUgZm9sbG93aW5nIG91dGxpbmVzIGFsbCB0aGUgVi1EZW1zIHZhcmlhYmxlcyBpbiB0aGUgZGF0YS4gCgotIEZyZWVkb20gZnJvbSB0b3J0dXJlIChgdjJjbHRvcnRgKSAKLSBGcmVlZG9tIGZyb20gcG9saXRpY2FsIGtpbGxpbmdzIChgdjJjbGtpbGxgKSAKLSBGcmVlZG9tIGZyb20gZm9yY2VkIGxhYm9yIGZvciBtZW4gKGB2MmNsc2xhdmVtYCkgCi0gRnJlZWRvbSBmcm9tIGZvcmNlZCBsYWJvciBmb3Igd29tZW4gKGB2MmNsc2xhdmVmYCkgCi0gVHJhbnNwYXJlbnQgbGF3cyB3aXRoIHByZWRpY3RhYmxlIGVuZm9yY2VtZW50IChgdjJjbHRybnNsd2ApIAotIFJpZ29yb3VzIGFuZCBpbXBhcnRpYWwgcHVibGljIGFkbWluaXN0cmF0aW9uIChgdjJjbHJzcGN0YCkgCi0gQWNjZXNzIHRvIGp1c3RpY2UgZm9yIG1lbiAoYHYyY2xhY2pzdG1gKSAKLSBBY2Nlc3MgdG8ganVzdGljZSBmb3Igd29tZW4gKGB2MmNsYWNqc3R3YCkgCi0gU29jaWFsIGNsYXNzIGVxdWFsaXR5IGluIHJlc3BlY3QgZm9yIGNpdmlsIGxpYmVydHkgKGB2MmNsYWNqdXN0YCkKLSBTb2NpYWwgZ3JvdXAgZXF1YWxpdHkgaW4gcmVzcGVjdCBmb3IgY2l2aWwgbGliZXJ0aWVzIChgdjJjbHNvY2dycGApCi0gRnJlZWRvbSBvZiBkaXNjdXNzaW9uIGZvciBtZW4gKGB2MmNsZGlzY21gKQotIEZyZWVkb20gb2YgZGlzY3Vzc2lvbiBmb3Igd29tZW4gKGB2MmNsZGlzY3dgKQotIEZyZWVkb20gb2YgYWNhZGVtaWMgYW5kIGN1bHR1cmFsIGV4cHJlc3Npb24gKGB2MmNsYWNmcmVlYCkgCi0gRnJlZWRvbSBvZiByZWxpZ2lvbiAoYHYyY2xyZWxpZ2ApIAotIEZyZWVkb20gb2YgZm9yZWlnbiBtb3ZlbWVudCAoYHYyY2xmbW92ZWApIAotIEZyZWVkb20gb2YgZG9tZXN0aWMgbW92ZW1lbnQgZm9yIG1lbiAoYHYyY2xkbW92ZW1gKSAKLSBGcmVlZG9tIG9mIGRvbWVzdGljIG1vdmVtZW50IGZvciB3b21lbiAoYHYyY2xkbW92ZXdgKSAKLSBTdGF0ZSBvd25lcnNoaXAgb2YgZWNvbm9teSAoYHYyY2xzdG93bmApIAotIFByb3BlcnR5IHJpZ2h0cyBmb3IgbWVuIChgdjJjbHBycHR5bWApIAotIFByb3BlcnR5IHJpZ2h0cyBmb3Igd29tZW4gKGB2MmNscHJwdHl3YCkKClRoZSBkYXRhIGhhcyBiZWVuIGFnZ3JlZ2F0ZWQgdG8gdGhlIGNvdW50cnkgbGV2ZWwgKGluIGFuIGVmZm9ydCB0byBrZWVwIHRoZSBmaWxlIHNpemUgc21hbGwpLiBUbyBkbyB0aGlzLCBJIGZpcnN0IHN1YnNldHRlZCB0aGUgZGF0YSB0byByZWZsZWN0IHRoZSBwb3N0LVdvcmxkIFdhciBJSSBwZXJpb2QgYW5kIHRoZW4gYXZlcmFnZWQgdGhlIHNjb3JlcyBmb3IgdGhlIGVudGlyZSB0aW1lIHNlcmllcy4gSW4gYWRkaXRpb24sIEkndmUgaW5jbHVkZWQgYSBjb3VudHJ5LWF2ZXJhZ2UgbWVhc3VyZSBvZiBgcG9saXR5YCwgd2hpY2ggb2ZmZXJzIGFuIGFsdGVybmF0aXZlIG1lYXN1cmUgb2YgZGVtb2NyYWN5IGdlbmVyYXRlZCBieSB0aGUgW0NlbnRlciBmb3IgU3lzdGVtaWMgUGVhY2VdKGh0dHBzOi8vd3d3LnN5c3RlbWljcGVhY2Uub3JnL3BvbGl0eXByb2plY3QuaHRtbCkuIChNb3JlIG9uIHRoaXMgYmVsb3cpLgoKIyBUYXNrIAoKTGV0J3MgZXhwbG9yZSBzb21lIG9mIHRoZSBjbHVzdGVyaW5nIG1ldGhvZHMgdXNlZCBpbiBsZWN0dXJlIHRvIHNlZSBpZiB3ZSBjYW4gY2x1c3RlciBjb3VudHJpZXMgaW50byBiYXNpYyByZWdpbWUgdHlwZXMgLS0tIGRlbW9jcmFjaWVzL25vbi1kZW1vY3JhY2llcyAtLS0gdXNpbmcgdGhlIFYtRGVtcyBkYXRhIG9mIGEgY291bnRyeSdzIGNpdmlsIGxpYmVydGllcyByZWNvcmQuIFdlJ2xsIHRoZW4gY29tcGFyZSBvdXIgY2x1c3RlcmVkIGNhdGVnb3JpZXMgdG8gdGhlIGF2ZXJhZ2VkIHBvbGl0eSBtZXRyaWMgdG8gc2VlIGlmIG91ciBiaW5zIHJlZmxlY3QgdGhlIGRlbW9jcmFjeSBzY2FsZSByZWZsZWN0ZWQgaW4gdGhhdCBtZXRyaWMuIAoKCiMgU3VtbWFyaXplCgpSZWFkIGluIHRoZSBkYXRhLgoKYGBge3J9CnZkZW1zIDwtIHJlYWRfY3N2KCJEYXRhL3ZkZW1zX2NpdmlsX2xpYmVydGllcy5jc3YiKQpgYGAKCgpRdWljayBzdW1tYXJ5IG9mIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbiB1c2luZyBgc2tpbXJgLiBTb21ldGhpbmdzIHRvIG5vdGU6CgotIFRoZXJlIGFyZSAxNzcgb2JzZXJ2YXRpb25zLCBtZWFuaW5nIHRoZXJlIGFyZSAxNzcgY291bnRyaWVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhLiAKLSBBbGwgdGhlIFYtRGVtcyB2YXJpYWJsZXMgYXJlIGFscmVhZHkgc2NhbGVkICh0aGlzIGFjdHVhbGx5IGhhcyB0byBkbyB3aXRoIGhvdyB0aGUgbWVhc3VyZXMgYXJlIGdlbmVyYXRlZCBmcm9tIHRoZSBleHBlcnQgc3VydmV5cykuIEdlbmVyYWxseSBzcGVha2luZywgc2luY2Ugd2UgbGV2ZXJhZ2UgdGhlIGNvbmNlcHQgb2YgImRpc3RhbmNlIiB0byBjbHVzdGVyLCB3ZSBuZWVkIGFsbCB0aGUgdmFyaWFibGVzIHRvIGV4aXN0IGluIHRoZSBzYW1lIHNwYWNlLiBUaGUgb25seSBleGNlcHRpb24gaGVyZSBpcyB0aGUgYHBvbGl0eWAgdmFyaWFibGUsIGJ1dCB3ZSdsbCBiZSB1c2luZyB0aGF0IGFzIGNvbmZpcm1hdGlvbiBvZiB0aGUgY2x1c3RlcnMgd2UgZHJhdyBvdXQgb2YgdGhlIGRhdGEgcmF0aGVyIHRoYW4gYW4gaW5wdXQgaW50byB0aGUgY2x1c3RlcmluZyBhbGdvcml0aG0uIAotIFRoZXJlIGlzIG5vIG1pc3NpbmduZXNzIGluIHRoZSBkYXRhLiAKLSBGcm9tIHRoZSBtaW5pIGhpc3RvZ3JhbXMgaW4gdGhlIGBza2ltcmAgcGxvdCwgdGhlcmUgZG9lc24ndCBhcHBlYXIgdG8gYmUgYW55IHNpZ25pZmljYW50IGRpc3RyaWJ1dGlvbmFsIGlzc3Vlcy4gCgpgYGB7cn0Kc2tpbXI6OnNraW0odmRlbXMpCmBgYAoKCkxldCdzIG5vdyBleHBsb3JlIHRoZSBjb3JyZWxhdGlvbiBvZiB0aGUgdmFyaWFibGVzLiBBcyB5b3UgY2FuIHNlZSwgYWxsIHRoZSB2YXJpYWJsZXMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggb25lIGFub3RoZXIuIFRoaXMgaXNuJ3Qgc3VycHJpc2luZyBzaW5jZSB0aGV5IGFsbCBhdHRlbXB0IHRvIGdldCBhdCBzaW1pbGFyIGNvbmNlcHRzLiBUaGF0IGlzLCB3aGVuIHlvdSBpbmZyaW5nZSB1cG9uIHRoZSBjaXZpbCBsaWJlcnRpZXMgYWxvbmcgb25lIGRpbWVuc2lvbiwgeW91IHVzdWFsbHkgYWxzbyBkbyBzbyBhbG9uZyBhbm90aGVyLiBDbHVzdGVyaW5nIGluIGFuIG9mIGl0c2VsZiBtYWtlcyBubyBwYXJhbWV0cmljIGFzc3VtcHRpb25zLCBzbyB3ZSBkb24ndCBuZWVkIHRvIHdvcnJ5IGFib3V0IGx1cmtpbmcgaXNzdWVzIGhlcmUsIHN1Y2ggYXMgbXVsdGljb2xpbmVhcml0eS4gVGhhdCBzYWlkLCB0aGVzZSBkYXRhIGFyZSBsaWtlbHkgcHJpbWUgY2FuZGlkYXRlcyBmb3IgYSBkZWNvbXBvc2l0aW9uIChzZWUgcmVhZGluZykhCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLmhlaWdodD00LGZpZy53aWR0aD03fQp2ZGVtcyAlPiUgCiAgc2VsZWN0KC1jb3VudHJ5LC1wb2xpdHkpICU+JSAgCiAgR0dhbGx5OjpnZ2NvcnIoLikKYGBgCgoKCiMgSyBNZWFucyBDbHVzdGVyaW5nIAoKVGhlIGFpbSBoZXJlIGlzIHRvIHNlZSBpZiB3ZSBjYW4gbGV2ZXJhZ2UgdGhlIFYtRGVtcyBjaXZpbCBsaWJlcnRpZXMgZGF0YSB0byBnZW5lcmF0ZSBhZC1ob2MgY2F0ZWdvcmllcyBjb250YWluaW5nIGRlbW9jcmFjaWVzIGFuZCBub24tZGVtb2NyYWNpZXMuIFdoYXQgaXMgdGhlIHZhbHVlIG9mIGRvaW5nIHRoaXM/IFdlbGwsIHNheSB3ZSBkaWRuJ3QgaGF2ZSBhbnkgaW5mb3JtYXRpb24gb24gd2hpY2ggb2JzZXJ2YXRpb25zIHdlcmUgZGVtb2NyYWNpZXMgYW5kIHdoaWNoIHdlcmUgbm90IChvciB3ZSBkaWRuJ3QgdHJ1c3QgZXhpc3RpbmcgbWVhc3VyZXMpLiBXZSdsbCB1bnN1cGVydmlzZWQgbGVhcm5pbmcgdGVjaG5pcXVlcywgbGlrZSBLLU1lYW5zIGNsdXN0ZXJpbmcsIG9mZmVycyB1cyBhIHdheSB0byBjbGFzc2lmeSBjbHVzdGVycyAoaS5lLiBncm91cHMsIHN0cnVjdHVyZXMsIGV0Yy4pIGluIHRoZSBkYXRhLiBUaGVzZSBncm91cHMgY2FuIGNvcnJlc3BvbmQgd2l0aCB0aGVvcmV0aWNhbGx5IHJlbGV2YW50IGNvbmNlcHRzIChsaWtlIGRlbW9jcmFjeSksIG9yIHRoZXkgY2FuIHNpbXBseSBvZmZlciB1c2VmdWwgd2F5cyBvZiBjbHVzdGVyaW5nIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZGF0YXNldCB0byAoYSkgZ2VuZXJhdGUgbmV3IGZlYXR1cmVzIHRvIGJlIHVzZWQgaW4gYSBzdXBlcnZpc2VkIG1hY2hpbmUgbGVhcm5pbmcgdGFzaywgYW5kL29yIChiKSBleHBsb3JlIHRoZSBkYXRhLiBUaGUgd2F5IHZhcmlhYmxlcyBjbHVtcCB0b2dldGhlciAob3IgZG9uJ3QgY2x1bXAgdG9nZXRoZXIpIGNhbiBzb21ldGltZXMgb2ZmZXIgaW50ZXJlc3RpbmcgaW5zaWdodHMuCgoKCmBgYHtyfQojIFN1YnNldCB0aGUgZGF0YSB0byBvbmx5IGluY2x1ZGUgdGhlIHZhcmlhYmxlcyB3ZSBhcmUgY2x1c3RlcmluZwpjX2RhdCAgPC0gdmRlbXMgJT4lICBzZWxlY3QoLWNvdW50cnksLXBvbGl0eSkKCiMgU2V0IGEgc2VlZCB0byByZXByb2R1Y2UgcmVzdWx0cywgYXMgd2hlcmUgeW91IHJhbmRvbWx5IHN0YXJ0IG1hdHRlcnMgCnNldC5zZWVkKDE5ODgpCgojIHJ1biB0aGUgSyBNZWFucyBjbHVzdGVyaW5nIGFsZ29yaXRobS4gSGVyZSAnY2VudGVycycgPT0gay4gCmttZWFuX2NsdXN0ZXIgPC0ga21lYW5zKGNfZGF0LGNlbnRlcnM9MikKa21lYW5fY2x1c3RlcgpgYGAKCkFzIHdlIGNhbiBzZWUgYWJvdmUsIHRoZSBrLW1lYW5zIGFsZ29yaXRobSBpcyBxdWljayB0byBydW4gYW5kIGl0IHNwaXRzIG91dCBhIGxvdCBvZiBpbnRlcmVzdGluZyBtYXRlcmlhbC4gCgoxLiB3ZSBjYW4gc2VlIHRoZSAqKldpdGhpbiBDbHVzdGVyIFN1bSBvZiBTcXVhcmVzKiouIFRoaXMgY2FwdHVyZXMgdGhlIGRlZ3JlZSB0byB3aGljaCB0aGUgY2x1c3RlciBpcyBfaG9tb2dlbmVvdXNfLiBUaGUgc21hbGxlciB0aGlzIHZhbHVlIGlzLCB0aGUgbW9yZSB0aGUgZGF0YSBwb2ludHMgY29udGFpbmVkIHdpdGhpbiB0aGUgY2x1c3RlciByZXNlbWJsZSBvbmUgYW5vdGhlci4gCgpgYGB7cn0Ka21lYW5fY2x1c3RlciR0b3Qud2l0aGluc3MKYGBgCgoKMi4gV2UgY2FuIHNlZSB0aGUgKipiZXR3ZWVuIGNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMqKi4gVGhpcyB0ZWxscyB1cyBob3cgX2RpZmZlcmVudF8gZWFjaCBjbHVzdGVyIGlzIGZyb20gdGhlIG90aGVyIGNsdXN0ZXJzLiBQdXQgZGlmZmVyZW50bHksIGl0J3MgYSBtZWFzdXJlIG9mIGhldGVyb2dlbmVpdHkgYmV0d2VlbiBjbHVzdGVycy4gCgpgYGB7cn0Ka21lYW5fY2x1c3RlciRiZXR3ZWVuc3MKYGBgCgpJbiBwcmFjdGljZSwgd2Ugd2FudCB0aGUgd2l0aGluLW5lc3MgdG8gYmUgc21hbGwsIGFuZCB0aGUgYmV0d2Vlbi1uZXNzIHRvIGJlIGxhcmdlLiBUaGF0IGlzLCBlYWNoIGRhdGEgcG9pbnQgaW4gYSBjbHVzdGVyIHJlYWxseSByZXNlbWJsZXMgaXRzIG5laWdoYm9ycyB3aGlsZSBlYWNoIGNsdXN0ZXIgaXMgZGlzdGluY3QgZnJvbSB0aGUgb3RoZXIgY2x1c3RlcnMuIAoKVGhpcyBpcyBtb3JlIG9mIGFuIGFydCB0aGFuIGEgc2NpZW5jZSwgYnV0IHRoZXJlIGlzIGEgY2xlYXIgd2F5IG9mIHRyeWluZyB0byBvcHRpbWl6ZSB0aGlzIGFycmFuZ2VtZW50IChzZWUgYmVsb3cpLgoKCjMuICBXZSBjYW4gc2VlIHRoYXQgdGhlIGsgbWVhbnMgYWxnb3JpdGhtIHNwaXRzIG91dCBjbGFzcyBkZXNpZ25hdGlvbnMuIFdlJ2xsIHVzZSB0aGVzZSBhcyB0aGUgY2F0ZWdvcmllcyB0aGF0IHdlJ2xsIGNsYXNzaWZ5IGVhY2ggZXZlbnQuIAoKYGBge3J9CmttZWFuX2NsdXN0ZXIkY2x1c3RlcgpgYGAKCldlIGNhbiBhY3R1YWxseSB0dXJuIHRoaXMgY2xhc3NpZmljYXRpb24gaW50byBhIHZhcmlhYmxlIHRoYXQgd2UgY2FuIHVzZSBpbiBhIHZpc3VhbGl6YXRpb24sIG1vZGVsLCBvciBkYXRhIHN1bW1hcnkuIE5vdGUgdGhhdCB3ZSBjb252ZXJ0IHRvIGEgZmFjdG9yIHNvIHRoYXQgYFJgIHRyZWF0cyBpdCBhcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGFuZCBub3QgYW4gb3JkZXJlZCBvbmUuIEl0J3MgYWx3YXlzIGltcG9ydGFudCB0byBrZWVwIGluIG1pbmQgdGhhdCB0aGVyZSBpcyBfbm8gaW50cmluc2ljIG9yZGVyaW5nXyBpbiB0aGVzZSBjYXRlZ29yaWNhbCBsZXZlbHMgLS0tIHRoYXQgaXMsIGdvaW5nIGZyb20gMSB0byAyIGRvZXNuJ3QgbWVhbiB5b3UncmUgaW5jcmVhc2luZyBvciBkZWNyZWFzaW5nLiAKCmBgYHtyfQp2ZGVtcyRrX2NsdXN0ZXJzIDwtIGFzLmZhY3RvcihrbWVhbl9jbHVzdGVyJGNsdXN0ZXIpCmBgYAoKU3BlY2lmaWNhbGx5LCBsZXQncyBleGFtaW5lIHRoZSBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gdGhlIGNsdXN0ZXJzLiBXZSBjYW4gc2VlIHRoZXJlIGFyZSBkaXN0aW5jdCBkaXZlcmdlbmNlcyBpbiB0aGUgbWVhbiBsZXZlbHMgYmV0d2VlbiB0aGUgdmFsdWVzIGluIGVhY2ggb2YgdGhlIHR3byBjbHVzdGVycy4gCgpgYGB7cn0KdmRlbXMgJT4lIAogIHNlbGVjdCgtY291bnRyeSwtcG9saXR5KSAlPiUgCiAgZ3JvdXBfYnkoa19jbHVzdGVycykgJT4lIAogIHN1bW1hcml6ZV9hbGwobWVhbikgCmBgYAoKCkEgYmV0dGVyIHdheSB0byBsb29rIGF0IHRoaXMgaXMgdG8gZXhhbWluZSB0aGUgdW5pdmFyaWF0ZSBkaXN0cmlidXRpb25zIG9mIHRoZSB0d28gY2x1c3RlciBjYXRlZ29yaWVzLiAgCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLmhlaWdodD02LGZpZy53aWR0aD03fQp2ZGVtcyAlPiUgCiAgCiAgIyBMZXQncyByZXNoYXBlIHRoZSBkYXRhIHNvIHRoYXQgdGhlIGltcHV0ZXMgYXJlIGluIGEgImxvbmciIGZvcm1hdAogIHBpdm90X2xvbmdlcihjb2xzPXYyY2x0b3J0OnYyY2xwb2xjbCkgJT4lIAogIAogICMgTGV0J3Mgbm93IHBsb3QgYXMgc2VwYXJhdGUgZGVuc2l0eSBwbG90cyB1c2luZyBmYWNldCB3cmFwCiAgZ2dwbG90KGFlcyh2YWx1ZSxmaWxsPWtfY2x1c3RlcnMpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41KSArCiAgCiAgIyBCcmVhayB1cCBlYWNoIHBsb3QgYnkgdmFyaWFibGUuCiAgZmFjZXRfd3JhcCh+bmFtZSxzY2FsZT0nZnJlZScsbmNvbD00KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgCmBgYAoKQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBhYm92ZSwgdGhlIGFsZ29yaXRobSBkb2VzIGEgZmFpcmx5IGdvb2Qgam9iIHNodWZmbGluZyB0aGUgZGF0YSBpbnRvIHR3byBwaWxlcy4gIFdlIGNhbiBzZWUgdGhpcyBwbGF5IG91dCBpbiBhIHNpbXBsZSBzY2F0dGVyIHBsb3QuIE5vdGUgdGhhdCB0aGUgY2x1c3RlcnMgYXJlbid0IHBlcmZlY3Q6IHRoZXJlIGRvZXMgYXBwZWFyIHRvIGJlIHNvbWUgY3Jvc3Mtb3ZlciwgYnV0IHRoZSBjbHVzdGVycyBhcHBlYXIgc3RhYmxlLiAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTd9CnZkZW1zICU+JSAKICBnZ3Bsb3QoYWVzKHYyY2xraWxsLHYyY2x0b3J0LGNvbG9yPWtfY2x1c3RlcnMpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKCiMjIyBCdXQgZGlkIHdlIGNhcHR1cmUgZGVtb2NyYWN5PwoKVGhlIGJpZyBxdWVzdGlvbiBub3cgaXMgd2hldGhlciB3ZSB3ZXJlIHN1Y2Nlc3NmdWwgb3Igbm90IGluIGNhcHR1cmluZyB0aGUgY29uY2VwdCBvZiBkZW1vY3JhY3kgYnkgdXNpbmcgdGhlc2UgZGF0YSB0byBjbHVzdGVyIGludG8gdHdvIGNhdGVnb3JpZXMuIEZpcnN0LCBsZXQncyBvdXRsaW5lIGEgZmV3IHRoaW5ncyB0byBrZWVwIGluIG1pbmQ6CgotIEFuIGltcG9ydGFudCB0aGluZyB0byBub3RlIGlzIHRoYXQgaXQncyByZWFsbHkgaGFyZCB0byBjbGFzc2lmeSBjb3VudHJpZXMgYXMgZGVtb2NyYWNpZXMgYW5kIG5vbi1kZW1vY3JhY2llcy4gTXVjaCBpbmsgaGFzIGJlZW4gc3BsaXQgb24gdGhlIHVuZGVydGFraW5nIGFuZCBjbHVzdGVyaW5nIG1ldGhvZHMgYXJlbid0IGdvaW5nIHRvIG9mZmVyIGEgbWFnaWMgd2FuZCB0aGF0IHdpbGwgZG8gdGhpcyBwZXJmZWN0bHkuIAotIFdlJ3JlIGdvaW5nIHRvIGNvbXBhcmUgaG93IHdlbGwgb3VyIGNsdXN0ZXJpbmcgYWxnb3JpdGhtIGJpbm5lZCBjb3VudHJpZXMgYnkgbG9va2luZyBhdCBob3cgaXQgcGVyZm9ybWVkIHJlbGF0aXZlIHRvIHRoZSBwb3B1bGFyIGBwb2xpdHlgIHNjYWxlICh3aGljaCBtZWFzdXJlcyBkZW1vY3JhY3kgb24gYSAtMTAgdG8gMTAgcmF0aW5nIHN5c3RlbSkuIEJ1dCBub3RlZCwgd2Ugb2Z0ZW4gZG9uJ3QgaGF2ZSBzdWNoIGEgc2NhbGUgdG8gbWVhc3VyZSB0aGUgdmFsaWRpdHkgb2Ygb3VyIHJlc3VsdHMuIEVsc2UsIHdoeSB3b3VsZCB3ZSBuZWVkIHRvIGNsdXN0ZXIsIHdlIGNvdWxkIGp1c3QgdXNlIHRoYXQgZXhpc3RpbmcgY2xhc3NpZmljYXRpb24gc3lzdGVtISBUaGlzIGdldHMgdG8gdGhlIGhlYXJ0IG9mIHdoeSB3ZSBjYWxsIHRoZXNlIG1ldGhvZHMgX3Vuc3VwZXJ2aXNlZF86IHRoZXJlIGlzIG5vIHJpZ2h0IG9yIHdyb25nIGFuc3dlciwganVzdCBpbnRlcnByZXRhdGlvbi4KLSBUaGUgY2x1c3RlciBjYXRlZ29yaWVzIGRvbid0IGFsd2F5cyBoYXZlIHRvICJtYWtlIHNlbnNlIiB0byBiZSB1c2VmdWwuIFJlbWVtYmVyLCBtdWNoIG9mIHN1cGVydmlzZWQgbWFjaGluZSBsZWFybmluZyBjYW4gb3BlcmF0ZSB1bmRlciB0aGUgcGFyYWRpZ20gb2YgInRocm93IGl0IGFsbCBpbiBhbmQgc2VlIHdoYXQgZG9lcyBiZXN0Ii4gCgpMZXQncyBub3cgY29tcGFyZSBvdXIgY2x1c3RlciBjYXRlZ29yaWVzIHRvIHRoZSBwb2xpdHkgc2NhbGUuIEFzIHdlIGNhbiBzZWUsIGl0IGxvb2tzIGxpa2Ugb3VyIGNsdXN0ZXJzIGRpZCBpbiBmYWN0IGJyb2FkbHkgY2F0ZWdvcml6ZSBkZW1vY3JhY2llcyBmcm9tIG5vbi1kZW1vY3JhY2llcy4gQ2x1c3RlciAyIGNsZWFybHkgY29udGFpbnMgY291bnRyaWVzIHRoYXQgaGF2ZSBhIGhpZ2hlciBwb2xpdHkgc2NvcmUgKGkuZS4gbW9yZSBkZW1vY3JhdGljKSB0aGFuIGNvdW50cmllcyBDbHVzdGVyIDEuIAoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9N30KdmRlbXMgJT4lIAogIGdncGxvdChhZXMoa19jbHVzdGVycyxwb2xpdHkpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgoKTGV0J3MgbG9vayBhdCB0aGUgY291bnRyeSBtZW1iZXJzaGlwIGludG8gZWFjaCBjYXRlZ29yeS4gQXMgd2UgY2FuIHNlZSwgaW4gQ2x1c3RlciAyIHdlIGNhcHR1cmUgY291bnRyaWVzIGxpa2UgdGhlIFVuaXRlZCBTdGF0ZXMsIEZpbmxhbmQsIENhbmFkYSwgZXRjLiBhbmQgaW4gQ2x1c3RlciAxIHdlIGNhcHR1cmUgc3RhdGVzIGxpa2UgU2F1ZGkgQXJhYmlhLCBSdXNzaWEsIGFuZCBOb3J0aCBLb3JlYS4gTm90ZSBhbHNvLCB0aGF0IHRoZSBjbHVzdGVycyBhcmVuJ3QgcGVyZmVjdC4gVGhlcmUgYXJlIHNvbWUgY291bnRyaWVzIHRoYXQgZmFsbCBsb3dlciBvbiB0aGUgcG9saXR5IHNjYWxlIHRoYXQgd2UgY2FwdHVyZWQgaW4gY2x1c3RlciAyIChlLmcuIEthemFraHN0YW4pLiBMaWtld2lzZSwgdGhlcmUgYXJlIGNvdW50cmllcyB0aGF0IHdlcmUgcmVsYXRpdmVseSBoaWdoIG9uIHRoZSBwb2xpdHkgc2NhbGUgdGhhdCB3ZXJlIGluIENsdXN0ZXIgMSAoZS5nZS4gVHVya2V5LCBTb3V0aCBBZnJpY2EpLiAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcuaGVpZ2h0PTgsZmlnLndpZHRoPTEwfQp2ZGVtcyAlPiUgCiAgZ2dwbG90KGFlcyhrX2NsdXN0ZXJzLHBvbGl0eSxjb2xvcj1rX2NsdXN0ZXJzKSkgKwogIGdlb21faml0dGVyKHdpZHRoPS4zLHNob3cubGVnZW5kID0gRikgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9Y291bnRyeSksc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2d0aGVtZXM6OnNjYWxlX2NvbG9yX2dkb2NzKCkKYGBgCgpUaGUgbWV0aG9kIGlzbid0IHBlcmZlY3QsIGJ1dCBmb3Igc29tZXRoaW5nIHRoYXQgdG9vayBsZXNzIHRoYW4gYSBzZWNvbmQgdG8gcnVuLCBub3QgYmFkLiAKCgojIyMgT3B0aW1pemluZyBLLW1lYW5zPwoKQXMgYSBzaWRlIG5vdGU6IG9uZSB0aGluZyB0aGF0IHdlIGNhbiBkbyBpcyB0byBsb29rIGZvciBhbiAib3B0aW1hbCIgdmFsdWUgb2YgYGtgIGJ5IHJ1bm5pbmcgdGhlIGFsZ29yaXRobSBtYW55IHRpbWVzIGFuZCBwbG90dGluZyB0aGUgd2l0aGluLW5lc3MgYW5kIGJldHdlZW4tbmVzcy4gVGhlcmUgc2hvdWxkIGJlIGEgcG9pbnQgLS0tIGFuICJlbGJvdyIgYXMgdGhlIGxpdGVyYXR1cmUgZ29lcyAtLS0gd2hlcmUgb25lIGFkZGl0aW9uYWwgY2x1c3RlciBicmluZ3MgdmVyeSBsaXR0bGUgcmV0dXJuLiAKClRoZSBmb2xsb3dpbmcgcGxvdHMgc2ltcGx5IHBsb3RzIHRoZSB3aXRoaW4gc3VtIG9mIHNxdWFyZXMgYW5kIHRoZSBiZXR3ZWVuIHN1bSBvZiBzcXVhcmVzIGFzIHdlIGluY3JlYXNlIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMuCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLmhlaWdodD00LGZpZy53aWR0aD03fQpiZXR3ZWVuX3N1bV9zcXVhcmVzIDwtIG51bWVyaWMoKQp3aXRoaW5fc3VtX3NxdWFyZXMgPC0gbnVtZXJpYygpCgojIFJ1biB0aGUgYWxnb3JpdGhtIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGsgCnNldC5zZWVkKDE5ODgpCgpmb3IoayBpbiBjKDE6MTApKXsKICAKICAjIEZvciBlYWNoIGssIGNhbGN1bGF0ZSBiZXR3ZWVuc3MgYW5kIHRvdC53aXRoaW5zcwogIGJldHdlZW5fc3VtX3NxdWFyZXNba10gPC0ga21lYW5zKGNfZGF0LCBjZW50ZXJzPWspJGJldHdlZW5zcwogIHdpdGhpbl9zdW1fc3F1YXJlc1trXSA8LSBrbWVhbnMoY19kYXQsIGNlbnRlcnM9aykkdG90LndpdGhpbnNzCiAgCn0KCiMgQmV0d2Vlbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmVzIHZzIENob2ljZSBvZiBrCmJzc19wbG90IDwtIHFwbG90KDE6MTAsIGJldHdlZW5fc3VtX3NxdWFyZXMsIGdlb209YygicG9pbnQiLCAibGluZSIpLCAKICAgICAgICAgICAgICAgICAgeGxhYj0iTnVtYmVyIG9mIGNsdXN0ZXJzIiwgeWxhYj0iQmV0d2Vlbi1jbHVzdGVyIHN1bSBvZiBzcXVhcmVzIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDEsIDEwLCAxKSkgKwogIHRoZW1lX2J3KCkKCiMgVG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMgdnMgQ2hvaWNlIG9mIGsKd3NzX3Bsb3QgPC0gcXBsb3QoMToxMCwgd2l0aGluX3N1bV9zcXVhcmVzLCBnZW9tPWMoInBvaW50IiwgImxpbmUiKSwKICAgICAgICAgICAgICAgICAgeGxhYj0iTnVtYmVyIG9mIGNsdXN0ZXJzIiwgeWxhYj0iVG90YWwgd2l0aGluLWNsdXN0ZXIgc3VtIG9mIHNxdWFyZXMiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMSwgMTAsIDEpKSArCiAgdGhlbWVfYncoKQoKIyBTdWJwbG90CmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGJzc19wbG90LCB3c3NfcGxvdCwgbmNvbD0yKQpgYGAKCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgYWJvdmUsIGFmdGVyIDQgY2x1c3RlcnMsIHdlIGdldCB2ZXJ5IGxpdHRsZSBieSB3YXkgb2YgYSByZXR1cm4gZnJvbSBhZGRpbmcgYW4gYWRkaXRpb25hbCBjbHVzdGVyLiBXaGF0J3MgaW50ZXJlc3RpbmcgaXMgdGhhdCB0aGVyZSBhcHBlYXJzIHRvIGJlIHNvbWV0aGluZyBjbG9zZXIgdG8gNCBjbHVzdGVycyBpbiB0aGUgZGF0YSwgc28gdGhlIGRhdGEgaXMgcG90ZW50aWFsbHkgbW9yZSBudWFuY2VkIHRoYW4gdGhlIHR3byBjYXRlZ29yaWVzIHdlIGp1c3Qgc2hvd2Nhc2VkLiAKCgojIEhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nIAoKQXMgd2UgZGlzY3Vzc2VkIGluIGxlY3R1cmUsIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIHRha2VzIGEgdmVyeSBkaWZmZXJlbnQgYXBwcm9hY2ggdG8gY2x1c3RlcmluZyBkYXRhIHBvaW50cy4gUmF0aGVyIHRoYW4gcHJlLXNwZWNpZnlpbmcgYSB2YWx1ZSBmb3IgYGtgLCB3ZSBidWlsZCB0aGUgY2x1c3RlcnMgb3JnYW5pY2FsbHkgZnJvbSB0aGUgYm90dG9tLXVwLCB1c2luZyBhIGNvbmNlcHQgb2YgZGlzdGFuY2UgYW5kIHRyZWUgc3RydWN0dXJlLgoKRmlyc3QsIG5vdGUgdGhhdCB3ZSdsbCBuZWVkIHRvIGNvbnZlcnQgb3VyIGRhdGEgaW50byBhIHBhaXItd2lzZSBkaXN0YW5jZSBtYXRyaXgsIHdoaWNoIGluIGEgc2luZ2xlIHNxdWFyZSBtYXRyaXggY2FwdHVyZXMgdGhlIGV1Y2xpZGVhbiBkaXN0YW5jZSBvZiBldmVyeSBvYnNlcnZhdGlvbiB0byBldmVyeSBvdGhlciBvYnNlcnZhdGlvbi4gVGhlIGJlbG93IGNvZGUgZG9lcyB0aGlzIGZvciB1cy4gCgpgYGB7cn0KZGlzdGFuY2VfbWF0IDwtIGRpc3QoY19kYXQpCmNsYXNzKGRpc3RhbmNlX21hdCkgCmBgYAoKClJlY2FsbCB0aGF0IHRoZSBjb25jZXB0IG9mIGRpc3NpbWlsYXJpdHkgYmV0d2VlbiBwYWlycyBvZiBvYnNlcnZhdGlvbnMgKCJsaW5rYWdlIikgY2FuIGJlIGNvbmNlcHR1YWxpemVkIGluIHZlcnkgZGlmZmVyZW50IHdheXMuIExldCdzIGV4cGxvcmUgaG93IHRoZSBoaWVyYXJjaGljYWwgdHJlZXMgbG9vayBkaWZmZXJlbnQgYXMgb25lIGNoYW5nZXMgdGhlIGNvbmNlcHQgb2YgbGlua2FnZS4KCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTd9CmhjX2NvbXBsZXRlIDwtIGhjbHVzdChkaXN0YW5jZV9tYXQsIG1ldGhvZD0iY29tcGxldGUiKQpwbG90KGhjX2NvbXBsZXRlLG1haW49IkhpZXJhcmNoaWNhbCBDbHVzdGVyIC0gQ29tcGxldGUgTGlua2FnZSIpCmBgYAoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9N30KaGNfYXZlcmFnZSA8LSBoY2x1c3QoZGlzdGFuY2VfbWF0LCBtZXRob2Q9ImF2ZXJhZ2UiKQpwbG90KGhjX2F2ZXJhZ2UsbWFpbj0iSGllcmFyY2hpY2FsIENsdXN0ZXIgLSBBdmVyYWdlIExpbmthZ2UiKQpgYGAKCgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZmlnLmhlaWdodD01LGZpZy53aWR0aD03fQpoY19jZW50cm9pZD1oY2x1c3QoZGlzdGFuY2VfbWF0LCBtZXRob2Q9ImNlbnRyb2lkIikKcGxvdChoY19jZW50cm9pZCxtYWluPSJIaWVyYXJjaGljYWwgQ2x1c3RlciAtIENlbnRyb2lkIExpbmthZ2UiKQpgYGAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTd9CmhjX3NpbmdsZSA8LSBoY2x1c3QoZGlzdGFuY2VfbWF0LCBtZXRob2Q9InNpbmdsZSIpCnBsb3QoaGNfc2luZ2xlLG1haW49IkhpZXJhcmNoaWNhbCBDbHVzdGVyIC0gU2luZ2xlIExpbmthZ2UiKQpgYGAKCkFzIHdlIGNhbiBzZWUsIHZlcnkgZGlmZmVyZW50IHN0b3JpZXMgZW1lcmdlIGZyb20gZWFjaCBvbmUuIFRoaXMgaXNuJ3QgYSBjYXVzZSBmb3IgYWxhcm0sIGJ1dCByYXRoZXIgYSBjYWxsIHRvIGludmVzdGlnYXRpb24uIEhvdyBkb2VzIGRpZmZlcmVuY2VzIGluIGxpbmthZ2VzIGNoYW5nZSB0aGUgdHlwZXMgb2YgY2x1c3RlcnMgdGhhdCBlbWVyZ2U/IERvZXMgdGhpcyBkbyBhIGJldHRlciBvciB3b3JzZSBqb2I/IERvIHRoZXNlIGRlY2lzaW9ucyBhcHBlYXIgdG8gcmV2ZWFsIGFueXRoaW5nIGludGVyZXN0aW5nIGZyb20gdGhlIGRhdGE/IAoKRm9yIGV4YW1wbGUsIHdoZW4gdXNpbmcgY2VudHJvaWQsIGF2ZXJhZ2UsIGFuZCBzaW5nbGUgbGlua2FnZSBtZXRob2QsIGFzIHNpbmdsZSBvYnNlcnZhdGlvbiAoYDExNGApIHN0YW5kcyBvdXQgZnJvbSB0aGUgcGFjay4gV2hhdCdzIHVwIHdpdGggdGhhdCBvYnNlcnZhdGlvbj8gTGV0J3MgbG9vay4KCmBgYHtyfQp2ZGVtcyAlPiUgc2xpY2UoMTE0KQpgYGAKCkFoLWhhISBJdCdzIE5vcnRoIEtvcmVhLiBBIGNsZWFyIG91dGxpZXIgb24gdGhlIGludGVybmF0aW9uYWwgc3RhZ2UuIFRoZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBtZXRob2QgY2xlYXJseSBub3RlZCB0aGUgc3RhcmsgZGlmZmVyZW5jZSBiZXR3ZWVuIE5vcnRoIEtvcmVhIGFuZCBhbGwgdGhlIG90aGVyIGNvdW50cmllcyBpbiB0aGUgZGF0YSBhbmQgdGhhdCAiZGlzdGFuY2UiIGlzIGNhcHR1cmVkIGluIGhvdyBvYnNlcnZhdGlvbnMgd2VyZSBjbHVzdGVyZWQuICAKCgojIyMgU28gaG93IGRpZCBpdCBkbyBjYXB0dXJpbmcgZGVtb2NyYWN5PwoKVG8gZ2V0IGNhdGVnb3JpZXMgZnJvbSBhIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIGFsZ29yaXRobSwgeW91IGNhbiBkbyBvbmUgb2YgdHdvIHRoaW5nczoKCjEuICJUcmltIiB0aGUgdHJlZSBhdCBhIGNlcnRhaW4gaGVpZ2h0LgoKYGBge3J9CmN1dHJlZShoY19jb21wbGV0ZSxoPTIwKQpgYGAKCjIuIEFzayBmb3IgYGtgIG51bWJlciBvZiBjbHVzdGVycyBiYWNrLCBhbmQgdGhlIHNvZnR3YXJlIHdpbGwgZmluZCB0aGUgcmlnaHQgaGVpZ2h0IHRvIGN1dCB0aGUgdHJlZSB0byByZXR1cm4gdGhhdCByZXN1bHQuIAoKYGBge3J9CmN1dHJlZShoY19jb21wbGV0ZSxrPTIpCmBgYAoKCkxldCdzIGRvIHRoZSBmb2xsb3dpbmc6CgotIEFzIGJlZm9yZSwgbGV0J3Mgc3BsaXQgdGhlIGRhdGEgaW50byB0d28gY2x1c3RlciBjYXRlZ29yaWVzLiBBZ2Fpbiwgd2UnbGwgY29udmVydCB0aGVzZSBjYXRlZ29yaWVzIHR3byBmYWN0b3JzIHNvIGBSYCBkb2Vzbid0IGdldCBjb25mdXNlZC4gIAotIExldCdzIHRoZW4gY29tcGFyZSB0aG9zZSBjYXRlZ29yaWVzIHRvIHBvbGl0eSBhbmQgc2VlIGlmIHRoZXkgY2FwdHVyZSBvdXIgImRlbW9jcmFjeSIvIm5vbi1kZW1vY3JhY3kiIGNvbmNlcHRzLgotIExldCdzIGRvIHRoaXMgZm9yIGV2ZXJ5IGxpbmthZ2UgbWV0aG9kIHRvIHNlZSBpZiB0aGVyZSBhcmUgYW55IG5vdGljZWFibGUgZGlmZmVyZW5jZXMuIAoKCmBgYHtyfQp2ZGVtcyRoX2NsdXN0X2NvbXBsZXRlIDwtIGFzLmZhY3RvcihjdXRyZWUoaGNfY29tcGxldGUsaz0yKSkKdmRlbXMkaF9jbHVzdF9hdmVyYWdlIDwtIGFzLmZhY3RvcihjdXRyZWUoaGNfYXZlcmFnZSxrPTIpKQp2ZGVtcyRoX2NsdXN0X2NlbnRyb2lkIDwtIGFzLmZhY3RvcihjdXRyZWUoaGNfY2VudHJvaWQgLGs9MikpCnZkZW1zJGhfY2x1c3Rfc2luZ2xlIDwtIGFzLmZhY3RvcihjdXRyZWUoaGNfc2luZ2xlLGs9MikpCmBgYAoKCkxldCdzIG5vdyBsZXQncyBwbG90LgoKYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLGZpZy5oZWlnaHQ9MyxmaWcud2lkdGg9NX0KdmRlbXMgJT4lIAogICMgU2VsZWN0IHRoZSBkYXRhLCBhbmQgc3ByZWFkIHRoZSBjbHVzdGVyIGNhdGVnb3JpZXMgbG9uZwogIHNlbGVjdChjb3VudHJ5LHBvbGl0eSxjb250YWlucygiaF9jbHVzdCIpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9Y29udGFpbnMoImhfY2x1c3QiKSkgICU+JSAKICAKICAjIEdlbmVyYXRlIHRoZSBib3ggcGxvdHMKICBnZ3Bsb3QoYWVzKHZhbHVlLHBvbGl0eSxmaWxsPXZhbHVlLGNvbG9yPXZhbHVlKSkgKwogIGdlb21fYm94cGxvdChhbHBoYT0uNykgKwogIGZhY2V0X3dyYXAofm5hbWUsc2NhbGVzPSJmcmVlIikKYGBgCgpXYWl0LCB3aGF0J3MgZ29pbmcgb24gaGVyZT8gV2h5IGFyZSBzb21lIG9mIHRoZSBjYXRlZ29yaWVzIHNvIHNxdWlzaGVkIGZvciBhIGZldyBvZiB0aGUgbWV0aG9kcz8gUmVjYWxsIHRoYXQgZm9yIG1hbnkgb2YgdGhlIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcyB0aGVyZSB3YXMgTm9ydGggS29yZWEgYW5kIHRoZW4gZXZlcnkgb3RoZXIgY291bnRyeS4gVGhpcyB3YXMgdHJ1ZSBmb3IgYWxsIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcyBidXQgdGhlIGBjb21wbGV0ZWAgbWV0aG9kLiAKCldlIGNvdWxkIHJlLXJ1biB0aGlzIHRvIHRoZW4gaW5jbHVkZSBtb3JlIGNsdXN0ZXJzLCBidXQgdGhlbiwgd2UnbGwgYmUgZG9pbmcgc29tZXRoaW5nIHNsaWdodGx5IGRpZmZlcmVudCB0aGFuIGdldHRpbmcgYSByYXcgbWVhc3VyZSBmb3IgZGVtcy9ub24tZGVtcy4gCgpGb3IgdGhlIGgtY2x1c3RlcmluZyBtZXRob2QgdGhhdCByZWxpZXMgb24gY29tcGxldGUgbGlua2FnZSwgd2UgY2FuIHNlZSB0aGF0IHdlIGdldCBhIGRpc3RpbmN0aW9uIHNpbWlsYXIgdG8gd2hhdCB3ZSByZWNvdmVyZWQgZnJvbSB0aGUgayBtZWFucyBhbGdvcml0aG0uIAoKSnVzdCBmb3IgdGhlIHNha2Ugb2YgaXQsIGxldCdzIGluY3JlYXNlIGsgdG8gNC4gV2hlbiB3ZSBkbyBzbywgd2UgY2FuIHNlZSB0aGF0IHRob3NlIG91dGxpZXIgY2F0ZWdvcmllcyBwcmV2YWlsLiBUaGlzIHNob3VsZCBtYWtlIHVzIHRoaW5rIGFib3V0IHdoYXQgb3V0bGllcnMgbWVhbiBmb3IgZGlmZmVyZW50IGxpbmthZ2UgbWV0aG9kcyAoYW5kIGV2ZW50dWFsIGludGVycHJldGF0aW9uKSB3aGVuIHVzaW5nIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nLiAKCmBgYHtyLGZpZy5hbGlnbj0iY2VudGVyIixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTd9CnZkZW1zJGhfY2x1c3RfY29tcGxldGUgPC0gYXMuZmFjdG9yKGN1dHJlZShoY19jb21wbGV0ZSxrPTQpKQp2ZGVtcyRoX2NsdXN0X2F2ZXJhZ2UgPC0gYXMuZmFjdG9yKGN1dHJlZShoY19hdmVyYWdlLGs9NCkpCnZkZW1zJGhfY2x1c3RfY2VudHJvaWQgPC0gYXMuZmFjdG9yKGN1dHJlZShoY19jZW50cm9pZCAsaz00KSkKdmRlbXMkaF9jbHVzdF9zaW5nbGUgPC0gYXMuZmFjdG9yKGN1dHJlZShoY19zaW5nbGUsaz00KSkKCnZkZW1zICU+JSAKICAjIFNlbGVjdCB0aGUgZGF0YSwgYW5kIHNwcmVhZCB0aGUgY2x1c3RlciBjYXRlZ29yaWVzIGxvbmcKICBzZWxlY3QoY291bnRyeSxwb2xpdHksY29udGFpbnMoImhfY2x1c3QiKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzPWNvbnRhaW5zKCJoX2NsdXN0IikpICAlPiUgCiAgCiAgIyBHZW5lcmF0ZSB0aGUgYm94IHBsb3RzCiAgZ2dwbG90KGFlcyh2YWx1ZSxwb2xpdHksZmlsbD12YWx1ZSxjb2xvcj12YWx1ZSkpICsKICBnZW9tX2JveHBsb3QoYWxwaGE9LjcpICsKICBmYWNldF93cmFwKH5uYW1lLHNjYWxlcz0iZnJlZSIpCmBgYAoK