General directions for this Workshop
You will work in RStudio. Create an R Notebook document to write
whatever is asked in this workshop.
You have to solve CHALLENGE exercises.
It is STRONGLY RECOMMENDED that you write your OWN NOTES as if this
were your notebook. Your own workshop/notebook will be very helpful for
your further study.
Keep saving your .Rmd file, and ONLY SUBMIT the .html version of your
.Rmd file. # Excel interface - Data gathering from an Excel file
You have to install and load the readxl package. Use the RStudio
interface (Package tab in the right hand side window pane). We will also
use the quantmod package.
The readxl reads Excel files
Instead of typing the tickers and weights in our R code, we will read
the tickers of a portfolio along with specific weights for each ticker
from an Excel file.
We load the libraries to the current R session.
library(readxl)
library(quantmod)
Now we set the working directory where you downloaded the Excel file.
You can set the working directory using the RStudio Menu: Session/Set
working directory/Choose Directory, and then you can copy and paste the
R code from the console to your R chunk.
We read a list of tickers from an Excel file. The Excel file has one
Sheet with a list of tickers along with 4 different portfolios with
their respective weights. You can download the Excel file
“InputsW5.xlsx” from the course site. Save this file in any folder you
want.
input.df<-read_excel("InputsW5.xlsx",sheet = "ticklist1")
tickers.list<-input.df$ticker
tickers.list
[1] "AMD" "WMT" "MSFT" "TSLA"
Now we have the input of the program in the data frame input.df. The
first column is the list of tickers and the other 4 columns are
portfolio weights for 4 different portfolios.
We create a matrix with the weight columns of input.df:
W<-matrix(c(input.df$W1, input.df$W2, input.df$W3, input.df$W4),nrow=4,ncol=4)
W
[,1] [,2] [,3] [,4]
[1,] 0.25 0.4 0.0 0.5
[2,] 0.25 0.1 0.5 0.0
[3,] 0.25 0.0 0.5 0.0
[4,] 0.25 0.5 0.0 0.5
With the matrix function we specify the number of rows and columns of
the matrix, otherwise it would create a long vertical vector.
We can get monthly data of the stocks from Yahoo from 2015 to
date:
getSymbols(Symbols=tickers.list, from="2015-01-01",
periodicity="monthly", to="2021-03-10", src="yahoo")
[1] "AMD" "WMT" "MSFT" "TSLA"
Since the getSymbols function creates an xts - zoo object for each
asset, it is convenient to merge those objects into one single object
using the merge function.
Up to now we do not have a way to make a reference to the zoo object.
We only have the name of the objects as a character list, which is
stored in ticker.list. We can use the function get to create a reference
to those objects.
Note that the merge function works for xts and zoo objects only, but
not for plain dataframes.
p1<-get(tickers.list[1])
p2<-get(tickers.list[2])
p3<-get(tickers.list[3])
p4<-get(tickers.list[4])
prices.zoo <- Ad(merge(p1, p2, p3, p4))
# I can do the merge with the names of R objects, but this code
# will NOT work if I change the tickers in my Excel file
#prices.zoo<-Ad(merge(AMZN,MSFT,TSLA,ALFAA.MX))
The Ad function extracts only the adjusted prices (columns) of an
xts-zoo object created by the getSymbols function.
We can now remove the objects we created since all the data is in the
prices.zoo object.
rm(p1, p2, p3, p4)
Now we calculate the compounded returns. We do this as the difference
in the log prices for asset i.
rit=Δ(log(priceit)) We use the diff and log functions:
returns.zoo <- diff(log(prices.zoo))
Monthly expected return and risk of several portfolios
Now that we have monthly returns in a data frame we can calculate the
expected return of each stock and create the variance-covariance matrix,
which is needed to compute the expected risk of a portfolio.
To estimate expected stock returns we can calculate the geometric
average of returns for all stocks located in returns.zoo. We can
estimate the vector of mean returns or expected returns (Mr) as:
ER=exp[Mr]=exp⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢r1¯r2¯…rN¯⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥−1
I calculate the vector Mr of expected simple monthly returns using
the exponential and the apply function at the same time:
ER <- exp(apply(returns.zoo, 2, mean, na.rm=TRUE)) - 1
ER
AMD.Adjusted WMT.Adjusted MSFT.Adjusted TSLA.Adjusted
0.047289405 0.008285827 0.025796291 0.038527212
In this case I applied the function mean to returns.zoo, and the mean
was calculated by column. With the second parameter equal to 2 I
indicated to calculate the means by column (1 is to apply the mean by
row). After the means are calculated, then the exponential function is
applied to these means. The parameter na.rm=TRUE is used to avoid using
null values (NA’s) to calculate the mean. Finally I subtract 1 to get
the geometric mean return, which is the expected return for each
stock.
I can also use the function colMeans to do the same we did above:
ER2 <- exp(colMeans(na.omit(returns.zoo))) - 1
ER2
AMD.Adjusted WMT.Adjusted MSFT.Adjusted TSLA.Adjusted
0.047289405 0.008285827 0.025796291 0.038527212
There is a slight difference between the calculation of ER and ER2.
With the apply function and the parameter na.rm=TRUE the NA values are
omited column by column. In the case of the na.omit function, if there
is an NA for one stock then the whole raw is not used to compute the
mean. The differences are very minor, but in the real world you must
apply your criteria and use the more accurate. I will use ER since it is
more accurate because it is considering all available history of returns
for each stock.
Now we compute the Var-Covariance matrix. The var function receives a
matrix of returns as parameter. The returns of stock 1 are in column 1,
returns of stock 2 are in column 2, and so on. This function calculates
the Variance-Covariance Matrix of stock returns.
Remember that the Variance-Covariance matrix contains Variances of
stock returns in the diagonal, and it contains the covariances of pairs
of stock returns in the non-diagonals. Also, this matrix is symmetric,
since Cov(Reti,Retj) = Cov(Retj,Reti).
For example, the variance-covariance matrix of 2 variables X1 and X2
contains the variance of each variable in its diagonal and covariances
between the variables in its non-diagonal terms. In other words, the
elements in the upright part of the matrix are repeated in the down-left
part of the matrix. More formally:
∑cov=[Var(X1)Cov(X2,X1)Cov(X1,X2)Var(X2)] We can easily calculate the
variance-covariance matrix in R as follows:
COV <- var(returns.zoo, na.rm = TRUE)
COV
AMD.Adjusted WMT.Adjusted MSFT.Adjusted
AMD.Adjusted 0.026313875 0.001051776 0.002971675
WMT.Adjusted 0.001051776 0.002816480 0.000508591
MSFT.Adjusted 0.002971675 0.000508591 0.003243242
TSLA.Adjusted 0.003926307 0.001363373 0.002937124
TSLA.Adjusted
AMD.Adjusted 0.003926307
WMT.Adjusted 0.001363373
MSFT.Adjusted 0.002937124
TSLA.Adjusted 0.025831067
We can also calculate the Correlation Matrix to better understand the
relationships of all different pairs of stock returns:
CORR<-cor(na.omit(returns.zoo))
CORR
AMD.Adjusted WMT.Adjusted MSFT.Adjusted
AMD.Adjusted 1.0000000 0.1221736 0.3216764
WMT.Adjusted 0.1221736 1.0000000 0.1682773
MSFT.Adjusted 0.3216764 0.1682773 1.0000000
TSLA.Adjusted 0.1505985 0.1598418 0.3208938
TSLA.Adjusted
AMD.Adjusted 0.1505985
WMT.Adjusted 0.1598418
MSFT.Adjusted 0.3208938
TSLA.Adjusted 1.0000000
We can also run the cov2cor function to get the correlation
matrix:
CORR2 <- cov2cor(COV)
Remember that the correlation between 2 stock returns can be any
value between -1 and 1. When the correlation is close to 0, it means
that both stocks have no relationship. If the correlation is close to 1
it means that both stock returns move in a very similar way in the same
direction.
We can estimate the expected return and expected risk of the 4
portfolios using the weights that we read from the Excel file.
Now we are ready to start estimating the expected return of the 4
portfolios using Matrix Algebra:
ERP1<-t(W)%*%ER
ERP1
[,1]
[1,] 0.02997468
[2,] 0.03900795
[3,] 0.01704106
[4,] 0.04290831
The vector ERP1 will have the monthly expected returns of the 4
portfolios with the specific weights stated in the Excel file.
The t function is the transpose function of a vector or matrix. The
result of multiplying the vector transposed times the vector of expected
returns of the stocks is the same as calculating a weighted average.
This is true since we use matrix multiplication to efficiently compute
SUM of PRODUCTS.
Now I can estimate the expected risk of the 4 portfolios using Matrix
Albegra:
EVARPORT=t(W)%*%COV%*%W
ERISK=sqrt(diag(EVARPORT))
ERISK
[1] 0.07233704 0.11174593 0.04206217 0.12247199
With this matrix multiplication we are applying Markowitz theory to
estimate the expected risk of 4 portfolios at the same time.
You can review why this is the case in my Notes about Portfolio
Theory. Make sure you understand why we do this matrix
multiplication.
The expected variance of the 4 portfolios will be in the diagonal of
the matrix multiplication W′∗COV∗W. Finally, we get the squared root of
the diagonal to get the expected risk of the 4 portfolios.
Challenge 1 - Create a frontier with portfolios of combinations of 2
assets
Download monthly stock prices from Yahoo Finance for 2 stocks of your
preference. Bring data from 2017 to date. With this data you have to do
the following:
Generate 11 portfolios of these 2 assets. The first portfolio will
have 0% of Microsoft and 100% of Wal-Mart; the 2nd portfolio will have
10% of Microsoft and 90% of Wal-Mart; etc.. until you endup with the
11th portfolio that has 100% of Microsoft and 0% of Wal-Mart.
For each portfolio estimate the expected return and risk of the
portfolio according to Portfolio Theory
Do a plot of expected risk and expected return of these 11
portfolios. Put the expected risk in the X axis and expected return in
the Y axis. This will represent a frontier of possible portfolios.
3.2 Challenge 1 Solution - Approach 1
Any programming problem receives input data that needs to be
processed to arrive to specific result(s).
The input data can be specifications or actual raw data. In this case
we have the specification that we have to use stock data for Microsoft
and Wal-Mart. The processing of the data can be divided in a) data
management, and b) functional algorithm(s) needed to process the data
and achieve the specific results.
In order to write programming code for data management and the
functional algorithm(s) you need to UNDERSTAND THE PROBLEM very well
(100%), and also you need to know very well the concepts, methods and/or
theories related to the problem. For this problem, you need to
understand the basics of Portfolio Theory.
The data management process is related to data collection, data
cleanning, and data merging.
The functional algorithm(s) are basically the specific sequential
steps the computer has to process in order to get the result.
As a good practice for programming, before you start writing
programming code, I strongly recommend you to write down WITH YOUR WORDS
your own conception of the problem. Write the specific INPUTS, and write
the specific steps you need to program for data processing and for the
functional algorithm(s). I will try to follow this recommendation for
this problem.
A simple illustration of the inputs, process and output can be:
INPUT: MICROSOFT and WAL-MART stock historical monthly prices
DATA MANAGEMENT: Download prices and merge them into one object
FUNCTIONAL ALGORITHM: It has to do the calculations to get the
expected risk and return of 11 portfolios, each portfolio will have
different weight combination
OUTPUT: 11 expected return and 11 expected risk of the 11 portfolios;
a graph to illustrate the 11 portfolios in terms of risk vs return
I will detail this in the following sections.
DATA MANAGEMENT PROCESS
I visualize the data management as:
Download monthly stock prices from Yahoo Finance using the getSymbols
function
Calculate historical continuously compounded returns for both stocks
using adjusted prices
Merge the data in one dataset
FUNCTIONAL ALGORITHM
Estimate the expected return of both stocks, which will be used to
estimate the expected return of different portfolios. Calculate
geometric return as expected stock returns. I can save these expected
returns in a vector
Estimate the variance-covariance matrix using the continuously
returns of Microsoft and Wal-Mart. Save this in a matrix. I need this to
later estimate the expected risk of the different portfolios.
Calculate the expected return and expected risk of the 11 portfolios.
The first portfolio will have 0% of Microsot stock and 100% of Wal-Mart,
the 2nd portfolio will have 10% of Microsoft and 90% of Wal-Mart, and so
on until the last portfolio that will have 100% Microsoft and 0%
Wal-Mart.
3.1. I will do this by creating a data frame that will have the
following columns: Microsoft weight (wm), Wal-Mart weight (ww), Expected
Portfolio Return (ERP) and Expected Portfolio Risk (ExpRisk). I
visualize this dataframe something like:
portfolio wm ww ERP VARP ExpRisk 1 0 1 ? ? ? 2 0.10 0.90 ? ? ? 3 0.20
0.80 ? ? ? .. .. .. .. .. .. 11 1 0 ? ? ? I can fill out the weights
manually or using the seq function.
3.2. Estimate the expected return following Markowitz Portfolio
Theory. Portfolio return can be estimated with a simple weighted average
according to each specific asset weight:
ERP=E[P]=wm∗E[Rm]+ww∗E[Rw] where E[Rm] is Expected return for
Microsoft and E[Rw] is the expected return of Wal-Mart. I can do this
using R vectorization with the data frame, so the column for ERP will be
fill-out in one operation.
3.3. Estimate the expected variance and expected risk following
Markowitz Portfolio Theory. Since I only have 2 assets I can follow the
analytical formula for portfolio variance, which is:
VAR(P)=wm2∗VAR(rm)+ww2∗VAR(rw)+2∗wm∗ww∗COV(rm,rw) I can simply get
the expected risk of each portfolio by taking the square root of the
expected variance:
ExpRisk(P)=VAR(P)−−−−−−−√
I can also to this with R vectorization, so that I can calculate the
columns VARP and ExpRisk using a mathematical expression following the
previous formulas.
Do a plot of the 11 portfolio return and risk. Use Expected Portfolio
Return as the Y-axis and Expected Portfolio Risk as the X-axis.
Programming Code
# I load the required R packages for the program:
# To download data from Yahoo I use quantmod
library(quantmod)
# To manage columns of data frames I use dplyr:
library(dplyr)
# DATA MANAGEMENT PROCESSES
# I first get stock prices from Yahoo Finance:
getSymbols(Symbols=c("MSFT","WMT"), from="2015-01-01",
periodicity="monthly", src="yahoo")
[1] "MSFT" "WMT"
# getSymbols create zoo object for each dataset brought from the Web.
# The merge function works only with zoo or xts objects.
# I merge the 2 zoo objects into one zoo dataset called prices:
prices<-merge(MSFT,WMT)
# I calculate continuously compounded returns to all columns of the price object:
rets<-diff(log(prices))
# I use the dplyr package to remove NA values (since the first month is not possible to
# calculate returns) and select only Adjusted columns
# The dplyr only works with data frame objects, so I need to convert the zoo object into
# data frame first, and then drop rows with NA, and then select only Adjusted columns:
rets <- as.data.frame(rets) %>%
na.omit() %>% # remove the NAs
select(contains("Adjusted"))
# Now rets is a data frame with only continuously compounded returns calculated with
# adjusted prices. This data frame has only 2 columns, one for each stock
# I change the names of the columns:
colnames(rets)<-c("rMSFT", "rWMT")
# I display the first rows of the data frame:
head(rets)
# I calculate the expected returns of each stock. I calculate the geometric
# average of the columns of the rets object:
MR=exp(colMeans(rets))-1
# MR will be a vector with the 2 geometric means, which I will use as the expected
# returns of the stocks:
MR
rMSFT rWMT
0.021871358 0.006966573
# Now I calculate the Variance-Covariance matrix using the rets data frame:
COV<-cov(rets)
# The function cov generates a matrix where the diagonal will have the variances of
# each column, in this case, the variances of Microsoft and Wal-Mart returns.
# In the non-diagonal the matrix has the paired covariances between the returns
#I display the variance-covariance matrix:
COV
rMSFT rWMT
rMSFT 0.0035480398 0.0008355751
rWMT 0.0008355751 0.0029902722
# Now I will create a data frame with the weights and expected return, variance and
# risk of each of the 11 portfolios:
# I start creating a vector for the weights of Microsoft:
wm<-seq(from=0, to=1, by=0.10)
# I can easily create the vector for Wal-Mart as a complement of the Microsoft vector:
ww<- 1 - wm
# I create a data frame with these vectors:
portfolios <- as.data.frame(cbind(wm,ww))
# The cbind function "binds" or put together vectors into one matrix. It binds by column
portfolios
# I calculate the expected returns of each of the portfolios using the
# geometric mean returns and the weight vectors.
# I add a new column in the portflios data frame:
portfolios$ERP<-portfolios$wm*MR[1] + portfolios$ww*MR[2]
# The ERP column is created and will be filled out according to the expression
# R performs this statement to all rows of the data frame,
# so we do not need to do a loop to fill out all expected returns for the 11 portfolios.
# This is also called R vectorization since R performs all operations to the elements
# of vectors or other R object like data frame
portfolios
# I create a column for the Variances of the 11 portfolios:
portfolios$VARP <- portfolios$wm^2*COV[1,1] + portfolios$ww^2*COV[2,2] + 2*portfolios$wm*portfolios$ww*COV[1,2]
# I create a column for the expected risk of the 11 portfolios:
portfolios$SDP=sqrt(portfolios$VARP)
portfolios
#Finally I do a plot to illustrate the relationship between expected risk and return
# of the 11 portfolios:
plot(portfolios$SDP,portfolios$ERP, xlab="Portfolio volatility",
ylab="Portfolio Expected Return",
main="Portfolios of 2 Assets: MSFT & WMT")
# I add labels of the weights
text(portfolios$SDP,portfolios$ERP,labels=wm, cex=0.7, pos=3)

