#install.packages("tseries")
library("tseries")
library("quantmod")
#install.packages('Quandl')
library("Quandl")
#install.packages("quantmod")
library("quantmod")
#install.packages("PortfolioAnalytics")
library("PortfolioAnalytics")
#install.packages("DEoptim")
library("DEoptim")
library("xts")
#install.packages("knitr")
#library("knitr")

# Reading of Data
data <- read.csv("data_final.csv", header = T)
data <- xts(data[ ,2:5], order.by = as.Date.factor(data[,1]))  
View(data)

# Indian Stocks from Bse Index
indian_stocks <- data[,1]
m_indian_stocks <- monthlyReturn(indian_stocks, type = "arithmetic")
colnames(indian_stocks) <- "m_indian_stocks"
table.AnnualizedReturns(m_indian_stocks)
charts.PerformanceSummary(m_indian_stocks)


# Indian Bonds

indian_bonds <- data[,2]
m_indian_bonds <- monthlyReturn(indian_bonds)
colnames(indian_bonds) <- "m_indian_bonds"
table.AnnualizedReturns(m_indian_bonds)
charts.PerformanceSummary(m_indian_bonds)


# International stocks

international_stock <- data[,3]
m_international_stock <- monthlyReturn(international_stock)
colnames(international_stock) <- "m_international_stock"
table.AnnualizedReturns(m_international_stock)
charts.PerformanceSummary(m_international_stock)



# International Bonds
international_bonds <- data[,4]
m_international_bond <- monthlyReturn(international_bonds)
colnames(international_bonds) <- "m_international_bond"
table.AnnualizedReturns(m_international_bond)
charts.PerformanceSummary(m_international_bond)


# Bonds Compare
bondscomp <- cbind(m_indian_bonds,m_international_bond)
table.AnnualizedReturns(bondscomp)
charts.PerformanceSummary(bondscomp)


# stocks Compare

stockcomp <- cbind(m_indian_stocks,m_international_stock)
table.AnnualizedReturns(stockcomp)
charts.PerformanceSummary(stockcomp)


# 4. Portfolio Optimization

# 4.1. Portfolio Performance Metrics

# 4.1.1. Sharpe Ratio 
#msharpe <- SharpeRatio(mlstocks,Rf=mean(mcash))
#msharpe

# 4.1.2. Treynor Ratio
#mtreynor <- TreynorRatio(Ra=mlstocks,Rb=mstocks,Rf=mean(mcash))
#mtreynor

# 4.2. Portfolio Benchmarks 

# 4.2.1. Portfolio Assets Returns Matrix
mport <- cbind(m_indian_stocks,m_international_stock,m_indian_bonds, m_international_stock)

# 4.2.2. Naive Global Portfolio (Monthly Rebalancing)
mnaivew <- as.numeric(t(c(0.25,0.25,0.25,0.25)))
names(mnaivew) <- c("m_indian_stocks","m_international_stock","m_indian_bonds","m_international_stock")
mnaive <- Return.portfolio(R=mport,weights=mnaivew,geometric=F,rebalance_on="months")
colnames(mnaive) <- "mnaive"

# 4.2.3. Roche Global Portfolio (Monthly Rebalancing)
mrochew <- as.numeric(t(c(0.24,0.18,0.33,0.25)))
names(mrochew) <- c("m_indian_stocks","m_international_stock","m_indian_bonds","m_international_stock")
mroche <- Return.portfolio(R=mport,weights=mrochew,geometric=F,rebalance_on="months")
colnames(mroche) <- "mroche"

# 4.2.4. Bogle U.S. Portfolio (Monthly Rebalancing)
mboglew <- as.numeric(t(c(0.40,0.60,0.00,0.00)))
names(mboglew) <- c("m_indian_stocks","m_international_stock","m_indian_bonds","m_international_stock")
mbogle <- Return.portfolio(R=mport,weights=mboglew,geometric=F,rebalance_on="months")
colnames(mbogle) <- "mbogle"

