Loading the data
Throughout the course, We will be loading data from R files with the extension .RData. An example is the file TCAG_brca.RData which we examine below.
.RData files are binary files (i.e., not human readable) that can store multiple R objects, such as vectors, lists, matrices, and data frames.
The R objects in .Rdata files are the results of previous R analyses, and the data is in tidy form. Tidy data sets have consistent structure and are easy to manipulate, visualize, and model.
We could spend the entire course on learning how to put data in tidy form, but our goal is the understand and analyze the data, which occurs after tidying the data.
# We simply `load()` TCGA_brca.RData
# The file.path() function tells `load()` where our data lives
# The argument "verbose = TRUE" makes `load()` tell us what R objects are being loaded
load(file.path(data_dir, "TCGA_brca.RData"),verbose=TRUE)
Loading objects:
brca_expr_norm_names_df
brca_gene_df
brca_clin_df
The objects were named to be be descriptive. * “df” stands for “dataframe” * “brca” stands for “TCGA breast cancer” * “expr” stands for “gene expression data” * “norm” means that the data is normalized to account for variability in the experiments * “names” reminds us that the data has the gene names included * “clin” is short for “clinical”
We looked at brca_clin_df last time.
Today we will also consider brca_expr_norm_names_df.
The Environment tab gives us basic information on the objects that were loaded.
We will use some of the R functions we learned to examine the data in more detail. * dim() tells us the dimensions (# row, # columns) of the objects. * head() shows us the top several rows of the objects. * indexing allows us to look at the rows and columns we choose.
dim(brca_expr_norm_names_df) # We should get a result consistent
[1] 18351 1083
# with what is in the Environment tab
Let’s see what’s in the rows and columns.
brca_expr_norm_names_df[1:5,1:5] # Inspect the first few rows of the data frame
The first column, “symbol” is the names of the genes. The remaining columns are the expression levels of the genes from different patient samples.
“TCGA-3C-AAAU” is the anonymized identifier for one patient’s sample.
To do analysis with the expression dataframe, we have to remove the “symbol” column so that the matrix contains only the numerical gene expression data. But we want to keep the information from the “symbol” column. R allows us to do this by assigning the symbols as the row names for our matrix.
brca_expr_mat <- as.matrix(brca_expr_norm_names_df[,-1]) # We remove the first column,
# use the function as.matrix().
# and assign the result to a new object.
# Now, we'll use the function row.names() to keep the gene symbols.
row.names(brca_expr_mat) <- brca_expr_norm_names_df$symbol
Let’s use indexing to check our the first 5 rows and columns of our matrix.
brca_expr_mat[1:5,1:5]
TCGA-3C-AAAU TCGA-3C-AALI TCGA-3C-AALJ TCGA-3C-AALK
TSPAN6 188.1840 207.7220 1005.4400 1104.6800
TNMD 0.3447 1.0875 39.8912 1.2412
DPM1 524.2260 809.1350 967.3620 463.3840
SCYL3 325.1410 1558.9400 335.8300 549.2550
C1orf112 124.2940 274.6660 241.6860 218.2250
TCGA-4H-AAAK
TSPAN6 942.5530
TNMD 4.6809
DPM1 486.3830
SCYL3 416.2850
C1orf112 179.4600
Let’s look at the average value of the expression for the first two genes, TSPAN6 and TNMD.
TSPAN6 codes for the protein Tetraspanin-6. This protein helps signal events that play a role in cell growth and motility.
TNMD codes for the protein Tenomodulin, which is important for the formation of tendons. TNMD is highly expressed in tendons, but lowly expressed in other parts of the body.
# mean() takes the average of a set of values
avg_TSPAN6_expr <- mean(brca_expr_mat[1,]) # We are taking the average of expression values
# for the first row of the matrix
avg_TNMD_expr <- mean(brca_expr_mat[2,]) # We are taking the average of expression values
# for the second row of the matrix
print(paste("Average expression of TSPAN6: ", round(avg_TSPAN6_expr,0)))
[1] "Average expression of TSPAN6: 996"
print(paste("Average expression of TNMD: ", round(avg_TNMD_expr,0)))
[1] "Average expression of TNMD: 24"
# The function paste() allows us to print text and numbers together.
# The function round() lets us choose how many decimal digits we want to show.
It would stink to have to do this for all 18,351 genes.
But we can use the function apply() to apply a function like mean() to all rows or columns of our matrix.
mean.expr <- apply(brca_expr_mat, 1, mean) # We "apply" the function mean() to all rows.
# The first argument is the matrix.
# The second argument is 1 for "rows".
# The third argument is the function name, `mean()`
as.table(round(mean.expr[1:25],0))
TSPAN6 TNMD DPM1 SCYL3 C1orf112 FGR CFH
996 24 699 624 320 187 1246
FUCA2 GCLC NFYA STPG1 NIPAL3 LAS1L ENPP4
1432 869 1326 215 985 1143 642
SEMA3F CFTR ANKIB1 CYP51A1 KRIT1 RAD52 BAD
2180 19 1614 1945 738 130 853
LAP3 CD99 HS3ST1 AOC1
2646 2751 91 84
It’s nice we can calculate all the means at once, but it’s not very helpful in comparing the mean of the different genes.
Let’s try plotting the means as a histogram.
hist(mean.expr, breaks=100, main="Distribution of Gene Expression Values",
xlab="Mean Expression")

# A histogram is a graphical display of data using bars of different heights.
# Each bar groups numbers into ranges. Taller bars show that more data falls in that range.
# The first argument is the data, the second is how bars we want to show,
# the third is a title for the plot, and the fourth is the name of the x-axis.
Wow! Most of the average expression values are relatively small (less than 200), but there must be a few really large values.
Let’s see how many genes have average expression greater than 10,000.
print(paste("Total values: ", length(mean.expr)))
[1] "Total values: 18351"
print(paste("Num values > 10,000: ", sum(mean.expr > 10000)))
[1] "Num values > 10,000: 201"
print(paste("Pencentage of mean values > 10,000: ", round(sum(mean.expr>10000)/length(mean.expr)*100,1)))
[1] "Pencentage of mean values > 10,000: 1.1"
So there are a few really big numbers. The curve in the histogram has a long right tail.
Nearly all genes have low expression, and very few genes have high expression.
Unfortunately, many analysis functions in R do not work well with this kind of distribution.
Instead, it is very common to assume the data follow a normal (or bell) curve.
In practive,very little real life biological data truly follow a normal curve. It has been established that most analysis works quite well if the data are close enough to a normal curve.
We can make our data more like normal data by doing a log transform. If we take the log of all the epxression values, we put the data more on equally footing.
Expression data is typically logged using base 2.
Log base 2 of 8 is 3 because 2 * 2 * 2 = 8.
Log base 4 of 4 is 2 because 2 * 2 = 4.
Log base 2 of 2 is 1 because 2 = 2.
So the values (8, 4 , 2) are transformed to (3, 2, 1).
Let’s consider some larger numbers:
a <- c(4096, 1024, 512, 64)
b <- log(a,2)
plot(a,b,pch=19,col="red")

Notice how the scale for b is much more compressed than for a.
By taking the log2 of numbers, we make them more similar to each other.
a
[1] 4096 1024 512 64
log(a,2)
[1] 12 10 9 6
There is one caveat. The log2 of 0 is infinity!
log(0,2)
[1] -Inf
But the log2 of 1 is “well-behaved.”
log(1,2)
[1] 0
So before taking the log2 of our expression data, we will add 1 to each value to avoid the occirence of “-Inf” values.
brca_expr_mat.log <- log(brca_expr_mat+1, 2) # We add 1 to each element, then take the log base 2.
#Let's look at some values:
brca_expr_mat.log[1:5,1:5]
TCGA-3C-AAAU TCGA-3C-AALI TCGA-3C-AALJ TCGA-3C-AALK
TSPAN6 7.5636463 7.705439 9.975045 10.110718
TNMD 0.4272843 1.061776 5.353718 1.164271
DPM1 9.0367945 9.662019 9.919403 8.859174
SCYL3 8.3493520 10.607275 8.395877 9.103957
C1orf112 6.9691735 8.106778 7.922947 7.776269
TCGA-4H-AAAK
TSPAN6 9.881960
TNMD 2.506120
DPM1 8.928912
SCYL3 8.704889
C1orf112 7.495535
Let’s check out what the curve is for the log-transformed expression values:
mean.expr <- apply(brca_expr_mat.log, 1, mean) # We "apply" the function mean() to all rows.
View(our_matrix)
# The first argument is the matrix.
# The second argument is 1 for "rows".
# The third argument is the function name, `mean()`
hist(mean.expr, breaks=100, main="Distribution of Log_2 Gene Expression Values",
xlab="Mean Log_2 Expression")

# A histogram is a graphical display of data using bars of different heights.
# Each bar groups numbers into ranges. Taller bars show that more data falls in that range.
# The first argument is the data, the second is how bars we want to show,
# the third is a title for the plot, and the fourth is the name of the x-axis.
This isn’t quite normal (especially at the lower range), but it is much closer, and importantly, close enough for some exploratory analyses.
Visualizing the data with heatmaps
Let’s start by taking a look at what the data looks like using a heatmap. We won’t be able to make a heatmap of the entire data set — there are just too many genes.
Just to remind ourselves, take another look at the size of the data.
dim(brca_expr_mat.log)
[1] 18351 1082
brca_expr_mat.log[1:5,1:5]
TCGA-3C-AAAU TCGA-3C-AALI TCGA-3C-AALJ TCGA-3C-AALK
TSPAN6 7.5636463 7.705439 9.975045 10.110718
TNMD 0.4272843 1.061776 5.353718 1.164271
DPM1 9.0367945 9.662019 9.919403 8.859174
SCYL3 8.3493520 10.607275 8.395877 9.103957
C1orf112 6.9691735 8.106778 7.922947 7.776269
TCGA-4H-AAAK
TSPAN6 9.881960
TNMD 2.506120
DPM1 8.928912
SCYL3 8.704889
C1orf112 7.495535
To reduce the number of genes, we will try to select the most important ones for an exploratory analysis. There are many different ways to do this, and your choice here can lead to profoundly different views of the data.
One common approach to select genes in an unbiased way is to find the ones with the biggest differences across the samples, or in statistics language, the ones with the highest variance
We’ll consider the 500 genes with the highest variance.
And order out matrix accordingly, so we make a matrix for the top 500 variable genes.
NUM.GENES <- 500 # How many genes we want to consider.
v <- apply(brca_expr_mat, 1, var) # Here, we use the function apply
# with the function var (for variance).
O <- order(v, decreasing=TRUE) # The function order will rank the values for us.
var_genes <- v[O] # We look at the top ten.
brca.log.sub <- brca_expr_mat.log[O[1:NUM.GENES],]
Let’s look at it.
brca.log.sub[1:5,1:5]
TCGA-3C-AAAU TCGA-3C-AALI TCGA-3C-AALJ TCGA-3C-AALK
CPB1 16.16135 4.243707 11.10774 6.928501
COL1A1 15.76215 17.451710 17.46421 18.729189
COL1A2 15.08131 16.591093 16.53135 17.853364
FN1 15.49303 16.703795 16.88043 17.056871
COL3A1 14.94762 16.132576 16.08866 17.581760
TCGA-4H-AAAK
CPB1 2.707503
COL1A1 18.659219
COL1A2 18.187168
FN1 17.901097
COL3A1 17.871713
When we’re doing exploratory analysis, we’ll often work with just a subset of the data. It makes things go faster, and the plots are easier to interpret. To pull out 10% of the samples, let’s store in the I.sample vector the indexes of every 10th sample. We’ll use this subset for now, but for the final analysis, we’ll certainly want to use the whole data set.
library("RColorBrewer") # We call a library that has nice colors
I.sample <- seq(1, ncol(brca.log.sub), 10) # We take every tenth sample.
heatmap(brca.log.sub[,I.sample],
Rowv=NA, Colv=NA, scale="none", labRow="", # These arguments are for plotting
labCol="", col=brewer.pal(10,"RdBu"), margins = c(1, 0)) # the heatmap.

Each row is a gene, and each column is a sample. It doesn’t quite look right, though. There are a bunch of horizontal stripes. This happens because some of the genes are expressed higher than others. While this is interesting, what we really want to see are the patterns of expression across the samples. In other words, we want to know, for each gene, whether it is higher in one group of samples versus the other. So we are more interested in the relative expression of the genes, rather than the absolute expression.
To get the relative gene expression, we will first normalize each of the genes. A common way to do this is to change each gene such that the mean expression is 0, and the variance is 1. The absolute gene expression values will be changed, but the relative expression (whether it is higher or lower in a particular sample) will be preserved.
R has an easy way to do this with the function scale().
help(scale)
Notice that scale() will scale the columns of our matrix. But we want to scale the genes, which are in the rows!
This is not a problem, because we can use the transpose function t() to convert rows to columns and columns to rows.
So we scale the transposed matrix. Then we have to transpose it back!!
Here, we are using three nested functions: * t() to transpose our matrix * scale() to scale the transposed matrix * another t() to transpose back so that genes are rows again.
brca.log.sub.scale <- t(scale(t(brca.log.sub)))
What does the heatmap look like now?
heatmap(brca.log.sub.scale[,I.sample],
Rowv=NA, Colv=NA, scale="none", labRow="", # The rest of the arguments are for plotting.
labCol="", col=brewer.pal(10,"RdBu"), zlim=c(-2, 2), margins = c(1, 0))

Nice! This is much better. We can more easily see which genes are overexpressed (red) and underexpressed (blue) in a relative manner.
Our next activity will be to organize this matrix so we can see patterns among the * genes (row), and * samples (columns),
and associate the patterns with clinical informations.
Practice
Save this file with another name.
Work through the activity again and change values such as NUM.GENES and I.sample.
How do your choices change what you see?
Clustering: Finding patterns in the data
Here, we will do hierarchical clustering.
We first calcuate the distances between the rows (genes) in our matrix. To do this, we apply the function dist() to our matrix.
Then we calculate the distances between the columns (samples) in our matrix. To do this, we apply dist() to the transpose of our matrix.
our_matrix <- brca.log.sub.scale[,I.sample]
row.dist <- dist(our_matrix) # Use dist() on our matrix
col.dist <- dist(t(our_matrix)) # Use distr() on the transpose of our matrix
Then we cluster the rows and columns based on the distances we calculated and create the dendrograms, i.e. the distance trees, with the function hclust().
row_clusters <- hclust(row.dist) # Apply `hclust()` to the rows
column_clusters <- hclust(col.dist) # Apply `hclust()` to the columns
Now, we will generate the clustered heatmaps.
heatmap(
our_matrix, # The matrix of expression values
Rowv=as.dendrogram(row_clusters), # Create row dendrogram from `row_clusters`
Colv=as.dendrogram(column_clusters), # Create column dendogram from `column_clusters`
scale="none", labRow="", labCol="", col=brewer.pal(10,"RdBu"), # plotting arguments
zlim=c(-2, 2), margins = c(1, 0) # more plotting arguments
)

Clusters and the underlying biology
From this heatmap, we can see that the tumors split up into different groups. Is there any biological significance to these clusters? Are these groups only seen in the gene expression patterns, or is it related to any known biology?
As you previously learned, breast cancer is split up into ER+ and ER- tumors, depending on whether the tumor expresses high levels of receptors for estrogen. This is really important to know because it tells you what’s driving the disease, and also how to treat it. To see whether ER status is associated with these clusters, let’s label the samples with a "+" for ER+ breast cancers, and "." for negative.
clin <- brca_clin_df[I.sample,] # We index the clinical data for
# our subset of samples.
x <- clin[["breast_carcinoma_estrogen_receptor_status"]] # We find and name the
print(sort(unique(x))) # different types of ER status.
[1] "[Not Evaluated]" "Negative" "Positive"
er <- rep("", length(x)) # We will label the columns of
er[x == "Positive"] <- "+" # our heat map with `er`.
er[x == "Negative"] <- "."
print(sum(er == ""))
[1] 6
heatmap(
our_matrix, # The matrix of expression values
Rowv=as.dendrogram(row_clusters), # Create row dendrogram from `row_clusters`
Colv=as.dendrogram(column_clusters), # Create column dendogram from `column_clusters`
scale="none", labRow="", labCol=er, col=brewer.pal(10,"RdBu"), # NOTICE labCol=er
zlim=c(-2, 2), margins = c(1, 0) # more plotting arguments
)

NA
NA
In this plot, I see about four or five clusters of samples. Most of them have a lot of ER+ tumors (marked by the row of pluses on the bottom), while one is nearly all ER-.
Beautiful!!
LS0tCnRpdGxlOiAnTW9kdWxlIDE6IEZpbmRpbmcgUGF0dGVybnMgaW4gRXhwcmVzc2lvbiBEYXRhJwphdXRob3I6ICJBbGV4IExld2lzIGFuZCBEaWFuYSBNdXJyYXkiCmRhdGU6ICJKdWx5IDMwLCAyMDIwIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyMgUHJlbGltaW5hcmllcwoKCgojIyMgVGhlIGtuaXRyIFIgcGFja2FnZSAKCioqa25pdHIoKSoqIGlzIHRoZSBSIHBhY2thZ2UgdGhhdCBnZW5lcmF0ZXMgdGhlIHJlcG9ydCBmcm9tIFIgTWFya2Rvd24uIFdlIGNhbiBjcmVhdGUgcmVwb3J0cyBhcyBXb3JkIGRvYywgUERGLCBhbmQgSFRNTCBmaWxlcy4gCgpBbiBSIHBhY2thZ2UgYnVuZGxlcyB0b2dldGhlciBjb2RlLCBkYXRhLCBkb2N1bWVudGF0aW9uLCBhbmQgdGVzdHMsIGFuZCBpcyBlYXN5IHRvIGRvd25sb2FkIGFuZCBzaGFyZSB3aXRoIG90aGVycy4KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCmRhdGFfZGlyIDwtICIvaG9tZS9kYXRhIiAgICAjIFRoZSBkYXRhIHdlIGFyZSB1c2luZyBpcyBsb2NhdGVkIGluIHRoaXMgZGlyZWN0b3J5IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBvbiBvdXIgY2xvdWQgY29tcHV0aW5nIHNlcnZlci4KCmBgYAoKIyMgQWJvdXQgdGhpcyBhY3Rpdml0eQoKWW91IHdpbGwgbG9hZCBhbmQgZXhhbWluZSBSIGRhdGFmcmFtZSBvYmplY3RzIHRoYXQgY29udGFpbiBkYXRhIApmcm9tIG92ZXIgMSwwMDAgYnJlYXN0IGNhbmNlciBwYXRpZW50cyBmcm9tIFRoZSBDYW5jZXIgR2Vub21lIEF0bGFzLiAKVGhlIG9iamVjdHMgaW5jbHVkZToKKiBjbGluaWNhbCBtZWFzdXJlbWVudHMgb24gdGhlIHBhdGllbnRzIGFuZCB0aGUgcGF0aWVudHMnIHR1bW9ycwoqIGdlbmUgZXhwcmVzc2lvbiBkYXRhICAKCltUaGUgQ2FuY2VyIEdlbm9tZSBBdGxhcyBvciBUQ0dBXShodHRwczovL3d3dy5jYW5jZXIuZ292L2Fib3V0LW5jaS9vcmdhbml6YXRpb24vY2NnL3Jlc2VhcmNoL3N0cnVjdHVyYWwtZ2Vub21pY3MvdGNnYSkgY2hhcmFjdGVyaXplZCBvdmVyIDIwLDAwMCBjYW5jZXIgc2FtcGxlcyBzcGFubmluZyAzMyBjYW5jZXIgdHlwZXMgd2l0aCBnZW5vbWljcy4gCgpJbiAyMDEyLCB0aGUgVENHQSBOZXR3b3JrIHJlcG9ydGVkIGZpbmRpbmdzIG9mIGFuYWx5c2VzIG9mIHByaW1hcnkgYnJlYXN0IGNhbmNlcnMgaW4gaHVuZHJlZHMgb2YgcGF0aWVudHMgd2l0aCBtdWx0aXBsZSBleHBlcmltZW50YWwgcGxhdGZvcm1zIChleG9tZSBzZXF1ZW5jaW5nLCBnZW5vbWljIEROQSBjb3B5IG51bWJlciBhcnJheXMsIEROQSBtZXRoeWxhdGlvbiwgbVJOQSBhcnJheXMsIG1pY3JvUk5BIHNlcXVlbmNpbmcsIGFuZCByZXZlcnNlLXBoYXNlIHByb3RlaW4gYXJyYXlzLikgSGVyZSwgd2Ugd2lsbCBjb25zaWRlciB0aGUgbm9ybWFsaXplZCByZWFkIGNvdW50IGV4cHJlc3Npb24gZGF0YSBmb3IgcGF0aWVudC1sZXZlbCBicmVhc3QgY2FuY2VyIChicmNhKSBkYXRhIGZyb20gVENHQS4KCi0tLQoKIyMgTG9hZGluZyB0aGUgZGF0YQoKVGhyb3VnaG91dCB0aGUgY291cnNlLCBXZSB3aWxsIGJlIGxvYWRpbmcgZGF0YSBmcm9tIFIgZmlsZXMgd2l0aCB0aGUgZXh0ZW5zaW9uIGAuUkRhdGFgLiBBbiBleGFtcGxlIGlzIHRoZSBmaWxlIGBUQ0FHX2JyY2EuUkRhdGFgIHdoaWNoIHdlIGV4YW1pbmUgYmVsb3cuCgpgLlJEYXRhYCBmaWxlcyBhcmUgYmluYXJ5IGZpbGVzIChpLmUuLCBub3QgaHVtYW4gcmVhZGFibGUpIHRoYXQgY2FuIHN0b3JlIG11bHRpcGxlIFIgb2JqZWN0cywgc3VjaCBhcyB2ZWN0b3JzLCBsaXN0cywgbWF0cmljZXMsIGFuZCBkYXRhIGZyYW1lcy4gCgpUaGUgUiBvYmplY3RzIGluIGAuUmRhdGFgIGZpbGVzIGFyZSB0aGUgcmVzdWx0cyBvZiBwcmV2aW91cyBSIGFuYWx5c2VzLCBhbmQgdGhlIGRhdGEgaXMgaW4gKip0aWR5KiogZm9ybS4gClRpZHkgZGF0YSBzZXRzIGhhdmUgY29uc2lzdGVudCBzdHJ1Y3R1cmUgYW5kIGFyZSBlYXN5IHRvIG1hbmlwdWxhdGUsIHZpc3VhbGl6ZSwgYW5kIG1vZGVsLiAKCldlIGNvdWxkIHNwZW5kIHRoZSBlbnRpcmUgY291cnNlIG9uIGxlYXJuaW5nIGhvdyB0byBwdXQgZGF0YSBpbiB0aWR5IGZvcm0sIGJ1dCBvdXIgZ29hbCBpcyB0aGUgdW5kZXJzdGFuZCBhbmQgYW5hbHl6ZSB0aGUgZGF0YSwgd2hpY2ggb2NjdXJzICphZnRlciogdGlkeWluZyB0aGUgZGF0YS4KCgpgYGB7cn0KCiMgV2Ugc2ltcGx5IGBsb2FkKClgIFRDR0FfYnJjYS5SRGF0YQojIFRoZSBmaWxlLnBhdGgoKSBmdW5jdGlvbiB0ZWxscyBgbG9hZCgpYCB3aGVyZSBvdXIgZGF0YSBsaXZlcwojIFRoZSBhcmd1bWVudCAidmVyYm9zZSA9IFRSVUUiIG1ha2VzIGBsb2FkKClgIHRlbGwgdXMgd2hhdCBSIG9iamVjdHMgYXJlIGJlaW5nIGxvYWRlZAoKbG9hZChmaWxlLnBhdGgoZGF0YV9kaXIsICJUQ0dBX2JyY2EuUkRhdGEiKSx2ZXJib3NlPVRSVUUpICAgCgpgYGAKClRoZSBvYmplY3RzIHdlcmUgbmFtZWQgdG8gYmUgYmUgZGVzY3JpcHRpdmUuCiogImRmIiBzdGFuZHMgZm9yICJkYXRhZnJhbWUiCiogImJyY2EiIHN0YW5kcyBmb3IgIlRDR0EgYnJlYXN0IGNhbmNlciIKKiAiZXhwciIgc3RhbmRzIGZvciAiZ2VuZSBleHByZXNzaW9uIGRhdGEiCiogIm5vcm0iIG1lYW5zIHRoYXQgdGhlIGRhdGEgaXMgbm9ybWFsaXplZCB0byBhY2NvdW50IGZvciB2YXJpYWJpbGl0eSBpbiB0aGUgZXhwZXJpbWVudHMKKiAibmFtZXMiIHJlbWluZHMgdXMgdGhhdCB0aGUgZGF0YSBoYXMgdGhlIGdlbmUgbmFtZXMgaW5jbHVkZWQKKiAiY2xpbiIgaXMgc2hvcnQgZm9yICJjbGluaWNhbCIKCldlIGxvb2tlZCBhdCBgYnJjYV9jbGluX2RmYCBsYXN0IHRpbWUuICAKVG9kYXkgd2Ugd2lsbCBhbHNvIGNvbnNpZGVyIGBicmNhX2V4cHJfbm9ybV9uYW1lc19kZmAuCgpUaGUgKkVudmlyb25tZW50KiB0YWIgZ2l2ZXMgdXMgYmFzaWMgaW5mb3JtYXRpb24gb24gdGhlIG9iamVjdHMgdGhhdCB3ZXJlIGxvYWRlZC4KCldlIHdpbGwgdXNlIHNvbWUgb2YgdGhlIFIgZnVuY3Rpb25zIHdlIGxlYXJuZWQgdG8gZXhhbWluZSB0aGUgZGF0YSBpbiBtb3JlIGRldGFpbC4KKiBgZGltKClgIHRlbGxzIHVzIHRoZSBkaW1lbnNpb25zICgjIHJvdywgIyBjb2x1bW5zKSBvZiB0aGUgb2JqZWN0cy4KKiBgaGVhZCgpYCBzaG93cyB1cyB0aGUgdG9wIHNldmVyYWwgcm93cyBvZiB0aGUgb2JqZWN0cy4KKiBpbmRleGluZyBhbGxvd3MgdXMgdG8gbG9vayBhdCB0aGUgcm93cyBhbmQgY29sdW1ucyB3ZSBjaG9vc2UuCgoKYGBge3J9CmRpbShicmNhX2V4cHJfbm9ybV9uYW1lc19kZikgICMgV2Ugc2hvdWxkIGdldCBhIHJlc3VsdCBjb25zaXN0ZW50CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2l0aCB3aGF0IGlzIGluIHRoZSBFbnZpcm9ubWVudCB0YWIKYGBgCgpMZXQncyBzZWUgd2hhdCdzIGluIHRoZSByb3dzIGFuZCBjb2x1bW5zLgoKYGBge3J9CmJyY2FfZXhwcl9ub3JtX25hbWVzX2RmWzE6NSwxOjVdICAgICAjIEluc3BlY3QgdGhlIGZpcnN0IGZldyByb3dzIG9mIHRoZSBkYXRhIGZyYW1lCmBgYAoKVGhlIGZpcnN0IGNvbHVtbiwgInN5bWJvbCIgaXMgdGhlIG5hbWVzIG9mIHRoZSBnZW5lcy4KVGhlIHJlbWFpbmluZyBjb2x1bW5zIGFyZSB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgb2YgdGhlIGdlbmVzIGZyb20gZGlmZmVyZW50IHBhdGllbnQgc2FtcGxlcy4KCiJUQ0dBLTNDLUFBQVUiIGlzIHRoZSBhbm9ueW1pemVkIGlkZW50aWZpZXIgZm9yIG9uZSBwYXRpZW50J3Mgc2FtcGxlLgoKVG8gZG8gYW5hbHlzaXMgd2l0aCB0aGUgZXhwcmVzc2lvbiBkYXRhZnJhbWUsIHdlIGhhdmUgdG8gcmVtb3ZlIHRoZSAic3ltYm9sIiBjb2x1bW4Kc28gdGhhdCB0aGUgbWF0cml4IGNvbnRhaW5zIG9ubHkgdGhlIG51bWVyaWNhbCBnZW5lIGV4cHJlc3Npb24gZGF0YS4KQnV0IHdlIHdhbnQgdG8ga2VlcCB0aGUgaW5mb3JtYXRpb24gZnJvbSB0aGUgInN5bWJvbCIgY29sdW1uLgpSIGFsbG93cyB1cyB0byBkbyB0aGlzIGJ5IGFzc2lnbmluZyB0aGUgc3ltYm9scyBhcyB0aGUgcm93IG5hbWVzIGZvciBvdXIgbWF0cml4LgoKCmBgYHtyfQoKYnJjYV9leHByX21hdCA8LSBhcy5tYXRyaXgoYnJjYV9leHByX25vcm1fbmFtZXNfZGZbLC0xXSkgICMgV2UgcmVtb3ZlIHRoZSBmaXJzdCBjb2x1bW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVzZSB0aGUgZnVuY3Rpb24gYXMubWF0cml4KCkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFuZCBhc3NpZ24gdGhlIHJlc3VsdCB0byBhIG5ldyBvYmplY3QuCgojIE5vdywgd2UnbGwgdXNlIHRoZSBmdW5jdGlvbiByb3cubmFtZXMoKSB0byBrZWVwIHRoZSBnZW5lIHN5bWJvbHMuCnJvdy5uYW1lcyhicmNhX2V4cHJfbWF0KSA8LSBicmNhX2V4cHJfbm9ybV9uYW1lc19kZiRzeW1ib2wKCmBgYAoKCkxldCdzIHVzZSBpbmRleGluZyB0byBjaGVjayBvdXIgdGhlIGZpcnN0IDUgcm93cyBhbmQgY29sdW1ucyBvZiBvdXIgbWF0cml4LgoKYGBge3J9CmJyY2FfZXhwcl9tYXRbMTo1LDE6NV0KYGBgCgpMZXQncyBsb29rIGF0IHRoZSBhdmVyYWdlIHZhbHVlIG9mIHRoZSBleHByZXNzaW9uIGZvciB0aGUgZmlyc3QgdHdvIGdlbmVzLCBUU1BBTjYgYW5kIFROTUQuCgpUU1BBTjYgY29kZXMgZm9yIHRoZSBwcm90ZWluIFRldHJhc3BhbmluLTYuIFRoaXMgcHJvdGVpbiBoZWxwcyBzaWduYWwgZXZlbnRzIHRoYXQgcGxheSBhIHJvbGUgaW4gY2VsbCBncm93dGggYW5kIG1vdGlsaXR5LgoKVE5NRCBjb2RlcyBmb3IgdGhlIHByb3RlaW4gVGVub21vZHVsaW4sIHdoaWNoIGlzIGltcG9ydGFudCBmb3IgdGhlIGZvcm1hdGlvbiBvZiB0ZW5kb25zLiBUTk1EIGlzIGhpZ2hseSBleHByZXNzZWQgaW4gdGVuZG9ucywgYnV0IGxvd2x5IGV4cHJlc3NlZCBpbiBvdGhlciBwYXJ0cyBvZiB0aGUgYm9keS4KCmBgYHtyfQoKIyBtZWFuKCkgdGFrZXMgdGhlIGF2ZXJhZ2Ugb2YgYSBzZXQgb2YgdmFsdWVzCgphdmdfVFNQQU42X2V4cHIgPC0gbWVhbihicmNhX2V4cHJfbWF0WzEsXSkgICAjIFdlIGFyZSB0YWtpbmcgdGhlIGF2ZXJhZ2Ugb2YgZXhwcmVzc2lvbiB2YWx1ZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmb3IgdGhlIGZpcnN0IHJvdyBvZiB0aGUgbWF0cml4CgphdmdfVE5NRF9leHByIDwtIG1lYW4oYnJjYV9leHByX21hdFsyLF0pICAgICAjIFdlIGFyZSB0YWtpbmcgdGhlIGF2ZXJhZ2Ugb2YgZXhwcmVzc2lvbiB2YWx1ZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmb3IgdGhlIHNlY29uZCByb3cgb2YgdGhlIG1hdHJpeAoKCnByaW50KHBhc3RlKCJBdmVyYWdlIGV4cHJlc3Npb24gb2YgVFNQQU42OiAiLCByb3VuZChhdmdfVFNQQU42X2V4cHIsMCkpKQoKcHJpbnQocGFzdGUoIkF2ZXJhZ2UgZXhwcmVzc2lvbiBvZiBUTk1EOiAiLCByb3VuZChhdmdfVE5NRF9leHByLDApKSkKCiMgVGhlIGZ1bmN0aW9uIHBhc3RlKCkgYWxsb3dzIHVzIHRvIHByaW50IHRleHQgYW5kIG51bWJlcnMgdG9nZXRoZXIuCiMgVGhlIGZ1bmN0aW9uIHJvdW5kKCkgbGV0cyB1cyBjaG9vc2UgaG93IG1hbnkgZGVjaW1hbCBkaWdpdHMgd2Ugd2FudCB0byBzaG93LgoKYGBgCgpJdCB3b3VsZCBzdGluayB0byBoYXZlIHRvIGRvIHRoaXMgZm9yIGFsbCAxOCwzNTEgZ2VuZXMuICAKCkJ1dCB3ZSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgYXBwbHkoKWAgdG8gYXBwbHkgYSBmdW5jdGlvbiBsaWtlIGBtZWFuKClgCnRvIGFsbCByb3dzIG9yIGNvbHVtbnMgb2Ygb3VyIG1hdHJpeC4KCgpgYGB7cn0KbWVhbi5leHByIDwtIGFwcGx5KGJyY2FfZXhwcl9tYXQsIDEsIG1lYW4pICAjIFdlICJhcHBseSIgdGhlIGZ1bmN0aW9uIG1lYW4oKSB0byBhbGwgcm93cy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRoZSBmaXJzdCBhcmd1bWVudCBpcyB0aGUgbWF0cml4LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGhlIHNlY29uZCBhcmd1bWVudCBpcyAxIGZvciAicm93cyIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgdGhpcmQgYXJndW1lbnQgaXMgdGhlIGZ1bmN0aW9uIG5hbWUsIGBtZWFuKClgCgphcy50YWJsZShyb3VuZChtZWFuLmV4cHJbMToyNV0sMCkpCgpgYGAKCkl0J3MgbmljZSB3ZSBjYW4gY2FsY3VsYXRlIGFsbCB0aGUgbWVhbnMgYXQgb25jZSwgYnV0IGl0J3Mgbm90IHZlcnkgaGVscGZ1bCBpbiBjb21wYXJpbmcgdGhlIG1lYW4gb2YgdGhlIGRpZmZlcmVudCBnZW5lcy4KCkxldCdzIHRyeSBwbG90dGluZyB0aGUgbWVhbnMgYXMgYSBoaXN0b2dyYW0uCgpgYGB7cn0KaGlzdChtZWFuLmV4cHIsIGJyZWFrcz0xMDAsIG1haW49IkRpc3RyaWJ1dGlvbiBvZiBHZW5lIEV4cHJlc3Npb24gVmFsdWVzIiwKICB4bGFiPSJNZWFuIEV4cHJlc3Npb24iKQoKIyBBIGhpc3RvZ3JhbSBpcyBhIGdyYXBoaWNhbCBkaXNwbGF5IG9mIGRhdGEgdXNpbmcgYmFycyBvZiBkaWZmZXJlbnQgaGVpZ2h0cy4gCiMgRWFjaCBiYXIgZ3JvdXBzIG51bWJlcnMgaW50byByYW5nZXMuIFRhbGxlciBiYXJzIHNob3cgdGhhdCBtb3JlIGRhdGEgZmFsbHMgaW4gdGhhdCByYW5nZS4gCiMgVGhlIGZpcnN0IGFyZ3VtZW50IGlzIHRoZSBkYXRhLCB0aGUgc2Vjb25kIGlzIGhvdyBiYXJzIHdlIHdhbnQgdG8gc2hvdywgCiMgdGhlIHRoaXJkIGlzIGEgdGl0bGUgZm9yIHRoZSBwbG90LCBhbmQgdGhlIGZvdXJ0aCBpcyB0aGUgbmFtZSBvZiB0aGUgeC1heGlzLgoKYGBgCgpXb3chICBNb3N0IG9mIHRoZSBhdmVyYWdlIGV4cHJlc3Npb24gdmFsdWVzIGFyZSByZWxhdGl2ZWx5IHNtYWxsIChsZXNzIHRoYW4gMjAwKSwgYnV0IHRoZXJlIG11c3QgYmUgYSBmZXcgcmVhbGx5IGxhcmdlIHZhbHVlcy4KCkxldCdzIHNlZSBob3cgbWFueSBnZW5lcyBoYXZlIGF2ZXJhZ2UgZXhwcmVzc2lvbiBncmVhdGVyIHRoYW4gMTAsMDAwLgoKCmBgYHtyfQoKcHJpbnQocGFzdGUoIlRvdGFsIHZhbHVlczogIiwgbGVuZ3RoKG1lYW4uZXhwcikpKQpwcmludChwYXN0ZSgiTnVtIHZhbHVlcyA+IDEwLDAwMDogIiwgc3VtKG1lYW4uZXhwciA+IDEwMDAwKSkpCnByaW50KHBhc3RlKCJQZW5jZW50YWdlIG9mIG1lYW4gdmFsdWVzID4gMTAsMDAwOiAiLCByb3VuZChzdW0obWVhbi5leHByPjEwMDAwKS9sZW5ndGgobWVhbi5leHByKSoxMDAsMSkpKQoKYGBgCgoKU28gdGhlcmUgYXJlIGEgZmV3IHJlYWxseSBiaWcgbnVtYmVycy4KVGhlIGN1cnZlIGluIHRoZSBoaXN0b2dyYW0gaGFzIGEgbG9uZyByaWdodCB0YWlsLiAgCk5lYXJseSBhbGwgZ2VuZXMgaGF2ZSAqbG93KiBleHByZXNzaW9uLCBhbmQgdmVyeSBmZXcgZ2VuZXMKaGF2ZSAqaGlnaCogZXhwcmVzc2lvbi4gIAoKVW5mb3J0dW5hdGVseSwgbWFueSBhbmFseXNpcyBmdW5jdGlvbnMgaW4gUiBkbyBub3QKd29yayB3ZWxsIHdpdGggdGhpcyBraW5kIG9mIGRpc3RyaWJ1dGlvbi4gIAoKSW5zdGVhZCwgaXQgaXMgdmVyeSBjb21tb24gdG8gYXNzdW1lIHRoZSBkYXRhIGZvbGxvdyBhIG5vcm1hbCAob3IgYmVsbCkgY3VydmUuCgpJbiBwcmFjdGl2ZSx2ZXJ5IGxpdHRsZSByZWFsIGxpZmUgYmlvbG9naWNhbCBkYXRhIHRydWx5IGZvbGxvdyBhIApub3JtYWwgY3VydmUuIEl0IGhhcyBiZWVuIGVzdGFibGlzaGVkIHRoYXQgbW9zdCBhbmFseXNpcyB3b3JrcyBxdWl0ZQp3ZWxsIGlmIHRoZSBkYXRhIGFyZSAqY2xvc2UgZW5vdWdoKiB0byBhIG5vcm1hbCBjdXJ2ZS4KCldlIGNhbiBtYWtlIG91ciBkYXRhIG1vcmUgbGlrZSBub3JtYWwgZGF0YSBieSBkb2luZyBhICpsb2cgdHJhbnNmb3JtKi4gCklmIHdlIHRha2UgdGhlIGxvZyBvZiBhbGwgdGhlIGVweHJlc3Npb24gdmFsdWVzLCB3ZSBwdXQgdGhlIGRhdGEgbW9yZSBvbgplcXVhbGx5IGZvb3RpbmcuIAoKRXhwcmVzc2lvbiBkYXRhIGlzIHR5cGljYWxseSBsb2dnZWQgdXNpbmcgYmFzZSAyLiAgCgpMb2cgYmFzZSAyIG9mIDggaXMgMyBiZWNhdXNlIDIgKiAyICogMiA9IDguCgpMb2cgYmFzZSA0IG9mIDQgaXMgMiBiZWNhdXNlIDIgKiAyID0gNC4KCkxvZyBiYXNlIDIgb2YgMiBpcyAxIGJlY2F1c2UgMiA9IDIuCgpTbyB0aGUgdmFsdWVzICg4LCA0ICwgMikgYXJlICp0cmFuc2Zvcm1lZCogdG8gKDMsIDIsIDEpLiAgCgpMZXQncyBjb25zaWRlciBzb21lIGxhcmdlciBudW1iZXJzOgogICAgCiAgICAKYGBge3J9CmEgPC0gYyg0MDk2LCAxMDI0LCA1MTIsIDY0KQoKYiA8LSBsb2coYSwyKQoKcGxvdChhLGIscGNoPTE5LGNvbD0icmVkIikKCmBgYAogICAgCk5vdGljZSBob3cgdGhlIHNjYWxlIGZvciBiIGlzIG11Y2ggbW9yZSBjb21wcmVzc2VkIHRoYW4gZm9yIGEuCgpCeSB0YWtpbmcgdGhlIGxvZzIgb2YgbnVtYmVycywgd2UgbWFrZSB0aGVtIG1vcmUgc2ltaWxhciB0byBlYWNoIG90aGVyLgoKCmBgYHtyfQoKYQoKbG9nKGEsMikKYGBgCgoKVGhlcmUgaXMgb25lIGNhdmVhdC4gIFRoZSBsb2cyIG9mIDAgaXMgaW5maW5pdHkhICAKCmBgYHtyfQoKbG9nKDAsMikKCmBgYAoKQnV0IHRoZSBsb2cyIG9mIDEgaXMgIndlbGwtYmVoYXZlZC4iCgpgYGB7cn0KbG9nKDEsMikKYGBgCgpTbyBiZWZvcmUgdGFraW5nIHRoZSBsb2cyIG9mIG91ciBleHByZXNzaW9uIGRhdGEsIHdlIHdpbGwgYWRkIDEgdG8gZWFjaCB2YWx1ZSB0byBhdm9pZCB0aGUgb2NjaXJlbmNlIG9mICItSW5mIiB2YWx1ZXMuCgogICAgCmBgYHtyfQoKYnJjYV9leHByX21hdC5sb2cgPC0gbG9nKGJyY2FfZXhwcl9tYXQrMSwgMikgICMgV2UgYWRkIDEgdG8gZWFjaCBlbGVtZW50LCB0aGVuIHRha2UgdGhlIGxvZyBiYXNlIDIuCgojTGV0J3MgbG9vayBhdCBzb21lIHZhbHVlczoKYnJjYV9leHByX21hdC5sb2dbMTo1LDE6NV0KCmBgYAogCiAKTGV0J3MgY2hlY2sgb3V0IHdoYXQgdGhlIGN1cnZlIGlzIGZvciB0aGUgbG9nLXRyYW5zZm9ybWVkIGV4cHJlc3Npb24gdmFsdWVzOiAKCmBgYHtyfQptZWFuLmV4cHIgPC0gYXBwbHkoYnJjYV9leHByX21hdC5sb2csIDEsIG1lYW4pICAjIFdlICJhcHBseSIgdGhlIGZ1bmN0aW9uIG1lYW4oKSB0byBhbGwgcm93cy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIG1hdHJpeC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgc2Vjb25kIGFyZ3VtZW50IGlzIDEgZm9yICJyb3dzIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgdGhpcmQgYXJndW1lbnQgaXMgdGhlIGZ1bmN0aW9uIG5hbWUsIGBtZWFuKClgCgpoaXN0KG1lYW4uZXhwciwgYnJlYWtzPTEwMCwgbWFpbj0iRGlzdHJpYnV0aW9uIG9mIExvZ18yIEdlbmUgRXhwcmVzc2lvbiBWYWx1ZXMiLAogIHhsYWI9Ik1lYW4gTG9nXzIgRXhwcmVzc2lvbiIpCgojIEEgaGlzdG9ncmFtIGlzIGEgZ3JhcGhpY2FsIGRpc3BsYXkgb2YgZGF0YSB1c2luZyBiYXJzIG9mIGRpZmZlcmVudCBoZWlnaHRzLiAKIyBFYWNoIGJhciBncm91cHMgbnVtYmVycyBpbnRvIHJhbmdlcy4gVGFsbGVyIGJhcnMgc2hvdyB0aGF0IG1vcmUgZGF0YSBmYWxscyBpbiB0aGF0IHJhbmdlLiAKIyBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIGRhdGEsIHRoZSBzZWNvbmQgaXMgaG93IGJhcnMgd2Ugd2FudCB0byBzaG93LCAKIyB0aGUgdGhpcmQgaXMgYSB0aXRsZSBmb3IgdGhlIHBsb3QsIGFuZCB0aGUgZm91cnRoIGlzIHRoZSBuYW1lIG9mIHRoZSB4LWF4aXMuCgpgYGAKIAogClRoaXMgaXNuJ3QgcXVpdGUgbm9ybWFsIChlc3BlY2lhbGx5IGF0IHRoZSBsb3dlciByYW5nZSksIGJ1dCBpdCBpcwptdWNoIGNsb3NlciwgYW5kIGltcG9ydGFudGx5LCBjbG9zZSBlbm91Z2ggZm9yIHNvbWUgZXhwbG9yYXRvcnkKYW5hbHlzZXMuCgoKIyMgU2FtcGxlczogRGlzdHJpYnV0aW9ucyBvZiBleHByZXNzaW9uIHZhbHVlcwoKSW4gYWRkaXRpb24gdG8gdGhlIGdlbmVzLCB3ZSBjYW4gYWxzbyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlCmV4cHJlc3Npb24gdmFsdWVzIG9mIHRoZSBzYW1wbGVzLiAgVGhpcyBpcyBjb21tb25seSBkb25lIHVzaW5nIGEKYm94cGxvdC4KCmBgYHtyfQpJIDwtIHNlcSgxLCBuY29sKGJyY2FfZXhwcl9tYXQubG9nKSwgMTApICAjIFdlIHdpbGwgbG9vayBhdCBldmVyeSB0ZW50aCBzYW1wbGUuCmJveHBsb3QoYnJjYV9leHByX21hdC5sb2dbLEldLCB4YXh0PSJuIiwgeGxhYj0iU2FtcGxlcyIsIHlsYWI9IkxvZ18yIEdlbmUgRXhwcmVzc2lvbiIsIAogIHBjaD0xOSwgY2V4PTEpCmBgYAogCiAKSGVyZSwgZWFjaCBvZiB0aGUgY29sdW1ucyBpcyBhIHNhbXBsZSwgYW5kIHRoZSBZLWF4aXMgc2hvd3MgdGhlCmRpc3RyaWJ1dGlvbiBvZiB0aGUgZXhwcmVzc2lvbiBvZiBnZW5lcyBpbiBlYWNoIHNhbXBsZS4gIApXaGVuIHdlIGxvb2sgYXQgdGhlc2UgcGxvdHMsIHdlIGhvcGUgdG8gc2VlIGEgc2ltaWxhciBkaXN0cmlidXRpb24gCm9mIGdlbmUgZXhwZXNzaW9uIHZhbHVlcyBhY3Jvc3MgYWxsIHNhbXBsZXMuICAKCldoaWxlIHRoZSBleHByZXNzaW9uIG9mIGFueSBpbmRpdmlkdWFsIGdlbmUgd2lsbCB2YXJ5IGZyb20gc2FtcGxlIAp0byBzYW1wbGUsIGFzIGEgd2hvbGUsIHRoZSBkaXN0cmlidXRpb24gc2hvdWxkIGJlIHNpbWlsYXIuICAKCklmIHdlIHNlZSBkaWZmZXJlbmNlcyAoaS5lLiBzb21lIHNhbXBsZXMgaGF2ZSB2ZXJ5IGRpZmZlcmVudCAKZXhwcmVzc2lvbiB2YWx1ZXMpLCB3ZSB3aWxsIG5lZWQgdG8gaW52ZXN0aWdhdGUgd2h5IHRoYXQgaXMgc28sIAp3aGV0aGVyIGl0IGlzIGR1ZSB0byBhIGRpZmZlcmVuY2UgaW4gdGhlIGJpb2xvZ3kgKGUuZy4gZGlmZmVyZW50IAp0aXNzdWVzIGNhbiBleGhpYml0IGRpZmZlcmVudCBleHByZXNzaW9uKSwgb3IgYSB0ZWNobmljYWwgYXJ0aWZhY3QgCmZyb20gdGhlIGV4cGVyaW1lbnRzIChyYXRoZXIgY29tbW9uLCB1bmZvcnR1bmF0ZWx5KS4gIEhlcmUsIHRoZSBkYXRhCmxvb2tzIHByZXR0eSBjbGVhbi4gIAoKCiMgVmlzdWFsaXppbmcgdGhlIGRhdGEgd2l0aCBoZWF0bWFwcwoKTGV0J3Mgc3RhcnQgYnkgdGFraW5nIGEgbG9vayBhdCB3aGF0IHRoZSBkYXRhIGxvb2tzIGxpa2UgdXNpbmcgYQpoZWF0bWFwLiAgV2Ugd29uJ3QgYmUgYWJsZSB0byBtYWtlIGEgaGVhdG1hcCBvZiB0aGUgZW50aXJlIGRhdGEKc2V0IOKAlCB0aGVyZSBhcmUganVzdCB0b28gbWFueSBnZW5lcy4KCkp1c3QgdG8gcmVtaW5kIG91cnNlbHZlcywgdGFrZSBhbm90aGVyIGxvb2sgYXQgdGhlIHNpemUgb2YgdGhlIGRhdGEuCgoKYGBge3J9CmRpbShicmNhX2V4cHJfbWF0LmxvZykKCmJyY2FfZXhwcl9tYXQubG9nWzE6NSwxOjVdCgpgYGAKCgpUbyByZWR1Y2UgdGhlIG51bWJlciBvZiBnZW5lcywgd2Ugd2lsbCB0cnkgdG8gc2VsZWN0IHRoZSAqbW9zdCBpbXBvcnRhbnQqIApvbmVzIGZvciBhbiBleHBsb3JhdG9yeSBhbmFseXNpcy4gIFRoZXJlIGFyZSBtYW55IGRpZmZlcmVudCB3YXlzIHRvIGRvIHRoaXMsIAphbmQgeW91ciBjaG9pY2UgaGVyZSBjYW4gbGVhZCB0byBwcm9mb3VuZGx5IGRpZmZlcmVudCB2aWV3cyBvZiB0aGUgZGF0YS4gIAoKT25lIGNvbW1vbiBhcHByb2FjaCB0byBzZWxlY3QgZ2VuZXMgaW4gYW4gdW5iaWFzZWQgd2F5IGlzIHRvIGZpbmQgdGhlIApvbmVzIHdpdGggdGhlICpiaWdnZXN0IGRpZmZlcmVuY2VzKiBhY3Jvc3MgdGhlIHNhbXBsZXMsIG9yIGluIHN0YXRpc3RpY3MgCmxhbmd1YWdlLCB0aGUgb25lcyB3aXRoIHRoZSBoaWdoZXN0IHZhcmlhbmNlCgpXZSdsbCBjb25zaWRlciB0aGUgNTAwIGdlbmVzIHdpdGggdGhlIGhpZ2hlc3QgdmFyaWFuY2UuCgpBbmQgb3JkZXIgb3V0IG1hdHJpeCBhY2NvcmRpbmdseSwgc28gd2UgbWFrZSBhIG1hdHJpeCBmb3IgdGhlIHRvcCA1MDAgdmFyaWFibGUgZ2VuZXMuCgpgYGB7cn0KTlVNLkdFTkVTIDwtIDUwMCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBIb3cgbWFueSBnZW5lcyB3ZSB3YW50IHRvIGNvbnNpZGVyLgp2IDwtIGFwcGx5KGJyY2FfZXhwcl9tYXQsIDEsIHZhcikgICAgIyBIZXJlLCB3ZSB1c2UgdGhlIGZ1bmN0aW9uIGFwcGx5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2l0aCB0aGUgZnVuY3Rpb24gdmFyIChmb3IgdmFyaWFuY2UpLgoKTyA8LSBvcmRlcih2LCBkZWNyZWFzaW5nPVRSVUUpICAgIyBUaGUgZnVuY3Rpb24gb3JkZXIgd2lsbCByYW5rIHRoZSB2YWx1ZXMgZm9yIHVzLgoKdmFyX2dlbmVzIDwtIHZbT10gICAgICAgICAgICAgICAgICAgICAgICMgV2UgbG9vayBhdCB0aGUgdG9wIHRlbi4KCgpicmNhLmxvZy5zdWIgPC0gYnJjYV9leHByX21hdC5sb2dbT1sxOk5VTS5HRU5FU10sXQpgYGAKCgpMZXQncyBsb29rIGF0IGl0LgoKYGBge3J9CgpicmNhLmxvZy5zdWJbMTo1LDE6NV0KCmBgYAoKV2hlbiB3ZSdyZSBkb2luZyBleHBsb3JhdG9yeSBhbmFseXNpcywgd2UnbGwgb2Z0ZW4gd29yayB3aXRoIGp1c3QKYSBzdWJzZXQgb2YgdGhlIGRhdGEuICBJdCBtYWtlcyB0aGluZ3MgZ28gZmFzdGVyLCBhbmQgdGhlIHBsb3RzIGFyZQplYXNpZXIgdG8gaW50ZXJwcmV0LiAgVG8gcHVsbCBvdXQgMTAlIG9mIHRoZSBzYW1wbGVzLCBsZXQncyBzdG9yZSBpbgp0aGUgYEkuc2FtcGxlYCB2ZWN0b3IgdGhlIGluZGV4ZXMgb2YgZXZlcnkgMTB0aCBzYW1wbGUuICBXZSdsbCB1c2UKdGhpcyBzdWJzZXQgZm9yIG5vdywgYnV0IGZvciB0aGUgZmluYWwgYW5hbHlzaXMsIHdlJ2xsIGNlcnRhaW5seSB3YW50CnRvIHVzZSB0aGUgd2hvbGUgZGF0YSBzZXQuCgoKYGBge3J9CmxpYnJhcnkoIlJDb2xvckJyZXdlciIpICAgICAgICAgICAgICMgV2UgY2FsbCBhIGxpYnJhcnkgdGhhdCBoYXMgbmljZSBjb2xvcnMKCkkuc2FtcGxlIDwtIHNlcSgxLCBuY29sKGJyY2EubG9nLnN1YiksIDEwKSAgICAgICMgV2UgdGFrZSBldmVyeSB0ZW50aCBzYW1wbGUuCgoKaGVhdG1hcChicmNhLmxvZy5zdWJbLEkuc2FtcGxlXSwKICAgICAgICBSb3d2PU5BLCBDb2x2PU5BLCBzY2FsZT0ibm9uZSIsIGxhYlJvdz0iIiwgICAgICAgICAgICAgICAgICAjIFRoZXNlIGFyZ3VtZW50cyBhcmUgZm9yIHBsb3R0aW5nCiAgICAgICAgbGFiQ29sPSIiLCBjb2w9YnJld2VyLnBhbCgxMCwiUmRCdSIpLCBtYXJnaW5zID0gYygxLCAwKSkgICAgIyB0aGUgaGVhdG1hcC4KYGBgCgoKRWFjaCByb3cgaXMgYSBnZW5lLCBhbmQgZWFjaCBjb2x1bW4gaXMgYSBzYW1wbGUuICBJdCBkb2Vzbid0IHF1aXRlCmxvb2sgcmlnaHQsIHRob3VnaC4gIFRoZXJlIGFyZSBhIGJ1bmNoIG9mIGhvcml6b250YWwgc3RyaXBlcy4gIFRoaXMKaGFwcGVucyBiZWNhdXNlIHNvbWUgb2YgdGhlIGdlbmVzIGFyZSBleHByZXNzZWQgaGlnaGVyIHRoYW4gb3RoZXJzLgpXaGlsZSB0aGlzIGlzIGludGVyZXN0aW5nLCB3aGF0IHdlIHJlYWxseSB3YW50IHRvIHNlZSBhcmUgdGhlIHBhdHRlcm5zCm9mIGV4cHJlc3Npb24gYWNyb3NzIHRoZSBzYW1wbGVzLiAgSW4gb3RoZXIgd29yZHMsIHdlIHdhbnQgdG8ga25vdywKZm9yIGVhY2ggZ2VuZSwgd2hldGhlciBpdCBpcyBoaWdoZXIgaW4gb25lIGdyb3VwIG9mIHNhbXBsZXMgdmVyc3VzIHRoZQpvdGhlci4gIFNvIHdlIGFyZSBtb3JlIGludGVyZXN0ZWQgaW4gdGhlIHJlbGF0aXZlIGV4cHJlc3Npb24gb2YgdGhlCmdlbmVzLCByYXRoZXIgdGhhbiB0aGUgYWJzb2x1dGUgZXhwcmVzc2lvbi4KClRvIGdldCB0aGUgcmVsYXRpdmUgZ2VuZSBleHByZXNzaW9uLCB3ZSB3aWxsIGZpcnN0IG5vcm1hbGl6ZSBlYWNoIG9mCnRoZSBnZW5lcy4gIEEgY29tbW9uIHdheSB0byBkbyB0aGlzIGlzIHRvIGNoYW5nZSBlYWNoIGdlbmUgc3VjaCB0aGF0CnRoZSBtZWFuIGV4cHJlc3Npb24gaXMgMCwgYW5kIHRoZSB2YXJpYW5jZSBpcyAxLiAgVGhlIGFic29sdXRlIGdlbmUKZXhwcmVzc2lvbiB2YWx1ZXMgd2lsbCBiZSBjaGFuZ2VkLCBidXQgdGhlIHJlbGF0aXZlIGV4cHJlc3Npb24KKHdoZXRoZXIgaXQgaXMgaGlnaGVyIG9yIGxvd2VyIGluIGEgcGFydGljdWxhciBzYW1wbGUpIHdpbGwgYmUKcHJlc2VydmVkLgoKClIgaGFzIGFuIGVhc3kgd2F5IHRvIGRvIHRoaXMgd2l0aCB0aGUgZnVuY3Rpb24gYHNjYWxlKClgLiAgCgoKCmBgYHtyfQoKaGVscChzY2FsZSkKYGBgCgoKTm90aWNlIHRoYXQgYHNjYWxlKClgIHdpbGwgc2NhbGUgdGhlICpjb2x1bW5zKiBvZiBvdXIgbWF0cml4LgpCdXQgd2Ugd2FudCB0byBzY2FsZSB0aGUgZ2VuZXMsIHdoaWNoIGFyZSBpbiB0aGUgcm93cyEKClRoaXMgaXMgbm90IGEgcHJvYmxlbSwgYmVjYXVzZSB3ZSBjYW4gdXNlIHRoZSB0cmFuc3Bvc2UgZnVuY3Rpb24gYHQoKWAKdG8gY29udmVydCByb3dzIHRvIGNvbHVtbnMgYW5kIGNvbHVtbnMgdG8gcm93cy4KClNvIHdlIHNjYWxlIHRoZSB0cmFuc3Bvc2VkIG1hdHJpeC4KVGhlbiB3ZSBoYXZlIHRvIHRyYW5zcG9zZSBpdCBiYWNrISEKCkhlcmUsIHdlIGFyZSB1c2luZyB0aHJlZSBuZXN0ZWQgZnVuY3Rpb25zOgoqIGB0KClgIHRvIHRyYW5zcG9zZSBvdXIgbWF0cml4CiogYHNjYWxlKClgIHRvIHNjYWxlIHRoZSB0cmFuc3Bvc2VkIG1hdHJpeAoqIGFub3RoZXIgYHQoKWAgdG8gdHJhbnNwb3NlIGJhY2sgc28gdGhhdCBnZW5lcyBhcmUgcm93cyBhZ2Fpbi4KCmBgYHtyfQpicmNhLmxvZy5zdWIuc2NhbGUgPC0gdChzY2FsZSh0KGJyY2EubG9nLnN1YikpKSAgIApgYGAKCgpXaGF0IGRvZXMgdGhlIGhlYXRtYXAgbG9vayBsaWtlIG5vdz8KCmBgYHtyfQpoZWF0bWFwKGJyY2EubG9nLnN1Yi5zY2FsZVssSS5zYW1wbGVdLAogICBSb3d2PU5BLCBDb2x2PU5BLCBzY2FsZT0ibm9uZSIsIGxhYlJvdz0iIiwgICAgICMgVGhlIHJlc3Qgb2YgdGhlIGFyZ3VtZW50cyBhcmUgZm9yIHBsb3R0aW5nLgogICBsYWJDb2w9IiIsIGNvbD1icmV3ZXIucGFsKDEwLCJSZEJ1IiksIHpsaW09YygtMiwgMiksIG1hcmdpbnMgPSBjKDEsIDApKQoKYGBgCgoKTmljZSEgIFRoaXMgaXMgbXVjaCBiZXR0ZXIuICBXZSBjYW4gbW9yZSBlYXNpbHkgc2VlIHdoaWNoIGdlbmVzIGFyZSBvdmVyZXhwcmVzc2VkIChyZWQpIGFuZCB1bmRlcmV4cHJlc3NlZCAoYmx1ZSkgaW4gYSByZWxhdGl2ZSBtYW5uZXIuICAKCk91ciBuZXh0IGFjdGl2aXR5IHdpbGwgYmUgdG8gb3JnYW5pemUgdGhpcyBtYXRyaXggc28gd2UgY2FuIHNlZSBwYXR0ZXJucyBhbW9uZyB0aGUgCiogZ2VuZXMgKHJvdyksIGFuZCAKKiBzYW1wbGVzIChjb2x1bW5zKSwKCmFuZCBhc3NvY2lhdGUgdGhlIHBhdHRlcm5zIHdpdGggY2xpbmljYWwgaW5mb3JtYXRpb25zLgoKCiMjIFByYWN0aWNlCgoxLiBTYXZlIHRoaXMgZmlsZSB3aXRoIGFub3RoZXIgbmFtZS4KCjIuIFdvcmsgdGhyb3VnaCB0aGUgYWN0aXZpdHkgYWdhaW4gYW5kIGNoYW5nZSB2YWx1ZXMgc3VjaCBhcyBOVU0uR0VORVMgYW5kIEkuc2FtcGxlLgoKMy4gSG93IGRvIHlvdXIgY2hvaWNlcyBjaGFuZ2Ugd2hhdCB5b3Ugc2VlPwoKIyMgQ2x1c3RlcmluZzogRmluZGluZyBwYXR0ZXJucyBpbiB0aGUgZGF0YQoKSGVyZSwgd2Ugd2lsbCBkbyAqaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcqLiAKCldlIGZpcnN0IGNhbGN1YXRlIHRoZSBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgcm93cyAoZ2VuZXMpIGluIG91ciBtYXRyaXguIApUbyBkbyB0aGlzLCB3ZSBhcHBseSB0aGUgZnVuY3Rpb24gYGRpc3QoKWAgdG8gb3VyIG1hdHJpeC4KClRoZW4gd2UgY2FsY3VsYXRlIHRoZSBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgY29sdW1ucyAoc2FtcGxlcykgaW4gb3VyIG1hdHJpeC4KVG8gZG8gdGhpcywgd2UgYXBwbHkgYGRpc3QoKWAgdG8gdGhlICp0cmFuc3Bvc2UqIG9mIG91ciBtYXRyaXguCgoKYGBge3J9CgpvdXJfbWF0cml4IDwtIGJyY2EubG9nLnN1Yi5zY2FsZVssSS5zYW1wbGVdCgpyb3cuZGlzdCA8LSBkaXN0KG91cl9tYXRyaXgpICAgICAgICMgVXNlIGRpc3QoKSBvbiBvdXIgbWF0cml4CmNvbC5kaXN0IDwtIGRpc3QodChvdXJfbWF0cml4KSkgICAgIyBVc2UgZGlzdHIoKSBvbiB0aGUgdHJhbnNwb3NlIG9mIG91ciBtYXRyaXgKCgpgYGAKCgpUaGVuIHdlICpjbHVzdGVyKiB0aGUgcm93cyBhbmQgY29sdW1ucyBiYXNlZCBvbiB0aGUgZGlzdGFuY2VzIHdlIGNhbGN1bGF0ZWQgYW5kIApjcmVhdGUgdGhlIGRlbmRyb2dyYW1zLCBpLmUuIHRoZSBkaXN0YW5jZSB0cmVlcywgd2l0aCB0aGUgZnVuY3Rpb24gYGhjbHVzdCgpYC4KCmBgYHtyfQoKcm93X2NsdXN0ZXJzIDwtIGhjbHVzdChyb3cuZGlzdCkgICAgICAgICMgQXBwbHkgYGhjbHVzdCgpYCB0byB0aGUgcm93cyAgCmNvbHVtbl9jbHVzdGVycyA8LSBoY2x1c3QoY29sLmRpc3QpICAgICAjIEFwcGx5IGBoY2x1c3QoKWAgdG8gdGhlIGNvbHVtbnMKCmBgYAoKCk5vdywgd2Ugd2lsbCBnZW5lcmF0ZSB0aGUgY2x1c3RlcmVkIGhlYXRtYXBzLgoKYGBge3J9CgpoZWF0bWFwKAogIG91cl9tYXRyaXgsICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgbWF0cml4IG9mIGV4cHJlc3Npb24gdmFsdWVzCiAgUm93dj1hcy5kZW5kcm9ncmFtKHJvd19jbHVzdGVycyksICAgICAjIENyZWF0ZSByb3cgZGVuZHJvZ3JhbSBmcm9tIGByb3dfY2x1c3RlcnNgCiAgQ29sdj1hcy5kZW5kcm9ncmFtKGNvbHVtbl9jbHVzdGVycyksICAjIENyZWF0ZSBjb2x1bW4gZGVuZG9ncmFtIGZyb20gYGNvbHVtbl9jbHVzdGVyc2AKICAKICBzY2FsZT0ibm9uZSIsIGxhYlJvdz0iIiwgbGFiQ29sPSIiLCBjb2w9YnJld2VyLnBhbCgxMCwiUmRCdSIpLCAgICMgcGxvdHRpbmcgYXJndW1lbnRzCiAgemxpbT1jKC0yLCAyKSwgbWFyZ2lucyA9IGMoMSwgMCkgICAgICAjIG1vcmUgcGxvdHRpbmcgYXJndW1lbnRzCikKCmBgYAoKCgojIyBDbHVzdGVycyBhbmQgdGhlIHVuZGVybHlpbmcgYmlvbG9neQoKRnJvbSB0aGlzIGhlYXRtYXAsIHdlIGNhbiBzZWUgdGhhdCB0aGUgdHVtb3JzIHNwbGl0IHVwIGludG8gZGlmZmVyZW50Cmdyb3Vwcy4gIElzIHRoZXJlIGFueSBiaW9sb2dpY2FsIHNpZ25pZmljYW5jZSB0byB0aGVzZSBjbHVzdGVycz8gIEFyZQp0aGVzZSBncm91cHMgb25seSBzZWVuIGluIHRoZSBnZW5lIGV4cHJlc3Npb24gcGF0dGVybnMsIG9yIGlzIGl0CnJlbGF0ZWQgdG8gYW55IGtub3duIGJpb2xvZ3k/CgpBcyB5b3UgcHJldmlvdXNseSBsZWFybmVkLCBicmVhc3QgY2FuY2VyIGlzIHNwbGl0IHVwIGludG8gRVIrIGFuZCBFUi0KdHVtb3JzLCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgdHVtb3IgZXhwcmVzc2VzIGhpZ2ggbGV2ZWxzIG9mCnJlY2VwdG9ycyBmb3IgZXN0cm9nZW4uICBUaGlzIGlzIHJlYWxseSBpbXBvcnRhbnQgdG8ga25vdyBiZWNhdXNlIGl0CnRlbGxzIHlvdSB3aGF0J3MgZHJpdmluZyB0aGUgZGlzZWFzZSwgYW5kIGFsc28gaG93IHRvIHRyZWF0IGl0LiAgVG8Kc2VlIHdoZXRoZXIgRVIgc3RhdHVzIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGVzZSBjbHVzdGVycywgbGV0J3MgbGFiZWwKdGhlIHNhbXBsZXMgd2l0aCBhIGAiKyJgIGZvciBFUisgYnJlYXN0IGNhbmNlcnMsIGFuZCBgIi4iYCBmb3IgbmVnYXRpdmUuCgoKYGBge3J9CmNsaW4gPC0gYnJjYV9jbGluX2RmW0kuc2FtcGxlLF0gICAgICAjIFdlIGluZGV4IHRoZSBjbGluaWNhbCBkYXRhIGZvciAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb3VyIHN1YnNldCBvZiBzYW1wbGVzLgoKCnggPC0gY2xpbltbImJyZWFzdF9jYXJjaW5vbWFfZXN0cm9nZW5fcmVjZXB0b3Jfc3RhdHVzIl1dICAgICAjIFdlIGZpbmQgYW5kIG5hbWUgdGhlCnByaW50KHNvcnQodW5pcXVlKHgpKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGRpZmZlcmVudCB0eXBlcyBvZiBFUiBzdGF0dXMuCmVyIDwtIHJlcCgiIiwgbGVuZ3RoKHgpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFdlIHdpbGwgbGFiZWwgdGhlIGNvbHVtbnMgb2YgCmVyW3ggPT0gIlBvc2l0aXZlIl0gPC0gIisiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG91ciBoZWF0IG1hcCB3aXRoIGBlcmAuCmVyW3ggPT0gIk5lZ2F0aXZlIl0gPC0gIi4iCnByaW50KHN1bShlciA9PSAiIikpCgpoZWF0bWFwKAogIG91cl9tYXRyaXgsICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgbWF0cml4IG9mIGV4cHJlc3Npb24gdmFsdWVzCiAgUm93dj1hcy5kZW5kcm9ncmFtKHJvd19jbHVzdGVycyksICAgICAjIENyZWF0ZSByb3cgZGVuZHJvZ3JhbSBmcm9tIGByb3dfY2x1c3RlcnNgCiAgQ29sdj1hcy5kZW5kcm9ncmFtKGNvbHVtbl9jbHVzdGVycyksICAjIENyZWF0ZSBjb2x1bW4gZGVuZG9ncmFtIGZyb20gYGNvbHVtbl9jbHVzdGVyc2AKICAKICBzY2FsZT0ibm9uZSIsIGxhYlJvdz0iIiwgbGFiQ29sPWVyLCBjb2w9YnJld2VyLnBhbCgxMCwiUmRCdSIpLCAgICMgTk9USUNFIGxhYkNvbD1lcgogIHpsaW09YygtMiwgMiksIG1hcmdpbnMgPSBjKDEsIDApICAgICAgIyBtb3JlIHBsb3R0aW5nIGFyZ3VtZW50cwopCgoKYGBgCgpJbiB0aGlzIHBsb3QsIEkgc2VlIGFib3V0IGZvdXIgb3IgZml2ZSBjbHVzdGVycyBvZiBzYW1wbGVzLiAgTW9zdCBvZiAKdGhlbSBoYXZlIGEgbG90IG9mIEVSKyB0dW1vcnMgKG1hcmtlZCBieSB0aGUgcm93IG9mIHBsdXNlcyBvbiB0aGUgYm90dG9tKSwgCndoaWxlIG9uZSBpcyBuZWFybHkgYWxsIEVSLS4gCgpCZWF1dGlmdWwhIQoKCg==