Q Challenge 1 - Approach 2
Modify approach 1 by applying matrix algebra to calculate expected
return and expected variance and risk of the 11 portfolios. Which
changes you need to do?
Q Challenge 2 - Create a frontier with portfolios of 2 assets
allowing for short sales
In portfolio formation you can have 2 type of positions: long and
short positions. Long positions is when you buy certain number of shares
of an asset (that represets a specific weigth with respect to your total
money you will use for the portfolio). A short position is when you
receive money for a certan number of shares of an asset, so that you
increase your money to invest in other stocks. Shorting is a way to
leverage your portfolio by borrowing money from a stock, and then invest
more money in other stocks. In this challenge you have to create
portfolios of 2 assets with short and long positions. Here are the
specific directions:
With the same stocks now create 19 portfolios instead of 11. The
first portfolio will have -40% in Microsoft and 140% in Wal-Mart; the
2nd portfolio will have -30% in Microsoft and 130% in Wal-Mart; … ; the
last portfolio will have 140% in Microsoft and -40% in Wal-Mart.
For each portfolio estimate the expected return and risk of the
portfolio according to Portfolio Theory
Do a plot of expected risk and expected return of these 11
portfolios. Put the expected risk in the X axis and expected return in
the Y axis.
Compare your plot in the case of shorting vs the plot you did in the
previous challenge. What do you see? What happen when you allow for
short positions?
LS0tCnRpdGxlOiAiRmluYW5jZSBQcm9ncmFtbWluZyAtIFdvcmtzaG9wIDUiCkF1dGhvcjogU3RlZmFuIFNjaHdlaXR6ZXIgLSBBMDEyMDk3NTUKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgR2VuZXJhbCBkaXJlY3Rpb25zIGZvciB0aGlzIFdvcmtzaG9wCgpZb3Ugd2lsbCB3b3JrIGluIFJTdHVkaW8uIENyZWF0ZSBhbiBSIE5vdGVib29rIGRvY3VtZW50IHRvIHdyaXRlIHdoYXRldmVyIGlzIGFza2VkIGluIHRoaXMgd29ya3Nob3AuCgpZb3UgaGF2ZSB0byBzb2x2ZSBDSEFMTEVOR0UgZXhlcmNpc2VzLgoKSXQgaXMgU1RST05HTFkgUkVDT01NRU5ERUQgdGhhdCB5b3Ugd3JpdGUgeW91ciBPV04gTk9URVMgYXMgaWYgdGhpcyB3ZXJlIHlvdXIgbm90ZWJvb2suIFlvdXIgb3duIHdvcmtzaG9wL25vdGVib29rIHdpbGwgYmUgdmVyeSBoZWxwZnVsIGZvciB5b3VyIGZ1cnRoZXIgc3R1ZHkuCgpLZWVwIHNhdmluZyB5b3VyIC5SbWQgZmlsZSwgYW5kIE9OTFkgU1VCTUlUIHRoZSAuaHRtbCB2ZXJzaW9uIG9mIHlvdXIgLlJtZCBmaWxlLiAjIEV4Y2VsIGludGVyZmFjZSAtIERhdGEgZ2F0aGVyaW5nIGZyb20gYW4gRXhjZWwgZmlsZQoKWW91IGhhdmUgdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgcmVhZHhsIHBhY2thZ2UuIFVzZSB0aGUgUlN0dWRpbyBpbnRlcmZhY2UgKFBhY2thZ2UgdGFiIGluIHRoZSByaWdodCBoYW5kIHNpZGUgd2luZG93IHBhbmUpLiBXZSB3aWxsIGFsc28gdXNlIHRoZSBxdWFudG1vZCBwYWNrYWdlLgoKVGhlIHJlYWR4bCByZWFkcyBFeGNlbCBmaWxlcwoKSW5zdGVhZCBvZiB0eXBpbmcgdGhlIHRpY2tlcnMgYW5kIHdlaWdodHMgaW4gb3VyIFIgY29kZSwgd2Ugd2lsbCByZWFkIHRoZSB0aWNrZXJzIG9mIGEgcG9ydGZvbGlvIGFsb25nIHdpdGggc3BlY2lmaWMgd2VpZ2h0cyBmb3IgZWFjaCB0aWNrZXIgZnJvbSBhbiBFeGNlbCBmaWxlLgoKV2UgbG9hZCB0aGUgbGlicmFyaWVzIHRvIHRoZSBjdXJyZW50IFIgc2Vzc2lvbi4KCmBgYHtyfQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShxdWFudG1vZCkKYGBgCgpOb3cgd2Ugc2V0IHRoZSB3b3JraW5nIGRpcmVjdG9yeSB3aGVyZSB5b3UgZG93bmxvYWRlZCB0aGUgRXhjZWwgZmlsZS4gWW91IGNhbiBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IHVzaW5nIHRoZSBSU3R1ZGlvIE1lbnU6IFNlc3Npb24vU2V0IHdvcmtpbmcgZGlyZWN0b3J5L0Nob29zZSBEaXJlY3RvcnksIGFuZCB0aGVuIHlvdSBjYW4gY29weSBhbmQgcGFzdGUgdGhlIFIgY29kZSBmcm9tIHRoZSBjb25zb2xlIHRvIHlvdXIgUiBjaHVuay4KCgpXZSByZWFkIGEgbGlzdCBvZiB0aWNrZXJzIGZyb20gYW4gRXhjZWwgZmlsZS4gVGhlIEV4Y2VsIGZpbGUgaGFzIG9uZSBTaGVldCB3aXRoIGEgbGlzdCBvZiB0aWNrZXJzIGFsb25nIHdpdGggNCBkaWZmZXJlbnQgcG9ydGZvbGlvcyB3aXRoIHRoZWlyIHJlc3BlY3RpdmUgd2VpZ2h0cy4gWW91IGNhbiBkb3dubG9hZCB0aGUgRXhjZWwgZmlsZSDigJxJbnB1dHNXNS54bHN44oCdIGZyb20gdGhlIGNvdXJzZSBzaXRlLiBTYXZlIHRoaXMgZmlsZSBpbiBhbnkgZm9sZGVyIHlvdSB3YW50LgoKYGBge3J9CmlucHV0LmRmPC1yZWFkX2V4Y2VsKCJJbnB1dHNXNS54bHN4IixzaGVldCA9ICJ0aWNrbGlzdDEiKQp0aWNrZXJzLmxpc3Q8LWlucHV0LmRmJHRpY2tlcgp0aWNrZXJzLmxpc3QKYGBgCgpOb3cgd2UgaGF2ZSB0aGUgaW5wdXQgb2YgdGhlIHByb2dyYW0gaW4gdGhlIGRhdGEgZnJhbWUgaW5wdXQuZGYuIFRoZSBmaXJzdCBjb2x1bW4gaXMgdGhlIGxpc3Qgb2YgdGlja2VycyBhbmQgdGhlIG90aGVyIDQgY29sdW1ucyBhcmUgcG9ydGZvbGlvIHdlaWdodHMgZm9yIDQgZGlmZmVyZW50IHBvcnRmb2xpb3MuCgpXZSBjcmVhdGUgYSBtYXRyaXggd2l0aCB0aGUgd2VpZ2h0IGNvbHVtbnMgb2YgaW5wdXQuZGY6CgpgYGB7cn0KVzwtbWF0cml4KGMoaW5wdXQuZGYkVzEsIGlucHV0LmRmJFcyLCBpbnB1dC5kZiRXMywgaW5wdXQuZGYkVzQpLG5yb3c9NCxuY29sPTQpClcKYGBgCldpdGggdGhlIG1hdHJpeCBmdW5jdGlvbiB3ZSBzcGVjaWZ5IHRoZSBudW1iZXIgb2Ygcm93cyBhbmQgY29sdW1ucyBvZiB0aGUgbWF0cml4LCBvdGhlcndpc2UgaXQgd291bGQgY3JlYXRlIGEgbG9uZyB2ZXJ0aWNhbCB2ZWN0b3IuCgpXZSBjYW4gZ2V0IG1vbnRobHkgZGF0YSBvZiB0aGUgc3RvY2tzIGZyb20gWWFob28gZnJvbSAyMDE1IHRvIGRhdGU6CgpgYGB7cn0KZ2V0U3ltYm9scyhTeW1ib2xzPXRpY2tlcnMubGlzdCwgZnJvbT0iMjAxNS0wMS0wMSIsCiAgICAgICAgICBwZXJpb2RpY2l0eT0ibW9udGhseSIsIHRvPSIyMDIxLTAzLTEwIiwgc3JjPSJ5YWhvbyIpCmBgYAoKU2luY2UgdGhlIGdldFN5bWJvbHMgZnVuY3Rpb24gY3JlYXRlcyBhbiB4dHMgLSB6b28gb2JqZWN0IGZvciBlYWNoIGFzc2V0LCBpdCBpcyBjb252ZW5pZW50IHRvIG1lcmdlIHRob3NlIG9iamVjdHMgaW50byBvbmUgc2luZ2xlIG9iamVjdCB1c2luZyB0aGUgbWVyZ2UgZnVuY3Rpb24uCgpVcCB0byBub3cgd2UgZG8gbm90IGhhdmUgYSB3YXkgdG8gbWFrZSBhIHJlZmVyZW5jZSB0byB0aGUgem9vIG9iamVjdC4gV2Ugb25seSBoYXZlIHRoZSBuYW1lIG9mIHRoZSBvYmplY3RzIGFzIGEgY2hhcmFjdGVyIGxpc3QsIHdoaWNoIGlzIHN0b3JlZCBpbiB0aWNrZXIubGlzdC4gV2UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gZ2V0IHRvIGNyZWF0ZSBhIHJlZmVyZW5jZSB0byB0aG9zZSBvYmplY3RzLgoKTm90ZSB0aGF0IHRoZSBtZXJnZSBmdW5jdGlvbiB3b3JrcyBmb3IgeHRzIGFuZCB6b28gb2JqZWN0cyBvbmx5LCBidXQgbm90IGZvciBwbGFpbiBkYXRhZnJhbWVzLgoKYGBge3J9CnAxPC1nZXQodGlja2Vycy5saXN0WzFdKQpwMjwtZ2V0KHRpY2tlcnMubGlzdFsyXSkKcDM8LWdldCh0aWNrZXJzLmxpc3RbM10pCnA0PC1nZXQodGlja2Vycy5saXN0WzRdKQpwcmljZXMuem9vIDwtIEFkKG1lcmdlKHAxLCBwMiwgcDMsIHA0KSkKCiMgSSBjYW4gZG8gdGhlIG1lcmdlIHdpdGggdGhlIG5hbWVzIG9mIFIgb2JqZWN0cywgYnV0IHRoaXMgY29kZQojICB3aWxsIE5PVCB3b3JrIGlmIEkgY2hhbmdlIHRoZSB0aWNrZXJzIGluIG15IEV4Y2VsIGZpbGUKI3ByaWNlcy56b288LUFkKG1lcmdlKEFNWk4sTVNGVCxUU0xBLEFMRkFBLk1YKSkKYGBgCgpUaGUgQWQgZnVuY3Rpb24gZXh0cmFjdHMgb25seSB0aGUgYWRqdXN0ZWQgcHJpY2VzIChjb2x1bW5zKSBvZiBhbiB4dHMtem9vIG9iamVjdCBjcmVhdGVkIGJ5IHRoZSBnZXRTeW1ib2xzIGZ1bmN0aW9uLgoKV2UgY2FuIG5vdyByZW1vdmUgdGhlIG9iamVjdHMgd2UgY3JlYXRlZCBzaW5jZSBhbGwgdGhlIGRhdGEgaXMgaW4gdGhlIHByaWNlcy56b28gb2JqZWN0LgoKYGBge3J9CnJtKHAxLCBwMiwgcDMsIHA0KSAKYGBgCgpOb3cgd2UgY2FsY3VsYXRlIHRoZSBjb21wb3VuZGVkIHJldHVybnMuIFdlIGRvIHRoaXMgYXMgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGxvZyBwcmljZXMgZm9yIGFzc2V0IGkuCgpyaXQ9zpQobG9nKHByaWNlaXQpKQpXZSB1c2UgdGhlIGRpZmYgYW5kIGxvZyBmdW5jdGlvbnM6CgpgYGB7cn0KcmV0dXJucy56b28gPC0gZGlmZihsb2cocHJpY2VzLnpvbykpCmBgYAoKIyMgTW9udGhseSBleHBlY3RlZCByZXR1cm4gYW5kIHJpc2sgb2Ygc2V2ZXJhbCBwb3J0Zm9saW9zCgpOb3cgdGhhdCB3ZSBoYXZlIG1vbnRobHkgcmV0dXJucyBpbiBhIGRhdGEgZnJhbWUgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgZXhwZWN0ZWQgcmV0dXJuIG9mIGVhY2ggc3RvY2sgYW5kIGNyZWF0ZSB0aGUgdmFyaWFuY2UtY292YXJpYW5jZSBtYXRyaXgsIHdoaWNoIGlzIG5lZWRlZCB0byBjb21wdXRlIHRoZSBleHBlY3RlZCByaXNrIG9mIGEgcG9ydGZvbGlvLgoKVG8gZXN0aW1hdGUgZXhwZWN0ZWQgc3RvY2sgcmV0dXJucyB3ZSBjYW4gY2FsY3VsYXRlIHRoZSBnZW9tZXRyaWMgYXZlcmFnZSBvZiByZXR1cm5zIGZvciBhbGwgc3RvY2tzIGxvY2F0ZWQgaW4gcmV0dXJucy56b28uIFdlIGNhbiBlc3RpbWF0ZSB0aGUgdmVjdG9yIG9mIG1lYW4gcmV0dXJucyBvciBleHBlY3RlZCByZXR1cm5zIChNcikgYXM6CgpFUj1leHBbTXJdPWV4cOKOoeKOo+KOouKOouKOouKOouKOouKOouKOouKOonIxwq9yMsKvLi4uck7Cr+KOpOKOpuKOpeKOpeKOpeKOpeKOpeKOpeKOpeKOpeKIkjEKCkkgY2FsY3VsYXRlIHRoZSB2ZWN0b3IgTXIgb2YgZXhwZWN0ZWQgc2ltcGxlIG1vbnRobHkgcmV0dXJucyB1c2luZyB0aGUgZXhwb25lbnRpYWwgYW5kIHRoZSBhcHBseSBmdW5jdGlvbiBhdCB0aGUgc2FtZSB0aW1lOgoKYGBge3J9CkVSIDwtIGV4cChhcHBseShyZXR1cm5zLnpvbywgMiwgbWVhbiwgbmEucm09VFJVRSkpIC0gMQpFUgpgYGAKCkluIHRoaXMgY2FzZSBJIGFwcGxpZWQgdGhlIGZ1bmN0aW9uIG1lYW4gdG8gcmV0dXJucy56b28sIGFuZCB0aGUgbWVhbiB3YXMgY2FsY3VsYXRlZCBieSBjb2x1bW4uIFdpdGggdGhlIHNlY29uZCBwYXJhbWV0ZXIgZXF1YWwgdG8gMiBJIGluZGljYXRlZCB0byBjYWxjdWxhdGUgdGhlIG1lYW5zIGJ5IGNvbHVtbiAoMSBpcyB0byBhcHBseSB0aGUgbWVhbiBieSByb3cpLiBBZnRlciB0aGUgbWVhbnMgYXJlIGNhbGN1bGF0ZWQsIHRoZW4gdGhlIGV4cG9uZW50aWFsIGZ1bmN0aW9uIGlzIGFwcGxpZWQgdG8gdGhlc2UgbWVhbnMuIFRoZSBwYXJhbWV0ZXIgbmEucm09VFJVRSBpcyB1c2VkIHRvIGF2b2lkIHVzaW5nIG51bGwgdmFsdWVzIChOQeKAmXMpIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbi4gRmluYWxseSBJIHN1YnRyYWN0IDEgdG8gZ2V0IHRoZSBnZW9tZXRyaWMgbWVhbiByZXR1cm4sIHdoaWNoIGlzIHRoZSBleHBlY3RlZCByZXR1cm4gZm9yIGVhY2ggc3RvY2suCgpJIGNhbiBhbHNvIHVzZSB0aGUgZnVuY3Rpb24gY29sTWVhbnMgdG8gZG8gdGhlIHNhbWUgd2UgZGlkIGFib3ZlOgoKYGBge3J9CkVSMiA8LSBleHAoY29sTWVhbnMobmEub21pdChyZXR1cm5zLnpvbykpKSAtIDEKRVIyCmBgYAoKVGhlcmUgaXMgYSBzbGlnaHQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjYWxjdWxhdGlvbiBvZiBFUiBhbmQgRVIyLiBXaXRoIHRoZSBhcHBseSBmdW5jdGlvbiBhbmQgdGhlIHBhcmFtZXRlciBuYS5ybT1UUlVFIHRoZSBOQSB2YWx1ZXMgYXJlIG9taXRlZCBjb2x1bW4gYnkgY29sdW1uLiBJbiB0aGUgY2FzZSBvZiB0aGUgbmEub21pdCBmdW5jdGlvbiwgaWYgdGhlcmUgaXMgYW4gTkEgZm9yIG9uZSBzdG9jayB0aGVuIHRoZSB3aG9sZSByYXcgaXMgbm90IHVzZWQgdG8gY29tcHV0ZSB0aGUgbWVhbi4gVGhlIGRpZmZlcmVuY2VzIGFyZSB2ZXJ5IG1pbm9yLCBidXQgaW4gdGhlIHJlYWwgd29ybGQgeW91IG11c3QgYXBwbHkgeW91ciBjcml0ZXJpYSBhbmQgdXNlIHRoZSBtb3JlIGFjY3VyYXRlLiBJIHdpbGwgdXNlIEVSIHNpbmNlIGl0IGlzIG1vcmUgYWNjdXJhdGUgYmVjYXVzZSBpdCBpcyBjb25zaWRlcmluZyBhbGwgYXZhaWxhYmxlIGhpc3Rvcnkgb2YgcmV0dXJucyBmb3IgZWFjaCBzdG9jay4KCk5vdyB3ZSBjb21wdXRlIHRoZSBWYXItQ292YXJpYW5jZSBtYXRyaXguIFRoZSB2YXIgZnVuY3Rpb24gcmVjZWl2ZXMgYSBtYXRyaXggb2YgcmV0dXJucyBhcyBwYXJhbWV0ZXIuIFRoZSByZXR1cm5zIG9mIHN0b2NrIDEgYXJlIGluIGNvbHVtbiAxLCByZXR1cm5zIG9mIHN0b2NrIDIgYXJlIGluIGNvbHVtbiAyLCBhbmQgc28gb24uIFRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyB0aGUgVmFyaWFuY2UtQ292YXJpYW5jZSBNYXRyaXggb2Ygc3RvY2sgcmV0dXJucy4KClJlbWVtYmVyIHRoYXQgdGhlIFZhcmlhbmNlLUNvdmFyaWFuY2UgbWF0cml4IGNvbnRhaW5zIFZhcmlhbmNlcyBvZiBzdG9jayByZXR1cm5zIGluIHRoZSBkaWFnb25hbCwgYW5kIGl0IGNvbnRhaW5zIHRoZSBjb3ZhcmlhbmNlcyBvZiBwYWlycyBvZiBzdG9jayByZXR1cm5zIGluIHRoZSBub24tZGlhZ29uYWxzLiBBbHNvLCB0aGlzIG1hdHJpeCBpcyBzeW1tZXRyaWMsIHNpbmNlIENvdihSZXRpLFJldGopID0gQ292KFJldGosUmV0aSkuCgpGb3IgZXhhbXBsZSwgdGhlIHZhcmlhbmNlLWNvdmFyaWFuY2UgbWF0cml4IG9mIDIgdmFyaWFibGVzIFgxIGFuZCBYMiBjb250YWlucyB0aGUgdmFyaWFuY2Ugb2YgZWFjaCB2YXJpYWJsZSBpbiBpdHMgZGlhZ29uYWwgYW5kIGNvdmFyaWFuY2VzIGJldHdlZW4gdGhlIHZhcmlhYmxlcyBpbiBpdHMgbm9uLWRpYWdvbmFsIHRlcm1zLiBJbiBvdGhlciB3b3JkcywgdGhlIGVsZW1lbnRzIGluIHRoZSB1cHJpZ2h0IHBhcnQgb2YgdGhlIG1hdHJpeCBhcmUgcmVwZWF0ZWQgaW4gdGhlIGRvd24tbGVmdCBwYXJ0IG9mIHRoZSBtYXRyaXguIE1vcmUgZm9ybWFsbHk6CgriiJFjb3Y9W1ZhcihYMSlDb3YoWDIsWDEpQ292KFgxLFgyKVZhcihYMildCldlIGNhbiBlYXNpbHkgY2FsY3VsYXRlIHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeCBpbiBSIGFzIGZvbGxvd3M6CgpgYGB7cn0KQ09WIDwtIHZhcihyZXR1cm5zLnpvbywgbmEucm0gPSBUUlVFKQpDT1YKYGBgCgpXZSBjYW4gYWxzbyBjYWxjdWxhdGUgdGhlIENvcnJlbGF0aW9uIE1hdHJpeCB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwcyBvZiBhbGwgZGlmZmVyZW50IHBhaXJzIG9mIHN0b2NrIHJldHVybnM6CgpgYGB7cn0KQ09SUjwtY29yKG5hLm9taXQocmV0dXJucy56b28pKQpDT1JSCmBgYApXZSBjYW4gYWxzbyBydW4gdGhlIGNvdjJjb3IgZnVuY3Rpb24gdG8gZ2V0IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXg6CgpgYGB7cn0KQ09SUjIgPC0gY292MmNvcihDT1YpCmBgYAoKUmVtZW1iZXIgdGhhdCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiAyIHN0b2NrIHJldHVybnMgY2FuIGJlIGFueSB2YWx1ZSBiZXR3ZWVuIC0xIGFuZCAxLiBXaGVuIHRoZSBjb3JyZWxhdGlvbiBpcyBjbG9zZSB0byAwLCBpdCBtZWFucyB0aGF0IGJvdGggc3RvY2tzIGhhdmUgbm8gcmVsYXRpb25zaGlwLiBJZiB0aGUgY29ycmVsYXRpb24gaXMgY2xvc2UgdG8gMSBpdCBtZWFucyB0aGF0IGJvdGggc3RvY2sgcmV0dXJucyBtb3ZlIGluIGEgdmVyeSBzaW1pbGFyIHdheSBpbiB0aGUgc2FtZSBkaXJlY3Rpb24uCgpXZSBjYW4gZXN0aW1hdGUgdGhlIGV4cGVjdGVkIHJldHVybiBhbmQgZXhwZWN0ZWQgcmlzayBvZiB0aGUgNCBwb3J0Zm9saW9zIHVzaW5nIHRoZSB3ZWlnaHRzIHRoYXQgd2UgcmVhZCBmcm9tIHRoZSBFeGNlbCBmaWxlLgoKTm93IHdlIGFyZSByZWFkeSB0byBzdGFydCBlc3RpbWF0aW5nIHRoZSBleHBlY3RlZCByZXR1cm4gb2YgdGhlIDQgcG9ydGZvbGlvcyB1c2luZyBNYXRyaXggQWxnZWJyYToKCmBgYHtyfQpFUlAxPC10KFcpJSolRVIKRVJQMQpgYGAKClRoZSB2ZWN0b3IgRVJQMSB3aWxsIGhhdmUgdGhlIG1vbnRobHkgZXhwZWN0ZWQgcmV0dXJucyBvZiB0aGUgNCBwb3J0Zm9saW9zIHdpdGggdGhlIHNwZWNpZmljIHdlaWdodHMgc3RhdGVkIGluIHRoZSBFeGNlbCBmaWxlLgoKVGhlIHQgZnVuY3Rpb24gaXMgdGhlIHRyYW5zcG9zZSBmdW5jdGlvbiBvZiBhIHZlY3RvciBvciBtYXRyaXguIFRoZSByZXN1bHQgb2YgbXVsdGlwbHlpbmcgdGhlIHZlY3RvciB0cmFuc3Bvc2VkIHRpbWVzIHRoZSB2ZWN0b3Igb2YgZXhwZWN0ZWQgcmV0dXJucyBvZiB0aGUgc3RvY2tzIGlzIHRoZSBzYW1lIGFzIGNhbGN1bGF0aW5nIGEgd2VpZ2h0ZWQgYXZlcmFnZS4gVGhpcyBpcyB0cnVlIHNpbmNlIHdlIHVzZSBtYXRyaXggbXVsdGlwbGljYXRpb24gdG8gZWZmaWNpZW50bHkgY29tcHV0ZSBTVU0gb2YgUFJPRFVDVFMuCgpOb3cgSSBjYW4gZXN0aW1hdGUgdGhlIGV4cGVjdGVkIHJpc2sgb2YgdGhlIDQgcG9ydGZvbGlvcyB1c2luZyBNYXRyaXggQWxiZWdyYToKCmBgYHtyfQpFVkFSUE9SVD10KFcpJSolQ09WJSolVwpFUklTSz1zcXJ0KGRpYWcoRVZBUlBPUlQpKQpFUklTSwpgYGAKV2l0aCB0aGlzIG1hdHJpeCBtdWx0aXBsaWNhdGlvbiB3ZSBhcmUgYXBwbHlpbmcgTWFya293aXR6IHRoZW9yeSB0byBlc3RpbWF0ZSB0aGUgZXhwZWN0ZWQgcmlzayBvZiA0IHBvcnRmb2xpb3MgYXQgdGhlIHNhbWUgdGltZS4KCllvdSBjYW4gcmV2aWV3IHdoeSB0aGlzIGlzIHRoZSBjYXNlIGluIG15IE5vdGVzIGFib3V0IFBvcnRmb2xpbyBUaGVvcnkuIE1ha2Ugc3VyZSB5b3UgdW5kZXJzdGFuZCB3aHkgd2UgZG8gdGhpcyBtYXRyaXggbXVsdGlwbGljYXRpb24uCgpUaGUgZXhwZWN0ZWQgdmFyaWFuY2Ugb2YgdGhlIDQgcG9ydGZvbGlvcyB3aWxsIGJlIGluIHRoZSBkaWFnb25hbCBvZiB0aGUgbWF0cml4IG11bHRpcGxpY2F0aW9uIFfigLLiiJdDT1biiJdXLiBGaW5hbGx5LCB3ZSBnZXQgdGhlIHNxdWFyZWQgcm9vdCBvZiB0aGUgZGlhZ29uYWwgdG8gZ2V0IHRoZSBleHBlY3RlZCByaXNrIG9mIHRoZSA0IHBvcnRmb2xpb3MuCgojIENoYWxsZW5nZSAxIC0gQ3JlYXRlIGEgZnJvbnRpZXIgd2l0aCBwb3J0Zm9saW9zIG9mIGNvbWJpbmF0aW9ucyBvZiAyIGFzc2V0cwoKRG93bmxvYWQgbW9udGhseSBzdG9jayBwcmljZXMgZnJvbSBZYWhvbyBGaW5hbmNlIGZvciAyIHN0b2NrcyBvZiB5b3VyIHByZWZlcmVuY2UuIEJyaW5nIGRhdGEgZnJvbSAyMDE3IHRvIGRhdGUuIFdpdGggdGhpcyBkYXRhIHlvdSBoYXZlIHRvIGRvIHRoZSBmb2xsb3dpbmc6CgpHZW5lcmF0ZSAxMSBwb3J0Zm9saW9zIG9mIHRoZXNlIDIgYXNzZXRzLiBUaGUgZmlyc3QgcG9ydGZvbGlvIHdpbGwgaGF2ZSAwJSBvZiBNaWNyb3NvZnQgYW5kIDEwMCUgb2YgV2FsLU1hcnQ7IHRoZSAybmQgcG9ydGZvbGlvIHdpbGwgaGF2ZSAxMCUgb2YgTWljcm9zb2Z0IGFuZCA5MCUgb2YgV2FsLU1hcnQ7IGV0Yy4uIHVudGlsIHlvdSBlbmR1cCB3aXRoIHRoZSAxMXRoIHBvcnRmb2xpbyB0aGF0IGhhcyAxMDAlIG9mIE1pY3Jvc29mdCBhbmQgMCUgb2YgV2FsLU1hcnQuCgpGb3IgZWFjaCBwb3J0Zm9saW8gZXN0aW1hdGUgdGhlIGV4cGVjdGVkIHJldHVybiBhbmQgcmlzayBvZiB0aGUgcG9ydGZvbGlvIGFjY29yZGluZyB0byBQb3J0Zm9saW8gVGhlb3J5CgpEbyBhIHBsb3Qgb2YgZXhwZWN0ZWQgcmlzayBhbmQgZXhwZWN0ZWQgcmV0dXJuIG9mIHRoZXNlIDExIHBvcnRmb2xpb3MuIFB1dCB0aGUgZXhwZWN0ZWQgcmlzayBpbiB0aGUgWCBheGlzIGFuZCBleHBlY3RlZCByZXR1cm4gaW4gdGhlIFkgYXhpcy4gVGhpcyB3aWxsIHJlcHJlc2VudCBhIGZyb250aWVyIG9mIHBvc3NpYmxlIHBvcnRmb2xpb3MuCgojIDMuMiBDaGFsbGVuZ2UgMSBTb2x1dGlvbiAtIEFwcHJvYWNoIDEKCkFueSBwcm9ncmFtbWluZyBwcm9ibGVtIHJlY2VpdmVzIGlucHV0IGRhdGEgdGhhdCBuZWVkcyB0byBiZSBwcm9jZXNzZWQgdG8gYXJyaXZlIHRvIHNwZWNpZmljIHJlc3VsdChzKS4KClRoZSBpbnB1dCBkYXRhIGNhbiBiZSBzcGVjaWZpY2F0aW9ucyBvciBhY3R1YWwgcmF3IGRhdGEuIEluIHRoaXMgY2FzZSB3ZSBoYXZlIHRoZSBzcGVjaWZpY2F0aW9uIHRoYXQgd2UgaGF2ZSB0byB1c2Ugc3RvY2sgZGF0YSBmb3IgTWljcm9zb2Z0IGFuZCBXYWwtTWFydC4KVGhlIHByb2Nlc3Npbmcgb2YgdGhlIGRhdGEgY2FuIGJlIGRpdmlkZWQgaW4gYSkgZGF0YSBtYW5hZ2VtZW50LCBhbmQgYikgZnVuY3Rpb25hbCBhbGdvcml0aG0ocykgbmVlZGVkIHRvIHByb2Nlc3MgdGhlIGRhdGEgYW5kIGFjaGlldmUgdGhlIHNwZWNpZmljIHJlc3VsdHMuCgpJbiBvcmRlciB0byB3cml0ZSBwcm9ncmFtbWluZyBjb2RlIGZvciBkYXRhIG1hbmFnZW1lbnQgYW5kIHRoZSBmdW5jdGlvbmFsIGFsZ29yaXRobShzKSB5b3UgbmVlZCB0byBVTkRFUlNUQU5EIFRIRSBQUk9CTEVNIHZlcnkgd2VsbCAoMTAwJSksIGFuZCBhbHNvIHlvdSBuZWVkIHRvIGtub3cgdmVyeSB3ZWxsIHRoZSBjb25jZXB0cywgbWV0aG9kcyBhbmQvb3IgdGhlb3JpZXMgcmVsYXRlZCB0byB0aGUgcHJvYmxlbS4gRm9yIHRoaXMgcHJvYmxlbSwgeW91IG5lZWQgdG8gdW5kZXJzdGFuZCB0aGUgYmFzaWNzIG9mIFBvcnRmb2xpbyBUaGVvcnkuCgpUaGUgZGF0YSBtYW5hZ2VtZW50IHByb2Nlc3MgaXMgcmVsYXRlZCB0byBkYXRhIGNvbGxlY3Rpb24sIGRhdGEgY2xlYW5uaW5nLCBhbmQgZGF0YSBtZXJnaW5nLgoKVGhlIGZ1bmN0aW9uYWwgYWxnb3JpdGhtKHMpIGFyZSBiYXNpY2FsbHkgdGhlIHNwZWNpZmljIHNlcXVlbnRpYWwgc3RlcHMgdGhlIGNvbXB1dGVyIGhhcyB0byBwcm9jZXNzIGluIG9yZGVyIHRvIGdldCB0aGUgcmVzdWx0LgoKQXMgYSBnb29kIHByYWN0aWNlIGZvciBwcm9ncmFtbWluZywgYmVmb3JlIHlvdSBzdGFydCB3cml0aW5nIHByb2dyYW1taW5nIGNvZGUsIEkgc3Ryb25nbHkgcmVjb21tZW5kIHlvdSB0byB3cml0ZSBkb3duIFdJVEggWU9VUiBXT1JEUyB5b3VyIG93biBjb25jZXB0aW9uIG9mIHRoZSBwcm9ibGVtLiBXcml0ZSB0aGUgc3BlY2lmaWMgSU5QVVRTLCBhbmQgd3JpdGUgdGhlIHNwZWNpZmljIHN0ZXBzIHlvdSBuZWVkIHRvIHByb2dyYW0gZm9yIGRhdGEgcHJvY2Vzc2luZyBhbmQgZm9yIHRoZSBmdW5jdGlvbmFsIGFsZ29yaXRobShzKS4gSSB3aWxsIHRyeSB0byBmb2xsb3cgdGhpcyByZWNvbW1lbmRhdGlvbiBmb3IgdGhpcyBwcm9ibGVtLgoKQSBzaW1wbGUgaWxsdXN0cmF0aW9uIG9mIHRoZSBpbnB1dHMsIHByb2Nlc3MgYW5kIG91dHB1dCBjYW4gYmU6CgpJTlBVVDogTUlDUk9TT0ZUIGFuZCBXQUwtTUFSVCBzdG9jayBoaXN0b3JpY2FsIG1vbnRobHkgcHJpY2VzCgpEQVRBIE1BTkFHRU1FTlQ6IERvd25sb2FkIHByaWNlcyBhbmQgbWVyZ2UgdGhlbSBpbnRvIG9uZSBvYmplY3QKCkZVTkNUSU9OQUwgQUxHT1JJVEhNOiBJdCBoYXMgdG8gZG8gdGhlIGNhbGN1bGF0aW9ucyB0byBnZXQgdGhlIGV4cGVjdGVkIHJpc2sgYW5kIHJldHVybiBvZiAxMSBwb3J0Zm9saW9zLCBlYWNoIHBvcnRmb2xpbyB3aWxsIGhhdmUgZGlmZmVyZW50IHdlaWdodCBjb21iaW5hdGlvbgoKT1VUUFVUOiAxMSBleHBlY3RlZCByZXR1cm4gYW5kIDExIGV4cGVjdGVkIHJpc2sgb2YgdGhlIDExIHBvcnRmb2xpb3M7IGEgZ3JhcGggdG8gaWxsdXN0cmF0ZSB0aGUgMTEgcG9ydGZvbGlvcyBpbiB0ZXJtcyBvZiByaXNrIHZzIHJldHVybgoKSSB3aWxsIGRldGFpbCB0aGlzIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbnMuCgojIElOUFVUCkkgbmVlZCB0byBnZXQgc3RvY2sgbW9udGhseSBwcmljZXMgZm9yIE1pY3Jvc29mdCBhbmQgV2FsLU1hcnQgZnJvbSAyMDE1IHRvIGRhdGUuCgojIERBVEEgTUFOQUdFTUVOVCBQUk9DRVNTCkkgdmlzdWFsaXplIHRoZSBkYXRhIG1hbmFnZW1lbnQgYXM6CgpEb3dubG9hZCBtb250aGx5IHN0b2NrIHByaWNlcyBmcm9tIFlhaG9vIEZpbmFuY2UgdXNpbmcgdGhlIGdldFN5bWJvbHMgZnVuY3Rpb24KCkNhbGN1bGF0ZSBoaXN0b3JpY2FsIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkIHJldHVybnMgZm9yIGJvdGggc3RvY2tzIHVzaW5nIGFkanVzdGVkIHByaWNlcwoKTWVyZ2UgdGhlIGRhdGEgaW4gb25lIGRhdGFzZXQKCiMgRlVOQ1RJT05BTCBBTEdPUklUSE0KCkVzdGltYXRlIHRoZSBleHBlY3RlZCByZXR1cm4gb2YgYm90aCBzdG9ja3MsIHdoaWNoIHdpbGwgYmUgdXNlZCB0byBlc3RpbWF0ZSB0aGUgZXhwZWN0ZWQgcmV0dXJuIG9mIGRpZmZlcmVudCBwb3J0Zm9saW9zLiBDYWxjdWxhdGUgZ2VvbWV0cmljIHJldHVybiBhcyBleHBlY3RlZCBzdG9jayByZXR1cm5zLiBJIGNhbiBzYXZlIHRoZXNlIGV4cGVjdGVkIHJldHVybnMgaW4gYSB2ZWN0b3IKCkVzdGltYXRlIHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeCB1c2luZyB0aGUgY29udGludW91c2x5IHJldHVybnMgb2YgTWljcm9zb2Z0IGFuZCBXYWwtTWFydC4gU2F2ZSB0aGlzIGluIGEgbWF0cml4LiBJIG5lZWQgdGhpcyB0byBsYXRlciBlc3RpbWF0ZSB0aGUgZXhwZWN0ZWQgcmlzayBvZiB0aGUgZGlmZmVyZW50IHBvcnRmb2xpb3MuCgpDYWxjdWxhdGUgdGhlIGV4cGVjdGVkIHJldHVybiBhbmQgZXhwZWN0ZWQgcmlzayBvZiB0aGUgMTEgcG9ydGZvbGlvcy4gVGhlIGZpcnN0IHBvcnRmb2xpbyB3aWxsIGhhdmUgMCUgb2YgTWljcm9zb3Qgc3RvY2sgYW5kIDEwMCUgb2YgV2FsLU1hcnQsIHRoZSAybmQgcG9ydGZvbGlvIHdpbGwgaGF2ZSAxMCUgb2YgTWljcm9zb2Z0IGFuZCA5MCUgb2YgV2FsLU1hcnQsIGFuZCBzbyBvbiB1bnRpbCB0aGUgbGFzdCBwb3J0Zm9saW8gdGhhdCB3aWxsIGhhdmUgMTAwJSBNaWNyb3NvZnQgYW5kIDAlIFdhbC1NYXJ0LgoKMy4xLiBJIHdpbGwgZG8gdGhpcyBieSBjcmVhdGluZyBhIGRhdGEgZnJhbWUgdGhhdCB3aWxsIGhhdmUgdGhlIGZvbGxvd2luZyBjb2x1bW5zOiBNaWNyb3NvZnQgd2VpZ2h0ICh3bSksIFdhbC1NYXJ0IHdlaWdodCAod3cpLCBFeHBlY3RlZCBQb3J0Zm9saW8gUmV0dXJuIChFUlApIGFuZCBFeHBlY3RlZCBQb3J0Zm9saW8gUmlzayAoRXhwUmlzaykuIEkgdmlzdWFsaXplIHRoaXMgZGF0YWZyYW1lIHNvbWV0aGluZyBsaWtlOgoKcG9ydGZvbGlvCXdtCXd3CUVSUAlWQVJQCUV4cFJpc2sKMQkwCTEJPwk/CT8KMgkwLjEwCTAuOTAJPwk/CT8KMwkwLjIwCTAuODAJPwk/CT8KLi4JLi4JLi4JLi4JLi4JLi4KMTEJMQkwCT8JPwk/CkkgY2FuIGZpbGwgb3V0IHRoZSB3ZWlnaHRzIG1hbnVhbGx5IG9yIHVzaW5nIHRoZSBzZXEgZnVuY3Rpb24uCgozLjIuIEVzdGltYXRlIHRoZSBleHBlY3RlZCByZXR1cm4gZm9sbG93aW5nIE1hcmtvd2l0eiBQb3J0Zm9saW8gVGhlb3J5LiBQb3J0Zm9saW8gcmV0dXJuIGNhbiBiZSBlc3RpbWF0ZWQgd2l0aCBhIHNpbXBsZSB3ZWlnaHRlZCBhdmVyYWdlIGFjY29yZGluZyB0byBlYWNoIHNwZWNpZmljIGFzc2V0IHdlaWdodDoKCkVSUD1FW1BdPXdt4oiXRVtSbV0rd3fiiJdFW1J3XQp3aGVyZSBFW1JtXSBpcyBFeHBlY3RlZCByZXR1cm4gZm9yIE1pY3Jvc29mdCBhbmQgRVtSd10gaXMgdGhlIGV4cGVjdGVkIHJldHVybiBvZiBXYWwtTWFydC4gSSBjYW4gZG8gdGhpcyB1c2luZyBSIHZlY3Rvcml6YXRpb24gd2l0aCB0aGUgZGF0YSBmcmFtZSwgc28gdGhlIGNvbHVtbiBmb3IgRVJQIHdpbGwgYmUgZmlsbC1vdXQgaW4gb25lIG9wZXJhdGlvbi4KCjMuMy4gRXN0aW1hdGUgdGhlIGV4cGVjdGVkIHZhcmlhbmNlIGFuZCBleHBlY3RlZCByaXNrIGZvbGxvd2luZyBNYXJrb3dpdHogUG9ydGZvbGlvIFRoZW9yeS4gU2luY2UgSSBvbmx5IGhhdmUgMiBhc3NldHMgSSBjYW4gZm9sbG93IHRoZSBhbmFseXRpY2FsIGZvcm11bGEgZm9yIHBvcnRmb2xpbyB2YXJpYW5jZSwgd2hpY2ggaXM6CgpWQVIoUCk9d20y4oiXVkFSKHJtKSt3dzLiiJdWQVIocncpKzLiiJd3beKIl3d34oiXQ09WKHJtLHJ3KQpJIGNhbiBzaW1wbHkgZ2V0IHRoZSBleHBlY3RlZCByaXNrIG9mIGVhY2ggcG9ydGZvbGlvIGJ5IHRha2luZyB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhlIGV4cGVjdGVkIHZhcmlhbmNlOgoKRXhwUmlzayhQKT1WQVIoUCniiJLiiJLiiJLiiJLiiJLiiJLiiJLiiJoKCkkgY2FuIGFsc28gdG8gdGhpcyB3aXRoIFIgdmVjdG9yaXphdGlvbiwgc28gdGhhdCBJIGNhbiBjYWxjdWxhdGUgdGhlIGNvbHVtbnMgVkFSUCBhbmQgRXhwUmlzayB1c2luZyBhIG1hdGhlbWF0aWNhbCBleHByZXNzaW9uIGZvbGxvd2luZyB0aGUgcHJldmlvdXMgZm9ybXVsYXMuCgpEbyBhIHBsb3Qgb2YgdGhlIDExIHBvcnRmb2xpbyByZXR1cm4gYW5kIHJpc2suIFVzZSBFeHBlY3RlZCBQb3J0Zm9saW8gUmV0dXJuIGFzIHRoZSBZLWF4aXMgYW5kIEV4cGVjdGVkIFBvcnRmb2xpbyBSaXNrIGFzIHRoZSBYLWF4aXMuCgojIFByb2dyYW1taW5nIENvZGUKYGBge3J9CiMgSSBsb2FkIHRoZSByZXF1aXJlZCBSIHBhY2thZ2VzIGZvciB0aGUgcHJvZ3JhbToKIyBUbyBkb3dubG9hZCBkYXRhIGZyb20gWWFob28gSSB1c2UgcXVhbnRtb2QKbGlicmFyeShxdWFudG1vZCkKIyBUbyBtYW5hZ2UgY29sdW1ucyBvZiBkYXRhIGZyYW1lcyBJIHVzZSBkcGx5cjoKbGlicmFyeShkcGx5cikKCiMgREFUQSBNQU5BR0VNRU5UIFBST0NFU1NFUwojIEkgZmlyc3QgZ2V0IHN0b2NrIHByaWNlcyBmcm9tIFlhaG9vIEZpbmFuY2U6CmdldFN5bWJvbHMoU3ltYm9scz1jKCJNU0ZUIiwiV01UIiksIGZyb209IjIwMTUtMDEtMDEiLCAKICAgICAgICAgICBwZXJpb2RpY2l0eT0ibW9udGhseSIsIHNyYz0ieWFob28iKQpgYGAKCmBgYHtyfQojIGdldFN5bWJvbHMgY3JlYXRlIHpvbyBvYmplY3QgZm9yIGVhY2ggZGF0YXNldCBicm91Z2h0IGZyb20gdGhlIFdlYi4gCiMgVGhlIG1lcmdlIGZ1bmN0aW9uIHdvcmtzIG9ubHkgd2l0aCB6b28gb3IgeHRzIG9iamVjdHMuIApgYGAKYGBge3J9CiMgSSBtZXJnZSB0aGUgMiB6b28gb2JqZWN0cyBpbnRvIG9uZSB6b28gZGF0YXNldCBjYWxsZWQgcHJpY2VzOgpwcmljZXM8LW1lcmdlKE1TRlQsV01UKQojIEkgY2FsY3VsYXRlIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkIHJldHVybnMgdG8gYWxsIGNvbHVtbnMgb2YgdGhlIHByaWNlIG9iamVjdDoKcmV0czwtZGlmZihsb2cocHJpY2VzKSkKIyBJIHVzZSB0aGUgZHBseXIgcGFja2FnZSB0byByZW1vdmUgTkEgdmFsdWVzIChzaW5jZSB0aGUgZmlyc3QgbW9udGggaXMgbm90IHBvc3NpYmxlIHRvIAojICAgY2FsY3VsYXRlIHJldHVybnMpIGFuZCBzZWxlY3Qgb25seSBBZGp1c3RlZCBjb2x1bW5zCiMgVGhlIGRwbHlyIG9ubHkgd29ya3Mgd2l0aCBkYXRhIGZyYW1lIG9iamVjdHMsIHNvIEkgbmVlZCB0byBjb252ZXJ0IHRoZSB6b28gb2JqZWN0IGludG8KIyAgIGRhdGEgZnJhbWUgZmlyc3QsIGFuZCB0aGVuIGRyb3Agcm93cyB3aXRoIE5BLCBhbmQgdGhlbiBzZWxlY3Qgb25seSBBZGp1c3RlZCBjb2x1bW5zOgpyZXRzIDwtIGFzLmRhdGEuZnJhbWUocmV0cykgJT4lICAgCiAgbmEub21pdCgpICU+JSAjIHJlbW92ZSB0aGUgTkFzCiAgc2VsZWN0KGNvbnRhaW5zKCJBZGp1c3RlZCIpKQojIE5vdyByZXRzIGlzIGEgZGF0YSBmcmFtZSB3aXRoIG9ubHkgY29udGludW91c2x5IGNvbXBvdW5kZWQgcmV0dXJucyBjYWxjdWxhdGVkIHdpdGgKIyAgIGFkanVzdGVkIHByaWNlcy4gVGhpcyBkYXRhIGZyYW1lIGhhcyBvbmx5IDIgY29sdW1ucywgb25lIGZvciBlYWNoIHN0b2NrCiMgSSBjaGFuZ2UgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zOgpjb2xuYW1lcyhyZXRzKTwtYygick1TRlQiLCAicldNVCIpCiMgSSBkaXNwbGF5IHRoZSBmaXJzdCByb3dzIG9mIHRoZSBkYXRhIGZyYW1lOgpoZWFkKHJldHMpCmBgYAoKYGBge3J9CiMgSSBjYWxjdWxhdGUgdGhlIGV4cGVjdGVkIHJldHVybnMgb2YgZWFjaCBzdG9jay4gSSBjYWxjdWxhdGUgdGhlIGdlb21ldHJpYwojICAgYXZlcmFnZSBvZiB0aGUgY29sdW1ucyBvZiB0aGUgcmV0cyBvYmplY3Q6Ck1SPWV4cChjb2xNZWFucyhyZXRzKSktMQojIE1SIHdpbGwgYmUgYSB2ZWN0b3Igd2l0aCB0aGUgMiBnZW9tZXRyaWMgbWVhbnMsIHdoaWNoIEkgd2lsbCB1c2UgYXMgdGhlIGV4cGVjdGVkCiMgICByZXR1cm5zIG9mIHRoZSBzdG9ja3M6Ck1SCmBgYApgYGB7cn0KIyBOb3cgSSBjYWxjdWxhdGUgdGhlIFZhcmlhbmNlLUNvdmFyaWFuY2UgbWF0cml4IHVzaW5nIHRoZSByZXRzIGRhdGEgZnJhbWU6CkNPVjwtY292KHJldHMpCiMgVGhlIGZ1bmN0aW9uIGNvdiBnZW5lcmF0ZXMgYSBtYXRyaXggd2hlcmUgdGhlIGRpYWdvbmFsIHdpbGwgaGF2ZSB0aGUgdmFyaWFuY2VzIG9mCiMgICBlYWNoIGNvbHVtbiwgaW4gdGhpcyBjYXNlLCB0aGUgdmFyaWFuY2VzIG9mIE1pY3Jvc29mdCBhbmQgV2FsLU1hcnQgcmV0dXJucy4KIyAgIEluIHRoZSBub24tZGlhZ29uYWwgdGhlIG1hdHJpeCBoYXMgdGhlIHBhaXJlZCBjb3ZhcmlhbmNlcyBiZXR3ZWVuIHRoZSByZXR1cm5zCgojSSBkaXNwbGF5IHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeDoKQ09WCmBgYApgYGB7cn0KIyBOb3cgSSB3aWxsIGNyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgd2VpZ2h0cyBhbmQgZXhwZWN0ZWQgcmV0dXJuLCB2YXJpYW5jZSBhbmQKIyAgcmlzayBvZiBlYWNoIG9mIHRoZSAxMSBwb3J0Zm9saW9zOgojIEkgc3RhcnQgY3JlYXRpbmcgYSB2ZWN0b3IgZm9yIHRoZSB3ZWlnaHRzIG9mIE1pY3Jvc29mdDoKd208LXNlcShmcm9tPTAsIHRvPTEsIGJ5PTAuMTApCiMgSSBjYW4gZWFzaWx5IGNyZWF0ZSB0aGUgdmVjdG9yIGZvciBXYWwtTWFydCBhcyBhIGNvbXBsZW1lbnQgb2YgdGhlIE1pY3Jvc29mdCB2ZWN0b3I6Cnd3PC0gMSAtIHdtCgojIEkgY3JlYXRlIGEgZGF0YSBmcmFtZSB3aXRoIHRoZXNlIHZlY3RvcnM6CnBvcnRmb2xpb3MgPC0gYXMuZGF0YS5mcmFtZShjYmluZCh3bSx3dykpCiMgVGhlIGNiaW5kIGZ1bmN0aW9uICJiaW5kcyIgb3IgcHV0IHRvZ2V0aGVyIHZlY3RvcnMgaW50byBvbmUgbWF0cml4LiBJdCBiaW5kcyBieSBjb2x1bW4KcG9ydGZvbGlvcwpgYGAKYGBge3J9CiMgSSBjYWxjdWxhdGUgdGhlIGV4cGVjdGVkIHJldHVybnMgb2YgZWFjaCBvZiB0aGUgcG9ydGZvbGlvcyB1c2luZyB0aGUKIyAgIGdlb21ldHJpYyBtZWFuIHJldHVybnMgYW5kIHRoZSB3ZWlnaHQgdmVjdG9ycy4KIyBJIGFkZCBhIG5ldyBjb2x1bW4gaW4gdGhlIHBvcnRmbGlvcyBkYXRhIGZyYW1lOgpwb3J0Zm9saW9zJEVSUDwtcG9ydGZvbGlvcyR3bSpNUlsxXSArIHBvcnRmb2xpb3Mkd3cqTVJbMl0KIyBUaGUgRVJQIGNvbHVtbiBpcyBjcmVhdGVkIGFuZCB3aWxsIGJlIGZpbGxlZCBvdXQgYWNjb3JkaW5nIHRvIHRoZSBleHByZXNzaW9uCiMgUiBwZXJmb3JtcyB0aGlzIHN0YXRlbWVudCB0byBhbGwgcm93cyBvZiB0aGUgZGF0YSBmcmFtZSwgCiMgIHNvIHdlIGRvIG5vdCBuZWVkIHRvIGRvIGEgbG9vcCB0byBmaWxsIG91dCBhbGwgZXhwZWN0ZWQgcmV0dXJucyBmb3IgdGhlIDExIHBvcnRmb2xpb3MuCiMgVGhpcyBpcyBhbHNvIGNhbGxlZCBSIHZlY3Rvcml6YXRpb24gc2luY2UgUiBwZXJmb3JtcyBhbGwgb3BlcmF0aW9ucyB0byB0aGUgZWxlbWVudHMgCiMgIG9mIHZlY3RvcnMgb3Igb3RoZXIgUiBvYmplY3QgbGlrZSBkYXRhIGZyYW1lCnBvcnRmb2xpb3MKYGBgCmBgYHtyfQojIEkgY3JlYXRlIGEgY29sdW1uIGZvciB0aGUgVmFyaWFuY2VzIG9mIHRoZSAxMSBwb3J0Zm9saW9zOgpwb3J0Zm9saW9zJFZBUlAgPC0gcG9ydGZvbGlvcyR3bV4yKkNPVlsxLDFdICsgcG9ydGZvbGlvcyR3d14yKkNPVlsyLDJdICsgICAyKnBvcnRmb2xpb3Mkd20qcG9ydGZvbGlvcyR3dypDT1ZbMSwyXQoKIyBJIGNyZWF0ZSBhIGNvbHVtbiBmb3IgdGhlIGV4cGVjdGVkIHJpc2sgb2YgdGhlIDExIHBvcnRmb2xpb3M6CnBvcnRmb2xpb3MkU0RQPXNxcnQocG9ydGZvbGlvcyRWQVJQKQpwb3J0Zm9saW9zCmBgYAoKYGBge3J9CiNGaW5hbGx5IEkgZG8gYSBwbG90IHRvIGlsbHVzdHJhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGV4cGVjdGVkIHJpc2sgYW5kIHJldHVybgojICBvZiB0aGUgMTEgcG9ydGZvbGlvczoKCnBsb3QocG9ydGZvbGlvcyRTRFAscG9ydGZvbGlvcyRFUlAsIHhsYWI9IlBvcnRmb2xpbyB2b2xhdGlsaXR5IiwgCiAgICAgeWxhYj0iUG9ydGZvbGlvIEV4cGVjdGVkIFJldHVybiIsCiAgICAgbWFpbj0iUG9ydGZvbGlvcyBvZiAyIEFzc2V0czogTVNGVCAmIFdNVCIpCiMgSSBhZGQgbGFiZWxzIG9mIHRoZSB3ZWlnaHRzCnRleHQocG9ydGZvbGlvcyRTRFAscG9ydGZvbGlvcyRFUlAsbGFiZWxzPXdtLCBjZXg9MC43LCBwb3M9MykKCmBgYAoKIyBRIENoYWxsZW5nZSAxIC0gQXBwcm9hY2ggMgpNb2RpZnkgYXBwcm9hY2ggMSBieSBhcHBseWluZyBtYXRyaXggYWxnZWJyYSB0byBjYWxjdWxhdGUgZXhwZWN0ZWQgcmV0dXJuIGFuZCBleHBlY3RlZCB2YXJpYW5jZSBhbmQgcmlzayBvZiB0aGUgMTEgcG9ydGZvbGlvcy4gV2hpY2ggY2hhbmdlcyB5b3UgbmVlZCB0byBkbz8KCiMgUSBDaGFsbGVuZ2UgMiAtIENyZWF0ZSBhIGZyb250aWVyIHdpdGggcG9ydGZvbGlvcyBvZiAyIGFzc2V0cyBhbGxvd2luZyBmb3Igc2hvcnQgc2FsZXMKSW4gcG9ydGZvbGlvIGZvcm1hdGlvbiB5b3UgY2FuIGhhdmUgMiB0eXBlIG9mIHBvc2l0aW9uczogbG9uZyBhbmQgc2hvcnQgcG9zaXRpb25zLiBMb25nIHBvc2l0aW9ucyBpcyB3aGVuIHlvdSBidXkgY2VydGFpbiBudW1iZXIgb2Ygc2hhcmVzIG9mIGFuIGFzc2V0ICh0aGF0IHJlcHJlc2V0cyBhIHNwZWNpZmljIHdlaWd0aCB3aXRoIHJlc3BlY3QgdG8geW91ciB0b3RhbCBtb25leSB5b3Ugd2lsbCB1c2UgZm9yIHRoZSBwb3J0Zm9saW8pLiBBIHNob3J0IHBvc2l0aW9uIGlzIHdoZW4geW91IHJlY2VpdmUgbW9uZXkgZm9yIGEgY2VydGFuIG51bWJlciBvZiBzaGFyZXMgb2YgYW4gYXNzZXQsIHNvIHRoYXQgeW91IGluY3JlYXNlIHlvdXIgbW9uZXkgdG8gaW52ZXN0IGluIG90aGVyIHN0b2Nrcy4gU2hvcnRpbmcgaXMgYSB3YXkgdG8gbGV2ZXJhZ2UgeW91ciBwb3J0Zm9saW8gYnkgYm9ycm93aW5nIG1vbmV5IGZyb20gYSBzdG9jaywgYW5kIHRoZW4gaW52ZXN0IG1vcmUgbW9uZXkgaW4gb3RoZXIgc3RvY2tzLiBJbiB0aGlzIGNoYWxsZW5nZSB5b3UgaGF2ZSB0byBjcmVhdGUgcG9ydGZvbGlvcyBvZiAyIGFzc2V0cyB3aXRoIHNob3J0IGFuZCBsb25nIHBvc2l0aW9ucy4gSGVyZSBhcmUgdGhlIHNwZWNpZmljIGRpcmVjdGlvbnM6CgpXaXRoIHRoZSBzYW1lIHN0b2NrcyBub3cgY3JlYXRlIDE5IHBvcnRmb2xpb3MgaW5zdGVhZCBvZiAxMS4gVGhlIGZpcnN0IHBvcnRmb2xpbyB3aWxsIGhhdmUgLTQwJSBpbiBNaWNyb3NvZnQgYW5kIDE0MCUgaW4gV2FsLU1hcnQ7IHRoZSAybmQgcG9ydGZvbGlvIHdpbGwgaGF2ZSAtMzAlIGluIE1pY3Jvc29mdCBhbmQgMTMwJSBpbiBXYWwtTWFydDsg4oCmIDsgdGhlIGxhc3QgcG9ydGZvbGlvIHdpbGwgaGF2ZSAxNDAlIGluIE1pY3Jvc29mdCBhbmQgLTQwJSBpbiBXYWwtTWFydC4KCkZvciBlYWNoIHBvcnRmb2xpbyBlc3RpbWF0ZSB0aGUgZXhwZWN0ZWQgcmV0dXJuIGFuZCByaXNrIG9mIHRoZSBwb3J0Zm9saW8gYWNjb3JkaW5nIHRvIFBvcnRmb2xpbyBUaGVvcnkKCkRvIGEgcGxvdCBvZiBleHBlY3RlZCByaXNrIGFuZCBleHBlY3RlZCByZXR1cm4gb2YgdGhlc2UgMTEgcG9ydGZvbGlvcy4gUHV0IHRoZSBleHBlY3RlZCByaXNrIGluIHRoZSBYIGF4aXMgYW5kIGV4cGVjdGVkIHJldHVybiBpbiB0aGUgWSBheGlzLgoKQ29tcGFyZSB5b3VyIHBsb3QgaW4gdGhlIGNhc2Ugb2Ygc2hvcnRpbmcgdnMgdGhlIHBsb3QgeW91IGRpZCBpbiB0aGUgcHJldmlvdXMgY2hhbGxlbmdlLiBXaGF0IGRvIHlvdSBzZWU/IFdoYXQgaGFwcGVuIHdoZW4geW91IGFsbG93IGZvciBzaG9ydCBwb3NpdGlvbnM/Cg==