Executive Summary
It is widely known the business of
portfolio management extends from separating the wheat from the chaff,
when it comes to identifying good investments, to the choice of finding
the optimal combinations of those identified investments. Arguably, what
makes a good portfolio manager is not how well they identify investment
opportunities but rather how they assign the investments relative
weights so that they make sense in a portfolio.
To answer the question of which weighting scheme provides the best
risk-adjusted return in a portfolio, a comparison of four(4) popular
weighting schemes is explored where it is found the Black-Litterman
Approach performs best for a hypothetical ETF portfolio among the Equal
Weight, Markowitz, Black-Litterman, and Covariance-Robust optimization
weighting schemes.
Assembling A Portfolio
After identifying attractive securities
for portfolio construction, it is typical for a portfolio manager to
consider how these securities might fit in a portfolio. This part of the
investment process often reduces to finding the “best” weights for the
various securities in the portfolio. The exact portfolio allocation
however, differs from one manager to the next with some preferring to
use ad hoc approaches for determining portfolio weights and others
relying on more structured risk-return analysis that often employs some
form of optimization modelling - a methodology for selecting an optimal
strategy given an objective and a set of constraints.
In terms of ad hoc approaches, the most widely used is the equal
weight approach where the amount invested in N candidate securities is
1/N of the available capital. For those who use optimization as a
weighting method, the general idea is to determine the weights of
securities in a portfolio that accomplish specific targets, usually in
the form of desired risk and return combinations, in the face of a set
of constraints and limitations faced by the portfolio manager. In both
of these approaches, however, it is generally assumed investors take a
single-period view of investing where the goal of portfolio allocation
is to invest optimally over some single predetermined period of
time.
As a case study for this article, the goal is to construct a
portfolio consisting of 9 ETFs: SPY(S&P 500), IWM(Russell 2000),
FEZ(Euro Stoxx 50), ACWI (MSCI All-Country World), AGG(Barclays
Aggregate US Bond), IAGG(iShares Core International Aggregate Bond),
IYR(Dow Jones US Real Estate), REET(iShares Global REIT), and
GSG(iShares GSCI Commodity Index); where it is explored how different
allocation procedures affect portfolio performance. The data used is
monthly price data gathered from the 2016-2021 period from Yahoo
Finance, which is evaluated on the 2022 price data. The weighting
schemes explored are
- Ad hoc:
- Optimization:
- Markowitz
- Black-Litterman
- Covariance-Robust
To make the analysis realistic, an
extended form of the above weighting schemes is explored where extended
is taken to mean accounting for possible constraints imposed on the
portfolio manager by either clients or regulators. The investing period
is assumed to be a year where it is assumed the investor never
rebalances their portfolio (i.e, does not change the allocation between
securities). While the assumption of no-rebalancing might seem
restricting, it is worth mentioning for such a short investment time
frame, taxes resulting from transactions could have a substantial impact
on portfolio performance.
The rest of the article, however, is organized as follows:
- Intuition Behind Optimization Methods
- Portfolio Constraints
- Portfolio Weights
- Overview of Portfolio Performance Metrics
- Performance Evaluation
- Risk Decomposition
Intuition Behind Optimization Methods
Markowitz(Mean-Variance Framework)
The classic Markowitz Mean-Variance
framework assumes investors make their allocation decisions based on
both the expected return and risk arising from their investments. Of
course, Markowitz defined risk as the variance of future returns which
for a portfolio was consistent of two parts - the variance of the
returns of individual assets as well as the covariances(equivalently,
the correlations) between those returns. In this framework, investing
all your money in assets that are strongly correlated is not a prudent
strategy even if the individual assets appear to be the equivalent of
“investment diamonds.” The reason is simple, if one asset performs worse
than expected, it is likely the other assets will also perform poorly
due to their high correlation.
Using this framework of future asset returns and variance from N
securities, the Markowitz Mean-Variance framework seeks to compare the
various portfolios that could be built from the N securities where the
portfolio with the lowest risk for a given level of expected return is
said to be optimal.
Of course, there are an infinite number of potential portfolios
that can be constructed from the various risk and return combinations.
Consequently, the problem is often reduced to using quadratic
programming to find the minimum-risk portfolio without explicitly
calculating every portfolio’s risk and return.
Black-Litterman Framework
Before covering the Black-Litterman
approach, it would be useful to note it is based on a Bayesian
estimation approach, i.e subjective interpretations of future
probabilities. For Bayesian approaches, a probability distribution known
as the prior is used to represent the investor’s knowledge about the
behavior of an asset’s returns before any data is observed. To
complement this view, observations of the asset’s returns behavior are
recorded to compute a new probability distribution known as the
‘posterior distribution’ of the asset’s returns future behavior.
In this context, the Black-Litterman approach, uses the same
framework of quadratic programming to find the minimum-risk portfolio
with the difference being the expected returns and variance are
generated from a combined view of observed data and the investor’s
subjective view of the behavior of future returns. Of course the
investor’s view can be expressed in either absolute terms - where the
investor has a view on individual asset performance or relative terms -
where the investor has a view on how an individual asset performs in
comparison to another. This ability to incorporate subjective views into
a portfolio expected return and variance is perhaps the most valuable
part of the framework.
In practice, the subjective views are often generated from a
Vector Autoregressive model of order p, a basic econometric model to
represent the returns time series of N assets.
Covariance-Robust Framework
An important omission in the explanation
of the Markowitz and Black Litterman Optimization frameworks is they do
not account for the anomalies that may exist in the input data, i.e the
portfolio returns and variance estimates. Of course, anomalies in this
case is a reference to those points that do not necessarily ‘stick’ out
in the fitted empirical mean, variance, and covariance estimates but
have substantial influence on those estimates from the returns data
set.
The importance of detecting and dealing with anomalies cannot be
underestimated because anomalies in the data can distort parameter
estimates, with the effect in the case of finding the optimal
risk-return combination for a portfolio, being the combinations more
appropriately describe the anomalies.
To see why this happens, an example would be useful. For example,
outliers, which are not picked up in the sample mean and covariance
estimates, pull the ordinary sample mean toward themselves, and
artificially inflate the ordinary sample covariance matrix. If we knew a
priori which points were anomalous, we could simply exclude them when
estimating the parameters. But, this information is often
unavailable.
This idea of minimizing the influence of anomalies in estimating
the mean and covariance matrix is what robust optimization seeks to
explore. The Minimum Covariance Determinant (MCD), a popular robust
optimization method, answers the question of estimating the right
empirical mean and covariance by taking all possible subsets of the
data, of a specified size, and estimates the mean and covariance matrix
for each subset. It then keeps the estimates for the subset whose
covariance matrix has the smallest determinant and scales them by a
‘consistency’ factor.
The underlying idea here is since the determinant of the
covariance matrix measures - roughly speaking - the spread of a returns
distribution, minimizing it is akin to selecting a subset of the data
that has the tightest distribution and consequently is less likely to be
affected by outliers.
Portfolio Constraints
In order to mimic a realistic portfolio
with realistic taken to mean constraints imposed by either clients or
regulators on a portfolio manager, additional constraints are made for
the optimization problem. In this article, the additional constraints
are
Long-Only Constraints - where the short selling is not allowed in
the portfolio.
Holding constraints - where a single ETF can be at most 40% of
the portfolio and at least 5% of the portfolio.
While imposing limits on the maximum
exposure on a single ETF is intuitive, it is worthwhile explaining the
lower bound. The underlying reason is to allow a holding size small yet
substantial enough that the position in the ETF can contribute to
portfolio performance. A more detailed reason however is that assets,
particularly stocks, are often traded in multiples of minimum
transaction costs or rounds and consequently, very small positions
cannot be realistically acquired.
# Library Imports - Package names
packages <- c("MASS", "xts", "quantmod", "PortfolioAnalytics",
"ROI", "ROI.plugin.glpk", "ROI.plugin.quadprog", "tidyverse",
"highcharter", "PerformanceAnalytics")
# Install packages if not yet installed - Neat trick from Antoine Soetewey's blog
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
install.packages(packages[!installed_packages])
}
# Packages loading
suppressMessages(lapply(packages, library, character.only = TRUE))
#' import data for each symbol and convert to monthly prices
#' Note conversion to monthly automatically removes NA-VALUES
etf.symbols <- c("SPY", "IWM", "FEZ", "ACWI","AGG","IAGG", "IYR","REET","GSG")
adj.close <- 6 # 6th field is adjusted close
etf.prices <- getSymbols(etf.symbols[1], source="yahoo",
auto.assign=FALSE, return.class="xts")[,adj.close]
for (i in 2:length(etf.symbols)) {
etf.tmp <- getSymbols(etf.symbols[i], source="yahoo",
auto.assign=FALSE, return.class="xts")[,adj.close]
etf.prices <- cbind(etf.prices, etf.tmp)
}
colnames(etf.prices) <- etf.symbols
etf.prices<- suppressWarnings(to.monthly(etf.prices,
indexAt='lastof',
OHLC=FALSE))
# Calculate Returns and remove na value in first row
etf.rets.data <- Return.calculate(na.omit(etf.prices),method='log') %>%
na.omit()
# Keep Returns from 2016-2021 for in-sample estimation
etf.rets<- etf.rets.data["2016/2021"]
# Keep Returns from 2022 for out-of-sample testing
etf.rets.test<- etf.rets.data["2022"]
###### Portfolio Weighting
# Portfolio Object Specification - Set up portfolio with objective and constraints(Long Only)
#' GMV = Global Minimum Variance , EW = Equally Weight
#' RO = Robust Optimization , BL = Black Litterman
port.spec <- portfolio.spec(assets = colnames(etf.rets)) %>%
add.objective( type="risk", name="StdDev") %>%
add.objective( type="return", name="mean") %>%
add.constraint(type="full_investment") %>%
add.constraint( type="long_only") %>%
add.constraint(type = "box", min=0.05, max=0.4)
port.spec.EW <- portfolio.spec(assets = colnames(etf.rets)) %>%
add.constraint(type="full_investment") %>%
add.constraint( type="long_only") %>%
add.constraint(type = "box", min=0.05, max=0.4)
# Set Portfolio Moments for Optimization Functions
samp.moments<- function(R){
out<-set.portfolio.moments(R = R, portfolio=port.spec, method= 'sample')
return(out)
}
#' Views are generated from a VAR-2 model from the MTS package
#' R is an xts return object
bl.moments<- function(R){
data<- fortify.zoo(R)[,-1]
m1<- MTS::VAR(data,p=2,output = F) # From MTS package
pred<- MTS::VARpred(m1,1,output = F) # 1 period ahead forecast
pred<- pred$pred
n.assets<-ncol(R)
pick<-diag(n.assets)
out<- black.litterman(R= R,P = pick,Views = pred)
out$mu<- out$BLMu
out$sigma<- out$BLSigma
return(out)
}
#' Find Optimal Weights
#' Rf= 0
GMV.weights<- optimize.portfolio(R = etf.rets,portfolio= port.spec,maxSR=TRUE,
optimize_method = "ROI",trace = TRUE,momentFUN='samp.moments')
print("Optimal Markowitz weights")
print(sprintf("%s : %s", etf.symbols,
scales::percent(as.numeric(GMV.weights$weights))))
#' The following function is obtained from Ross Bennett's (2018) Paper
#' Estimates Covariance Matrix
sigma.robust<- function(R){
out<- list()
set.seed(1234)
out$sigma<- cov.rob(R,method='mcd',nsamp = 'best')$cov
return(out)
}
RO.weights <-optimize.portfolio(R = etf.rets,portfolio= port.spec,maxSR=TRUE,
optimize_method = "ROI",trace = TRUE,momentFUN='sigma.robust')
print("Covariance-Robust Optimization Weights")
print(sprintf("%s : %s", etf.symbols,
scales::percent(as.numeric(RO.weights$weights))))
EW.weights <- equal.weight(etf.rets, portfolio= port.spec.EW)
print("Equal weights")
print(sprintf("%s : %s", etf.symbols,
scales::percent(as.numeric(EW.weights$weights))))
#' The optimizer is not able to find a unique 'tangential' solution, so remove
#' Max Sharpe ratio objective.
#' This 'loosened' optimization implementation is then focused on maximizing only portfolio
#' return subject to constraints on weights.
BL.weights<-invisible(optimize.portfolio(R = etf.rets,portfolio= port.spec,
optimize_method = "ROI",trace = TRUE,momentFUN='bl.moments'))
print("Black-Litterman Weights")
print(sprintf("%s : %s", etf.symbols,
scales::percent(as.numeric(BL.weights$weights))))
Portfolio Weights
Applying the various weighting schemes, a
bar plot of portfolio weights is produced along with a table containing
the same information in detail. Broadly speaking, it can be seen except
for the Black-Litterman approach, the optimization approaches are
concentrated in the bond ETFs which one can argue heuristically is a
reasonable allocation given the market turbulence of 2020 and 2021. The
Black-Litterman approach however, appears to be concentrated in the
Commodity ETF.
# Create List of portfolio objects and display their weights in a barplot
port.list <- list(GMV.weights,EW.weights, RO.weights, BL.weights)
names(port.list) <- c("Markowitz","Equal-Weight", 'Covariance Robust Optimization',
'Black-Litterman')
chart.Weights(combine.optimizations(port.list), plot.type = "barplot",
main="Weights stacked by Asset (Long-only)")