# 4.2.6. Benchmark Portfolios Returns Comparison
benchcomp <- cbind(mnaive,mroche,mbogle)
table.AnnualizedReturns(benchcomp)
charts.PerformanceSummary(benchcomp)


# 4.3. Portfolio Optimization 

# 4.3.1. Mean Maximization 

# Portfolio Specifications
mport1c <- portfolio.spec(assets = colnames(mport))

# Portfolio Constraints
mport1c <- add.constraint(mport1c,type="weight_sum",min_sum=0.99,max_sum=1.01)
mport1c <- add.constraint(mport1c,type="long_only")

# Portfolio Objectives
mport1c <- add.objective(mport1c,type="return",name="mean")

# Portfolio Optimization
mportopt1 <- optimize.portfolio(R=mport["::2021-12-31"],portfolio=mport1c,optimize_method="DEoptim",search_size=20000,trace=T )
Iteration: 1 bestvalit: -0.012355 bestmemit:    0.002000    0.688000    0.010000    0.308000
Iteration: 2 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 3 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 4 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 5 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 6 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 7 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 8 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
Iteration: 9 bestvalit: -0.012412 bestmemit:    0.012000    0.038000    0.000000    0.960000
[1] 0.012 0.038 0.000 0.960
chart.Weights(mportopt1)


# 4.3.2. Standard deviation minimization

# Portfolio Specifications
mport2c <- portfolio.spec(assets=colnames(mport))

# Portfolio Constraints
mport2c <- add.constraint(mport2c,type="weight_sum",min_sum=0.99,max_sum=1.01)
mport2c <- add.constraint(mport2c,type="long_only")

# Portfolio Objectives
mport2c <- add.objective(mport2c,type="risk",name="StdDev")

# Portfolio Optimization
mportopt2 <- optimize.portfolio(R=mport["::2021-12-31"],portfolio=mport2c,optimize_method="DEoptim",search_size=20000,trace=T)
Iteration: 1 bestvalit: 0.000913 bestmemit:    0.010000    0.000000    0.978000    0.006000
Iteration: 2 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 3 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 4 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 5 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 6 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 7 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 8 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
Iteration: 9 bestvalit: 0.000875 bestmemit:    0.010000    0.000000    0.978000    0.004279
[1] 0.010000000 0.000000000 0.978000000
[4] 0.004278807
chart.Weights(mportopt2)


# 4.3.3. Mean Maximization and Standard Deviation Minimization Portfolio

# Portfolio Specifications
mport3c <- portfolio.spec(assets=colnames(mport))

# Portfolio Constraints
mport3c <- add.constraint(mport3c,type="weight_sum",min_sum=0.99,max_sum=1.01)
mport3c <- add.constraint(mport3c,type="long_only")

# Portfolio Objectives
mport3c <- add.objective(mport3c,type="return",name="mean")
mport3c <- add.objective(mport3c,type="risk",name="StdDev")

# Portfolio Optimization
mportopt3 <- optimize.portfolio(R=mport["::2021-12-31"],portfolio=mport3c,optimize_method="DEoptim",search_size=20000,trace=T)
Iteration: 1 bestvalit: -0.004148 bestmemit:    0.018000    0.068000    0.904000    0.000000
Iteration: 2 bestvalit: -0.004148 bestmemit:    0.018000    0.068000    0.904000    0.000000
Iteration: 3 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 4 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 5 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 6 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 7 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 8 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 9 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
Iteration: 10 bestvalit: -0.006212 bestmemit:    0.006000    0.012000    0.986000    0.006000
[1] 0.006 0.012 0.986 0.006
chart.Weights(mportopt3)

chart.EfficientFrontier(mportopt3,match.col="StdDev")


# 4.3.4. Mean Maximization Value at Risk (VaR) Minimization Portfolio

