Challange of Classical Portfolio Selection
Markowitz’s 1952 paper set the foundations for what is now popularly referred to as Modern Portfolio Theory (MPT) and had a profound impact on the financial industry. Individual security selection lay at the heart of the standard investment practice until then. Afterward, the focus shifted toward diversification and assessment of the contribution of individual securities to the risk-return profile of a portfolio. Mean-variance analysis rests on the assumption that rational investors select among risky assets on the basis of expected portfolio return and risk (as measured by the portfolio variance).
The classical approach to asset allocation is a two-step process: In the first step one estimates the parameters for return distribution. In the second stage, portfolio weights using the estimated parameters can be optimized. However, the reputation of this classical approach among practitioners has suffered due to numerous implementation difficulties. Portfolio weights derived from it are notoriously sensitive to the inputs, especially expected returns, and often represent unintuitive or extreme allocations exposing an investor to unintended risks. These inputs (expected returns, variances, and covariances) are all subject to estimation errors that an optimizer picks up and then leverages.
Bayesian Approach for Portfolio Allocation
Bayesian approach provides a way to limit the sensitivity of the final allocation to the input parameters by shrinking the estimate of the market parameters toward the investor’s prior. Using the Bayesian approach to estimation we can naturally identify a suitable uncertainty range for the market parameters, namely the location-dispersion ellipsoid of their posterior distribution. Bayesian allocations are the solutions to a robust optimization problem that uses as uncertainty range the Bayesian location-dispersion ellipsoid.
R Codes and Empirical Results
#===================================================
# Bayesian Approach for Portfolio Selection
#===================================================
#--------------------
# Prepare data
#--------------------
rm(list = ls())
library(tidyverse)
library(tidyquant)
symbols <- c("FB", "AMZN", "NFLX", "GOOG", "^IXIC")
tq_get(x = symbols, from = "2017-01-01", to = "2020-12-31") -> data_raw
data_raw %>%
select(date, symbol, adjusted) %>%
pivot_wider(names_from = symbol, values_from = adjusted) %>%
slice(-which.min(date)) -> data_wide_price
date_ymd <- data_wide_price$date
market_data <- data_wide_price$`^IXIC`
stocks_data <- data_wide_price %>% select(symbols[1:4])
data_raw %>%
filter(symbol %in% symbols[1:4]) %>%
group_by(symbol) %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = "daily",
type = "log",
col_rename = "daily_return") %>%
pivot_wider(names_from = symbol, values_from = daily_return) %>%
slice(-which.min(date)) -> data_wide_return
#--------------------------------------------------------------
# Bayesian Approach for Portfolio Selection/Asset Allocation
#--------------------------------------------------------------
# Remove date column:
data_wide_return %>% select(-date) -> return_wide_train
# Calculate stock mean:
mean_ret <- colMeans(return_wide_train)
# Covariance matrix:
cov_mat <- cov(return_wide_train)
# Number of observations:
T_rows <- nrow(return_wide_train)
# Number of stock symbols:
N <- ncol(return_wide_train)
# Set parameters as proposed by Rachev et al. (2008) at page 106, Baysian Method in Finance:
nu <- N + 2 # (v parameter)
tau <- 500 # (tau parameter)
data_stan <- list(
T_rows = T_rows,
N = N,
nu = nu,
tau = tau,
eta = mean_ret,
R = as.matrix(return_wide_train),
omega = cov_mat * (nu - N -1)
)
# Extract the posterior distribution of sigma:
sigma_post <- list_of_draws$sigma
# Extract the posterior distribution of mu:
mu_post <- list_of_draws$mu
# Function extracts weights by Bayesian Approach:
weights_bayesian <- function(i) {
bayesian_sigma_port <- sigma_post[i, , ]
top_mat <- cbind(2*bayesian_sigma_port, rep(1, N))
bot_vec <- c(rep(1, N), 0)
Am_mat <- rbind(top_mat, bot_vec)
b_vec <- c(rep(0, N), 1)
zm_mat <- solve(Am_mat) %*% b_vec
X_min_var_baysian <- zm_mat[1:N, 1]
return(X_min_var_baysian)
}
# Calculate Bayesian weights:
number_sigmas <- length(sigma_post) / (N*N)
sapply(1:number_sigmas, weights_bayesian) %>%
t() %>%
colMeans() -> bayesian_weights
# Bayesian approach for asset allocation:
bayesian_portfolio <- function(...) {
bayesian_sigma_port <- sigma_post[1, , ]
top_mat <- cbind(2*bayesian_sigma_port, rep(1, N))
bot_vec <- c(rep(1, N), 0)
Am_mat <- rbind(top_mat, bot_vec)
b_vec <- c(rep(0, N), 1)
zm_mat <- solve(Am_mat) %*% b_vec
X_min_var_baysian <- zm_mat[1:N, 1]
return(X_min_var_baysian)
}
# Traditional approach (as proposed by Markowitz) for asset allocation:
markowitz_portfolio <- function(...) {
top_mat <- cbind(2*cov_mat, rep(1, N))
bot_vec <- c(rep(1, N), 0)
Am_mat <- rbind(top_mat, bot_vec)
b_vec <- c(rep(0, N), 1)
zm_mat <- solve(Am_mat) %*% b_vec
X_min_var_markowitz <- zm_mat[1:N, 1]
return(X_min_var_markowitz)
}
#------------------------------------------------------------
# Compare the two methods by Portfolio Backtesting Process
#------------------------------------------------------------
portfolios <- list("Bayesian" = bayesian_portfolio, "Markowitz" = markowitz_portfolio)
library(xts)
xts(stocks_data, order.by = date_ymd) -> stocks_data
xts(market_data, order.by = date_ymd) -> market_data
data <- list(list(adjusted = stocks_data, index = market_data))
library(portfolioBacktest)
bt <- portfolioBacktest(portfolios, data, benchmark = c("uniform", "index"), show_progress_bar = TRUE)
res_sum <- backtestSummary(bt)
res_sum$performance_summary[1:9, 1:2] %>%
as.data.frame() %>%
mutate(Criterion = row.names(.)) %>%
mutate_if(is.numeric, function(x) {round(x, 3)}) %>%
select(Criterion, everything()) -> df_compare
library(kableExtra) # For presenting table.
df_compare %>%
kbl(caption = "Table 1: Portfolio Performance by Approach", escape = TRUE) %>%
kable_classic(full_width = FALSE, html_font = "Cambria")
Table 1: Portfolio Performance by Approach
Criterion
|
Bayesian
|
Markowitz
|
Sharpe ratio
|
0.915
|
0.877
|
max drawdown
|
0.265
|
0.269
|
annual return
|
0.267
|
0.256
|
annual volatility
|
0.292
|
0.292
|
Sterling ratio
|
1.009
|
0.951
|
Omega ratio
|
1.189
|
1.183
|
ROT (bps)
|
1948.218
|
1900.753
|
VaR (0.95)
|
0.031
|
0.031
|
CVaR (0.95)
|
0.045
|
0.045
|
LS0tDQp0aXRsZTogJ1F1YW50aXRhdGl2ZSBGaW5hbmNlOiBCYXllc2lhbiBQb3J0Zm9saW8gU2VsZWN0aW9uJw0KYXV0aG9yOiAnQXV0aG9yOiBOZ3V5ZW4gQ2hpIER1bmcnDQpzdWJ0aXRsZTogIlIgRmluYW5jZSBTZXJpZXMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAjIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogemVuYnVybg0KICAgICMgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogImZsYXRseSINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgY2FjaGUgPSBUUlVFKQ0KDQpgYGANCg0KIyBDaGFsbGFuZ2Ugb2YgQ2xhc3NpY2FsIFBvcnRmb2xpbyBTZWxlY3Rpb24gDQoNCk1hcmtvd2l0euKAmXMgMTk1MiBwYXBlciBzZXQgdGhlIGZvdW5kYXRpb25zIGZvciB3aGF0IGlzIG5vdyBwb3B1bGFybHkgcmVmZXJyZWQgdG8gYXMgKk1vZGVybiBQb3J0Zm9saW8gVGhlb3J5IChNUFQpKiBhbmQgaGFkIGEgcHJvZm91bmQgaW1wYWN0IG9uIHRoZSBmaW5hbmNpYWwgaW5kdXN0cnkuIEluZGl2aWR1YWwgc2VjdXJpdHkgc2VsZWN0aW9uIGxheSBhdCB0aGUgaGVhcnQgb2YgdGhlIHN0YW5kYXJkIGludmVzdG1lbnQgcHJhY3RpY2UgdW50aWwgdGhlbi4gQWZ0ZXJ3YXJkLCB0aGUgZm9jdXMgc2hpZnRlZCB0b3dhcmQgZGl2ZXJzaWZpY2F0aW9uIGFuZCBhc3Nlc3NtZW50IG9mIHRoZSBjb250cmlidXRpb24gb2YgaW5kaXZpZHVhbCBzZWN1cml0aWVzIHRvIHRoZSByaXNrLXJldHVybiBwcm9maWxlIG9mIGEgcG9ydGZvbGlvLiBNZWFuLXZhcmlhbmNlIGFuYWx5c2lzIHJlc3RzIG9uIHRoZSBhc3N1bXB0aW9uIHRoYXQgcmF0aW9uYWwgaW52ZXN0b3JzIHNlbGVjdCBhbW9uZyByaXNreSBhc3NldHMgb24gdGhlIGJhc2lzIG9mIGV4cGVjdGVkIHBvcnRmb2xpbyByZXR1cm4gYW5kIHJpc2sgKGFzIG1lYXN1cmVkIGJ5IHRoZSBwb3J0Zm9saW8gdmFyaWFuY2UpLg0KDQpUaGUgY2xhc3NpY2FsIGFwcHJvYWNoIHRvIGFzc2V0IGFsbG9jYXRpb24gaXMgYSB0d28tc3RlcCBwcm9jZXNzOiBJbiB0aGUgZmlyc3Qgc3RlcCBvbmUgZXN0aW1hdGVzIHRoZSBwYXJhbWV0ZXJzIGZvciByZXR1cm4gZGlzdHJpYnV0aW9uLiBJbiB0aGUgc2Vjb25kIHN0YWdlLCBwb3J0Zm9saW8gd2VpZ2h0cyB1c2luZyB0aGUgZXN0aW1hdGVkIHBhcmFtZXRlcnMgY2FuIGJlIG9wdGltaXplZC4gSG93ZXZlciwgdGhlIHJlcHV0YXRpb24gb2YgdGhpcyBjbGFzc2ljYWwgYXBwcm9hY2ggYW1vbmcgcHJhY3RpdGlvbmVycyBoYXMgc3VmZmVyZWQgZHVlIHRvIG51bWVyb3VzIGltcGxlbWVudGF0aW9uIGRpZmZpY3VsdGllcy4gUG9ydGZvbGlvIHdlaWdodHMgZGVyaXZlZCBmcm9tIGl0IGFyZSBub3RvcmlvdXNseSBzZW5zaXRpdmUgdG8gdGhlIGlucHV0cywgZXNwZWNpYWxseSBleHBlY3RlZCByZXR1cm5zLCBhbmQgb2Z0ZW4gcmVwcmVzZW50IHVuaW50dWl0aXZlIG9yIGV4dHJlbWUgYWxsb2NhdGlvbnMgZXhwb3NpbmcgYW4gaW52ZXN0b3IgdG8gdW5pbnRlbmRlZCByaXNrcy4gVGhlc2UgaW5wdXRzIChleHBlY3RlZCByZXR1cm5zLCB2YXJpYW5jZXMsIGFuZCBjb3ZhcmlhbmNlcykgYXJlIGFsbCBzdWJqZWN0IHRvIGVzdGltYXRpb24gZXJyb3JzIHRoYXQgYW4gb3B0aW1pemVyIHBpY2tzIHVwIGFuZCB0aGVuIGxldmVyYWdlcy4NCg0KIyBCYXllc2lhbiBBcHByb2FjaCBmb3IgUG9ydGZvbGlvIEFsbG9jYXRpb24NCg0KQmF5ZXNpYW4gYXBwcm9hY2ggcHJvdmlkZXMgYSB3YXkgdG8gbGltaXQgdGhlIHNlbnNpdGl2aXR5IG9mIHRoZSBmaW5hbCBhbGxvY2F0aW9uIHRvIHRoZSBpbnB1dCBwYXJhbWV0ZXJzIGJ5IHNocmlua2luZyB0aGUgZXN0aW1hdGUgb2YgdGhlIG1hcmtldCBwYXJhbWV0ZXJzIHRvd2FyZCB0aGUgaW52ZXN0b3LigJlzIHByaW9yLiBVc2luZyB0aGUgQmF5ZXNpYW4gYXBwcm9hY2ggdG8gZXN0aW1hdGlvbiB3ZSBjYW4gbmF0dXJhbGx5IGlkZW50aWZ5IGEgc3VpdGFibGUgdW5jZXJ0YWludHkgcmFuZ2UgZm9yIHRoZSBtYXJrZXQgcGFyYW1ldGVycywgbmFtZWx5IHRoZSBsb2NhdGlvbi1kaXNwZXJzaW9uIGVsbGlwc29pZCBvZiB0aGVpciBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uLiBCYXllc2lhbiBhbGxvY2F0aW9ucyBhcmUgdGhlIHNvbHV0aW9ucyB0byBhIHJvYnVzdCBvcHRpbWl6YXRpb24gcHJvYmxlbSB0aGF0IHVzZXMgYXMgdW5jZXJ0YWludHkgcmFuZ2UgdGhlIEJheWVzaWFuIGxvY2F0aW9uLWRpc3BlcnNpb24gZWxsaXBzb2lkLg0KDQojIFIgQ29kZXMgYW5kIEVtcGlyaWNhbCBSZXN1bHRzDQoNCmBgYHtyfQ0KDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgIEJheWVzaWFuIEFwcHJvYWNoIGZvciBQb3J0Zm9saW8gU2VsZWN0aW9uDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgICBQcmVwYXJlIGRhdGENCiMtLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpybShsaXN0ID0gbHMoKSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5cXVhbnQpDQoNCnN5bWJvbHMgPC0gYygiRkIiLCAiQU1aTiIsICJORkxYIiwgIkdPT0ciLCAiXklYSUMiKQ0KDQp0cV9nZXQoeCA9IHN5bWJvbHMsIGZyb20gPSAiMjAxNy0wMS0wMSIsIHRvID0gIjIwMjAtMTItMzEiKSAtPiBkYXRhX3Jhdw0KDQpkYXRhX3JhdyAlPiUgDQogIHNlbGVjdChkYXRlLCBzeW1ib2wsIGFkanVzdGVkKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzeW1ib2wsIHZhbHVlc19mcm9tID0gYWRqdXN0ZWQpICU+JSANCiAgc2xpY2UoLXdoaWNoLm1pbihkYXRlKSkgLT4gZGF0YV93aWRlX3ByaWNlDQoNCmRhdGVfeW1kIDwtIGRhdGFfd2lkZV9wcmljZSRkYXRlDQptYXJrZXRfZGF0YSA8LSBkYXRhX3dpZGVfcHJpY2UkYF5JWElDYA0Kc3RvY2tzX2RhdGEgPC0gZGF0YV93aWRlX3ByaWNlICU+JSBzZWxlY3Qoc3ltYm9sc1sxOjRdKQ0KDQpkYXRhX3JhdyAlPiUNCiAgZmlsdGVyKHN5bWJvbCAlaW4lIHN5bWJvbHNbMTo0XSkgJT4lIA0KICBncm91cF9ieShzeW1ib2wpICU+JQ0KICB0cV90cmFuc211dGUoc2VsZWN0ID0gYWRqdXN0ZWQsIA0KICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwgDQogICAgICAgICAgICAgICBwZXJpb2QgPSAiZGFpbHkiLCANCiAgICAgICAgICAgICAgIHR5cGUgPSAibG9nIiwNCiAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAiZGFpbHlfcmV0dXJuIikgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc3ltYm9sLCB2YWx1ZXNfZnJvbSA9IGRhaWx5X3JldHVybikgJT4lIA0KICBzbGljZSgtd2hpY2gubWluKGRhdGUpKSAtPiBkYXRhX3dpZGVfcmV0dXJuDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgQmF5ZXNpYW4gQXBwcm9hY2ggZm9yIFBvcnRmb2xpbyBTZWxlY3Rpb24vQXNzZXQgQWxsb2NhdGlvbg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgUmVtb3ZlIGRhdGUgY29sdW1uOiANCg0KZGF0YV93aWRlX3JldHVybiAlPiUgc2VsZWN0KC1kYXRlKSAtPiByZXR1cm5fd2lkZV90cmFpbg0KDQojIENhbGN1bGF0ZSBzdG9jayBtZWFuOiANCm1lYW5fcmV0IDwtIGNvbE1lYW5zKHJldHVybl93aWRlX3RyYWluKSANCg0KIyBDb3ZhcmlhbmNlIG1hdHJpeDogDQoNCmNvdl9tYXQgPC0gY292KHJldHVybl93aWRlX3RyYWluKQ0KDQojIE51bWJlciBvZiBvYnNlcnZhdGlvbnM6IA0KVF9yb3dzIDwtIG5yb3cocmV0dXJuX3dpZGVfdHJhaW4pDQoNCiMgTnVtYmVyIG9mIHN0b2NrIHN5bWJvbHM6IA0KTiA8LSBuY29sKHJldHVybl93aWRlX3RyYWluKQ0KDQojIFNldCBwYXJhbWV0ZXJzIGFzIHByb3Bvc2VkIGJ5IFJhY2hldiBldCBhbC4gKDIwMDgpIGF0IHBhZ2UgMTA2LCBCYXlzaWFuIE1ldGhvZCBpbiBGaW5hbmNlOiANCg0KbnUgPC0gTiArIDIgIyAodiBwYXJhbWV0ZXIpDQp0YXUgPC0gNTAwICMgKHRhdSBwYXJhbWV0ZXIpDQoNCmRhdGFfc3RhbiA8LSBsaXN0KA0KICBUX3Jvd3MgPSBUX3Jvd3MsDQogIE4gPSBOLA0KICBudSA9IG51LA0KICB0YXUgPSB0YXUsDQogIGV0YSA9IG1lYW5fcmV0LA0KICBSID0gYXMubWF0cml4KHJldHVybl93aWRlX3RyYWluKSwNCiAgb21lZ2EgPSBjb3ZfbWF0ICogKG51IC0gTiAtMSkNCikNCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBTdGFuIGNvZGVzIChkb3dubG9hZCBmcm9tIGh0dHBzOi8vd3d3Lm1lZGlhZmlyZS5jb20vZmlsZS83cTdjemNlOGR0cng1NmovbXlfc3Rhbl9jb2Rlc19iYXllc2lhbl9wb3Iuc3Rhbi9maWxlKTogDQpkYXRhIHsNCiAgLy81IGlzIGFyYml0cmFyeQ0KICBpbnQ8bG93ZXIgPSA1PiBUX3Jvd3M7DQogIGludDxsb3dlciA9IDI+IE47DQogIHJlYWw8bG93ZXIgPSBOIC0gMT4gbnU7DQogIHJlYWw8bG93ZXIgPSAwPiB0YXU7DQogIHZlY3RvcltOXSBldGE7DQogIG1hdHJpeFtUX3Jvd3MsIE5dIFI7DQogIGNvdl9tYXRyaXhbTl0gb21lZ2E7DQp9DQoNCnBhcmFtZXRlcnMgew0KICB2ZWN0b3JbTl0gbXU7DQogIGNvdl9tYXRyaXhbTl0gc2lnbWE7DQp9DQoNCnRyYW5zZm9ybWVkIHBhcmFtZXRlcnN7DQogIGNvdl9tYXRyaXhbTl0gc2lnbWFfc2NhbGVkOw0KICBzaWdtYV9zY2FsZWQgPSAoMSAvIHRhdSkgKiBzaWdtYTsNCn0NCg0KbW9kZWwgew0KICANCiAgdGFyZ2V0ICs9IGludl93aXNoYXJ0X2xwZGYoc2lnbWEgfCBudSwgb21lZ2EpOw0KICB0YXJnZXQgKz0gbXVsdGlfbm9ybWFsX2xwZGYobXUgfCBldGEsIHNpZ21hX3NjYWxlZCk7DQogIGZvcih0IGluIDE6VF9yb3dzKXsNCiAgICB0YXJnZXQgKz0gbXVsdGlfbm9ybWFsX2xwZGYoUlt0XXwgbXUsIHNpZ21hKTsNCiAgfQ0KICANCn0NCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0NCg0KIyBGaXR0aW5nIHRoZSBtb2RlbDogDQoNCmxpYnJhcnkocnN0YW4pDQoNCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkNCg0KcnN0YW5fb3B0aW9ucyhhdXRvX3dyaXRlID0gVFJVRSkNCg0KIyBTZXQgdGhlIG51bWJlciBvZiBNYXJrb3YgY2hhaW5zOiANCmNoYWlucyA8LSBOICsgMg0KDQojIFNldCB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgZm9yIGVhY2ggY2hhaW46IA0KaXRlciA8LSAyMDAwDQoNCiMgTm8tVS1UdXJuIHNhbXBsZXIgdmFyaWFudCBvZiBIYW1pbHRvbmlhbiBNb250ZSBDYXJsbyANCiMgKEhvZmZtYW4gYW5kIEdlbG1hbiAyMDExLCBCZXRhbmNvdXJ0IDIwMTcpIHByb2Nlc3M6IA0KDQpteV9hbGdvcml0aG0gPC0gIk5VVFMiDQoNCiMgRml0IEJheWVzaWFuIFByb2Nlc3M6IA0KDQpzeXN0ZW0udGltZSgNCiAgZml0IDwtIHN0YW4oDQogICAgZmlsZSA9ICJDOi9Vc2Vycy9BRE1JTi9Eb2N1bWVudHMvbXlfc3Rhbl9jb2Rlc19iYXllc2lhbl9wb3Iuc3RhbiIsDQogICAgZGF0YSA9IGRhdGFfc3RhbiwNCiAgICBhbGdvcml0aG0gPSBteV9hbGdvcml0aG0sIA0KICAgIGNoYWlucyA9IGNoYWlucywNCiAgICB3YXJtdXAgPSBpdGVyIC8gMiwNCiAgICBpdGVyID0gaXRlciwNCiAgICBzZWVkID0gMjksIA0KICAgIHZlcmJvc2UgPSBUUlVFDQogICkNCikNCg0KDQpsaXN0X29mX2RyYXdzIDwtIHJzdGFuOjpleHRyYWN0KGZpdCkNCg0KIyBzYXZlUkRTKGxpc3Rfb2ZfZHJhd3MsIGZpbGUgPSAibGlzdF9vZl9kcmF3cy5SZHMiKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQpsaXN0X29mX2RyYXdzIDwtIHJlYWRSRFMoZmlsZSA9ICJDOi9Vc2Vycy9BRE1JTi9Eb2N1bWVudHMvbGlzdF9vZl9kcmF3cy5SZHMiKQ0KYGBgDQoNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCg0KIyBFeHRyYWN0IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIG9mIHNpZ21hOiANCg0Kc2lnbWFfcG9zdCA8LSBsaXN0X29mX2RyYXdzJHNpZ21hDQoNCiMgRXh0cmFjdCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBvZiBtdTogDQoNCm11X3Bvc3QgPC0gbGlzdF9vZl9kcmF3cyRtdQ0KDQojIEZ1bmN0aW9uIGV4dHJhY3RzIHdlaWdodHMgYnkgQmF5ZXNpYW4gQXBwcm9hY2g6IA0KDQp3ZWlnaHRzX2JheWVzaWFuIDwtIGZ1bmN0aW9uKGkpIHsNCiAgDQogIGJheWVzaWFuX3NpZ21hX3BvcnQgPC0gc2lnbWFfcG9zdFtpLCAsIF0NCiAgDQogIHRvcF9tYXQgPC0gY2JpbmQoMipiYXllc2lhbl9zaWdtYV9wb3J0LCByZXAoMSwgTikpDQogIA0KICBib3RfdmVjIDwtIGMocmVwKDEsIE4pLCAwKQ0KICANCiAgQW1fbWF0IDwtIHJiaW5kKHRvcF9tYXQsIGJvdF92ZWMpDQogIA0KICBiX3ZlYyA8LSBjKHJlcCgwLCBOKSwgMSkNCiAgDQogIHptX21hdCA8LSBzb2x2ZShBbV9tYXQpICUqJSBiX3ZlYw0KICANCiAgWF9taW5fdmFyX2JheXNpYW4gPC0gem1fbWF0WzE6TiwgMV0NCiAgDQogIHJldHVybihYX21pbl92YXJfYmF5c2lhbikNCn0NCg0KDQojIENhbGN1bGF0ZSBCYXllc2lhbiB3ZWlnaHRzOiANCg0KbnVtYmVyX3NpZ21hcyA8LSBsZW5ndGgoc2lnbWFfcG9zdCkgLyAoTipOKQ0KDQpzYXBwbHkoMTpudW1iZXJfc2lnbWFzLCB3ZWlnaHRzX2JheWVzaWFuKSAlPiUgDQogIHQoKSAlPiUgDQogIGNvbE1lYW5zKCkgLT4gYmF5ZXNpYW5fd2VpZ2h0cw0KDQojIEJheWVzaWFuIGFwcHJvYWNoIGZvciBhc3NldCBhbGxvY2F0aW9uOiANCg0KYmF5ZXNpYW5fcG9ydGZvbGlvIDwtIGZ1bmN0aW9uKC4uLikgew0KICANCiAgYmF5ZXNpYW5fc2lnbWFfcG9ydCA8LSBzaWdtYV9wb3N0WzEsICwgXQ0KICANCiAgdG9wX21hdCA8LSBjYmluZCgyKmJheWVzaWFuX3NpZ21hX3BvcnQsIHJlcCgxLCBOKSkNCiAgDQogIGJvdF92ZWMgPC0gYyhyZXAoMSwgTiksIDApDQogIA0KICBBbV9tYXQgPC0gcmJpbmQodG9wX21hdCwgYm90X3ZlYykNCiAgDQogIGJfdmVjIDwtIGMocmVwKDAsIE4pLCAxKQ0KICANCiAgem1fbWF0IDwtIHNvbHZlKEFtX21hdCkgJSolIGJfdmVjDQogIA0KICBYX21pbl92YXJfYmF5c2lhbiA8LSB6bV9tYXRbMTpOLCAxXQ0KICANCiAgcmV0dXJuKFhfbWluX3Zhcl9iYXlzaWFuKQ0KfQ0KDQoNCiMgVHJhZGl0aW9uYWwgYXBwcm9hY2ggKGFzIHByb3Bvc2VkIGJ5IE1hcmtvd2l0eikgZm9yIGFzc2V0IGFsbG9jYXRpb246IA0KDQptYXJrb3dpdHpfcG9ydGZvbGlvIDwtIGZ1bmN0aW9uKC4uLikgew0KICANCiAgdG9wX21hdCA8LSBjYmluZCgyKmNvdl9tYXQsIHJlcCgxLCBOKSkNCiAgDQogIGJvdF92ZWMgPC0gYyhyZXAoMSwgTiksIDApDQogIA0KICBBbV9tYXQgPC0gcmJpbmQodG9wX21hdCwgYm90X3ZlYykNCiAgDQogIGJfdmVjIDwtIGMocmVwKDAsIE4pLCAxKQ0KICANCiAgem1fbWF0IDwtIHNvbHZlKEFtX21hdCkgJSolIGJfdmVjDQogIA0KICBYX21pbl92YXJfbWFya293aXR6IDwtIHptX21hdFsxOk4sIDFdDQogIA0KICByZXR1cm4oWF9taW5fdmFyX21hcmtvd2l0eikNCg0KfQ0KDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIENvbXBhcmUgdGhlIHR3byBtZXRob2RzIGJ5IFBvcnRmb2xpbyBCYWNrdGVzdGluZyBQcm9jZXNzDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KcG9ydGZvbGlvcyA8LSBsaXN0KCJCYXllc2lhbiIgPSBiYXllc2lhbl9wb3J0Zm9saW8sICJNYXJrb3dpdHoiID0gbWFya293aXR6X3BvcnRmb2xpbykNCg0KbGlicmFyeSh4dHMpDQoNCnh0cyhzdG9ja3NfZGF0YSwgb3JkZXIuYnkgPSBkYXRlX3ltZCkgLT4gc3RvY2tzX2RhdGENCnh0cyhtYXJrZXRfZGF0YSwgb3JkZXIuYnkgPSBkYXRlX3ltZCkgLT4gbWFya2V0X2RhdGENCg0KDQpkYXRhIDwtIGxpc3QobGlzdChhZGp1c3RlZCA9IHN0b2Nrc19kYXRhLCBpbmRleCA9IG1hcmtldF9kYXRhKSkNCg0KbGlicmFyeShwb3J0Zm9saW9CYWNrdGVzdCkNCmJ0IDwtIHBvcnRmb2xpb0JhY2t0ZXN0KHBvcnRmb2xpb3MsIGRhdGEsIGJlbmNobWFyayA9IGMoInVuaWZvcm0iLCAiaW5kZXgiKSwgc2hvd19wcm9ncmVzc19iYXIgPSBUUlVFKQ0KDQpyZXNfc3VtIDwtIGJhY2t0ZXN0U3VtbWFyeShidCkNCg0KcmVzX3N1bSRwZXJmb3JtYW5jZV9zdW1tYXJ5WzE6OSwgMToyXSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogIG11dGF0ZShDcml0ZXJpb24gPSByb3cubmFtZXMoLikpICU+JSANCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bmN0aW9uKHgpIHtyb3VuZCh4LCAzKX0pICU+JSANCiAgc2VsZWN0KENyaXRlcmlvbiwgZXZlcnl0aGluZygpKSAtPiBkZl9jb21wYXJlDQoNCg0KbGlicmFyeShrYWJsZUV4dHJhKSAjIEZvciBwcmVzZW50aW5nIHRhYmxlLiANCg0KZGZfY29tcGFyZSAlPiUgDQogIGtibChjYXB0aW9uID0gIlRhYmxlIDE6IFBvcnRmb2xpbyBQZXJmb3JtYW5jZSBieSBBcHByb2FjaCIsIGVzY2FwZSA9IFRSVUUpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGQUxTRSwgaHRtbF9mb250ID0gIkNhbWJyaWEiKQ0KDQojIGJhY2t0ZXN0Q2hhcnRDdW1SZXR1cm5zKGJ0LCBjKCJCYXllc2lhbiIsICJNYXJrb3dpdHoiKSkNCg0KYnQkQmF5ZXNpYW4kZGF0YTEkcmV0dXJuICU+JSBjdW1zdW0oKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogIG11dGF0ZShkYXRlX3ltZCA9IHJvdy5uYW1lcyguKSAlPiUgeW1kKCkpICU+JSANCiAgcmVuYW1lKEN1bVJldHVybiA9IGBwb3J0Zm9saW8gcmV0dXJuYCkgJT4lIA0KICBtdXRhdGUoQXBwcm9hY2ggPSAiQmF5ZXNpYW4iKSAtPiBkZjENCg0KYnQkTWFya293aXR6JGRhdGExJHJldHVybiAlPiUgY3Vtc3VtKCkgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBtdXRhdGUoZGF0ZV95bWQgPSByb3cubmFtZXMoLikgJT4lIHltZCgpKSAlPiUgDQogIHJlbmFtZShDdW1SZXR1cm4gPSBgcG9ydGZvbGlvIHJldHVybmApICU+JSANCiAgbXV0YXRlKEFwcHJvYWNoICA9ICJNYXJrb3dpdHoiKSAtPiBkZjINCg0KYmluZF9yb3dzKGRmMSwgZGYyKSAtPiBkZg0KDQpkZiAlPiUgDQogIG11dGF0ZShDdW1SZXR1cm4gPSByb3VuZChDdW1SZXR1cm4sIDMpLCBEYXRlID0gZGF0ZV95bWQpICU+JSANCiAgZ2dwbG90KGFlcyhEYXRlLCBDdW1SZXR1cm4sIGNvbG9yID0gQXBwcm9hY2gpKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAxOiBEYWlseSBDdW1tdWxhdGl2ZSBSZXR1cm4gYnkgQXBwcm9hY2giKSAtPiBwDQoNCnBsb3RseTo6Z2dwbG90bHkocCkNCg0KDQpgYGANCg0K