# Put Weights in a data frame(Scale by 100 to get it in percentages)
weights<- cbind(GMV.weights$weights,EW.weights$weights,
RO.weights$weights, BL.weights$weights)
weights<- round(weights,4)*100
colnames(weights)<- names(port.list)
knitr::kable(weights,caption= "Table 1 - Weights in (%)")
Table 1 - Weights in (%)
| SPY |
22.11 |
11.11 |
13.36 |
5 |
| IWM |
5.00 |
11.11 |
10.92 |
25 |
| FEZ |
5.00 |
11.11 |
5.00 |
5 |
| ACWI |
5.00 |
11.11 |
5.00 |
5 |
| AGG |
40.00 |
11.11 |
10.73 |
5 |
| IAGG |
7.89 |
11.11 |
40.00 |
5 |
| IYR |
5.00 |
11.11 |
5.00 |
5 |
| REET |
5.00 |
11.11 |
5.00 |
5 |
| GSG |
5.00 |
11.11 |
5.00 |
40 |
Overview of Portfolio Performance Metrics
Of course, it would be pointless to
construct portfolios from the various weighting schemes without
assessing how each scheme affected the portfolio’s performance. To this
end, a brief summary of popular performance metrics is presented to
assess the value of each weighting scheme.
Annualized Return: Geometric average of annual
returns generated by a portfolio over a given investment period.
Active Return: Excess portfolio returns over some
specified benchmark. Note how it differs from excess return.
Excess Return: Excess portfolio returns over some
specified risk-free asset.
Annualized Standard Deviation: Geometric average of
variability of a portfolio’s annual returns over a given investment
period. The higher the standard deviation of returns, the riskier the
portfolio weighting scheme is.
Beta(CAPM): Reflects risk of a portfolio in relation
to some benchmark. Statistically, it is the regression coefficient
reflecting how much a portfolio’s returns change for each unit change in
the benchmark’s returns. Higher betas mean the portfolio’s returns are
more sensitive to the benchmark’s returns.
Sharpe Ratio: Portfolio excess returns per unit of
risk. Excess returns here is the excess portfolio returns over some
specified risk-free asset while risk is the portfolio standard
deviation. In general, higher Sharpe ratios mean the portfolio provides
greater returns over the risk free asset while offering the same or less
variability of returns. Higher Sharpe ratios are thus usually
better.
Treynor Ratio: Portfolio excess returns per unit of
beta/benchmark risk. Like the Sharpe, excess returns here is the excess
portfolio returns over some specified risk-free asset. In general,
higher Treynor ratios mean the portfolio provides greater returns over
the risk free asset while offering less exposure to the benchmark.
Higher Treynor ratios are thus usually better.
Modigliani \(M^2\):
Adjusts each portfolio’s returns to what it would have been had the
portfolio manager taken the same amount of risk as the benchmark. In
general, higher Modigliani \(M^2\)
measures mean the portfolio provides greater returns while taking the
same amount risk as the benchmark where risk is the benchmark’s standard
deviation. Higher Modigliani \(M^2\)
measures are thus usually better.
Information Ratio: Ratio of excess portfolio returns
over the benchmark to the standard of the excess portfolio returns. In
general, higher information ratios mean the portfolio provides greater
excess returns over the benchmark per unit of risk. Higher information
ratios are thus usually better.
Tracking Error: Standard Deviation of excess
portfolio returns over the benchmark. The greater the tracking error,
the more the portfolio returns deviate from the benchmark.
Diversification Ratio: Ratio of the weighted average
of volatility individual assets to the overall portfolio volatility.
Here, weights are the portfolio weights. For a well diversified
long-only portfolio, the ratio should be greater than 1.
Concentration Ratio:
Ratio of the weighted sum of squared
individual asset volatility to weighted sum of individual asset
volatility squared. While confusing, the idea for the numerator is to
square the individual weighted volatilities before you sum, where
weights are the portfolio weights.
For the denominator, you take the weighted sum of individual asset
volatility before you take the square. For a well diversified, long-only
portfolio, the ratio should be less than 1. Additionally, portfolio
allocations with higher concentration ratios are judged to be more
concentrated than their weighting counterparts. Put simply, a lower
concentration ratio is usually better.
Customizing the Benchmark:
Since most investments establish a
benchmark to evaluate a portfolio manager’s performance, a customized
index is created for this purpose. The customized index is created to
better reflect the investor’s objective which for this article is a
desired exposure to Index ETFs.
Of course, this investor is assumed to desire exposure to indices
that track stocks, bonds, commodities, and real estate. To make the
analysis tractable, a price-weighted index is constructed which averages
equally the value of each Index ETF in the portfolio.
Performance Evaluation
Table 2 shows the historical performance
of each portfolio weighting scheme. It can be seen - generally speaking
- the Black-Litterman approach performs best for the investment period.
In particular, it produced better active and excess returns, higher
sharpe, treynor and information ratios among others. It is worth noting
while the Black-Litterman portfolio was well diversified, i.e in terms
of its diversification ratio, it had the most concentrated portfolio in
comparison to the other ETF portfolios.(from its concentration
ratio)
To show what this performance means for the investor, a line graph
is presented showing the growth of $10,000 in each portfolio weighting
scheme.
weights <- cbind(GMV.weights$weights,EW.weights$weights,
RO.weights$weights,BL.weights$weights)
# rets = returns
rets<-c()
#' Calculate Returns on Out-of-Sample Data - With Wealth Progression
#' Combine returns of each portfolio in a single data frame
for (i in 1:ncol(weights)) {
rets.values <- Return.portfolio(etf.rets.test, weights = weights[,i],
wealth.index = TRUE)
rets<-cbind(rets,rets.values)
}
#' Combine Returns into a single data frame
amount<- 10000
rets.scale<- rets*amount
date <- as.Date("2021-12-31")
init.investment <- xts(matrix(amount, nrow=1,ncol=4), order.by=date)
rets.scale<- rbind(init.investment, rets.scale)
names(rets.scale) <- c("Markowitz","Equal-Weight","Covariance-Robust Optimization",
"Black Litterman")
#' Performance - Cumulative Returns Chart
cum.rets.chart<-highchart(type='stock')%>%
hc_title(text='Hypothetical Growth of $10,000 ') %>%
hc_add_series(round(rets.scale[,1],2),
name=colnames(rets.scale)[1])%>%
hc_add_series(round(rets.scale[,2],2),
name=colnames(rets.scale)[2])%>%
hc_add_series(round(rets.scale[,3],2),
name=colnames(rets.scale)[3])%>%
hc_add_series(round(rets.scale[,4],2),
name=colnames(rets.scale)[4])%>%
hc_navigator(enabled=FALSE)%>%
hc_scrollbar(enabled=FALSE) %>%
hc_add_theme(hc_theme_flat())%>%
hc_exporting(enabled=TRUE)%>%
hc_legend(enabled=TRUE) %>%
hc_plotOptions(series = list(animation = FALSE))
cum.rets.chart
key.measures<- function( Ra, port.weight, bm, scale = 12,Sigma = cov(etf.rets), Rf= 0){
ret<- Return.annualized(Ra,scale = scale) *100
act.ret<- ActiveReturn(Ra ,Rb= bm,scale = scale) *100
ex.ret<- sum(Return.excess(Ra))*100 # Rf= 0
#' Note ret = ex.ret since Rf=0
#' That is, total returns should be roughly equal to excess returns
#' Where total returns = annualized returns if the investment period < or = 1 year
st.dev<- StdDev.annualized(Ra,weights=port.weight,scale = scale) *100
beta<- CAPM.beta(Ra,bm)
sharpe<- SharpeRatio.annualized(Ra, Rf= Rf, scale = scale)
treynor<- TreynorRatio(Ra, Rb = bm,scale=scale)
i.ratio<- InformationRatio(Ra, Rb = bm,scale=scale)
m.square<- Modigliani(Ra, Rb = bm,scale=scale)
t.error<- TrackingError(Ra, Rb = bm,scale = scale)
dr <- FRAPO::dr(port.weight, Sigma ) # Function obtained from FRAPO package
cr <- FRAPO::cr(port.weight, Sigma) # Function obtained from FRAPO package
res<- round(rbind(ret,act.ret,ex.ret, st.dev,beta,sharpe, treynor,m.square,i.ratio, t.error, dr,cr),3)
rownames(res) <- c("Annualized Return(%)","Active Return(%)","Excess Return(%)",
'Annualized Standard Deviation(%)',"Beta",'Sharpe','Treynor',
"M^2 of Modigliani", "Information Ratio","Tracking Error",
"Diversification Ratio","Concentration Ratio")
return(res)
}
#' Note the portfolio by construction is invested in the overall market.
#' The Benchmark used here is a Price-Weighted index.
#' Price- Weighted indices by construction average prices equally.
#' comp.ind = composite index returns
#' The motivation for this multi-asset composite index is the
#' FTSE Multi-Asset Composite Index Series which
#' according to FTSE Russell
#' is designed to measure cross-asset market returns for a range of risk exposures.
etf.prices$comp<-rowMeans(etf.prices)
#' Calculate Returns and remove na value in first row
#' Select Returns from 2022
comp.ind <- Return.calculate(etf.prices$comp,method='log') %>%
na.omit()
comp.ind<- comp.ind['2022']
# rets = returns
rets<-c()
#' Calculate Returns on Out-of-Sample Data - Without Wealth Progression
#' Combine returns of each portfolio in a single data frame
for (i in 1:ncol(weights)) {
rets.values <- Return.portfolio(etf.rets.test, weights = weights[,i])
rets<-cbind(rets,rets.values)
}
# ports = portfolios
ports<-c()
# Combine performance measures of each portfolio in a single data frame
for (i in 1:ncol(weights)) {
measures <- key.measures(port.weight = weights[,i],
Ra = rets[,i], bm = comp.ind)
ports<-cbind(ports,measures)
}
#' Note for the benchmark, all we need are the annualized
#' Returns, StDev, and Excess Returns
#' Since the benchmark is price-weighted, the weights used in the function is the Equal Weight
bm <- key.measures(port.weight = EW.weights$weights,
Ra = comp.ind, bm = comp.ind)
keep.rows<- c("Annualized Return(%)","Excess Return(%)",
'Annualized Standard Deviation(%)')
# Assign NA to those values not in keep.rows
bm[!(bm %in% bm[keep.rows,]),]<- NA
all.ports <- cbind(ports,bm)
colnames(all.ports) <- append(names(rets.scale),"Benchmark")
knitr::kable(all.ports,
caption="Table 2 - Key Portfolio Performance Measures")
Table 2 - Key Portfolio Performance Measures
| Annualized Return(%) |
-12.817 |
-12.955 |
-12.087 |
-3.541 |
-16.231 |
| Active Return(%) |
3.414 |
3.275 |
4.143 |
12.690 |
NA |
| Excess Return(%) |
-12.776 |
-12.515 |
-12.046 |
-2.342 |
-15.766 |
| Annualized Standard Deviation(%) |
13.645 |
16.604 |
12.901 |
16.405 |
19.814 |
| Beta |
0.675 |
0.823 |
0.645 |
0.669 |
NA |
| Sharpe |
-0.939 |
-0.780 |
-0.937 |
-0.216 |
NA |
| Treynor |
-0.190 |
-0.157 |
-0.187 |
-0.053 |
NA |
| M^2 of Modigliani |
-0.015 |
-0.012 |
-0.015 |
-0.002 |
NA |
| Information Ratio |
0.489 |
0.699 |
0.570 |
1.087 |
NA |
| Tracking Error |
0.070 |
0.047 |
0.073 |
0.117 |
NA |
| Diversification Ratio |
1.282 |
1.189 |
1.282 |
1.145 |
NA |
| Concentration Ratio |
0.163 |
0.135 |
0.138 |
0.336 |
NA |
Risk Decomposition
As a conclusion to this article, it would
be useful to examine how exposures to individual ETFs affect the
variability portfolio returns for each weighting scheme. This breakdown
of portfolio risk into contributions by individual ETFs when combined
with the portfolio weights shows whether historically the portfolio has
been over or underexposed to specific ETFs.
Should our hypothetical investor desire to re-allocate their
capital among the ETFs for a given weighting scheme, they can use this
risk decomposition information to increase or decrease portfolio
allocation to specific ETFs. For example, while the SPY makes up 22% of
the Markowitz ETF portfolio, it accounts for 35% of the portfolio return
volatility. Our investor might consider reducing exposure to the SPY on
this basis.
Table 3 shows the risk decomposition of each portfolio weighting
scheme.
##### Component Contribution to Portfolio Volatility/ Standard Deviation
# What percentage of portfolio St.Dev did each position account for?
all.comps.sd<-c()
# Combine component contributions of each portfolio in a single data frame
for (i in 1:ncol(weights)) {
# Scale by 100 to get percent from decimals like say 0.2 to 20%
Std <- (StdDev(etf.rets.test, weights = weights[,i], portfolio_method=
"component")$pct_contrib_StdDev)*100
all.comps.sd<-cbind(all.comps.sd,Std)
}
colnames(all.comps.sd) <- names(rets.scale)
knitr::kable(all.comps.sd,
caption ="Table 3 - Component Contribution to Portfolio Volatility/ Standard Deviation(%)")
Table 3 - Component Contribution to Portfolio Volatility/
Standard Deviation(%)
| SPY |
34.394427 |
14.230269 |
22.081628 |
5.827865 |
| IWM |
7.918145 |
14.507161 |
18.708315 |
30.750616 |
| FEZ |
9.392703 |
16.798717 |
9.741107 |
6.280780 |
| ACWI |
7.506255 |
13.570762 |
7.877084 |
5.389567 |
| AGG |
20.240645 |
4.039012 |
5.381124 |
1.197094 |
| IAGG |
3.379680 |
3.653431 |
17.929786 |
1.244528 |
| IYR |
7.518222 |
13.891722 |
7.936467 |
5.348458 |
| REET |
7.618834 |
14.050253 |
8.049772 |
5.618056 |
| GSG |
2.031089 |
5.258672 |
2.294717 |
38.343036 |
Resources Used
Bacon, Carl R. Practical Risk-Adjusted Performance Measurement.
Second edition. Wiley Finance Series. Hoboken, NJ: Wiley, 2022.
Fabozzi, Frank J., and Dessislava A. Pachamanova. Portfolio
Construction and Analytics. Frank J. Fabozzi Series. Hoboken, New
Jersey: John Wiley & Sons, Inc, 2016.
Black F, Litterman R (1992) Global portfolio optimization. Financial
Analysts J. 48(5):28–43.
Rosenthal, Dale W. R. A Quantitative Primer on Investments with r.
Chicago, IL: Q36 LLC, 2018.
Harry Markowitz, 1952. “Portfolio Selection,” Journal of Finance,
American Finance Association, vol. 7(1), pages 77-91, March.
Bennett Ross, 2018. “Custom Moment and Objective Functions”
Ali Pardhan, “Intuitive Explanation of Minimum Covariance Determinant
(MCD).” Cross Validated, July 5, 2020. https://stats.stackexchange.com/questions/475636/intuitive-explanation-of-minimum-covariance-determinant-mcd.
Brian G. Peterson and Peter Carl (2018). PortfolioAnalytics:
Portfolio Analysis, Including Numerical Methods for Optimization of
Portfolios. R package version 1.1.0. https://CRAN.R-project.org/package=PortfolioAnalytics
Brian G. Peterson and Peter Carl (2020). PerformanceAnalytics:
Econometric Tools for Performance and Risk Analysis. R package version
2.0.4. https://CRAN.R-project.org/package=PerformanceAnalytics
LS0tCnRpdGxlOiAiUG9ydGZvbGlvIENvbnN0cnVjdGlvbiBhbmQgQW5hbHl0aWNzIgphdXRob3I6IEtvYmVuYSBBbW9haApkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19kZXB0aDogMgogICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICBrZWVwX21kOiB0cnVlIAphbHdheXNfYWxsb3dfaHRtbDogeWVzCi0tLQojIyBFeGVjdXRpdmUgU3VtbWFyeQoKfCAgICAgICBJdCBpcyB3aWRlbHkga25vd24gdGhlIGJ1c2luZXNzIG9mIHBvcnRmb2xpbyBtYW5hZ2VtZW50IGV4dGVuZHMgZnJvbSBzZXBhcmF0aW5nIHRoZSB3aGVhdCBmcm9tIHRoZSBjaGFmZiwgd2hlbiBpdCBjb21lcyB0byBpZGVudGlmeWluZyBnb29kIGludmVzdG1lbnRzLCB0byB0aGUgY2hvaWNlIG9mIGZpbmRpbmcgdGhlIG9wdGltYWwgY29tYmluYXRpb25zIG9mIHRob3NlIGlkZW50aWZpZWQgaW52ZXN0bWVudHMuIEFyZ3VhYmx5LCB3aGF0IG1ha2VzIGEgZ29vZCBwb3J0Zm9saW8gbWFuYWdlciBpcyBub3QgaG93IHdlbGwgdGhleSBpZGVudGlmeSBpbnZlc3RtZW50IG9wcG9ydHVuaXRpZXMgYnV0IHJhdGhlciBob3cgdGhleSBhc3NpZ24gdGhlIGludmVzdG1lbnRzIHJlbGF0aXZlIHdlaWdodHMgc28gdGhhdCB0aGV5IG1ha2Ugc2Vuc2UgaW4gYSBwb3J0Zm9saW8uCnwgICAgICAgVG8gYW5zd2VyIHRoZSBxdWVzdGlvbiBvZiB3aGljaCB3ZWlnaHRpbmcgc2NoZW1lIHByb3ZpZGVzIHRoZSBiZXN0IHJpc2stYWRqdXN0ZWQgcmV0dXJuIGluIGEgcG9ydGZvbGlvLCBhIGNvbXBhcmlzb24gb2YgZm91cig0KSBwb3B1bGFyIHdlaWdodGluZyBzY2hlbWVzIGlzIGV4cGxvcmVkIHdoZXJlIGl0IGlzIGZvdW5kIHRoZSBCbGFjay1MaXR0ZXJtYW4gQXBwcm9hY2ggcGVyZm9ybXMgYmVzdCBmb3IgYSBoeXBvdGhldGljYWwgRVRGIHBvcnRmb2xpbyBhbW9uZyB0aGUgRXF1YWwgV2VpZ2h0LCBNYXJrb3dpdHosIEJsYWNrLUxpdHRlcm1hbiwgYW5kIENvdmFyaWFuY2UtUm9idXN0IG9wdGltaXphdGlvbiB3ZWlnaHRpbmcgc2NoZW1lcy4KCiMjIEFzc2VtYmxpbmcgQSBQb3J0Zm9saW8KfCAgICAgICBBZnRlciBpZGVudGlmeWluZyBhdHRyYWN0aXZlIHNlY3VyaXRpZXMgZm9yIHBvcnRmb2xpbyBjb25zdHJ1Y3Rpb24sIGl0IGlzIHR5cGljYWwgZm9yIGEgcG9ydGZvbGlvIG1hbmFnZXIgdG8gY29uc2lkZXIgaG93IHRoZXNlIHNlY3VyaXRpZXMgbWlnaHQgZml0IGluIGEgcG9ydGZvbGlvLiBUaGlzIHBhcnQgb2YgdGhlIGludmVzdG1lbnQgcHJvY2VzcyBvZnRlbiByZWR1Y2VzIHRvIGZpbmRpbmcgdGhlICJiZXN0IiB3ZWlnaHRzIGZvciB0aGUgdmFyaW91cyBzZWN1cml0aWVzIGluIHRoZSBwb3J0Zm9saW8uIFRoZSBleGFjdCBwb3J0Zm9saW8gYWxsb2NhdGlvbiBob3dldmVyLCBkaWZmZXJzIGZyb20gb25lIG1hbmFnZXIgdG8gdGhlIG5leHQgd2l0aCBzb21lIHByZWZlcnJpbmcgdG8gdXNlIGFkIGhvYyBhcHByb2FjaGVzIGZvciBkZXRlcm1pbmluZyBwb3J0Zm9saW8gd2VpZ2h0cyBhbmQgb3RoZXJzIHJlbHlpbmcgb24gbW9yZSBzdHJ1Y3R1cmVkIHJpc2stcmV0dXJuIGFuYWx5c2lzIHRoYXQgb2Z0ZW4gZW1wbG95cyBzb21lIGZvcm0gb2Ygb3B0aW1pemF0aW9uIG1vZGVsbGluZyAtIGEgbWV0aG9kb2xvZ3kgZm9yIHNlbGVjdGluZyBhbiBvcHRpbWFsIHN0cmF0ZWd5IGdpdmVuIGFuIG9iamVjdGl2ZSBhbmQgYSBzZXQgb2YgY29uc3RyYWludHMuIAp8ICAgICAgIEluIHRlcm1zIG9mIGFkIGhvYyBhcHByb2FjaGVzLCB0aGUgbW9zdCB3aWRlbHkgdXNlZCBpcyB0aGUgZXF1YWwgd2VpZ2h0IGFwcHJvYWNoIHdoZXJlIHRoZSBhbW91bnQgaW52ZXN0ZWQgaW4gTiBjYW5kaWRhdGUgc2VjdXJpdGllcyBpcyAxL04gb2YgdGhlIGF2YWlsYWJsZSBjYXBpdGFsLiBGb3IgdGhvc2Ugd2hvIHVzZSBvcHRpbWl6YXRpb24gYXMgYSB3ZWlnaHRpbmcgbWV0aG9kLCB0aGUgZ2VuZXJhbCBpZGVhIGlzIHRvIGRldGVybWluZSB0aGUgd2VpZ2h0cyBvZiBzZWN1cml0aWVzIGluIGEgcG9ydGZvbGlvIHRoYXQgYWNjb21wbGlzaCBzcGVjaWZpYyB0YXJnZXRzLCB1c3VhbGx5IGluIHRoZSBmb3JtIG9mIGRlc2lyZWQgcmlzayBhbmQgcmV0dXJuIGNvbWJpbmF0aW9ucywgaW4gdGhlIGZhY2Ugb2YgYSBzZXQgb2YgY29uc3RyYWludHMgYW5kIGxpbWl0YXRpb25zIGZhY2VkIGJ5IHRoZSBwb3J0Zm9saW8gbWFuYWdlci4gSW4gYm90aCBvZiB0aGVzZSBhcHByb2FjaGVzLCBob3dldmVyLCBpdCBpcyBnZW5lcmFsbHkgYXNzdW1lZCBpbnZlc3RvcnMgdGFrZSBhIHNpbmdsZS1wZXJpb2QgdmlldyBvZiBpbnZlc3Rpbmcgd2hlcmUgdGhlIGdvYWwgb2YgcG9ydGZvbGlvIGFsbG9jYXRpb24gaXMgdG8gaW52ZXN0IG9wdGltYWxseSBvdmVyIHNvbWUgc2luZ2xlIHByZWRldGVybWluZWQgcGVyaW9kIG9mIHRpbWUuIAp8ICAgICAgIEFzIGEgY2FzZSBzdHVkeSBmb3IgdGhpcyBhcnRpY2xlLCB0aGUgZ29hbCBpcyB0byBjb25zdHJ1Y3QgYSBwb3J0Zm9saW8gY29uc2lzdGluZyBvZiA5IEVURnM6IFNQWShTJlAgNTAwKSwgSVdNKFJ1c3NlbGwgMjAwMCksIEZFWihFdXJvIFN0b3h4IDUwKSwgQUNXSSAoTVNDSSBBbGwtQ291bnRyeSBXb3JsZCksIEFHRyhCYXJjbGF5cyBBZ2dyZWdhdGUgVVMgQm9uZCksIElBR0coaVNoYXJlcyBDb3JlICBJbnRlcm5hdGlvbmFsIEFnZ3JlZ2F0ZSBCb25kKSwgSVlSKERvdyBKb25lcyBVUyBSZWFsIEVzdGF0ZSksIFJFRVQoaVNoYXJlcyBHbG9iYWwgUkVJVCksIGFuZCBHU0coaVNoYXJlcyBHU0NJIENvbW1vZGl0eSBJbmRleCk7IHdoZXJlIGl0IGlzIGV4cGxvcmVkIGhvdyBkaWZmZXJlbnQgYWxsb2NhdGlvbiBwcm9jZWR1cmVzIGFmZmVjdCBwb3J0Zm9saW8gcGVyZm9ybWFuY2UuIFRoZSBkYXRhIHVzZWQgaXMgbW9udGhseSBwcmljZSBkYXRhIGdhdGhlcmVkIGZyb20gdGhlIDIwMTYtMjAyMSBwZXJpb2QgZnJvbSBZYWhvbyBGaW5hbmNlLCB3aGljaCBpcyBldmFsdWF0ZWQgb24gdGhlIDIwMjIgcHJpY2UgZGF0YS4gVGhlIHdlaWdodGluZyBzY2hlbWVzIGV4cGxvcmVkIGFyZQoKYSkgQWQgaG9jOgogICAtIEVxdWFsIFdlaWdodAogICAKYikgT3B0aW1pemF0aW9uOiAKICAgLSBNYXJrb3dpdHoKICAgLSBCbGFjay1MaXR0ZXJtYW4KICAgLSBDb3ZhcmlhbmNlLVJvYnVzdAogICAKfCAgICAgICBUbyBtYWtlIHRoZSBhbmFseXNpcyByZWFsaXN0aWMsIGFuIGV4dGVuZGVkIGZvcm0gb2YgdGhlIGFib3ZlIHdlaWdodGluZyBzY2hlbWVzIGlzIGV4cGxvcmVkIHdoZXJlIGV4dGVuZGVkIGlzIHRha2VuIHRvIG1lYW4gYWNjb3VudGluZyBmb3IgcG9zc2libGUgY29uc3RyYWludHMgaW1wb3NlZCBvbiB0aGUgcG9ydGZvbGlvIG1hbmFnZXIgYnkgZWl0aGVyIGNsaWVudHMgb3IgcmVndWxhdG9ycy4gVGhlIGludmVzdGluZyBwZXJpb2QgaXMgYXNzdW1lZCB0byBiZSBhIHllYXIgd2hlcmUgaXQgaXMgYXNzdW1lZCB0aGUgaW52ZXN0b3IgbmV2ZXIgcmViYWxhbmNlcyB0aGVpciBwb3J0Zm9saW8gKGkuZSwgZG9lcyBub3QgY2hhbmdlIHRoZSBhbGxvY2F0aW9uIGJldHdlZW4gc2VjdXJpdGllcykuIFdoaWxlIHRoZSBhc3N1bXB0aW9uIG9mIG5vLXJlYmFsYW5jaW5nIG1pZ2h0IHNlZW0gcmVzdHJpY3RpbmcsIGl0IGlzIHdvcnRoIG1lbnRpb25pbmcgZm9yIHN1Y2ggYSBzaG9ydCBpbnZlc3RtZW50IHRpbWUgZnJhbWUsIHRheGVzIHJlc3VsdGluZyBmcm9tIHRyYW5zYWN0aW9ucyBjb3VsZCBoYXZlIGEgc3Vic3RhbnRpYWwgaW1wYWN0IG9uIHBvcnRmb2xpbyBwZXJmb3JtYW5jZS4gCnwgICAgICAgVGhlIHJlc3Qgb2YgdGhlIGFydGljbGUsIGhvd2V2ZXIsIGlzIG9yZ2FuaXplZCBhcyBmb2xsb3dzOgotIEludHVpdGlvbiBCZWhpbmQgT3B0aW1pemF0aW9uIE1ldGhvZHMKLSBQb3J0Zm9saW8gQ29uc3RyYWludHMKLSBQb3J0Zm9saW8gV2VpZ2h0cwotIE92ZXJ2aWV3IG9mIFBvcnRmb2xpbyBQZXJmb3JtYW5jZSBNZXRyaWNzCi0gUGVyZm9ybWFuY2UgRXZhbHVhdGlvbgotIFJpc2sgRGVjb21wb3NpdGlvbgogCiMjIEludHVpdGlvbiBCZWhpbmQgT3B0aW1pemF0aW9uIE1ldGhvZHMKCioqTWFya293aXR6KE1lYW4tVmFyaWFuY2UgRnJhbWV3b3JrKSoqCgp8ICAgICAgIFRoZSBjbGFzc2ljIE1hcmtvd2l0eiBNZWFuLVZhcmlhbmNlIGZyYW1ld29yayBhc3N1bWVzIGludmVzdG9ycyBtYWtlIHRoZWlyIGFsbG9jYXRpb24gZGVjaXNpb25zIGJhc2VkIG9uIGJvdGggdGhlIGV4cGVjdGVkIHJldHVybiBhbmQgcmlzayBhcmlzaW5nIGZyb20gdGhlaXIgaW52ZXN0bWVudHMuIE9mIGNvdXJzZSwgTWFya293aXR6IGRlZmluZWQgcmlzayBhcyB0aGUgdmFyaWFuY2Ugb2YgZnV0dXJlIHJldHVybnMgd2hpY2ggZm9yIGEgcG9ydGZvbGlvIHdhcyBjb25zaXN0ZW50IG9mIHR3byBwYXJ0cyAtIHRoZSB2YXJpYW5jZSBvZiB0aGUgcmV0dXJucyBvZiBpbmRpdmlkdWFsIGFzc2V0cyBhcyB3ZWxsIGFzIHRoZSBjb3ZhcmlhbmNlcyhlcXVpdmFsZW50bHksIHRoZSBjb3JyZWxhdGlvbnMpIGJldHdlZW4gdGhvc2UgcmV0dXJucy4gSW4gdGhpcyBmcmFtZXdvcmssIGludmVzdGluZyBhbGwgeW91ciBtb25leSBpbiBhc3NldHMgdGhhdCBhcmUgc3Ryb25nbHkgY29ycmVsYXRlZCBpcyBub3QgYSBwcnVkZW50IHN0cmF0ZWd5IGV2ZW4gaWYgdGhlIGluZGl2aWR1YWwgYXNzZXRzIGFwcGVhciB0byBiZSB0aGUgZXF1aXZhbGVudCBvZiAiaW52ZXN0bWVudCBkaWFtb25kcy4iIFRoZSByZWFzb24gaXMgc2ltcGxlLCBpZiBvbmUgYXNzZXQgcGVyZm9ybXMgd29yc2UgdGhhbiBleHBlY3RlZCwgaXQgaXMgbGlrZWx5IHRoZSBvdGhlciBhc3NldHMgd2lsbCBhbHNvIHBlcmZvcm0gcG9vcmx5IGR1ZSB0byB0aGVpciBoaWdoIGNvcnJlbGF0aW9uLgp8ICAgICAgIFVzaW5nIHRoaXMgZnJhbWV3b3JrIG9mIGZ1dHVyZSBhc3NldCByZXR1cm5zIGFuZCB2YXJpYW5jZSBmcm9tIE4gc2VjdXJpdGllcywgdGhlICBNYXJrb3dpdHogTWVhbi1WYXJpYW5jZSBmcmFtZXdvcmsgc2Vla3MgdG8gY29tcGFyZSB0aGUgdmFyaW91cyBwb3J0Zm9saW9zIHRoYXQgY291bGQgYmUgYnVpbHQgZnJvbSB0aGUgTiBzZWN1cml0aWVzIHdoZXJlIHRoZSBwb3J0Zm9saW8gd2l0aCB0aGUgbG93ZXN0IHJpc2sgZm9yIGEgZ2l2ZW4gbGV2ZWwgb2YgZXhwZWN0ZWQgcmV0dXJuIGlzIHNhaWQgdG8gYmUgb3B0aW1hbC4KfCAgICAgICBPZiBjb3Vyc2UsIHRoZXJlIGFyZSBhbiBpbmZpbml0ZSBudW1iZXIgb2YgcG90ZW50aWFsIHBvcnRmb2xpb3MgdGhhdCBjYW4gYmUgY29uc3RydWN0ZWQgZnJvbSB0aGUgdmFyaW91cyByaXNrIGFuZCByZXR1cm4gY29tYmluYXRpb25zLiBDb25zZXF1ZW50bHksIHRoZSBwcm9ibGVtIGlzIG9mdGVuIHJlZHVjZWQgdG8gdXNpbmcgcXVhZHJhdGljIHByb2dyYW1taW5nIHRvIGZpbmQgdGhlIG1pbmltdW0tcmlzayBwb3J0Zm9saW8gd2l0aG91dCBleHBsaWNpdGx5IGNhbGN1bGF0aW5nIGV2ZXJ5IHBvcnRmb2xpbydzIHJpc2sgYW5kIHJldHVybi4KICAKKipCbGFjay1MaXR0ZXJtYW4gRnJhbWV3b3JrKioKCnwgICAgICAgQmVmb3JlIGNvdmVyaW5nIHRoZSBCbGFjay1MaXR0ZXJtYW4gYXBwcm9hY2gsIGl0IHdvdWxkIGJlIHVzZWZ1bCB0byBub3RlIGl0IGlzIGJhc2VkIG9uIGEgQmF5ZXNpYW4gZXN0aW1hdGlvbiBhcHByb2FjaCwgaS5lIHN1YmplY3RpdmUgaW50ZXJwcmV0YXRpb25zIG9mIGZ1dHVyZSBwcm9iYWJpbGl0aWVzLiBGb3IgQmF5ZXNpYW4gYXBwcm9hY2hlcywgYSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24ga25vd24gYXMgdGhlIHByaW9yIGlzIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBpbnZlc3RvcidzIGtub3dsZWRnZSBhYm91dCB0aGUgYmVoYXZpb3Igb2YgYW4gYXNzZXQncyByZXR1cm5zIGJlZm9yZSBhbnkgZGF0YSBpcyBvYnNlcnZlZC4gVG8gY29tcGxlbWVudCB0aGlzIHZpZXcsIG9ic2VydmF0aW9ucyBvZiB0aGUgYXNzZXQncyByZXR1cm5zIGJlaGF2aW9yIGFyZSByZWNvcmRlZCB0byBjb21wdXRlIGEgbmV3IHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBrbm93biBhcyB0aGUgJ3Bvc3RlcmlvciBkaXN0cmlidXRpb24nIG9mIHRoZSBhc3NldCdzIHJldHVybnMgZnV0dXJlIGJlaGF2aW9yLgp8ICAgICAgIEluIHRoaXMgY29udGV4dCwgdGhlIEJsYWNrLUxpdHRlcm1hbiBhcHByb2FjaCwgdXNlcyB0aGUgc2FtZSBmcmFtZXdvcmsgb2YgcXVhZHJhdGljIHByb2dyYW1taW5nIHRvIGZpbmQgdGhlIG1pbmltdW0tcmlzayBwb3J0Zm9saW8gd2l0aCB0aGUgZGlmZmVyZW5jZSBiZWluZyB0aGUgZXhwZWN0ZWQgcmV0dXJucyBhbmQgdmFyaWFuY2UgYXJlIGdlbmVyYXRlZCBmcm9tIGEgY29tYmluZWQgdmlldyBvZiBvYnNlcnZlZCBkYXRhIGFuZCB0aGUgaW52ZXN0b3IncyBzdWJqZWN0aXZlIHZpZXcgb2YgdGhlIGJlaGF2aW9yIG9mIGZ1dHVyZSByZXR1cm5zLiBPZiBjb3Vyc2UgdGhlIGludmVzdG9yJ3MgdmlldyBjYW4gYmUgZXhwcmVzc2VkIGluIGVpdGhlciBhYnNvbHV0ZSB0ZXJtcyAtIHdoZXJlIHRoZSBpbnZlc3RvciBoYXMgYSB2aWV3IG9uIGluZGl2aWR1YWwgYXNzZXQgcGVyZm9ybWFuY2Ugb3IgcmVsYXRpdmUgdGVybXMgLSB3aGVyZSB0aGUgaW52ZXN0b3IgaGFzIGEgdmlldyBvbiBob3cgYW4gaW5kaXZpZHVhbCBhc3NldCBwZXJmb3JtcyBpbiBjb21wYXJpc29uIHRvIGFub3RoZXIuIFRoaXMgYWJpbGl0eSB0byBpbmNvcnBvcmF0ZSBzdWJqZWN0aXZlIHZpZXdzIGludG8gYSBwb3J0Zm9saW8gZXhwZWN0ZWQgcmV0dXJuIGFuZCB2YXJpYW5jZSBpcyBwZXJoYXBzIHRoZSBtb3N0IHZhbHVhYmxlIHBhcnQgb2YgdGhlIGZyYW1ld29yay4KfCAgICAgICBJbiBwcmFjdGljZSwgdGhlIHN1YmplY3RpdmUgdmlld3MgYXJlIG9mdGVuIGdlbmVyYXRlZCBmcm9tIGEgVmVjdG9yIEF1dG9yZWdyZXNzaXZlIG1vZGVsIG9mIG9yZGVyIHAsIGEgYmFzaWMgZWNvbm9tZXRyaWMgbW9kZWwgdG8gcmVwcmVzZW50IHRoZSByZXR1cm5zIHRpbWUgc2VyaWVzIG9mIE4gYXNzZXRzLgoKKipDb3ZhcmlhbmNlLVJvYnVzdCBGcmFtZXdvcmsqKgoKfCAgICAgICBBbiBpbXBvcnRhbnQgb21pc3Npb24gaW4gdGhlIGV4cGxhbmF0aW9uIG9mIHRoZSBNYXJrb3dpdHogYW5kIEJsYWNrIExpdHRlcm1hbiBPcHRpbWl6YXRpb24gZnJhbWV3b3JrcyBpcyB0aGV5IGRvIG5vdCBhY2NvdW50IGZvciB0aGUgYW5vbWFsaWVzIHRoYXQgbWF5IGV4aXN0IGluIHRoZSBpbnB1dCBkYXRhLCBpLmUgdGhlIHBvcnRmb2xpbyByZXR1cm5zIGFuZCB2YXJpYW5jZSBlc3RpbWF0ZXMuIE9mIGNvdXJzZSwgYW5vbWFsaWVzIGluIHRoaXMgY2FzZSBpcyBhIHJlZmVyZW5jZSB0byB0aG9zZSBwb2ludHMgdGhhdCBkbyBub3QgbmVjZXNzYXJpbHkgJ3N0aWNrJyBvdXQgaW4gdGhlIGZpdHRlZCBlbXBpcmljYWwgbWVhbiwgdmFyaWFuY2UsIGFuZCBjb3ZhcmlhbmNlIGVzdGltYXRlcyBidXQgaGF2ZSBzdWJzdGFudGlhbCBpbmZsdWVuY2Ugb24gdGhvc2UgZXN0aW1hdGVzIGZyb20gdGhlIHJldHVybnMgZGF0YSBzZXQuCnwgICAgICAgVGhlIGltcG9ydGFuY2Ugb2YgZGV0ZWN0aW5nIGFuZCBkZWFsaW5nIHdpdGggYW5vbWFsaWVzIGNhbm5vdCBiZSB1bmRlcmVzdGltYXRlZCBiZWNhdXNlIGFub21hbGllcyBpbiB0aGUgZGF0YSBjYW4gZGlzdG9ydCBwYXJhbWV0ZXIgZXN0aW1hdGVzLCB3aXRoIHRoZSBlZmZlY3QgaW4gdGhlIGNhc2Ugb2YgZmluZGluZyB0aGUgb3B0aW1hbCByaXNrLXJldHVybiBjb21iaW5hdGlvbiBmb3IgYSBwb3J0Zm9saW8sIGJlaW5nIHRoZSBjb21iaW5hdGlvbnMgbW9yZSBhcHByb3ByaWF0ZWx5IGRlc2NyaWJlIHRoZSBhbm9tYWxpZXMuCnwgICAgICAgVG8gc2VlIHdoeSB0aGlzIGhhcHBlbnMsIGFuIGV4YW1wbGUgd291bGQgYmUgdXNlZnVsLiBGb3IgZXhhbXBsZSwgb3V0bGllcnMsIHdoaWNoIGFyZSBub3QgcGlja2VkIHVwIGluIHRoZSBzYW1wbGUgbWVhbiBhbmQgY292YXJpYW5jZSBlc3RpbWF0ZXMsIHB1bGwgdGhlIG9yZGluYXJ5IHNhbXBsZSBtZWFuIHRvd2FyZCB0aGVtc2VsdmVzLCBhbmQgYXJ0aWZpY2lhbGx5IGluZmxhdGUgdGhlIG9yZGluYXJ5IHNhbXBsZSBjb3ZhcmlhbmNlIG1hdHJpeC4gSWYgd2Uga25ldyBhIHByaW9yaSB3aGljaCBwb2ludHMgd2VyZSBhbm9tYWxvdXMsIHdlIGNvdWxkIHNpbXBseSBleGNsdWRlIHRoZW0gd2hlbiBlc3RpbWF0aW5nIHRoZSBwYXJhbWV0ZXJzLiBCdXQsIHRoaXMgaW5mb3JtYXRpb24gaXMgb2Z0ZW4gdW5hdmFpbGFibGUuCnwgICAgICAgVGhpcyBpZGVhIG9mIG1pbmltaXppbmcgdGhlIGluZmx1ZW5jZSBvZiBhbm9tYWxpZXMgaW4gZXN0aW1hdGluZyB0aGUgbWVhbiBhbmQgY292YXJpYW5jZSBtYXRyaXggaXMgd2hhdCByb2J1c3Qgb3B0aW1pemF0aW9uIHNlZWtzIHRvIGV4cGxvcmUuIFRoZSBNaW5pbXVtIENvdmFyaWFuY2UgRGV0ZXJtaW5hbnQgKE1DRCksIGEgcG9wdWxhciByb2J1c3Qgb3B0aW1pemF0aW9uIG1ldGhvZCwgYW5zd2VycyB0aGUgcXVlc3Rpb24gb2YgZXN0aW1hdGluZyB0aGUgcmlnaHQgZW1waXJpY2FsIG1lYW4gYW5kIGNvdmFyaWFuY2UgYnkgdGFraW5nIGFsbCBwb3NzaWJsZSBzdWJzZXRzIG9mIHRoZSBkYXRhLCBvZiBhIHNwZWNpZmllZCBzaXplLCBhbmQgZXN0aW1hdGVzIHRoZSBtZWFuIGFuZCBjb3ZhcmlhbmNlIG1hdHJpeCBmb3IgZWFjaCBzdWJzZXQuIEl0IHRoZW4ga2VlcHMgdGhlIGVzdGltYXRlcyBmb3IgdGhlIHN1YnNldCB3aG9zZSBjb3ZhcmlhbmNlIG1hdHJpeCBoYXMgdGhlIHNtYWxsZXN0IGRldGVybWluYW50IGFuZCBzY2FsZXMgdGhlbSBieSBhICdjb25zaXN0ZW5jeScgZmFjdG9yLgp8ICAgICAgIFRoZSB1bmRlcmx5aW5nIGlkZWEgaGVyZSBpcyBzaW5jZSB0aGUgZGV0ZXJtaW5hbnQgb2YgdGhlIGNvdmFyaWFuY2UgbWF0cml4IG1lYXN1cmVzIC0gcm91Z2hseSBzcGVha2luZyAtIHRoZSBzcHJlYWQgb2YgYSByZXR1cm5zIGRpc3RyaWJ1dGlvbiwgbWluaW1pemluZyBpdCBpcyBha2luIHRvIHNlbGVjdGluZyBhIHN1YnNldCBvZiB0aGUgZGF0YSB0aGF0IGhhcyB0aGUgdGlnaHRlc3QgZGlzdHJpYnV0aW9uIGFuZCBjb25zZXF1ZW50bHkgaXMgbGVzcyBsaWtlbHkgdG8gYmUgYWZmZWN0ZWQgYnkgb3V0bGllcnMuCgojIyBQb3J0Zm9saW8gQ29uc3RyYWludHMKCnwgICAgICAgSW4gb3JkZXIgdG8gbWltaWMgYSByZWFsaXN0aWMgcG9ydGZvbGlvIHdpdGggcmVhbGlzdGljIHRha2VuIHRvIG1lYW4gY29uc3RyYWludHMgaW1wb3NlZCBieSBlaXRoZXIgY2xpZW50cyBvciByZWd1bGF0b3JzIG9uIGEgcG9ydGZvbGlvIG1hbmFnZXIsIGFkZGl0aW9uYWwgY29uc3RyYWludHMgYXJlIG1hZGUgZm9yIHRoZSBvcHRpbWl6YXRpb24gcHJvYmxlbS4gSW4gdGhpcyBhcnRpY2xlLCB0aGUgYWRkaXRpb25hbCBjb25zdHJhaW50cyBhcmUKCmEpIExvbmctT25seSBDb25zdHJhaW50cyAtIHdoZXJlIHRoZSBzaG9ydCBzZWxsaW5nIGlzIG5vdCBhbGxvd2VkIGluIHRoZSBwb3J0Zm9saW8uCgpiKSBIb2xkaW5nIGNvbnN0cmFpbnRzIC0gd2hlcmUgYSBzaW5nbGUgRVRGIGNhbiBiZSBhdCBtb3N0IDQwJSBvZiB0aGUgcG9ydGZvbGlvIGFuZCBhdCBsZWFzdCA1JSBvZiB0aGUgcG9ydGZvbGlvLgoKfCAgICAgICBXaGlsZSBpbXBvc2luZyBsaW1pdHMgb24gdGhlIG1heGltdW0gZXhwb3N1cmUgb24gYSBzaW5nbGUgRVRGIGlzIGludHVpdGl2ZSwgaXQgaXMgd29ydGh3aGlsZSBleHBsYWluaW5nIHRoZSBsb3dlciBib3VuZC4gVGhlIHVuZGVybHlpbmcgcmVhc29uIGlzIHRvIGFsbG93IGEgaG9sZGluZyBzaXplIHNtYWxsIHlldCBzdWJzdGFudGlhbCBlbm91Z2ggdGhhdCB0aGUgcG9zaXRpb24gaW4gdGhlIEVURiBjYW4gY29udHJpYnV0ZSB0byBwb3J0Zm9saW8gcGVyZm9ybWFuY2UuIEEgbW9yZSBkZXRhaWxlZCByZWFzb24gaG93ZXZlciBpcyB0aGF0IGFzc2V0cywgcGFydGljdWxhcmx5IHN0b2NrcywgYXJlIG9mdGVuIHRyYWRlZCBpbiBtdWx0aXBsZXMgb2YgbWluaW11bSB0cmFuc2FjdGlvbiBjb3N0cyBvciByb3VuZHMgYW5kIGNvbnNlcXVlbnRseSwgdmVyeSBzbWFsbCBwb3NpdGlvbnMgY2Fubm90IGJlIHJlYWxpc3RpY2FsbHkgYWNxdWlyZWQuCgpgYGB7ciBzZXR1cCx3YXJuaW5nPUZBTFNFLGNvbW1lbnQ9TkEscmVzdWx0cz0naGlkZSd9CiMgTGlicmFyeSBJbXBvcnRzIC0gUGFja2FnZSBuYW1lcwpwYWNrYWdlcyA8LSBjKCJNQVNTIiwgInh0cyIsICJxdWFudG1vZCIsICJQb3J0Zm9saW9BbmFseXRpY3MiLAogICAgICAgICAgICAgICJST0kiLCAiUk9JLnBsdWdpbi5nbHBrIiwgIlJPSS5wbHVnaW4ucXVhZHByb2ciLCAidGlkeXZlcnNlIiwgCiAgICAgICAgICAgICAgImhpZ2hjaGFydGVyIiwgIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikKCiMgSW5zdGFsbCBwYWNrYWdlcyBpZiBub3QgeWV0IGluc3RhbGxlZCAtIE5lYXQgdHJpY2sgZnJvbSBBbnRvaW5lIFNvZXRld2V5J3MgYmxvZwppbnN0YWxsZWRfcGFja2FnZXMgPC0gcGFja2FnZXMgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkKaWYgKGFueShpbnN0YWxsZWRfcGFja2FnZXMgPT0gRkFMU0UpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlc1shaW5zdGFsbGVkX3BhY2thZ2VzXSkKfQoKIyBQYWNrYWdlcyBsb2FkaW5nCnN1cHByZXNzTWVzc2FnZXMobGFwcGx5KHBhY2thZ2VzLCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQoKIycgaW1wb3J0IGRhdGEgZm9yIGVhY2ggc3ltYm9sIGFuZCBjb252ZXJ0IHRvIG1vbnRobHkgcHJpY2VzCiMnIE5vdGUgY29udmVyc2lvbiB0byBtb250aGx5IGF1dG9tYXRpY2FsbHkgcmVtb3ZlcyBOQS1WQUxVRVMKZXRmLnN5bWJvbHMgPC0gYygiU1BZIiwgIklXTSIsICJGRVoiLCAiQUNXSSIsIkFHRyIsIklBR0ciLCAiSVlSIiwiUkVFVCIsIkdTRyIpCmFkai5jbG9zZSA8LSA2ICAjIDZ0aCBmaWVsZCBpcyBhZGp1c3RlZCBjbG9zZQpldGYucHJpY2VzIDwtIGdldFN5bWJvbHMoZXRmLnN5bWJvbHNbMV0sIHNvdXJjZT0ieWFob28iLAogICAgICAgICAgICAgICAgICAgICAgICAgYXV0by5hc3NpZ249RkFMU0UsIHJldHVybi5jbGFzcz0ieHRzIilbLGFkai5jbG9zZV0KZm9yIChpIGluIDI6bGVuZ3RoKGV0Zi5zeW1ib2xzKSkgewogIGV0Zi50bXAgPC0gZ2V0U3ltYm9scyhldGYuc3ltYm9sc1tpXSwgc291cmNlPSJ5YWhvbyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG8uYXNzaWduPUZBTFNFLCByZXR1cm4uY2xhc3M9Inh0cyIpWyxhZGouY2xvc2VdCiAgZXRmLnByaWNlcyA8LSBjYmluZChldGYucHJpY2VzLCBldGYudG1wKQp9CmNvbG5hbWVzKGV0Zi5wcmljZXMpIDwtIGV0Zi5zeW1ib2xzCgpldGYucHJpY2VzPC0gc3VwcHJlc3NXYXJuaW5ncyh0by5tb250aGx5KGV0Zi5wcmljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4QXQ9J2xhc3RvZicsCiAgICAgICAgICAgICAgICAgICAgICAgIE9ITEM9RkFMU0UpKQoKIyBDYWxjdWxhdGUgUmV0dXJucyBhbmQgcmVtb3ZlIG5hIHZhbHVlIGluIGZpcnN0IHJvdwpldGYucmV0cy5kYXRhIDwtIFJldHVybi5jYWxjdWxhdGUobmEub21pdChldGYucHJpY2VzKSxtZXRob2Q9J2xvZycpICU+JQogICAgICAgICAgICAgICAgbmEub21pdCgpCgojIEtlZXAgUmV0dXJucyBmcm9tIDIwMTYtMjAyMSBmb3IgaW4tc2FtcGxlIGVzdGltYXRpb24KZXRmLnJldHM8LSBldGYucmV0cy5kYXRhWyIyMDE2LzIwMjEiXQoKIyBLZWVwIFJldHVybnMgZnJvbSAyMDIyIGZvciBvdXQtb2Ytc2FtcGxlIHRlc3RpbmcKZXRmLnJldHMudGVzdDwtIGV0Zi5yZXRzLmRhdGFbIjIwMjIiXQoKIyMjIyMjIFBvcnRmb2xpbyBXZWlnaHRpbmcKCiMgIFBvcnRmb2xpbyBPYmplY3QgU3BlY2lmaWNhdGlvbiAtIFNldCB1cCBwb3J0Zm9saW8gd2l0aCBvYmplY3RpdmUgYW5kIGNvbnN0cmFpbnRzKExvbmcgT25seSkKCiMnICBHTVYgPSBHbG9iYWwgTWluaW11bSBWYXJpYW5jZSAgLCAgICBFVyAgPSBFcXVhbGx5IFdlaWdodAojJyAgUk8gID0gUm9idXN0IE9wdGltaXphdGlvbiAsICAgQkwgID0gQmxhY2sgTGl0dGVybWFuCgpwb3J0LnNwZWMgPC0gcG9ydGZvbGlvLnNwZWMoYXNzZXRzID0gY29sbmFtZXMoZXRmLnJldHMpKSAlPiUKICAgICAgICAgICAgICAgIGFkZC5vYmplY3RpdmUoIHR5cGU9InJpc2siLCBuYW1lPSJTdGREZXYiKSAlPiUKICAgICAgICAgICAgICAgIGFkZC5vYmplY3RpdmUoIHR5cGU9InJldHVybiIsIG5hbWU9Im1lYW4iKSAlPiUKICAgICAgICAgICAgICAgIGFkZC5jb25zdHJhaW50KHR5cGU9ImZ1bGxfaW52ZXN0bWVudCIpICAlPiUKICAgICAgICAgICAgICAgIGFkZC5jb25zdHJhaW50KCB0eXBlPSJsb25nX29ubHkiKSAgJT4lCiAgICAgICAgICAgICAgICBhZGQuY29uc3RyYWludCh0eXBlID0gImJveCIsIG1pbj0wLjA1LCBtYXg9MC40KQoKcG9ydC5zcGVjLkVXIDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cyA9IGNvbG5hbWVzKGV0Zi5yZXRzKSkgJT4lCiAgICAgICAgICAgICAgICAgIGFkZC5jb25zdHJhaW50KHR5cGU9ImZ1bGxfaW52ZXN0bWVudCIpICAlPiUKICAgICAgICAgICAgICAgICAgYWRkLmNvbnN0cmFpbnQoIHR5cGU9Imxvbmdfb25seSIpICAlPiUKICAgICAgICAgICAgICAgICAgYWRkLmNvbnN0cmFpbnQodHlwZSA9ICJib3giLCBtaW49MC4wNSwgbWF4PTAuNCkKCiMgU2V0IFBvcnRmb2xpbyBNb21lbnRzIGZvciBPcHRpbWl6YXRpb24gRnVuY3Rpb25zCnNhbXAubW9tZW50czwtICBmdW5jdGlvbihSKXsKICAgIG91dDwtc2V0LnBvcnRmb2xpby5tb21lbnRzKFIgPSBSLCBwb3J0Zm9saW89cG9ydC5zcGVjLCBtZXRob2Q9ICdzYW1wbGUnKQogICAgcmV0dXJuKG91dCkKfQoKCiMnIFZpZXdzIGFyZSBnZW5lcmF0ZWQgZnJvbSBhIFZBUi0yIG1vZGVsIGZyb20gdGhlIE1UUyBwYWNrYWdlCiMnIFIgaXMgYW4geHRzIHJldHVybiBvYmplY3QKYmwubW9tZW50czwtIGZ1bmN0aW9uKFIpewogIGRhdGE8LSBmb3J0aWZ5LnpvbyhSKVssLTFdCiAgbTE8LSBNVFM6OlZBUihkYXRhLHA9MixvdXRwdXQgPSBGKSAjIEZyb20gTVRTIHBhY2thZ2UKICBwcmVkPC0gTVRTOjpWQVJwcmVkKG0xLDEsb3V0cHV0ID0gRikgIyAxIHBlcmlvZCBhaGVhZCBmb3JlY2FzdAogIHByZWQ8LSBwcmVkJHByZWQgICAKICBuLmFzc2V0czwtbmNvbChSKQogIHBpY2s8LWRpYWcobi5hc3NldHMpCiAgb3V0PC0gYmxhY2subGl0dGVybWFuKFI9IFIsUCA9IHBpY2ssVmlld3MgPSBwcmVkKQogIG91dCRtdTwtIG91dCRCTE11CiAgb3V0JHNpZ21hPC0gb3V0JEJMU2lnbWEKICByZXR1cm4ob3V0KQp9CgojJyBGaW5kIE9wdGltYWwgV2VpZ2h0cwojJyBSZj0gMCAKR01WLndlaWdodHM8LSBvcHRpbWl6ZS5wb3J0Zm9saW8oUiA9IGV0Zi5yZXRzLHBvcnRmb2xpbz0gcG9ydC5zcGVjLG1heFNSPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpbWl6ZV9tZXRob2QgPSAiUk9JIix0cmFjZSA9IFRSVUUsbW9tZW50RlVOPSdzYW1wLm1vbWVudHMnKQogcHJpbnQoIk9wdGltYWwgTWFya293aXR6IHdlaWdodHMiKQogcHJpbnQoc3ByaW50ZigiJXMgOiAlcyIsIGV0Zi5zeW1ib2xzLAogICAgICAgICAgICAgIHNjYWxlczo6cGVyY2VudChhcy5udW1lcmljKEdNVi53ZWlnaHRzJHdlaWdodHMpKSkpCgojJyBUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIGlzIG9idGFpbmVkIGZyb20gUm9zcyBCZW5uZXR0J3MgKDIwMTgpIFBhcGVyCiMnIEVzdGltYXRlcyBDb3ZhcmlhbmNlIE1hdHJpeApzaWdtYS5yb2J1c3Q8LSBmdW5jdGlvbihSKXsKICBvdXQ8LSBsaXN0KCkKICBzZXQuc2VlZCgxMjM0KQogIG91dCRzaWdtYTwtIGNvdi5yb2IoUixtZXRob2Q9J21jZCcsbnNhbXAgPSAnYmVzdCcpJGNvdgogIHJldHVybihvdXQpCn0KClJPLndlaWdodHMgPC1vcHRpbWl6ZS5wb3J0Zm9saW8oUiA9IGV0Zi5yZXRzLHBvcnRmb2xpbz0gcG9ydC5zcGVjLG1heFNSPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGltaXplX21ldGhvZCA9ICJST0kiLHRyYWNlID0gVFJVRSxtb21lbnRGVU49J3NpZ21hLnJvYnVzdCcpCgogcHJpbnQoIkNvdmFyaWFuY2UtUm9idXN0IE9wdGltaXphdGlvbiBXZWlnaHRzIikKIHByaW50KHNwcmludGYoIiVzIDogJXMiLCBldGYuc3ltYm9scywKICAgICAgICAgICAgICBzY2FsZXM6OnBlcmNlbnQoYXMubnVtZXJpYyhSTy53ZWlnaHRzJHdlaWdodHMpKSkpCgoKRVcud2VpZ2h0cyA8LSBlcXVhbC53ZWlnaHQoZXRmLnJldHMsIHBvcnRmb2xpbz0gcG9ydC5zcGVjLkVXKQogcHJpbnQoIkVxdWFsIHdlaWdodHMiKQogcHJpbnQoc3ByaW50ZigiJXMgOiAlcyIsIGV0Zi5zeW1ib2xzLAogICAgICAgICAgICAgIHNjYWxlczo6cGVyY2VudChhcy5udW1lcmljKEVXLndlaWdodHMkd2VpZ2h0cykpKSkKIAojJyBUaGUgb3B0aW1pemVyIGlzIG5vdCBhYmxlIHRvIGZpbmQgYSB1bmlxdWUgJ3RhbmdlbnRpYWwnIHNvbHV0aW9uLCBzbyByZW1vdmUgCiMnIE1heCBTaGFycGUgcmF0aW8gb2JqZWN0aXZlLgojJyBUaGlzICdsb29zZW5lZCcgb3B0aW1pemF0aW9uIGltcGxlbWVudGF0aW9uIGlzIHRoZW4gZm9jdXNlZCBvbiBtYXhpbWl6aW5nIG9ubHkgcG9ydGZvbGlvCiMnIHJldHVybiBzdWJqZWN0IHRvIGNvbnN0cmFpbnRzIG9uIHdlaWdodHMuCkJMLndlaWdodHM8LWludmlzaWJsZShvcHRpbWl6ZS5wb3J0Zm9saW8oUiA9IGV0Zi5yZXRzLHBvcnRmb2xpbz0gcG9ydC5zcGVjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW1pemVfbWV0aG9kID0gIlJPSSIsdHJhY2UgPSBUUlVFLG1vbWVudEZVTj0nYmwubW9tZW50cycpKQogcHJpbnQoIkJsYWNrLUxpdHRlcm1hbiBXZWlnaHRzIikKIHByaW50KHNwcmludGYoIiVzIDogJXMiLCBldGYuc3ltYm9scywKICAgICAgICAgICAgICBzY2FsZXM6OnBlcmNlbnQoYXMubnVtZXJpYyhCTC53ZWlnaHRzJHdlaWdodHMpKSkpCmBgYAogCiMjIFBvcnRmb2xpbyBXZWlnaHRzCgp8ICAgICAgIEFwcGx5aW5nIHRoZSB2YXJpb3VzIHdlaWdodGluZyBzY2hlbWVzLCBhIGJhciBwbG90IG9mIHBvcnRmb2xpbyB3ZWlnaHRzIGlzIHByb2R1Y2VkIGFsb25nIHdpdGggYSB0YWJsZSBjb250YWluaW5nIHRoZSBzYW1lIGluZm9ybWF0aW9uIGluIGRldGFpbC4gQnJvYWRseSBzcGVha2luZywgaXQgY2FuIGJlIHNlZW4gZXhjZXB0IGZvciB0aGUgQmxhY2stTGl0dGVybWFuIGFwcHJvYWNoLCB0aGUgb3B0aW1pemF0aW9uIGFwcHJvYWNoZXMgYXJlIGNvbmNlbnRyYXRlZCBpbiB0aGUgYm9uZCBFVEZzIHdoaWNoIG9uZSBjYW4gYXJndWUgaGV1cmlzdGljYWxseSBpcyBhIHJlYXNvbmFibGUgYWxsb2NhdGlvbiBnaXZlbiB0aGUgbWFya2V0IHR1cmJ1bGVuY2Ugb2YgMjAyMCBhbmQgMjAyMS4gVGhlIEJsYWNrLUxpdHRlcm1hbiBhcHByb2FjaCBob3dldmVyLCBhcHBlYXJzIHRvIGJlIGNvbmNlbnRyYXRlZCBpbiB0aGUgQ29tbW9kaXR5IEVURi4KYGBge3IgMm5kLGNvbW1lbnQ9TkEsIGZpZy5kaW09Yyg4LDYpLHdhcm5pbmc9RkFMU0V9CiMgQ3JlYXRlIExpc3Qgb2YgcG9ydGZvbGlvIG9iamVjdHMgYW5kIGRpc3BsYXkgdGhlaXIgd2VpZ2h0cyBpbiBhIGJhcnBsb3QKcG9ydC5saXN0IDwtIGxpc3QoR01WLndlaWdodHMsRVcud2VpZ2h0cywgUk8ud2VpZ2h0cywgQkwud2VpZ2h0cykKbmFtZXMocG9ydC5saXN0KSA8LSBjKCJNYXJrb3dpdHoiLCJFcXVhbC1XZWlnaHQiLCAnQ292YXJpYW5jZSBSb2J1c3QgT3B0aW1pemF0aW9uJywgCiAgICAgICAgICAgICAgICAgICAgICAnQmxhY2stTGl0dGVybWFuJykKY2hhcnQuV2VpZ2h0cyhjb21iaW5lLm9wdGltaXphdGlvbnMocG9ydC5saXN0KSwgcGxvdC50eXBlID0gImJhcnBsb3QiLCAKICAgICAgICAgICAgICBtYWluPSJXZWlnaHRzIHN0YWNrZWQgYnkgQXNzZXQgKExvbmctb25seSkiKQoKIyBQdXQgV2VpZ2h0cyBpbiBhIGRhdGEgZnJhbWUoU2NhbGUgYnkgMTAwIHRvIGdldCBpdCBpbiBwZXJjZW50YWdlcykKd2VpZ2h0czwtIGNiaW5kKEdNVi53ZWlnaHRzJHdlaWdodHMsRVcud2VpZ2h0cyR3ZWlnaHRzLAogICAgICAgICAgICAgICAgUk8ud2VpZ2h0cyR3ZWlnaHRzLCBCTC53ZWlnaHRzJHdlaWdodHMpCndlaWdodHM8LSByb3VuZCh3ZWlnaHRzLDQpKjEwMApjb2xuYW1lcyh3ZWlnaHRzKTwtIG5hbWVzKHBvcnQubGlzdCkKCmtuaXRyOjprYWJsZSh3ZWlnaHRzLGNhcHRpb249ICJUYWJsZSAxIC0gV2VpZ2h0cyBpbiAoJSkiKQpgYGAKCiMjIE92ZXJ2aWV3IG9mIFBvcnRmb2xpbyBQZXJmb3JtYW5jZSBNZXRyaWNzCgp8ICAgICAgIE9mIGNvdXJzZSwgaXQgd291bGQgYmUgcG9pbnRsZXNzIHRvIGNvbnN0cnVjdCBwb3J0Zm9saW9zIGZyb20gdGhlIHZhcmlvdXMgd2VpZ2h0aW5nIHNjaGVtZXMgd2l0aG91dCBhc3Nlc3NpbmcgaG93IGVhY2ggc2NoZW1lIGFmZmVjdGVkIHRoZSBwb3J0Zm9saW8ncyBwZXJmb3JtYW5jZS4gVG8gdGhpcyBlbmQsIGEgYnJpZWYgc3VtbWFyeSBvZiBwb3B1bGFyIHBlcmZvcm1hbmNlIG1ldHJpY3MgaXMgcHJlc2VudGVkIHRvIGFzc2VzcyB0aGUgdmFsdWUgb2YgZWFjaCB3ZWlnaHRpbmcgc2NoZW1lLgoKKipBbm51YWxpemVkIFJldHVybjoqKiBHZW9tZXRyaWMgYXZlcmFnZSBvZiBhbm51YWwgcmV0dXJucyBnZW5lcmF0ZWQgYnkgYSBwb3J0Zm9saW8gb3ZlciBhIGdpdmVuIGludmVzdG1lbnQgcGVyaW9kLgoKKipBY3RpdmUgUmV0dXJuOioqIEV4Y2VzcyBwb3J0Zm9saW8gcmV0dXJucyBvdmVyIHNvbWUgc3BlY2lmaWVkIGJlbmNobWFyay4gTm90ZSBob3cgaXQgZGlmZmVycyBmcm9tIGV4Y2VzcyByZXR1cm4uCgoqKkV4Y2VzcyBSZXR1cm46KiogRXhjZXNzIHBvcnRmb2xpbyByZXR1cm5zIG92ZXIgc29tZSBzcGVjaWZpZWQgcmlzay1mcmVlIGFzc2V0LiAKCioqQW5udWFsaXplZCBTdGFuZGFyZCBEZXZpYXRpb246KiogR2VvbWV0cmljIGF2ZXJhZ2Ugb2YgdmFyaWFiaWxpdHkgb2YgYSBwb3J0Zm9saW8ncyBhbm51YWwgcmV0dXJucyBvdmVyIGEgZ2l2ZW4gaW52ZXN0bWVudCBwZXJpb2QuIFRoZSBoaWdoZXIgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiByZXR1cm5zLCB0aGUgcmlza2llciB0aGUgcG9ydGZvbGlvIHdlaWdodGluZyBzY2hlbWUgaXMuCgoqKkJldGEoQ0FQTSk6KiogUmVmbGVjdHMgcmlzayBvZiBhIHBvcnRmb2xpbyBpbiByZWxhdGlvbiB0byBzb21lIGJlbmNobWFyay4gU3RhdGlzdGljYWxseSwgaXQgaXMgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgcmVmbGVjdGluZyBob3cgbXVjaCBhIHBvcnRmb2xpbydzIHJldHVybnMgY2hhbmdlIGZvciBlYWNoIHVuaXQgY2hhbmdlIGluIHRoZSBiZW5jaG1hcmsncyByZXR1cm5zLiBIaWdoZXIgYmV0YXMgbWVhbiB0aGUgcG9ydGZvbGlvJ3MgcmV0dXJucyBhcmUgbW9yZSBzZW5zaXRpdmUgdG8gdGhlIGJlbmNobWFyaydzIHJldHVybnMuCgoqKlNoYXJwZSBSYXRpbzoqKiBQb3J0Zm9saW8gZXhjZXNzIHJldHVybnMgcGVyIHVuaXQgb2Ygcmlzay4gRXhjZXNzIHJldHVybnMgaGVyZSBpcyB0aGUgZXhjZXNzIHBvcnRmb2xpbyByZXR1cm5zIG92ZXIgc29tZSBzcGVjaWZpZWQgcmlzay1mcmVlIGFzc2V0IHdoaWxlIHJpc2sgaXMgdGhlIHBvcnRmb2xpbyBzdGFuZGFyZCBkZXZpYXRpb24uIEluIGdlbmVyYWwsIGhpZ2hlciBTaGFycGUgcmF0aW9zIG1lYW4gdGhlIHBvcnRmb2xpbyBwcm92aWRlcyBncmVhdGVyIHJldHVybnMgb3ZlciB0aGUgcmlzayBmcmVlIGFzc2V0IHdoaWxlIG9mZmVyaW5nIHRoZSBzYW1lIG9yIGxlc3MgdmFyaWFiaWxpdHkgb2YgcmV0dXJucy4gSGlnaGVyIFNoYXJwZSByYXRpb3MgYXJlIHRodXMgdXN1YWxseSBiZXR0ZXIuCgoqKlRyZXlub3IgUmF0aW86KiogUG9ydGZvbGlvIGV4Y2VzcyByZXR1cm5zIHBlciB1bml0IG9mIGJldGEvYmVuY2htYXJrIHJpc2suIExpa2UgdGhlIFNoYXJwZSwgZXhjZXNzIHJldHVybnMgaGVyZSBpcyB0aGUgZXhjZXNzIHBvcnRmb2xpbyByZXR1cm5zIG92ZXIgc29tZSBzcGVjaWZpZWQgcmlzay1mcmVlIGFzc2V0LiBJbiBnZW5lcmFsLCBoaWdoZXIgVHJleW5vciByYXRpb3MgbWVhbiB0aGUgcG9ydGZvbGlvIHByb3ZpZGVzIGdyZWF0ZXIgcmV0dXJucyBvdmVyIHRoZSByaXNrIGZyZWUgYXNzZXQgd2hpbGUgb2ZmZXJpbmcgbGVzcyBleHBvc3VyZSB0byB0aGUgYmVuY2htYXJrLiBIaWdoZXIgVHJleW5vciByYXRpb3MgYXJlIHRodXMgdXN1YWxseSBiZXR0ZXIuCgoqKk1vZGlnbGlhbmkqKiAkTV4yJDogIEFkanVzdHMgZWFjaCBwb3J0Zm9saW8ncyByZXR1cm5zIHRvIHdoYXQgaXQgd291bGQgaGF2ZSBiZWVuIGhhZCB0aGUgcG9ydGZvbGlvIG1hbmFnZXIgdGFrZW4gdGhlIHNhbWUgYW1vdW50IG9mIHJpc2sgYXMgdGhlIGJlbmNobWFyay4gSW4gZ2VuZXJhbCwgaGlnaGVyIE1vZGlnbGlhbmkgJE1eMiQgbWVhc3VyZXMgbWVhbiB0aGUgcG9ydGZvbGlvIHByb3ZpZGVzIGdyZWF0ZXIgcmV0dXJucyB3aGlsZSB0YWtpbmcgdGhlIHNhbWUgYW1vdW50IHJpc2sgYXMgdGhlIGJlbmNobWFyayB3aGVyZSByaXNrIGlzIHRoZSBiZW5jaG1hcmsncyBzdGFuZGFyZCBkZXZpYXRpb24uIEhpZ2hlciBNb2RpZ2xpYW5pICRNXjIkIG1lYXN1cmVzIGFyZSB0aHVzIHVzdWFsbHkgYmV0dGVyLgoKKipJbmZvcm1hdGlvbiBSYXRpbzoqKiBSYXRpbyBvZiBleGNlc3MgcG9ydGZvbGlvIHJldHVybnMgb3ZlciB0aGUgYmVuY2htYXJrIHRvIHRoZSBzdGFuZGFyZCBvZiB0aGUgZXhjZXNzIHBvcnRmb2xpbyByZXR1cm5zLiBJbiBnZW5lcmFsLCBoaWdoZXIgaW5mb3JtYXRpb24gcmF0aW9zIG1lYW4gdGhlIHBvcnRmb2xpbyBwcm92aWRlcyBncmVhdGVyIGV4Y2VzcyByZXR1cm5zIG92ZXIgdGhlIGJlbmNobWFyayBwZXIgdW5pdCBvZiByaXNrLiBIaWdoZXIgaW5mb3JtYXRpb24gcmF0aW9zIGFyZSB0aHVzIHVzdWFsbHkgYmV0dGVyLgoKKipUcmFja2luZyBFcnJvcjoqKiBTdGFuZGFyZCBEZXZpYXRpb24gb2YgZXhjZXNzIHBvcnRmb2xpbyByZXR1cm5zIG92ZXIgdGhlIGJlbmNobWFyay4gVGhlIGdyZWF0ZXIgdGhlIHRyYWNraW5nIGVycm9yLCB0aGUgbW9yZSB0aGUgcG9ydGZvbGlvIHJldHVybnMgZGV2aWF0ZSBmcm9tIHRoZSBiZW5jaG1hcmsuCgoqKkRpdmVyc2lmaWNhdGlvbiBSYXRpbzoqKiBSYXRpbyBvZiB0aGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiB2b2xhdGlsaXR5IGluZGl2aWR1YWwgYXNzZXRzIHRvIHRoZSBvdmVyYWxsIHBvcnRmb2xpbyB2b2xhdGlsaXR5LiBIZXJlLCB3ZWlnaHRzIGFyZSB0aGUgcG9ydGZvbGlvIHdlaWdodHMuIEZvciBhIHdlbGwgZGl2ZXJzaWZpZWQgbG9uZy1vbmx5IHBvcnRmb2xpbywgdGhlIHJhdGlvIHNob3VsZCBiZSBncmVhdGVyIHRoYW4gMS4KCioqQ29uY2VudHJhdGlvbiBSYXRpbzoqKiAKCnwgICAgICAgUmF0aW8gb2YgdGhlIHdlaWdodGVkIHN1bSBvZiBzcXVhcmVkIGluZGl2aWR1YWwgYXNzZXQgdm9sYXRpbGl0eSB0byB3ZWlnaHRlZCBzdW0gb2YgaW5kaXZpZHVhbCBhc3NldCB2b2xhdGlsaXR5IHNxdWFyZWQuIFdoaWxlIGNvbmZ1c2luZywgdGhlIGlkZWEgZm9yIHRoZSBudW1lcmF0b3IgaXMgdG8gc3F1YXJlIHRoZSBpbmRpdmlkdWFsIHdlaWdodGVkIHZvbGF0aWxpdGllcyBiZWZvcmUgeW91IHN1bSwgd2hlcmUgd2VpZ2h0cyBhcmUgdGhlIHBvcnRmb2xpbyB3ZWlnaHRzLgp8ICAgICAgIEZvciB0aGUgZGVub21pbmF0b3IsIHlvdSB0YWtlIHRoZSB3ZWlnaHRlZCBzdW0gb2YgaW5kaXZpZHVhbCBhc3NldCB2b2xhdGlsaXR5IGJlZm9yZSB5b3UgdGFrZSB0aGUgc3F1YXJlLiBGb3IgYSB3ZWxsIGRpdmVyc2lmaWVkLCBsb25nLW9ubHkgcG9ydGZvbGlvLCB0aGUgcmF0aW8gc2hvdWxkIGJlIGxlc3MgdGhhbiAxLiBBZGRpdGlvbmFsbHksIHBvcnRmb2xpbyBhbGxvY2F0aW9ucyB3aXRoIGhpZ2hlciBjb25jZW50cmF0aW9uIHJhdGlvcyBhcmUganVkZ2VkIHRvIGJlIG1vcmUgY29uY2VudHJhdGVkIHRoYW4gdGhlaXIgd2VpZ2h0aW5nIGNvdW50ZXJwYXJ0cy4gUHV0IHNpbXBseSwgYSBsb3dlciBjb25jZW50cmF0aW9uIHJhdGlvIGlzIHVzdWFsbHkgYmV0dGVyLgoKKipDdXN0b21pemluZyB0aGUgQmVuY2htYXJrOioqCgp8ICAgICAgIFNpbmNlIG1vc3QgaW52ZXN0bWVudHMgZXN0YWJsaXNoIGEgYmVuY2htYXJrIHRvIGV2YWx1YXRlIGEgcG9ydGZvbGlvIG1hbmFnZXIncyBwZXJmb3JtYW5jZSwgYSBjdXN0b21pemVkIGluZGV4IGlzIGNyZWF0ZWQgZm9yIHRoaXMgcHVycG9zZS4gVGhlIGN1c3RvbWl6ZWQgaW5kZXggaXMgY3JlYXRlZCB0byBiZXR0ZXIgcmVmbGVjdCB0aGUgaW52ZXN0b3IncyBvYmplY3RpdmUgd2hpY2ggZm9yIHRoaXMgYXJ0aWNsZSBpcyBhIGRlc2lyZWQgZXhwb3N1cmUgdG8gSW5kZXggRVRGcy4KfCAgICAgICBPZiBjb3Vyc2UsIHRoaXMgaW52ZXN0b3IgaXMgYXNzdW1lZCB0byBkZXNpcmUgZXhwb3N1cmUgdG8gaW5kaWNlcyB0aGF0IHRyYWNrIHN0b2NrcywgYm9uZHMsIGNvbW1vZGl0aWVzLCBhbmQgcmVhbCBlc3RhdGUuIFRvIG1ha2UgdGhlIGFuYWx5c2lzIHRyYWN0YWJsZSwgYSBwcmljZS13ZWlnaHRlZCBpbmRleCBpcyBjb25zdHJ1Y3RlZCB3aGljaCBhdmVyYWdlcyBlcXVhbGx5IHRoZSB2YWx1ZSBvZiBlYWNoIEluZGV4IEVURiBpbiB0aGUgcG9ydGZvbGlvLgoKIyMgUGVyZm9ybWFuY2UgRXZhbHVhdGlvbgoKfCAgICAgICBUYWJsZSAyIHNob3dzIHRoZSBoaXN0b3JpY2FsIHBlcmZvcm1hbmNlIG9mIGVhY2ggcG9ydGZvbGlvIHdlaWdodGluZyBzY2hlbWUuIEl0IGNhbiBiZSBzZWVuIC0gZ2VuZXJhbGx5IHNwZWFraW5nIC0gdGhlIEJsYWNrLUxpdHRlcm1hbiBhcHByb2FjaCBwZXJmb3JtcyBiZXN0IGZvciB0aGUgaW52ZXN0bWVudCBwZXJpb2QuIEluIHBhcnRpY3VsYXIsIGl0IHByb2R1Y2VkIGJldHRlciBhY3RpdmUgYW5kIGV4Y2VzcyByZXR1cm5zLCBoaWdoZXIgc2hhcnBlLCB0cmV5bm9yIGFuZCBpbmZvcm1hdGlvbiByYXRpb3MgYW1vbmcgb3RoZXJzLiBJdCBpcyB3b3J0aCBub3Rpbmcgd2hpbGUgdGhlIEJsYWNrLUxpdHRlcm1hbiBwb3J0Zm9saW8gd2FzIHdlbGwgZGl2ZXJzaWZpZWQsIGkuZSBpbiB0ZXJtcyBvZiBpdHMgZGl2ZXJzaWZpY2F0aW9uIHJhdGlvLCBpdCBoYWQgdGhlIG1vc3QgY29uY2VudHJhdGVkIHBvcnRmb2xpbyBpbiBjb21wYXJpc29uIHRvIHRoZSBvdGhlciBFVEYgcG9ydGZvbGlvcy4oZnJvbSBpdHMgY29uY2VudHJhdGlvbiByYXRpbykgCnwgICAgICAgVG8gc2hvdyB3aGF0IHRoaXMgcGVyZm9ybWFuY2UgbWVhbnMgZm9yIHRoZSBpbnZlc3RvciwgYSBsaW5lIGdyYXBoIGlzIHByZXNlbnRlZCBzaG93aW5nIHRoZSBncm93dGggb2YgJDEwLDAwMCBpbiBlYWNoIHBvcnRmb2xpbyB3ZWlnaHRpbmcgc2NoZW1lLgpgYGB7ciAzcmQsZmlnLmNhcD0iQ3VtdWxhdGVkIFBvcnRvZmxpbyBSZXR1cm5zIixjb21tZW50PU5BLGZpZy5kaW09Yyg4LDYpLHdhcm5pbmc9RkFMU0UsZGV2PSdwbmcnfQp3ZWlnaHRzIDwtIGNiaW5kKEdNVi53ZWlnaHRzJHdlaWdodHMsRVcud2VpZ2h0cyR3ZWlnaHRzLAogICAgICAgICAgICAgICAgIFJPLndlaWdodHMkd2VpZ2h0cyxCTC53ZWlnaHRzJHdlaWdodHMpCiMgcmV0cyA9IHJldHVybnMKcmV0czwtYygpCgojJyBDYWxjdWxhdGUgUmV0dXJucyBvbiBPdXQtb2YtU2FtcGxlIERhdGEgLSBXaXRoIFdlYWx0aCBQcm9ncmVzc2lvbgojJyBDb21iaW5lIHJldHVybnMgb2YgZWFjaCBwb3J0Zm9saW8gaW4gYSBzaW5nbGUgZGF0YSBmcmFtZQpmb3IgKGkgaW4gMTpuY29sKHdlaWdodHMpKSB7CiAgcmV0cy52YWx1ZXMgPC0gUmV0dXJuLnBvcnRmb2xpbyhldGYucmV0cy50ZXN0LCB3ZWlnaHRzICA9IHdlaWdodHNbLGldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VhbHRoLmluZGV4ID0gVFJVRSkKICByZXRzPC1jYmluZChyZXRzLHJldHMudmFsdWVzKQp9CgojJyBDb21iaW5lIFJldHVybnMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCmFtb3VudDwtIDEwMDAwCnJldHMuc2NhbGU8LSByZXRzKmFtb3VudApkYXRlIDwtIGFzLkRhdGUoIjIwMjEtMTItMzEiKQppbml0LmludmVzdG1lbnQgPC0geHRzKG1hdHJpeChhbW91bnQsIG5yb3c9MSxuY29sPTQpLCBvcmRlci5ieT1kYXRlKQpyZXRzLnNjYWxlPC0gcmJpbmQoaW5pdC5pbnZlc3RtZW50LCByZXRzLnNjYWxlKQpuYW1lcyhyZXRzLnNjYWxlKSA8LSBjKCJNYXJrb3dpdHoiLCJFcXVhbC1XZWlnaHQiLCJDb3ZhcmlhbmNlLVJvYnVzdCBPcHRpbWl6YXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICJCbGFjayBMaXR0ZXJtYW4iKQoKIycgUGVyZm9ybWFuY2UgLSBDdW11bGF0aXZlIFJldHVybnMgQ2hhcnQKY3VtLnJldHMuY2hhcnQ8LWhpZ2hjaGFydCh0eXBlPSdzdG9jaycpJT4lCiAgaGNfdGl0bGUodGV4dD0nSHlwb3RoZXRpY2FsIEdyb3d0aCBvZiAkMTAsMDAwICcpICU+JQogIGhjX2FkZF9zZXJpZXMocm91bmQocmV0cy5zY2FsZVssMV0sMiksIAogICAgICAgICAgICAgICAgbmFtZT1jb2xuYW1lcyhyZXRzLnNjYWxlKVsxXSklPiUKICBoY19hZGRfc2VyaWVzKHJvdW5kKHJldHMuc2NhbGVbLDJdLDIpLCAKICAgICAgICAgICAgICAgIG5hbWU9Y29sbmFtZXMocmV0cy5zY2FsZSlbMl0pJT4lCiAgaGNfYWRkX3Nlcmllcyhyb3VuZChyZXRzLnNjYWxlWywzXSwyKSwgCiAgICAgICAgICAgICAgICBuYW1lPWNvbG5hbWVzKHJldHMuc2NhbGUpWzNdKSU+JQogIGhjX2FkZF9zZXJpZXMocm91bmQocmV0cy5zY2FsZVssNF0sMiksIAogICAgICAgICAgICAgICAgbmFtZT1jb2xuYW1lcyhyZXRzLnNjYWxlKVs0XSklPiUKICBoY19uYXZpZ2F0b3IoZW5hYmxlZD1GQUxTRSklPiUKICBoY19zY3JvbGxiYXIoZW5hYmxlZD1GQUxTRSkgJT4lCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2ZsYXQoKSklPiUKICBoY19leHBvcnRpbmcoZW5hYmxlZD1UUlVFKSU+JQogIGhjX2xlZ2VuZChlbmFibGVkPVRSVUUpICU+JSAKICBoY19wbG90T3B0aW9ucyhzZXJpZXMgPSBsaXN0KGFuaW1hdGlvbiA9IEZBTFNFKSkKY3VtLnJldHMuY2hhcnQKCgprZXkubWVhc3VyZXM8LSBmdW5jdGlvbiggUmEsIHBvcnQud2VpZ2h0LCBibSwgc2NhbGUgPSAxMixTaWdtYSA9IGNvdihldGYucmV0cyksIFJmPSAwKXsKICByZXQ8LSAgICAgUmV0dXJuLmFubnVhbGl6ZWQoUmEsc2NhbGUgPSBzY2FsZSkgKjEwMAogIGFjdC5yZXQ8LSAgQWN0aXZlUmV0dXJuKFJhICxSYj0gYm0sc2NhbGUgPSBzY2FsZSkgKjEwMAogIGV4LnJldDwtICAgc3VtKFJldHVybi5leGNlc3MoUmEpKSoxMDAgICAjIFJmPSAwIAogICMnIE5vdGUgcmV0ID0gZXgucmV0IHNpbmNlIFJmPTAKICAjJyBUaGF0IGlzLCB0b3RhbCByZXR1cm5zIHNob3VsZCBiZSByb3VnaGx5IGVxdWFsIHRvIGV4Y2VzcyByZXR1cm5zCiAgIycgV2hlcmUgdG90YWwgcmV0dXJucyA9IGFubnVhbGl6ZWQgcmV0dXJucyBpZiB0aGUgaW52ZXN0bWVudCBwZXJpb2QgPCBvciA9IDEgeWVhcgogIAogIHN0LmRldjwtICBTdGREZXYuYW5udWFsaXplZChSYSx3ZWlnaHRzPXBvcnQud2VpZ2h0LHNjYWxlID0gc2NhbGUpICoxMDAKICBiZXRhPC0gQ0FQTS5iZXRhKFJhLGJtKQogIHNoYXJwZTwtICBTaGFycGVSYXRpby5hbm51YWxpemVkKFJhLCBSZj0gUmYsIHNjYWxlID0gc2NhbGUpCiAgdHJleW5vcjwtIFRyZXlub3JSYXRpbyhSYSwgUmIgPSBibSxzY2FsZT1zY2FsZSkKICBpLnJhdGlvPC0gSW5mb3JtYXRpb25SYXRpbyhSYSwgUmIgPSBibSxzY2FsZT1zY2FsZSkKICBtLnNxdWFyZTwtIE1vZGlnbGlhbmkoUmEsIFJiID0gYm0sc2NhbGU9c2NhbGUpCiAgdC5lcnJvcjwtIFRyYWNraW5nRXJyb3IoUmEsIFJiID0gYm0sc2NhbGUgPSBzY2FsZSkKICBkciA8LSAgICAgRlJBUE86OmRyKHBvcnQud2VpZ2h0LCBTaWdtYSApICMgRnVuY3Rpb24gb2J0YWluZWQgZnJvbSBGUkFQTyBwYWNrYWdlCiAgY3IgPC0gICAgIEZSQVBPOjpjcihwb3J0LndlaWdodCwgU2lnbWEpICAjIEZ1bmN0aW9uIG9idGFpbmVkIGZyb20gRlJBUE8gcGFja2FnZQogIHJlczwtICAgICByb3VuZChyYmluZChyZXQsYWN0LnJldCxleC5yZXQsIHN0LmRldixiZXRhLHNoYXJwZSwgdHJleW5vcixtLnNxdWFyZSxpLnJhdGlvLCB0LmVycm9yLCBkcixjciksMykKCiAgcm93bmFtZXMocmVzKSA8LSBjKCJBbm51YWxpemVkIFJldHVybiglKSIsIkFjdGl2ZSBSZXR1cm4oJSkiLCJFeGNlc3MgUmV0dXJuKCUpIiwKICAgICAgICAgICAgICAgICAgICAgJ0FubnVhbGl6ZWQgU3RhbmRhcmQgRGV2aWF0aW9uKCUpJywiQmV0YSIsJ1NoYXJwZScsJ1RyZXlub3InLAogICAgICAgICAgICAgICAgICAiTV4yIG9mIE1vZGlnbGlhbmkiLCAiSW5mb3JtYXRpb24gUmF0aW8iLCJUcmFja2luZyBFcnJvciIsCiAgICAgICAgICAgICAgICAgICJEaXZlcnNpZmljYXRpb24gUmF0aW8iLCJDb25jZW50cmF0aW9uIFJhdGlvIikKICByZXR1cm4ocmVzKQp9CgojJyAgIE5vdGUgdGhlIHBvcnRmb2xpbyBieSBjb25zdHJ1Y3Rpb24gaXMgaW52ZXN0ZWQgaW4gdGhlIG92ZXJhbGwgbWFya2V0LgojJyAgIFRoZSBCZW5jaG1hcmsgdXNlZCBoZXJlIGlzIGEgUHJpY2UtV2VpZ2h0ZWQgaW5kZXguCiMnICAgUHJpY2UtIFdlaWdodGVkIGluZGljZXMgYnkgY29uc3RydWN0aW9uIGF2ZXJhZ2UgcHJpY2VzIGVxdWFsbHkuCiMnICAgY29tcC5pbmQgPSBjb21wb3NpdGUgaW5kZXggcmV0dXJucwoKIycgICBUaGUgbW90aXZhdGlvbiBmb3IgdGhpcyBtdWx0aS1hc3NldCBjb21wb3NpdGUgaW5kZXggaXMgdGhlCiMnICAgRlRTRSBNdWx0aS1Bc3NldCBDb21wb3NpdGUgSW5kZXggU2VyaWVzIHdoaWNoIAojJyAgIGFjY29yZGluZyB0byBGVFNFIFJ1c3NlbGwKIycgICBpcyBkZXNpZ25lZCB0byBtZWFzdXJlIGNyb3NzLWFzc2V0IG1hcmtldCByZXR1cm5zIGZvciBhIHJhbmdlIG9mIHJpc2sgZXhwb3N1cmVzLgoKZXRmLnByaWNlcyRjb21wPC1yb3dNZWFucyhldGYucHJpY2VzKQojJyBDYWxjdWxhdGUgUmV0dXJucyBhbmQgcmVtb3ZlIG5hIHZhbHVlIGluIGZpcnN0IHJvdwojJyBTZWxlY3QgUmV0dXJucyBmcm9tIDIwMjIgCmNvbXAuaW5kIDwtIFJldHVybi5jYWxjdWxhdGUoZXRmLnByaWNlcyRjb21wLG1ldGhvZD0nbG9nJykgJT4lCiAgICAgICAgICAgIG5hLm9taXQoKQpjb21wLmluZDwtIGNvbXAuaW5kWycyMDIyJ10KCiMgcmV0cyA9IHJldHVybnMKcmV0czwtYygpCgojJyBDYWxjdWxhdGUgUmV0dXJucyBvbiBPdXQtb2YtU2FtcGxlIERhdGEgLSBXaXRob3V0IFdlYWx0aCBQcm9ncmVzc2lvbgojJyBDb21iaW5lIHJldHVybnMgb2YgZWFjaCBwb3J0Zm9saW8gaW4gYSBzaW5nbGUgZGF0YSBmcmFtZQpmb3IgKGkgaW4gMTpuY29sKHdlaWdodHMpKSB7CiAgcmV0cy52YWx1ZXMgPC0gUmV0dXJuLnBvcnRmb2xpbyhldGYucmV0cy50ZXN0LCB3ZWlnaHRzICA9IHdlaWdodHNbLGldKQogIHJldHM8LWNiaW5kKHJldHMscmV0cy52YWx1ZXMpCn0KCiMgcG9ydHMgPSBwb3J0Zm9saW9zCnBvcnRzPC1jKCkKIyBDb21iaW5lIHBlcmZvcm1hbmNlIG1lYXN1cmVzIG9mIGVhY2ggcG9ydGZvbGlvIGluIGEgc2luZ2xlIGRhdGEgZnJhbWUKZm9yIChpIGluIDE6bmNvbCh3ZWlnaHRzKSkgewogIG1lYXN1cmVzIDwtIGtleS5tZWFzdXJlcyhwb3J0LndlaWdodCA9IHdlaWdodHNbLGldLCAKICAgICAgICAgICAgICAgICBSYSA9IHJldHNbLGldLCBibSA9ICBjb21wLmluZCkKICBwb3J0czwtY2JpbmQocG9ydHMsbWVhc3VyZXMpCn0KCiMnICBOb3RlIGZvciB0aGUgYmVuY2htYXJrLCBhbGwgd2UgbmVlZCBhcmUgdGhlIGFubnVhbGl6ZWQKIycgIFJldHVybnMsIFN0RGV2LCBhbmQgRXhjZXNzIFJldHVybnMKIycgIFNpbmNlIHRoZSBiZW5jaG1hcmsgaXMgcHJpY2Utd2VpZ2h0ZWQsIHRoZSB3ZWlnaHRzIHVzZWQgaW4gdGhlIGZ1bmN0aW9uIGlzIHRoZSBFcXVhbCBXZWlnaHQKYm0gPC0ga2V5Lm1lYXN1cmVzKHBvcnQud2VpZ2h0ID0gRVcud2VpZ2h0cyR3ZWlnaHRzLCAKICAgICAgICAgICAgICAgICAgUmEgPSBjb21wLmluZCwgYm0gPSAgY29tcC5pbmQpCgprZWVwLnJvd3M8LSBjKCJBbm51YWxpemVkIFJldHVybiglKSIsIkV4Y2VzcyBSZXR1cm4oJSkiLAogICAgICAgICAnQW5udWFsaXplZCBTdGFuZGFyZCBEZXZpYXRpb24oJSknKQojIEFzc2lnbiBOQSB0byB0aG9zZSB2YWx1ZXMgbm90IGluIGtlZXAucm93cwpibVshKGJtICVpbiUgYm1ba2VlcC5yb3dzLF0pLF08LSBOQSAgCmFsbC5wb3J0cyA8LSBjYmluZChwb3J0cyxibSkKCgpjb2xuYW1lcyhhbGwucG9ydHMpIDwtIGFwcGVuZChuYW1lcyhyZXRzLnNjYWxlKSwiQmVuY2htYXJrIikKa25pdHI6OmthYmxlKGFsbC5wb3J0cywKICAgICAgICAgICAgIGNhcHRpb249IlRhYmxlIDIgLSBLZXkgUG9ydGZvbGlvIFBlcmZvcm1hbmNlIE1lYXN1cmVzIikKYGBgCgoKIyMgUmlzayBEZWNvbXBvc2l0aW9uCnwgICAgICAgQXMgYSBjb25jbHVzaW9uIHRvIHRoaXMgYXJ0aWNsZSwgaXQgd291bGQgYmUgdXNlZnVsIHRvIGV4YW1pbmUgaG93IGV4cG9zdXJlcyB0byBpbmRpdmlkdWFsIEVURnMgYWZmZWN0IHRoZSB2YXJpYWJpbGl0eSBwb3J0Zm9saW8gcmV0dXJucyBmb3IgZWFjaCB3ZWlnaHRpbmcgc2NoZW1lLiBUaGlzIGJyZWFrZG93biBvZiBwb3J0Zm9saW8gcmlzayBpbnRvIGNvbnRyaWJ1dGlvbnMgYnkgaW5kaXZpZHVhbCBFVEZzIHdoZW4gY29tYmluZWQgd2l0aCB0aGUgcG9ydGZvbGlvIHdlaWdodHMgc2hvd3Mgd2hldGhlciBoaXN0b3JpY2FsbHkgdGhlIHBvcnRmb2xpbyBoYXMgYmVlbiBvdmVyIG9yIHVuZGVyZXhwb3NlZCB0byBzcGVjaWZpYyBFVEZzLiAKfCAgICAgICBTaG91bGQgb3VyIGh5cG90aGV0aWNhbCBpbnZlc3RvciBkZXNpcmUgdG8gcmUtYWxsb2NhdGUgdGhlaXIgY2FwaXRhbCBhbW9uZyB0aGUgRVRGcyBmb3IgYSBnaXZlbiB3ZWlnaHRpbmcgc2NoZW1lLCB0aGV5IGNhbiB1c2UgdGhpcyByaXNrIGRlY29tcG9zaXRpb24gaW5mb3JtYXRpb24gdG8gaW5jcmVhc2Ugb3IgZGVjcmVhc2UgcG9ydGZvbGlvIGFsbG9jYXRpb24gdG8gc3BlY2lmaWMgRVRGcy4gRm9yIGV4YW1wbGUsIHdoaWxlIHRoZSBTUFkgbWFrZXMgdXAgMjIlIG9mIHRoZSBNYXJrb3dpdHogRVRGIHBvcnRmb2xpbywgaXQgYWNjb3VudHMgZm9yIDM1JSBvZiB0aGUgcG9ydGZvbGlvIHJldHVybiB2b2xhdGlsaXR5LiBPdXIgaW52ZXN0b3IgbWlnaHQgY29uc2lkZXIgcmVkdWNpbmcgZXhwb3N1cmUgdG8gdGhlIFNQWSBvbiB0aGlzIGJhc2lzLgp8ICAgICAgIFRhYmxlIDMgc2hvd3MgdGhlIHJpc2sgZGVjb21wb3NpdGlvbiBvZiBlYWNoIHBvcnRmb2xpbyB3ZWlnaHRpbmcgc2NoZW1lLgpgYGB7ciA0dGgsIGNvbW1lbnQ9TkEsZmlnLmRpbT1jKDgsNiksd2FybmluZz1GQUxTRX0KIyMjIyMgQ29tcG9uZW50IENvbnRyaWJ1dGlvbiB0byBQb3J0Zm9saW8gVm9sYXRpbGl0eS8gU3RhbmRhcmQgRGV2aWF0aW9uCgojICAgV2hhdCBwZXJjZW50YWdlIG9mIHBvcnRmb2xpbyBTdC5EZXYgZGlkIGVhY2ggcG9zaXRpb24gYWNjb3VudCBmb3I/CgphbGwuY29tcHMuc2Q8LWMoKQojIENvbWJpbmUgY29tcG9uZW50IGNvbnRyaWJ1dGlvbnMgb2YgZWFjaCBwb3J0Zm9saW8gaW4gYSBzaW5nbGUgZGF0YSBmcmFtZQpmb3IgKGkgaW4gMTpuY29sKHdlaWdodHMpKSB7CiAgIyBTY2FsZSBieSAxMDAgdG8gZ2V0IHBlcmNlbnQgZnJvbSBkZWNpbWFscyBsaWtlIHNheSAwLjIgdG8gMjAlCiAgU3RkIDwtIChTdGREZXYoZXRmLnJldHMudGVzdCwgd2VpZ2h0cyA9IHdlaWdodHNbLGldLCBwb3J0Zm9saW9fbWV0aG9kPSAgCiAgICAgICAgICAgICAgICAgICJjb21wb25lbnQiKSRwY3RfY29udHJpYl9TdGREZXYpKjEwMAogIGFsbC5jb21wcy5zZDwtY2JpbmQoYWxsLmNvbXBzLnNkLFN0ZCkKfQoKY29sbmFtZXMoYWxsLmNvbXBzLnNkKSA8LSBuYW1lcyhyZXRzLnNjYWxlKQprbml0cjo6a2FibGUoYWxsLmNvbXBzLnNkLAogICAgICAgICAgICAgY2FwdGlvbiA9IlRhYmxlIDMgLSBDb21wb25lbnQgQ29udHJpYnV0aW9uIHRvIFBvcnRmb2xpbyBWb2xhdGlsaXR5LyBTdGFuZGFyZCBEZXZpYXRpb24oJSkiKQpgYGAKCiMjIFJlc291cmNlcyBVc2VkCgpCYWNvbiwgQ2FybCBSLiBQcmFjdGljYWwgUmlzay1BZGp1c3RlZCBQZXJmb3JtYW5jZSBNZWFzdXJlbWVudC4gU2Vjb25kIGVkaXRpb24uIFdpbGV5IEZpbmFuY2UgU2VyaWVzLiBIb2Jva2VuLCBOSjogV2lsZXksIDIwMjIuCgpGYWJvenppLCBGcmFuayBKLiwgYW5kIERlc3Npc2xhdmEgQS4gUGFjaGFtYW5vdmEuIFBvcnRmb2xpbyBDb25zdHJ1Y3Rpb24gYW5kIEFuYWx5dGljcy4gRnJhbmsgSi4gRmFib3p6aSBTZXJpZXMuIEhvYm9rZW4sIE5ldyBKZXJzZXk6IEpvaG4gV2lsZXkgJiBTb25zLCBJbmMsIDIwMTYuCgpCbGFjayBGLCBMaXR0ZXJtYW4gUiAoMTk5MikgR2xvYmFsIHBvcnRmb2xpbyBvcHRpbWl6YXRpb24uIEZpbmFuY2lhbCBBbmFseXN0cyBKLiA0OCg1KToyOOKAkzQzLgoKUm9zZW50aGFsLCBEYWxlIFcuIFIuIEEgUXVhbnRpdGF0aXZlIFByaW1lciBvbiBJbnZlc3RtZW50cyB3aXRoIHIuIENoaWNhZ28sIElMOiBRMzYgTExDLCAyMDE4LgoKSGFycnkgTWFya293aXR6LCAxOTUyLiAiUG9ydGZvbGlvIFNlbGVjdGlvbiwiIEpvdXJuYWwgb2YgRmluYW5jZSwgQW1lcmljYW4gRmluYW5jZSBBc3NvY2lhdGlvbiwgdm9sLiA3KDEpLCBwYWdlcyA3Ny05MSwgTWFyY2guCgpCZW5uZXR0IFJvc3MsIDIwMTguICJDdXN0b20gTW9tZW50IGFuZCBPYmplY3RpdmUgRnVuY3Rpb25zIgoKQWxpIFBhcmRoYW4sIOKAnEludHVpdGl2ZSBFeHBsYW5hdGlvbiBvZiBNaW5pbXVtIENvdmFyaWFuY2UgRGV0ZXJtaW5hbnQgKE1DRCku4oCdIENyb3NzIFZhbGlkYXRlZCwgSnVseSA1LCAyMDIwLiBodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy80NzU2MzYvaW50dWl0aXZlLWV4cGxhbmF0aW9uLW9mLW1pbmltdW0tY292YXJpYW5jZS1kZXRlcm1pbmFudC1tY2QuIAoKQnJpYW4gRy4gUGV0ZXJzb24gYW5kIFBldGVyIENhcmwgKDIwMTgpLiBQb3J0Zm9saW9BbmFseXRpY3M6IFBvcnRmb2xpbyBBbmFseXNpcywKICBJbmNsdWRpbmcgTnVtZXJpY2FsIE1ldGhvZHMgZm9yIE9wdGltaXphdGlvbiBvZiBQb3J0Zm9saW9zLiBSIHBhY2thZ2UgdmVyc2lvbiAxLjEuMC4KICBodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPVBvcnRmb2xpb0FuYWx5dGljcwoKQnJpYW4gRy4gUGV0ZXJzb24gYW5kIFBldGVyIENhcmwgKDIwMjApLiBQZXJmb3JtYW5jZUFuYWx5dGljczogRWNvbm9tZXRyaWMgVG9vbHMgZm9yCiAgUGVyZm9ybWFuY2UgYW5kIFJpc2sgQW5hbHlzaXMuIFIgcGFja2FnZSB2ZXJzaW9uIDIuMC40LgogIGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9UGVyZm9ybWFuY2VBbmFseXRpY3M=