# Portfolio Specifications
mport4c <- portfolio.spec(assets=colnames(mport))

# Portfolio Constraints
mport4c <- add.constraint(mport4c,type="weight_sum",min_sum=0.99,max_sum=1.01)
mport4c <- add.constraint(mport4c,type="long_only")

# Portfolio Objectives
mport4c <- add.objective(mport4c,type="return",name="mean")
mport4c <- add.objective(mport4c,type="risk",name="VaR",arguments=list(p = 0.99,method="modified"))

# Portfolio Optimization
mportopt4 <- optimize.portfolio(R=mport["::2021-12-31"],portfolio=mport4c,optimize_method="DEoptim",search_size=20000,trace=T)
Iteration: 1 bestvalit: 0.002548 bestmemit:    0.094000    0.008000    0.898000    0.006000
Iteration: 2 bestvalit: 0.002548 bestmemit:    0.094000    0.008000    0.898000    0.006000
Iteration: 3 bestvalit: -0.003647 bestmemit:    0.030000    0.058000    0.920000    0.002000
Iteration: 4 bestvalit: -0.003647 bestmemit:    0.030000    0.058000    0.920000    0.002000
Iteration: 5 bestvalit: -0.005864 bestmemit:    0.000000    0.030000    0.926000    0.052000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.00157553045118132
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.00800.9580.024
Iteration: 6 bestvalit: -0.005864 bestmemit:    0.000000    0.030000    0.926000    0.052000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -6.90829274658297e-05
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.03800.9540.002
Iteration: 7 bestvalit: -0.005864 bestmemit:    0.000000    0.030000    0.926000    0.052000
Iteration: 8 bestvalit: -0.006120 bestmemit:    0.028000    0.012000    0.946000    0.024000
Iteration: 9 bestvalit: -0.006754 bestmemit:    0.020000    0.010000    0.934000    0.030000
Iteration: 10 bestvalit: -0.006754 bestmemit:    0.020000    0.010000    0.934000    0.030000
Iteration: 11 bestvalit: -0.007049 bestmemit:    0.002000    0.054000    0.936000    0.012000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.0014757113543874
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.020.0020.9680.002
Iteration: 12 bestvalit: -0.007049 bestmemit:    0.002000    0.054000    0.936000    0.012000
Iteration: 13 bestvalit: -0.007049 bestmemit:    0.002000    0.054000    0.936000    0.012000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.000776293722815273
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.0120.0060.950.03
Iteration: 14 bestvalit: -0.007049 bestmemit:    0.002000    0.054000    0.936000    0.012000
Iteration: 15 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
Iteration: 16 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
Iteration: 17 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
Iteration: 18 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.000147798621543293
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.0040.0480.9380.00816507252357672
Iteration: 19 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
Iteration: 20 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
Iteration: 21 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
VaR calculation produces unreliable result (inverse risk) for column: 1 : -1.53409120965025e-05
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.001999999999999990.0603482989168770.9362294183330390
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.00130191054928627
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.0080.0320.9560.002
VaR calculation produces unreliable result (inverse risk) for column: 1 : -0.00175569663332701
Warning in FUN(newX[, i], ...) :
  NA or NaN produced in objective function for weights 0.0020.010.970.02
Iteration: 22 bestvalit: -0.007224 bestmemit:    0.000000    0.032000    0.934000    0.034000
[1] 0.000 0.032 0.934 0.034
chart.Weights(mportopt4)


