If any issues, questions or suggestions feel free to reach me out via e-mail or Linkedin. You can also visit my Github.

if(!require(pacman)) install.packages('pacman')
pacman::p_load(PolishStock, dplyr, ggplot2)

Assume there are \(N\) assets available with expected returns \(\mu = \left[ \mu_1, \dots, \mu_n \right]^T\) and covariance matrix \(\Sigma = \left[ \sigma_{i,j} \right]^N_{i,j=1}\). Portfolio is defined by weights vector \(\omega = \left[ \omega_1, \dots, \omega_n \right]^T\) such that \(\Sigma_{i=1}^N \omega_i = 1\). Then expected return of the portfolio is \[\mu_R = \omega^T\mu = \Sigma_{i=1}^N \omega_i \mu_i\] and variance of the portfolio is \[\sigma_R^2 = \omega^T \Sigma \omega = \Sigma_{i=1}^N \Sigma_{j=1}^N \omega_i \omega_k \sigma_{ij} \text{.}\] If \(N>2\) then set of attainable portfolios is 2-dimensional plane (assuming assets ain’t perfectly correlated) with convex left edge. Variance minimization problem is either quadratic programming problem (if short sale is forbidden) or using Lagrance multipliers can be reduced to the system of linear equations (if short sale is allowed). However, in this post we will simulate \(10000\) portfolios and select the optimal ones. Optimal means either portfolio with minimal variance or portfolio with maximal Sharpe ratio which is defined \[\text{Sharpe} = \frac{\mu_R - \mu_F}{\sigma_R} \text{,}\] where \(\mu_F\) is risk-free insterest rate. It can be easily verified that when putting \(\sigma_R\) formula into Sharpe ratio formula then lower correlation between asset returns gives us higher Sharpe ratio. In other words, portfolios with high sharpe ratio should be well-diversified.

We will build portfolios from 4 ETFs:
- iShares MSCI Emerging Markets ETF (EEM.US)
- iShares Gold Trust (IAU.US)
- iShares MSCI World ETF (URTH.US)
- iShares TIPS Bond ETF (TIP.US)

We use PolishStock package to download data from the website stooq.pl. Daily data for period January 2012 - February 2022 consists of 2345 observations.

tickers <- c('EEM.US', 'IAU.US', 'URTH.US', 'TIP.US')

for (ticker in tickers){
  stooq_download(ticker, '20120101', '20220228'
                 ,destination = paste0(getwd(), '/datasets/'))
}

close_prices <- df_prices(paste0(tickers, '.csv')
                          ,source = 'datasets/')

returns <- sapply(select(close_prices, -Date)
                  ,FUN = function(x) diff(log(x), lag = 1))

Although in the package PolishStock package there exists a function which does all the steps below (portfolio_simulations(close_prices, 1e4, risk_measure = ‘standard deviation’, risk_free = 0.02)), for educational purposes we write it explicitly below. First we calculate annualized average returns and covariance matrix of ETFs returns. Assume \(2\%\) risk-free interest rate.

mean_returns <- (colMeans(returns) + 1)^252 - 1
cov_returns <- cov(returns) * 252
sd_returns <- diag(cov_returns) %>% sqrt()
rf <- 0.02

We initialize matrix where portoflios weights will be stored and data frame where portfolios return, risk and sharpe ratio will be stored.

weights <- matrix(nrow = num_of_portfolios, ncol = ncol(returns))

portfolio_metrics <- data.frame(
  returns = rep(0, num_of_portfolios)
  ,risk = rep(0, num_of_portfolios)
  ,sharpe = rep(0, num_of_portfolios)
)

We simulate \(10000\) random portfolios with random weights from Uniform[0,1] distribution (which means that short sale is not allowed in our model). We calculate portfolio return, risk and sharpe ratio as explained above.

num_of_portfolios <- 1e4
set.seed(2137)
for (i in 1:num_of_portfolios) {
  
  random_weights <- runif(ncol(weights))
  random_weights <- random_weights / sum(random_weights)
  weights[i, ] <- random_weights
  
  portfolio_metrics$returns[i] <- random_weights %*% mean_returns
  portfolio_metrics$risk[i] <- sqrt(t(random_weights) %*% (cov_returns %*% random_weights))
  portfolio_metrics$sharpe[i] <- (portfolio_metrics$returns[i] - rf) / portfolio_metrics$risk[i]
  
}

Below we see optimal portfolios:
- minimal variance portfolio has only \(3.38\%\) expected annual return and mainly consists of treasury inflation-protected bonds
- maximal sharpe portfolio has \(7.23\%\) expected annual return and almost two times higher standard deviation than minimal variance portfolio. Miximal sharpe portfolio consists of developed markets stocks and treasury inflation-protected bonds in proportion 50:50.

optimal_portfolios <- data.frame(
  Min_Variance = c(
    round(100*weights[which.min(portfolio_metrics$risk),], 2)
    ,round(100*portfolio_metrics[which.min(portfolio_metrics$risk), ], 2) %>% as.numeric()
  )
  ,Max_Sharpe = c(
    round(100*weights[which.max(portfolio_metrics$sharpe),], 2)
    ,round(100*portfolio_metrics[which.max(portfolio_metrics$sharpe), ], 2) %>% as.numeric()
  )
) %>% t() %>% as.data.frame()

colnames(optimal_portfolios) <- c(colnames(returns), 'Expected Return', 'Standard Deviation', 'Sharpe Ratio')
optimal_portfolios

Below we see simulated portfolios on 2-dimensional risk-return plane. Minimal variance portfolio is green triangle and maximal sharpe portfolio is the orange one.

ggplot(portfolio_metrics, aes(x = risk, y = returns, color = sharpe)) +
  geom_point() +
  geom_point(aes(x = (optimal_portfolios$`Standard Deviation`[1] / 100)
                 ,y = (optimal_portfolios$`Expected Return`)[1] / 100)
             ,color = '#2ca02c', size = 5, shape = 17) +
  geom_point(aes(x = (optimal_portfolios$`Standard Deviation`[2] / 100)
                 ,y = (optimal_portfolios$`Expected Return`)[2] / 100)
             ,color = '#ff7f0e', size = 5, shape = 17) + 
  theme_bw()

LS0tDQp0aXRsZTogIlBvcnRmb2xpbyBTaW11bGF0aW9ucyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCklmIGFueSBpc3N1ZXMsIHF1ZXN0aW9ucyBvciBzdWdnZXN0aW9ucyBmZWVsIGZyZWUgdG8gcmVhY2ggbWUgb3V0IHZpYSBlLW1haWwgPHdpZWN6eW5za2lwYXdlbEBnbWFpbC5jb20+IG9yIFtMaW5rZWRpbl0oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL3Bhd2VsLXdpZWN6eW5za2kvKS4gWW91IGNhbiBhbHNvIHZpc2l0IG15IFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXdlbC13aWVjenluc2tpKS4NCg0KYGBge3IgbGlicmFyaWVzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KaWYoIXJlcXVpcmUocGFjbWFuKSkgaW5zdGFsbC5wYWNrYWdlcygncGFjbWFuJykNCnBhY21hbjo6cF9sb2FkKFBvbGlzaFN0b2NrLCBkcGx5ciwgZ2dwbG90MikNCmBgYA0KDQpBc3N1bWUgdGhlcmUgYXJlICROJCBhc3NldHMgYXZhaWxhYmxlIHdpdGggZXhwZWN0ZWQgcmV0dXJucyAkXG11ID0gXGxlZnRbIFxtdV8xLCBcZG90cywgXG11X24gXHJpZ2h0XV5UJCBhbmQgY292YXJpYW5jZSBtYXRyaXggJFxTaWdtYSA9IFxsZWZ0WyBcc2lnbWFfe2ksan0gXHJpZ2h0XV5OX3tpLGo9MX0kLiBQb3J0Zm9saW8gaXMgZGVmaW5lZCBieSB3ZWlnaHRzIHZlY3RvciAkXG9tZWdhID0gXGxlZnRbIFxvbWVnYV8xLCBcZG90cywgXG9tZWdhX24gXHJpZ2h0XV5UJCBzdWNoIHRoYXQgJFxTaWdtYV97aT0xfV5OIFxvbWVnYV9pID0gMSQuIFRoZW4gZXhwZWN0ZWQgcmV0dXJuIG9mIHRoZSBwb3J0Zm9saW8gaXMgJCRcbXVfUiA9IFxvbWVnYV5UXG11ID0gXFNpZ21hX3tpPTF9Xk4gXG9tZWdhX2kgXG11X2kkJCBhbmQgdmFyaWFuY2Ugb2YgdGhlIHBvcnRmb2xpbyBpcyAkJFxzaWdtYV9SXjIgPSBcb21lZ2FeVCBcU2lnbWEgXG9tZWdhID0gXFNpZ21hX3tpPTF9Xk4gXFNpZ21hX3tqPTF9Xk4gXG9tZWdhX2kgXG9tZWdhX2sgXHNpZ21hX3tpan0gXHRleHR7Ln0kJCBJZiAkTj4yJCB0aGVuIHNldCBvZiBhdHRhaW5hYmxlIHBvcnRmb2xpb3MgaXMgMi1kaW1lbnNpb25hbCBwbGFuZSAoYXNzdW1pbmcgYXNzZXRzIGFpbid0IHBlcmZlY3RseSBjb3JyZWxhdGVkKSB3aXRoIGNvbnZleCBsZWZ0IGVkZ2UuIFZhcmlhbmNlIG1pbmltaXphdGlvbiBwcm9ibGVtIGlzIGVpdGhlciBxdWFkcmF0aWMgcHJvZ3JhbW1pbmcgcHJvYmxlbSAoaWYgc2hvcnQgc2FsZSBpcyBmb3JiaWRkZW4pIG9yIHVzaW5nIExhZ3JhbmNlIG11bHRpcGxpZXJzIGNhbiBiZSByZWR1Y2VkIHRvIHRoZSBzeXN0ZW0gb2YgbGluZWFyIGVxdWF0aW9ucyAoaWYgc2hvcnQgc2FsZSBpcyBhbGxvd2VkKS4gSG93ZXZlciwgaW4gdGhpcyBwb3N0IHdlIHdpbGwgc2ltdWxhdGUgJDEwMDAwJCBwb3J0Zm9saW9zIGFuZCBzZWxlY3QgdGhlIG9wdGltYWwgb25lcy4gKk9wdGltYWwqIG1lYW5zIGVpdGhlciBwb3J0Zm9saW8gd2l0aCBtaW5pbWFsIHZhcmlhbmNlIG9yIHBvcnRmb2xpbyB3aXRoIG1heGltYWwgU2hhcnBlIHJhdGlvIHdoaWNoIGlzIGRlZmluZWQgJCRcdGV4dHtTaGFycGV9ID0gXGZyYWN7XG11X1IgLSBcbXVfRn17XHNpZ21hX1J9IFx0ZXh0eyx9JCQgd2hlcmUgJFxtdV9GJCBpcyByaXNrLWZyZWUgaW5zdGVyZXN0IHJhdGUuIEl0IGNhbiBiZSBlYXNpbHkgdmVyaWZpZWQgdGhhdCB3aGVuIHB1dHRpbmcgJFxzaWdtYV9SJCBmb3JtdWxhIGludG8gU2hhcnBlIHJhdGlvIGZvcm11bGEgdGhlbiBsb3dlciBjb3JyZWxhdGlvbiBiZXR3ZWVuIGFzc2V0IHJldHVybnMgZ2l2ZXMgdXMgaGlnaGVyIFNoYXJwZSByYXRpby4gSW4gb3RoZXIgd29yZHMsIHBvcnRmb2xpb3Mgd2l0aCBoaWdoIHNoYXJwZSByYXRpbyBzaG91bGQgYmUgd2VsbC1kaXZlcnNpZmllZC4NCg0KV2Ugd2lsbCBidWlsZCBwb3J0Zm9saW9zIGZyb20gNCBFVEZzOiBcDQogLSBpU2hhcmVzIE1TQ0kgRW1lcmdpbmcgTWFya2V0cyBFVEYgKEVFTS5VUykgXA0KIC0gaVNoYXJlcyBHb2xkIFRydXN0IChJQVUuVVMpIFwNCiAtIGlTaGFyZXMgTVNDSSBXb3JsZCBFVEYgKFVSVEguVVMpIFwNCiAtIGlTaGFyZXMgVElQUyBCb25kIEVURiAoVElQLlVTKQ0KIA0KV2UgdXNlIFtQb2xpc2hTdG9jayBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vcGF3ZWwtd2llY3p5bnNraS9Qb2xpc2hTdG9jaykgdG8gZG93bmxvYWQgZGF0YSBmcm9tIHRoZSB3ZWJzaXRlIFtzdG9vcS5wbF0oaHR0cHM6Ly9zdG9vcS5wbC8pLiBEYWlseSBkYXRhIGZvciBwZXJpb2QgSmFudWFyeSAyMDEyIC0gRmVicnVhcnkgMjAyMiBjb25zaXN0cyBvZiAyMzQ1IG9ic2VydmF0aW9ucy4NCg0KYGBge3IgZ2V0X2RhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0aWNrZXJzIDwtIGMoJ0VFTS5VUycsICdJQVUuVVMnLCAnVVJUSC5VUycsICdUSVAuVVMnKQ0KDQpmb3IgKHRpY2tlciBpbiB0aWNrZXJzKXsNCiAgc3Rvb3FfZG93bmxvYWQodGlja2VyLCAnMjAxMjAxMDEnLCAnMjAyMjAyMjgnDQogICAgICAgICAgICAgICAgICxkZXN0aW5hdGlvbiA9IHBhc3RlMChnZXR3ZCgpLCAnL2RhdGFzZXRzLycpKQ0KfQ0KDQpjbG9zZV9wcmljZXMgPC0gZGZfcHJpY2VzKHBhc3RlMCh0aWNrZXJzLCAnLmNzdicpDQogICAgICAgICAgICAgICAgICAgICAgICAgICxzb3VyY2UgPSAnZGF0YXNldHMvJykNCg0KcmV0dXJucyA8LSBzYXBwbHkoc2VsZWN0KGNsb3NlX3ByaWNlcywgLURhdGUpDQogICAgICAgICAgICAgICAgICAsRlVOID0gZnVuY3Rpb24oeCkgZGlmZihsb2coeCksIGxhZyA9IDEpKQ0KDQpgYGANCg0KQWx0aG91Z2ggaW4gdGhlIHBhY2thZ2UgW1BvbGlzaFN0b2NrIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXdlbC13aWVjenluc2tpL1BvbGlzaFN0b2NrKSB0aGVyZSBleGlzdHMgYSBmdW5jdGlvbiB3aGljaCBkb2VzIGFsbCB0aGUgc3RlcHMgYmVsb3cgKCpwb3J0Zm9saW9fc2ltdWxhdGlvbnMoY2xvc2VfcHJpY2VzLCAxZTQsIHJpc2tfbWVhc3VyZSA9ICdzdGFuZGFyZCBkZXZpYXRpb24nLCByaXNrX2ZyZWUgPSAwLjAyKSopLCBmb3IgZWR1Y2F0aW9uYWwgcHVycG9zZXMgd2Ugd3JpdGUgaXQgZXhwbGljaXRseSBiZWxvdy4gRmlyc3Qgd2UgY2FsY3VsYXRlIGFubnVhbGl6ZWQgYXZlcmFnZSByZXR1cm5zIGFuZCBjb3ZhcmlhbmNlIG1hdHJpeCBvZiBFVEZzIHJldHVybnMuIEFzc3VtZSAkMlwlJCByaXNrLWZyZWUgaW50ZXJlc3QgcmF0ZS4NCmBgYHtyIG1lYW5fYW5kX2NvdmFyaWFuY2V9DQptZWFuX3JldHVybnMgPC0gKGNvbE1lYW5zKHJldHVybnMpICsgMSleMjUyIC0gMQ0KY292X3JldHVybnMgPC0gY292KHJldHVybnMpICogMjUyDQpzZF9yZXR1cm5zIDwtIGRpYWcoY292X3JldHVybnMpICU+JSBzcXJ0KCkNCnJmIDwtIDAuMDINCmBgYA0KDQpXZSBpbml0aWFsaXplIG1hdHJpeCB3aGVyZSBwb3J0b2ZsaW9zIHdlaWdodHMgd2lsbCBiZSBzdG9yZWQgYW5kIGRhdGEgZnJhbWUgd2hlcmUgcG9ydGZvbGlvcyByZXR1cm4sIHJpc2sgYW5kIHNoYXJwZSByYXRpbyB3aWxsIGJlIHN0b3JlZC4NCmBgYHtyIGluaXRpYWxpemVfdGFibGVzfQ0Kd2VpZ2h0cyA8LSBtYXRyaXgobnJvdyA9IG51bV9vZl9wb3J0Zm9saW9zLCBuY29sID0gbmNvbChyZXR1cm5zKSkNCg0KcG9ydGZvbGlvX21ldHJpY3MgPC0gZGF0YS5mcmFtZSgNCiAgcmV0dXJucyA9IHJlcCgwLCBudW1fb2ZfcG9ydGZvbGlvcykNCiAgLHJpc2sgPSByZXAoMCwgbnVtX29mX3BvcnRmb2xpb3MpDQogICxzaGFycGUgPSByZXAoMCwgbnVtX29mX3BvcnRmb2xpb3MpDQopDQpgYGANCg0KV2Ugc2ltdWxhdGUgJDEwMDAwJCByYW5kb20gcG9ydGZvbGlvcyB3aXRoIHJhbmRvbSB3ZWlnaHRzIGZyb20gVW5pZm9ybVswLDFdIGRpc3RyaWJ1dGlvbiAod2hpY2ggbWVhbnMgdGhhdCBzaG9ydCBzYWxlIGlzIG5vdCBhbGxvd2VkIGluIG91ciBtb2RlbCkuIFdlIGNhbGN1bGF0ZSBwb3J0Zm9saW8gcmV0dXJuLCByaXNrIGFuZCBzaGFycGUgcmF0aW8gYXMgZXhwbGFpbmVkIGFib3ZlLg0KYGBge3Igc2ltdWxhdGlvbn0NCm51bV9vZl9wb3J0Zm9saW9zIDwtIDFlNA0Kc2V0LnNlZWQoMjEzNykNCmZvciAoaSBpbiAxOm51bV9vZl9wb3J0Zm9saW9zKSB7DQogIA0KICByYW5kb21fd2VpZ2h0cyA8LSBydW5pZihuY29sKHdlaWdodHMpKQ0KICByYW5kb21fd2VpZ2h0cyA8LSByYW5kb21fd2VpZ2h0cyAvIHN1bShyYW5kb21fd2VpZ2h0cykNCiAgd2VpZ2h0c1tpLCBdIDwtIHJhbmRvbV93ZWlnaHRzDQogIA0KICBwb3J0Zm9saW9fbWV0cmljcyRyZXR1cm5zW2ldIDwtIHJhbmRvbV93ZWlnaHRzICUqJSBtZWFuX3JldHVybnMNCiAgcG9ydGZvbGlvX21ldHJpY3Mkcmlza1tpXSA8LSBzcXJ0KHQocmFuZG9tX3dlaWdodHMpICUqJSAoY292X3JldHVybnMgJSolIHJhbmRvbV93ZWlnaHRzKSkNCiAgcG9ydGZvbGlvX21ldHJpY3Mkc2hhcnBlW2ldIDwtIChwb3J0Zm9saW9fbWV0cmljcyRyZXR1cm5zW2ldIC0gcmYpIC8gcG9ydGZvbGlvX21ldHJpY3Mkcmlza1tpXQ0KICANCn0NCmBgYA0KDQpCZWxvdyB3ZSBzZWUgb3B0aW1hbCBwb3J0Zm9saW9zOiBcDQogLSBtaW5pbWFsIHZhcmlhbmNlIHBvcnRmb2xpbyBoYXMgb25seSAkMy4zOFwlJCBleHBlY3RlZCBhbm51YWwgcmV0dXJuIGFuZCBtYWlubHkgY29uc2lzdHMgb2YgdHJlYXN1cnkgaW5mbGF0aW9uLXByb3RlY3RlZCBib25kcyBcDQogLSBtYXhpbWFsIHNoYXJwZSBwb3J0Zm9saW8gaGFzICQ3LjIzXCUkIGV4cGVjdGVkIGFubnVhbCByZXR1cm4gYW5kIGFsbW9zdCB0d28gdGltZXMgaGlnaGVyIHN0YW5kYXJkIGRldmlhdGlvbiB0aGFuIG1pbmltYWwgdmFyaWFuY2UgcG9ydGZvbGlvLiBNaXhpbWFsIHNoYXJwZSBwb3J0Zm9saW8gY29uc2lzdHMgb2YgZGV2ZWxvcGVkIG1hcmtldHMgc3RvY2tzIGFuZCB0cmVhc3VyeSBpbmZsYXRpb24tcHJvdGVjdGVkIGJvbmRzIGluIHByb3BvcnRpb24gNTA6NTAuDQpgYGB7ciBvcHRpbWFsX3BvcnRmb2xpb3N9DQpvcHRpbWFsX3BvcnRmb2xpb3MgPC0gZGF0YS5mcmFtZSgNCiAgTWluX1ZhcmlhbmNlID0gYygNCiAgICByb3VuZCgxMDAqd2VpZ2h0c1t3aGljaC5taW4ocG9ydGZvbGlvX21ldHJpY3MkcmlzayksXSwgMikNCiAgICAscm91bmQoMTAwKnBvcnRmb2xpb19tZXRyaWNzW3doaWNoLm1pbihwb3J0Zm9saW9fbWV0cmljcyRyaXNrKSwgXSwgMikgJT4lIGFzLm51bWVyaWMoKQ0KICApDQogICxNYXhfU2hhcnBlID0gYygNCiAgICByb3VuZCgxMDAqd2VpZ2h0c1t3aGljaC5tYXgocG9ydGZvbGlvX21ldHJpY3Mkc2hhcnBlKSxdLCAyKQ0KICAgICxyb3VuZCgxMDAqcG9ydGZvbGlvX21ldHJpY3Nbd2hpY2gubWF4KHBvcnRmb2xpb19tZXRyaWNzJHNoYXJwZSksIF0sIDIpICU+JSBhcy5udW1lcmljKCkNCiAgKQ0KKSAlPiUgdCgpICU+JSBhcy5kYXRhLmZyYW1lKCkNCg0KY29sbmFtZXMob3B0aW1hbF9wb3J0Zm9saW9zKSA8LSBjKGNvbG5hbWVzKHJldHVybnMpLCAnRXhwZWN0ZWQgUmV0dXJuJywgJ1N0YW5kYXJkIERldmlhdGlvbicsICdTaGFycGUgUmF0aW8nKQ0Kb3B0aW1hbF9wb3J0Zm9saW9zDQpgYGANCg0KQmVsb3cgd2Ugc2VlIHNpbXVsYXRlZCBwb3J0Zm9saW9zIG9uIDItZGltZW5zaW9uYWwgcmlzay1yZXR1cm4gcGxhbmUuIE1pbmltYWwgdmFyaWFuY2UgcG9ydGZvbGlvIGlzIGdyZWVuIHRyaWFuZ2xlIGFuZCBtYXhpbWFsIHNoYXJwZSBwb3J0Zm9saW8gaXMgdGhlIG9yYW5nZSBvbmUuIA0KYGBge3Igdml6dWFsaXphdGlvbn0NCmdncGxvdChwb3J0Zm9saW9fbWV0cmljcywgYWVzKHggPSByaXNrLCB5ID0gcmV0dXJucywgY29sb3IgPSBzaGFycGUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSAob3B0aW1hbF9wb3J0Zm9saW9zJGBTdGFuZGFyZCBEZXZpYXRpb25gWzFdIC8gMTAwKQ0KICAgICAgICAgICAgICAgICAseSA9IChvcHRpbWFsX3BvcnRmb2xpb3MkYEV4cGVjdGVkIFJldHVybmApWzFdIC8gMTAwKQ0KICAgICAgICAgICAgICxjb2xvciA9ICcjMmNhMDJjJywgc2l6ZSA9IDUsIHNoYXBlID0gMTcpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IChvcHRpbWFsX3BvcnRmb2xpb3MkYFN0YW5kYXJkIERldmlhdGlvbmBbMl0gLyAxMDApDQogICAgICAgICAgICAgICAgICx5ID0gKG9wdGltYWxfcG9ydGZvbGlvcyRgRXhwZWN0ZWQgUmV0dXJuYClbMl0gLyAxMDApDQogICAgICAgICAgICAgLGNvbG9yID0gJyNmZjdmMGUnLCBzaXplID0gNSwgc2hhcGUgPSAxNykgKyANCiAgdGhlbWVfYncoKQ0KYGBg