# 4.3.5. Optimized Portfolios Backtesting Comparison
# mportcomp <- cbind(mnaive["2015-01-31::"],mportopt1,mportopt2,mportopt3,mportopt4)
mportcomp <- cbind(mportopt1,mportopt2,mportopt3,mportopt4)
#mportcomp = cbind(mnaive["2015-01-31::"],mport1c,mport2c,mport3c,mport4c)
table.AnnualizedReturns(mportcomp)
Error in if (class(x) == "numeric") { : the condition has length > 1

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQotLS0NCmBgYHtyfQ0KDQojaW5zdGFsbC5wYWNrYWdlcygidHNlcmllcyIpDQpsaWJyYXJ5KCJ0c2VyaWVzIikNCmxpYnJhcnkoInF1YW50bW9kIikNCiNpbnN0YWxsLnBhY2thZ2VzKCdRdWFuZGwnKQ0KbGlicmFyeSgiUXVhbmRsIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJxdWFudG1vZCIpDQpsaWJyYXJ5KCJxdWFudG1vZCIpDQojaW5zdGFsbC5wYWNrYWdlcygiUG9ydGZvbGlvQW5hbHl0aWNzIikNCmxpYnJhcnkoIlBvcnRmb2xpb0FuYWx5dGljcyIpDQojaW5zdGFsbC5wYWNrYWdlcygiREVvcHRpbSIpDQpsaWJyYXJ5KCJERW9wdGltIikNCmxpYnJhcnkoInh0cyIpDQojaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KI2xpYnJhcnkoImtuaXRyIikNCg0KIyBSZWFkaW5nIG9mIERhdGENCmRhdGEgPC0gcmVhZC5jc3YoImRhdGFfZmluYWwuY3N2IiwgaGVhZGVyID0gVCkNCmRhdGEgPC0geHRzKGRhdGFbICwyOjVdLCBvcmRlci5ieSA9IGFzLkRhdGUuZmFjdG9yKGRhdGFbLDFdKSkgIA0KVmlldyhkYXRhKQ0KDQojIEluZGlhbiBTdG9ja3MgZnJvbSBCc2UgSW5kZXgNCmluZGlhbl9zdG9ja3MgPC0gZGF0YVssMV0NCm1faW5kaWFuX3N0b2NrcyA8LSBtb250aGx5UmV0dXJuKGluZGlhbl9zdG9ja3MsIHR5cGUgPSAiYXJpdGhtZXRpYyIpDQpjb2xuYW1lcyhpbmRpYW5fc3RvY2tzKSA8LSAibV9pbmRpYW5fc3RvY2tzIg0KdGFibGUuQW5udWFsaXplZFJldHVybnMobV9pbmRpYW5fc3RvY2tzKQ0KY2hhcnRzLlBlcmZvcm1hbmNlU3VtbWFyeShtX2luZGlhbl9zdG9ja3MpDQoNCiMgSW5kaWFuIEJvbmRzDQoNCmluZGlhbl9ib25kcyA8LSBkYXRhWywyXQ0KbV9pbmRpYW5fYm9uZHMgPC0gbW9udGhseVJldHVybihpbmRpYW5fYm9uZHMpDQpjb2xuYW1lcyhpbmRpYW5fYm9uZHMpIDwtICJtX2luZGlhbl9ib25kcyINCnRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKG1faW5kaWFuX2JvbmRzKQ0KY2hhcnRzLlBlcmZvcm1hbmNlU3VtbWFyeShtX2luZGlhbl9ib25kcykNCg0KIyBJbnRlcm5hdGlvbmFsIHN0b2Nrcw0KDQppbnRlcm5hdGlvbmFsX3N0b2NrIDwtIGRhdGFbLDNdDQptX2ludGVybmF0aW9uYWxfc3RvY2sgPC0gbW9udGhseVJldHVybihpbnRlcm5hdGlvbmFsX3N0b2NrKQ0KY29sbmFtZXMoaW50ZXJuYXRpb25hbF9zdG9jaykgPC0gIm1faW50ZXJuYXRpb25hbF9zdG9jayINCnRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKG1faW50ZXJuYXRpb25hbF9zdG9jaykNCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkobV9pbnRlcm5hdGlvbmFsX3N0b2NrKQ0KDQoNCiMgSW50ZXJuYXRpb25hbCBCb25kcw0KaW50ZXJuYXRpb25hbF9ib25kcyA8LSBkYXRhWyw0XQ0KbV9pbnRlcm5hdGlvbmFsX2JvbmQgPC0gbW9udGhseVJldHVybihpbnRlcm5hdGlvbmFsX2JvbmRzKQ0KY29sbmFtZXMoaW50ZXJuYXRpb25hbF9ib25kcykgPC0gIm1faW50ZXJuYXRpb25hbF9ib25kIg0KdGFibGUuQW5udWFsaXplZFJldHVybnMobV9pbnRlcm5hdGlvbmFsX2JvbmQpDQpjaGFydHMuUGVyZm9ybWFuY2VTdW1tYXJ5KG1faW50ZXJuYXRpb25hbF9ib25kKQ0KDQojIEJvbmRzIENvbXBhcmUNCmJvbmRzY29tcCA8LSBjYmluZChtX2luZGlhbl9ib25kcyxtX2ludGVybmF0aW9uYWxfYm9uZCkNCnRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKGJvbmRzY29tcCkNCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoYm9uZHNjb21wKQ0KDQojIHN0b2NrcyBDb21wYXJlDQoNCnN0b2NrY29tcCA8LSBjYmluZChtX2luZGlhbl9zdG9ja3MsbV9pbnRlcm5hdGlvbmFsX3N0b2NrKQ0KdGFibGUuQW5udWFsaXplZFJldHVybnMoc3RvY2tjb21wKQ0KY2hhcnRzLlBlcmZvcm1hbmNlU3VtbWFyeShzdG9ja2NvbXApDQoNCiMgNC4gUG9ydGZvbGlvIE9wdGltaXphdGlvbg0KDQojIDQuMS4gUG9ydGZvbGlvIFBlcmZvcm1hbmNlIE1ldHJpY3MNCg0KIyA0LjEuMS4gU2hhcnBlIFJhdGlvIA0KI21zaGFycGUgPC0gU2hhcnBlUmF0aW8obWxzdG9ja3MsUmY9bWVhbihtY2FzaCkpDQojbXNoYXJwZQ0KDQojIDQuMS4yLiBUcmV5bm9yIFJhdGlvDQojbXRyZXlub3IgPC0gVHJleW5vclJhdGlvKFJhPW1sc3RvY2tzLFJiPW1zdG9ja3MsUmY9bWVhbihtY2FzaCkpDQojbXRyZXlub3INCg0KIyA0LjIuIFBvcnRmb2xpbyBCZW5jaG1hcmtzIA0KDQojIDQuMi4xLiBQb3J0Zm9saW8gQXNzZXRzIFJldHVybnMgTWF0cml4DQptcG9ydCA8LSBjYmluZChtX2luZGlhbl9zdG9ja3MsbV9pbnRlcm5hdGlvbmFsX3N0b2NrLG1faW5kaWFuX2JvbmRzLCBtX2ludGVybmF0aW9uYWxfc3RvY2spDQoNCiMgNC4yLjIuIE5haXZlIEdsb2JhbCBQb3J0Zm9saW8gKE1vbnRobHkgUmViYWxhbmNpbmcpDQptbmFpdmV3IDwtIGFzLm51bWVyaWModChjKDAuMjUsMC4yNSwwLjI1LDAuMjUpKSkNCm5hbWVzKG1uYWl2ZXcpIDwtIGMoIm1faW5kaWFuX3N0b2NrcyIsIm1faW50ZXJuYXRpb25hbF9zdG9jayIsIm1faW5kaWFuX2JvbmRzIiwibV9pbnRlcm5hdGlvbmFsX3N0b2NrIikNCm1uYWl2ZSA8LSBSZXR1cm4ucG9ydGZvbGlvKFI9bXBvcnQsd2VpZ2h0cz1tbmFpdmV3LGdlb21ldHJpYz1GLHJlYmFsYW5jZV9vbj0ibW9udGhzIikNCmNvbG5hbWVzKG1uYWl2ZSkgPC0gIm1uYWl2ZSINCg0KIyA0LjIuMy4gUm9jaGUgR2xvYmFsIFBvcnRmb2xpbyAoTW9udGhseSBSZWJhbGFuY2luZykNCm1yb2NoZXcgPC0gYXMubnVtZXJpYyh0KGMoMC4yNCwwLjE4LDAuMzMsMC4yNSkpKQ0KbmFtZXMobXJvY2hldykgPC0gYygibV9pbmRpYW5fc3RvY2tzIiwibV9pbnRlcm5hdGlvbmFsX3N0b2NrIiwibV9pbmRpYW5fYm9uZHMiLCJtX2ludGVybmF0aW9uYWxfc3RvY2siKQ0KbXJvY2hlIDwtIFJldHVybi5wb3J0Zm9saW8oUj1tcG9ydCx3ZWlnaHRzPW1yb2NoZXcsZ2VvbWV0cmljPUYscmViYWxhbmNlX29uPSJtb250aHMiKQ0KY29sbmFtZXMobXJvY2hlKSA8LSAibXJvY2hlIg0KDQojIDQuMi40LiBCb2dsZSBVLlMuIFBvcnRmb2xpbyAoTW9udGhseSBSZWJhbGFuY2luZykNCm1ib2dsZXcgPC0gYXMubnVtZXJpYyh0KGMoMC40MCwwLjYwLDAuMDAsMC4wMCkpKQ0KbmFtZXMobWJvZ2xldykgPC0gYygibV9pbmRpYW5fc3RvY2tzIiwibV9pbnRlcm5hdGlvbmFsX3N0b2NrIiwibV9pbmRpYW5fYm9uZHMiLCJtX2ludGVybmF0aW9uYWxfc3RvY2siKQ0KbWJvZ2xlIDwtIFJldHVybi5wb3J0Zm9saW8oUj1tcG9ydCx3ZWlnaHRzPW1ib2dsZXcsZ2VvbWV0cmljPUYscmViYWxhbmNlX29uPSJtb250aHMiKQ0KY29sbmFtZXMobWJvZ2xlKSA8LSAibWJvZ2xlIg0KDQojIDQuMi42LiBCZW5jaG1hcmsgUG9ydGZvbGlvcyBSZXR1cm5zIENvbXBhcmlzb24NCmJlbmNoY29tcCA8LSBjYmluZChtbmFpdmUsbXJvY2hlLG1ib2dsZSkNCnRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKGJlbmNoY29tcCkNCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoYmVuY2hjb21wKQ0KDQojIDQuMy4gUG9ydGZvbGlvIE9wdGltaXphdGlvbiANCg0KIyA0LjMuMS4gTWVhbiBNYXhpbWl6YXRpb24gDQoNCiMgUG9ydGZvbGlvIFNwZWNpZmljYXRpb25zDQptcG9ydDFjIDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cyA9IGNvbG5hbWVzKG1wb3J0KSkNCg0KIyBQb3J0Zm9saW8gQ29uc3RyYWludHMNCm1wb3J0MWMgPC0gYWRkLmNvbnN0cmFpbnQobXBvcnQxYyx0eXBlPSJ3ZWlnaHRfc3VtIixtaW5fc3VtPTAuOTksbWF4X3N1bT0xLjAxKQ0KbXBvcnQxYyA8LSBhZGQuY29uc3RyYWludChtcG9ydDFjLHR5cGU9Imxvbmdfb25seSIpDQoNCiMgUG9ydGZvbGlvIE9iamVjdGl2ZXMNCm1wb3J0MWMgPC0gYWRkLm9iamVjdGl2ZShtcG9ydDFjLHR5cGU9InJldHVybiIsbmFtZT0ibWVhbiIpDQoNCiMgUG9ydGZvbGlvIE9wdGltaXphdGlvbg0KbXBvcnRvcHQxIDwtIG9wdGltaXplLnBvcnRmb2xpbyhSPW1wb3J0WyI6OjIwMjEtMTItMzEiXSxwb3J0Zm9saW89bXBvcnQxYyxvcHRpbWl6ZV9tZXRob2Q9IkRFb3B0aW0iLHNlYXJjaF9zaXplPTIwMDAwLHRyYWNlPVQgKQ0KY2hhcnQuV2VpZ2h0cyhtcG9ydG9wdDEpDQoNCiMgNC4zLjIuIFN0YW5kYXJkIGRldmlhdGlvbiBtaW5pbWl6YXRpb24NCg0KIyBQb3J0Zm9saW8gU3BlY2lmaWNhdGlvbnMNCm1wb3J0MmMgPC0gcG9ydGZvbGlvLnNwZWMoYXNzZXRzPWNvbG5hbWVzKG1wb3J0KSkNCg0KIyBQb3J0Zm9saW8gQ29uc3RyYWludHMNCm1wb3J0MmMgPC0gYWRkLmNvbnN0cmFpbnQobXBvcnQyYyx0eXBlPSJ3ZWlnaHRfc3VtIixtaW5fc3VtPTAuOTksbWF4X3N1bT0xLjAxKQ0KbXBvcnQyYyA8LSBhZGQuY29uc3RyYWludChtcG9ydDJjLHR5cGU9Imxvbmdfb25seSIpDQoNCiMgUG9ydGZvbGlvIE9iamVjdGl2ZXMNCm1wb3J0MmMgPC0gYWRkLm9iamVjdGl2ZShtcG9ydDJjLHR5cGU9InJpc2siLG5hbWU9IlN0ZERldiIpDQoNCiMgUG9ydGZvbGlvIE9wdGltaXphdGlvbg0KbXBvcnRvcHQyIDwtIG9wdGltaXplLnBvcnRmb2xpbyhSPW1wb3J0WyI6OjIwMjEtMTItMzEiXSxwb3J0Zm9saW89bXBvcnQyYyxvcHRpbWl6ZV9tZXRob2Q9IkRFb3B0aW0iLHNlYXJjaF9zaXplPTIwMDAwLHRyYWNlPVQpDQpjaGFydC5XZWlnaHRzKG1wb3J0b3B0MikNCg0KIyA0LjMuMy4gTWVhbiBNYXhpbWl6YXRpb24gYW5kIFN0YW5kYXJkIERldmlhdGlvbiBNaW5pbWl6YXRpb24gUG9ydGZvbGlvDQoNCiMgUG9ydGZvbGlvIFNwZWNpZmljYXRpb25zDQptcG9ydDNjIDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cz1jb2xuYW1lcyhtcG9ydCkpDQoNCiMgUG9ydGZvbGlvIENvbnN0cmFpbnRzDQptcG9ydDNjIDwtIGFkZC5jb25zdHJhaW50KG1wb3J0M2MsdHlwZT0id2VpZ2h0X3N1bSIsbWluX3N1bT0wLjk5LG1heF9zdW09MS4wMSkNCm1wb3J0M2MgPC0gYWRkLmNvbnN0cmFpbnQobXBvcnQzYyx0eXBlPSJsb25nX29ubHkiKQ0KDQojIFBvcnRmb2xpbyBPYmplY3RpdmVzDQptcG9ydDNjIDwtIGFkZC5vYmplY3RpdmUobXBvcnQzYyx0eXBlPSJyZXR1cm4iLG5hbWU9Im1lYW4iKQ0KbXBvcnQzYyA8LSBhZGQub2JqZWN0aXZlKG1wb3J0M2MsdHlwZT0icmlzayIsbmFtZT0iU3RkRGV2IikNCg0KIyBQb3J0Zm9saW8gT3B0aW1pemF0aW9uDQptcG9ydG9wdDMgPC0gb3B0aW1pemUucG9ydGZvbGlvKFI9bXBvcnRbIjo6MjAyMS0xMi0zMSJdLHBvcnRmb2xpbz1tcG9ydDNjLG9wdGltaXplX21ldGhvZD0iREVvcHRpbSIsc2VhcmNoX3NpemU9MjAwMDAsdHJhY2U9VCkNCmNoYXJ0LldlaWdodHMobXBvcnRvcHQzKQ0KY2hhcnQuRWZmaWNpZW50RnJvbnRpZXIobXBvcnRvcHQzLG1hdGNoLmNvbD0iU3RkRGV2IikNCg0KIyA0LjMuNC4gTWVhbiBNYXhpbWl6YXRpb24gVmFsdWUgYXQgUmlzayAoVmFSKSBNaW5pbWl6YXRpb24gUG9ydGZvbGlvDQoNCiMgUG9ydGZvbGlvIFNwZWNpZmljYXRpb25zDQptcG9ydDRjIDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cz1jb2xuYW1lcyhtcG9ydCkpDQoNCiMgUG9ydGZvbGlvIENvbnN0cmFpbnRzDQptcG9ydDRjIDwtIGFkZC5jb25zdHJhaW50KG1wb3J0NGMsdHlwZT0id2VpZ2h0X3N1bSIsbWluX3N1bT0wLjk5LG1heF9zdW09MS4wMSkNCm1wb3J0NGMgPC0gYWRkLmNvbnN0cmFpbnQobXBvcnQ0Yyx0eXBlPSJsb25nX29ubHkiKQ0KDQojIFBvcnRmb2xpbyBPYmplY3RpdmVzDQptcG9ydDRjIDwtIGFkZC5vYmplY3RpdmUobXBvcnQ0Yyx0eXBlPSJyZXR1cm4iLG5hbWU9Im1lYW4iKQ0KbXBvcnQ0YyA8LSBhZGQub2JqZWN0aXZlKG1wb3J0NGMsdHlwZT0icmlzayIsbmFtZT0iVmFSIixhcmd1bWVudHM9bGlzdChwID0gMC45OSxtZXRob2Q9Im1vZGlmaWVkIikpDQoNCiMgUG9ydGZvbGlvIE9wdGltaXphdGlvbg0KbXBvcnRvcHQ0IDwtIG9wdGltaXplLnBvcnRmb2xpbyhSPW1wb3J0WyI6OjIwMjEtMTItMzEiXSxwb3J0Zm9saW89bXBvcnQ0YyxvcHRpbWl6ZV9tZXRob2Q9IkRFb3B0aW0iLHNlYXJjaF9zaXplPTIwMDAwLHRyYWNlPVQpDQpjaGFydC5XZWlnaHRzKG1wb3J0b3B0NCkNCg0KIyA0LjMuNS4gT3B0aW1pemVkIFBvcnRmb2xpb3MgQmFja3Rlc3RpbmcgQ29tcGFyaXNvbg0KIyBtcG9ydGNvbXAgPC0gY2JpbmQobW5haXZlWyIyMDE1LTAxLTMxOjoiXSxtcG9ydG9wdDEsbXBvcnRvcHQyLG1wb3J0b3B0MyxtcG9ydG9wdDQpDQptcG9ydGNvbXAgPC0gY2JpbmQobXBvcnRvcHQxLG1wb3J0b3B0MixtcG9ydG9wdDMsbXBvcnRvcHQ0KQ0KI21wb3J0Y29tcCA9IGNiaW5kKG1uYWl2ZVsiMjAxNS0wMS0zMTo6Il0sbXBvcnQxYyxtcG9ydDJjLG1wb3J0M2MsbXBvcnQ0YykNCnRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKG1wb3J0Y29tcCkNCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkobXBvcnRjb21wKQ0KYGBgDQoNCg0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg==