Email             :
RPubs            : https://rpubs.com/brigitatiaraem/
Jurusan          : Statistika
Address         : ARA Center, Matana University Tower
                         Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.


install.packages("installr")
library("installr")
updateR()
library(tidyquant)
library(plotly)
library(timetk)

# saham telkom, kimia farma, Djarum, BCA, dan Sinarmas
tick <- c('TLKM.JK', 'KAEF.JK', 'HMSP.JK', 'BBCA.JK', 'BSIM.JK')


price_data <- tq_get(tick,
                     from = '2020-01-01',
                     to   = Sys.Date(),
                     get  = 'stock.prices')

price_data
## # A tibble: 3,595 × 8
##    symbol  date        open  high   low close    volume adjusted
##    <chr>   <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>
##  1 TLKM.JK 2020-01-02  3970  4000  3900  3910  52094000    3417.
##  2 TLKM.JK 2020-01-03  3960  3980  3930  3980  70032900    3478.
##  3 TLKM.JK 2020-01-06  3930  3970  3930  3960  42908900    3461.
##  4 TLKM.JK 2020-01-07  3930  3970  3920  3940  51837600    3443.
##  5 TLKM.JK 2020-01-08  3920  3950  3900  3900  52402600    3408.
##  6 TLKM.JK 2020-01-09  3920  3970  3920  3960  37580300    3461.
##  7 TLKM.JK 2020-01-10  3980  3990  3950  3980  48099000    3478.
##  8 TLKM.JK 2020-01-13  4000  4030  3990  4030  61913800    3522.
##  9 TLKM.JK 2020-01-14  3980  4000  3940  3950  95058600    3452.
## 10 TLKM.JK 2020-01-15  3960  3960  3870  3880 147583300    3391.
## # … with 3,585 more rows

1 Return

log_ret_tidy <- price_data %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted,
               mutate_fun = periodReturn,
               period     = 'daily',
               col_rename = 'ret',
               type       = 'log')

library(DT) 
datatable(log_ret_tidy)

Adapun fungsi yang digunakan untuk mengubah menjadi format lebar yaitu spread() dan mengubah menjadi objek runtun waktu yaitu xts().

library(tidyr)

log_ret_xts = log_ret_tidy %>%
  spread(symbol, value = ret) %>%
  tk_xts()

datatable(log_ret_xts)

1.1 Rata-rata Pengembalian

Langkah ini digunakan untuk menghitung rata-rata pengembalian setiap harian untuk setiap saham yang digunakan.

mean_ret <- colMeans(log_ret_xts)
print ( round (mean_ret, 4))
## BBCA.JK BSIM.JK HMSP.JK KAEF.JK TLKM.JK 
##   4e-04   5e-04  -8e-04  -1e-04   1e-04

1.2 Matriks Kovariansi

Matriks kovarian digunakan untuk melihat hubungan pada setiap saham untuk periode satu tahun sebanyak 252 hari ( kecuali hari libur dan hari raya).

cov_mat <- cov(log_ret_xts) * 252
print(round(cov_mat,4))
##         BBCA.JK BSIM.JK HMSP.JK KAEF.JK TLKM.JK
## BBCA.JK  0.0831  0.0068  0.0391  0.0486  0.0446
## BSIM.JK  0.0068  0.3231  0.0167  0.0048  0.0011
## HMSP.JK  0.0391  0.0167  0.1283  0.0706  0.0447
## KAEF.JK  0.0486  0.0048  0.0706  0.5393  0.0374
## TLKM.JK  0.0446  0.0011  0.0447  0.0374  0.1087

2 Penerapan Metode Portofolio

Metode portofolio dapat dilakukan untuk memperhitungkan pengembalian atau rerturn dan nilai risiko dari masing-masing portofolio. Berikut merupakan langkah-langkah dalam R.

wts <- runif(n = length(tick))
wts <- wts/sum(wts)

port_returns <- (sum(wts * mean_ret) + 1)^252 - 1
port_risk <- sqrt(t(wts) %*% (cov_mat %*% wts))
sharpe_ratio <- port_returns/port_risk

Untuk melihat tingkat signifikan pada masing-masing portofolio dapat dilakukan simulasi sebanyak 5000 kali.

num_port <- 5000

all_wts <- matrix(nrow = num_port, ncol = length(tick))
port_returns <- vector('numeric', length = num_port)
port_risk <- vector('numeric', length = num_port)
sharpe_ratio <- vector('numeric', length = num_port)
for (i in seq_along(port_returns)) {
  
  wts <- runif(length(tick))
  wts <- wts/sum(wts)
  
  all_wts[i,] <- wts
  
  
  port_ret <- sum(wts * mean_ret)
  port_ret <- ((port_ret + 1)^252) - 1
  
  port_returns[i] <- port_ret
  
  
  port_sd <- sqrt(t(wts) %*% (cov_mat  %*% wts))
  port_risk[i] <- port_sd
  
  sr <- port_ret/port_sd
  sharpe_ratio[i] <- sr
}

Setelah melakukan proses loop 5000 kali, maka langkah selanjutnya membuat tabel data.

portfolio_values <- tibble(Return = port_returns,
                             Risk = port_risk,
                      SharpeRatio = sharpe_ratio)
all_wts <- tk_tbl(all_wts)

colnames(all_wts) <- colnames(log_ret_xts)

portfolio_values <- tk_tbl(cbind(all_wts, portfolio_values))

datatable(portfolio_values)

Dari tabel diatas, masing-masing portofolio pada setiap saham memiliki pengembalian, risiko, dan sharpe ratio.

3 Variasi Minimum

library(forcats)

min_var <- portfolio_values[which.min(portfolio_values$Risk),]

p <- min_var %>%
  gather(BBCA.JK:TLKM.JK, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Aset', 
       y = 'Bobot', 
       title = "Bobot Portofolio dengan Variansi Minimum") +
  scale_y_continuous(labels = scales::percent) +
  theme(legend.position = "none" )

ggplotly(p)

Dari output di atas, portofolio variansi minimum pada saham KAEF.JK dan HMSP.JK. Kebanyakan inverstor investasi di BBCA.JK dan TLKM.JK.

4 Portofolio Tangensi

Sharpe ratio adalah rasio yang menunjukkan besaran return instrumen investasi. Setelah melihat portofolio variansi minimum dapat melakukan portofolio tangensi dengan sharpe ratio tertinggi.

max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]

p <- max_sr %>%
  gather(BBCA.JK:TLKM.JK, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Aset', 
       y = 'Bobot', 
       title = "Bobot Portofolio Tangensi (Maksimum Sharpe Ratio)") +
  scale_y_continuous(labels = scales::percent) +
  theme(legend.position = "none" )

ggplotly(p)

Dari ouotput diatas dapat dilihat bahwa

4.1 Batas Efisien Portofolio

p <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  theme_classic() +
  scale_y_continuous(labels = scales::percent) +
  scale_x_continuous(labels = scales::percent) +
  labs(x = 'Risiko Tahunan',
       y = 'Pengembalian Tahunan',
       title = "Optimasi Portofolio & Perbatasan yang Efisien") +
  geom_point(aes(x = Risk, y = Return), data = min_var, color = 'red') +
  geom_point(aes(x = Risk, y = Return), data = max_sr, color = 'red') +
  annotate('text', x = 0.31, y = 0.31, label = "Portofolio Tangensi") +
  annotate('text', x = 0.24, y = 0.11, label = "Portofolio Varians minimum") +
  annotate(geom = 'segment', x = 0.3023, xend = 0.3023,  y = 0.23, 
           yend = 0.29, color = 'red', arrow = arrow(type = "open")) +
  annotate(geom = 'segment', x = 0.25, xend = 0.25,  y = 0.015, 
           yend = 0.10, color = 'red', arrow = arrow(type = "open"))
  
ggplotly(p)
LS0tDQp0aXRsZTogIk9QVElNQVNJIg0Kc3VidGl0bGU6ICJXRUVLIDE1Ig0KYXV0aG9yOiAiQnJpZ2l0YSBUaWFyYSBFbGdpdHlhbmEgTWVsYW50aWthICgyMDIwNDkyMDAwMSkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50OiANCiAgICBodG1sX2RvY3VtZW50OiBudWxsDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IHNhbmRzdG9uZQ0KICAgIGNzczogc3R5bGUxLmNzcw0KICAgIGhpZ2hsaWdodDogbW9ub2Nocm9tZQ0KLS0tDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoY2xhc3Muc291cmNlID0gIm5vY29weSIsDQogICAgICAgICAgICAgICAgICAgICAgY2xhc3Mub3V0cHV0ID0gIm5vY29weSIsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEYsDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEYpDQpgYGANCg0KPGltZyBzdHlsZT0iZmxvYXQ6IHJpZ2h0OyBtYXJnaW46IDBweCAxMDBweCAwcHggMHB4OyB3aWR0aDoyNSUiIHNyYz0iZm90b2JhcnVrdS5qcGVnIi8+IA0KDQpgYGB7ciBsb2dvLCBlY2hvPUZBTFNFLGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoID0gJzMwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibG9nb21hdGFuYS5wbmciKQ0KYGBgDQoNCkVtYWlsICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOzogIGJyaWdpdGEubWVsYW50aWthQHN0dWRlbnQubWF0YW5hdW5pdmVyc2l0eS5hYy5pZCA8YnI+DQpSUHVicyAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBodHRwczovL3JwdWJzLmNvbS9icmlnaXRhdGlhcmFlbS8gPGJyPg0KSnVydXNhbiAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBbU3RhdGlzdGlrYV0oaHR0cHM6Ly9tYXRhbmF1bml2ZXJzaXR5LmFjLmlkLz9seT1hY2FkZW1pYyZjPXNiKSA8YnI+DQpBZGRyZXNzICAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgOiBBUkEgQ2VudGVyLCBNYXRhbmEgVW5pdmVyc2l0eSBUb3dlciA8YnI+DQombmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOyBKbC4gQ0JEIEJhcmF0IEthdiwgUlQuMSwgQ3VydWcgU2FuZ2VyZW5nLCBLZWxhcGEgRHVhLCBUYW5nZXJhbmcsIEJhbnRlbiAxNTgxMC4NCg0KKioqKg0KDQpgYGB7ciBldmFsID1GQUxTRX0NCmluc3RhbGwucGFja2FnZXMoImluc3RhbGxyIikNCmxpYnJhcnkoImluc3RhbGxyIikNCnVwZGF0ZVIoKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5cXVhbnQpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkodGltZXRrKQ0KDQojIHNhaGFtIHRlbGtvbSwga2ltaWEgZmFybWEsIERqYXJ1bSwgQkNBLCBkYW4gU2luYXJtYXMNCnRpY2sgPC0gYygnVExLTS5KSycsICdLQUVGLkpLJywgJ0hNU1AuSksnLCAnQkJDQS5KSycsICdCU0lNLkpLJykNCg0KDQpwcmljZV9kYXRhIDwtIHRxX2dldCh0aWNrLA0KICAgICAgICAgICAgICAgICAgICAgZnJvbSA9ICcyMDIwLTAxLTAxJywNCiAgICAgICAgICAgICAgICAgICAgIHRvICAgPSBTeXMuRGF0ZSgpLA0KICAgICAgICAgICAgICAgICAgICAgZ2V0ICA9ICdzdG9jay5wcmljZXMnKQ0KDQpwcmljZV9kYXRhDQpgYGANCg0KIyBSZXR1cm4NCmBgYHtyfQ0KbG9nX3JldF90aWR5IDwtIHByaWNlX2RhdGEgJT4lDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lDQogIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsDQogICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLA0KICAgICAgICAgICAgICAgcGVyaW9kICAgICA9ICdkYWlseScsDQogICAgICAgICAgICAgICBjb2xfcmVuYW1lID0gJ3JldCcsDQogICAgICAgICAgICAgICB0eXBlICAgICAgID0gJ2xvZycpDQoNCmxpYnJhcnkoRFQpIA0KZGF0YXRhYmxlKGxvZ19yZXRfdGlkeSkNCmBgYA0KQWRhcHVuIGZ1bmdzaSB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW5ndWJhaCBtZW5qYWRpIGZvcm1hdCBsZWJhciB5YWl0dSBgc3ByZWFkKClgIGRhbiBtZW5ndWJhaCBtZW5qYWRpIG9iamVrIHJ1bnR1biB3YWt0dSB5YWl0dSBgeHRzKClgLg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXIpDQoNCmxvZ19yZXRfeHRzID0gbG9nX3JldF90aWR5ICU+JQ0KICBzcHJlYWQoc3ltYm9sLCB2YWx1ZSA9IHJldCkgJT4lDQogIHRrX3h0cygpDQoNCmRhdGF0YWJsZShsb2dfcmV0X3h0cykNCmBgYA0KDQojIyBSYXRhLXJhdGEgUGVuZ2VtYmFsaWFuDQoNCkxhbmdrYWggaW5pIGRpZ3VuYWthbiB1bnR1ayBtZW5naGl0dW5nIHJhdGEtcmF0YSBwZW5nZW1iYWxpYW4gc2V0aWFwIGhhcmlhbiB1bnR1ayBzZXRpYXAgc2FoYW0geWFuZyBkaWd1bmFrYW4uDQoNCmBgYHtyfQ0KbWVhbl9yZXQgPC0gY29sTWVhbnMobG9nX3JldF94dHMpDQpwcmludCAoIHJvdW5kIChtZWFuX3JldCwgNCkpDQpgYGANCiMjIE1hdHJpa3MgS292YXJpYW5zaQ0KDQpNYXRyaWtzIGtvdmFyaWFuIGRpZ3VuYWthbiB1bnR1ayBtZWxpaGF0IGh1YnVuZ2FuIHBhZGEgc2V0aWFwIHNhaGFtIHVudHVrIHBlcmlvZGUgc2F0dSB0YWh1biBzZWJhbnlhayAyNTIgaGFyaSAoIGtlY3VhbGkgaGFyaSBsaWJ1ciBkYW4gaGFyaSByYXlhKS4NCg0KYGBge3J9DQpjb3ZfbWF0IDwtIGNvdihsb2dfcmV0X3h0cykgKiAyNTINCnByaW50KHJvdW5kKGNvdl9tYXQsNCkpDQpgYGANCg0KIyBQZW5lcmFwYW4gTWV0b2RlIFBvcnRvZm9saW8NCg0KTWV0b2RlIHBvcnRvZm9saW8gZGFwYXQgZGlsYWt1a2FuIHVudHVrIG1lbXBlcmhpdHVuZ2thbiBwZW5nZW1iYWxpYW4gYXRhdSByZXJ0dXJuIGRhbiBuaWxhaSByaXNpa28gZGFyaSBtYXNpbmctbWFzaW5nIHBvcnRvZm9saW8uIEJlcmlrdXQgbWVydXBha2FuIGxhbmdrYWgtbGFuZ2thaCBkYWxhbSBSLg0KDQpgYGB7cn0NCnd0cyA8LSBydW5pZihuID0gbGVuZ3RoKHRpY2spKQ0Kd3RzIDwtIHd0cy9zdW0od3RzKQ0KDQpwb3J0X3JldHVybnMgPC0gKHN1bSh3dHMgKiBtZWFuX3JldCkgKyAxKV4yNTIgLSAxDQpwb3J0X3Jpc2sgPC0gc3FydCh0KHd0cykgJSolIChjb3ZfbWF0ICUqJSB3dHMpKQ0Kc2hhcnBlX3JhdGlvIDwtIHBvcnRfcmV0dXJucy9wb3J0X3Jpc2sNCmBgYA0KDQpVbnR1ayBtZWxpaGF0IHRpbmdrYXQgc2lnbmlmaWthbiBwYWRhIG1hc2luZy1tYXNpbmcgcG9ydG9mb2xpbyBkYXBhdCBkaWxha3VrYW4gc2ltdWxhc2kgc2ViYW55YWsgNTAwMCBrYWxpLg0KDQpgYGB7cn0NCm51bV9wb3J0IDwtIDUwMDANCg0KYWxsX3d0cyA8LSBtYXRyaXgobnJvdyA9IG51bV9wb3J0LCBuY29sID0gbGVuZ3RoKHRpY2spKQ0KcG9ydF9yZXR1cm5zIDwtIHZlY3RvcignbnVtZXJpYycsIGxlbmd0aCA9IG51bV9wb3J0KQ0KcG9ydF9yaXNrIDwtIHZlY3RvcignbnVtZXJpYycsIGxlbmd0aCA9IG51bV9wb3J0KQ0Kc2hhcnBlX3JhdGlvIDwtIHZlY3RvcignbnVtZXJpYycsIGxlbmd0aCA9IG51bV9wb3J0KQ0KDQpgYGANCg0KYGBge3J9DQpmb3IgKGkgaW4gc2VxX2Fsb25nKHBvcnRfcmV0dXJucykpIHsNCiAgDQogIHd0cyA8LSBydW5pZihsZW5ndGgodGljaykpDQogIHd0cyA8LSB3dHMvc3VtKHd0cykNCiAgDQogIGFsbF93dHNbaSxdIDwtIHd0cw0KICANCiAgDQogIHBvcnRfcmV0IDwtIHN1bSh3dHMgKiBtZWFuX3JldCkNCiAgcG9ydF9yZXQgPC0gKChwb3J0X3JldCArIDEpXjI1MikgLSAxDQogIA0KICBwb3J0X3JldHVybnNbaV0gPC0gcG9ydF9yZXQNCiAgDQogIA0KICBwb3J0X3NkIDwtIHNxcnQodCh3dHMpICUqJSAoY292X21hdCAgJSolIHd0cykpDQogIHBvcnRfcmlza1tpXSA8LSBwb3J0X3NkDQogIA0KICBzciA8LSBwb3J0X3JldC9wb3J0X3NkDQogIHNoYXJwZV9yYXRpb1tpXSA8LSBzcg0KfQ0KDQpgYGANCg0KU2V0ZWxhaCBtZWxha3VrYW4gcHJvc2VzIGxvb3AgNTAwMCBrYWxpLCBtYWthIGxhbmdrYWggc2VsYW5qdXRueWEgbWVtYnVhdCB0YWJlbCBkYXRhLg0KDQpgYGB7cn0NCnBvcnRmb2xpb192YWx1ZXMgPC0gdGliYmxlKFJldHVybiA9IHBvcnRfcmV0dXJucywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmlzayA9IHBvcnRfcmlzaywNCiAgICAgICAgICAgICAgICAgICAgICBTaGFycGVSYXRpbyA9IHNoYXJwZV9yYXRpbykNCmFsbF93dHMgPC0gdGtfdGJsKGFsbF93dHMpDQoNCmNvbG5hbWVzKGFsbF93dHMpIDwtIGNvbG5hbWVzKGxvZ19yZXRfeHRzKQ0KDQpwb3J0Zm9saW9fdmFsdWVzIDwtIHRrX3RibChjYmluZChhbGxfd3RzLCBwb3J0Zm9saW9fdmFsdWVzKSkNCg0KZGF0YXRhYmxlKHBvcnRmb2xpb192YWx1ZXMpDQpgYGANCg0KRGFyaSB0YWJlbCBkaWF0YXMsIG1hc2luZy1tYXNpbmcgcG9ydG9mb2xpbyBwYWRhIHNldGlhcCBzYWhhbSBtZW1pbGlraSBwZW5nZW1iYWxpYW4sIHJpc2lrbywgZGFuIHNoYXJwZSByYXRpby4NCg0KIyBWYXJpYXNpIE1pbmltdW0NCg0KYGBge3J9DQpsaWJyYXJ5KGZvcmNhdHMpDQoNCm1pbl92YXIgPC0gcG9ydGZvbGlvX3ZhbHVlc1t3aGljaC5taW4ocG9ydGZvbGlvX3ZhbHVlcyRSaXNrKSxdDQoNCnAgPC0gbWluX3ZhciAlPiUNCiAgZ2F0aGVyKEJCQ0EuSks6VExLTS5KSywga2V5ID0gQXNzZXQsDQogICAgICAgICB2YWx1ZSA9IFdlaWdodHMpICU+JQ0KICBtdXRhdGUoQXNzZXQgPSBhcy5mYWN0b3IoQXNzZXQpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoQXNzZXQsV2VpZ2h0cyksIHkgPSBXZWlnaHRzLCBmaWxsID0gQXNzZXQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoeCA9ICdBc2V0JywgDQogICAgICAgeSA9ICdCb2JvdCcsIA0KICAgICAgIHRpdGxlID0gIkJvYm90IFBvcnRvZm9saW8gZGVuZ2FuIFZhcmlhbnNpIE1pbmltdW0iKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiICkNCg0KZ2dwbG90bHkocCkNCg0KYGBgDQogRGFyaSBvdXRwdXQgZGkgYXRhcywgcG9ydG9mb2xpbyB2YXJpYW5zaSBtaW5pbXVtIHBhZGEgc2FoYW0gS0FFRi5KSyBkYW4gSE1TUC5KSy4gS2ViYW55YWthbiBpbnZlcnN0b3IgaW52ZXN0YXNpIGRpIEJCQ0EuSksgZGFuIFRMS00uSksuDQogDQojIFBvcnRvZm9saW8gVGFuZ2Vuc2kNCg0KU2hhcnBlIHJhdGlvIGFkYWxhaCByYXNpbyB5YW5nIG1lbnVuanVra2FuIGJlc2FyYW4gcmV0dXJuIGluc3RydW1lbiBpbnZlc3Rhc2kuIFNldGVsYWggbWVsaWhhdCBwb3J0b2ZvbGlvIHZhcmlhbnNpIG1pbmltdW0gZGFwYXQgbWVsYWt1a2FuIHBvcnRvZm9saW8gdGFuZ2Vuc2kgZGVuZ2FuIHNoYXJwZSByYXRpbyB0ZXJ0aW5nZ2kuDQoNCmBgYHtyfQ0KbWF4X3NyIDwtIHBvcnRmb2xpb192YWx1ZXNbd2hpY2gubWF4KHBvcnRmb2xpb192YWx1ZXMkU2hhcnBlUmF0aW8pLF0NCg0KcCA8LSBtYXhfc3IgJT4lDQogIGdhdGhlcihCQkNBLkpLOlRMS00uSkssIGtleSA9IEFzc2V0LA0KICAgICAgICAgdmFsdWUgPSBXZWlnaHRzKSAlPiUNCiAgbXV0YXRlKEFzc2V0ID0gYXMuZmFjdG9yKEFzc2V0KSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKEFzc2V0LFdlaWdodHMpLCB5ID0gV2VpZ2h0cywgZmlsbCA9IEFzc2V0KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAnQXNldCcsIA0KICAgICAgIHkgPSAnQm9ib3QnLCANCiAgICAgICB0aXRsZSA9ICJCb2JvdCBQb3J0b2ZvbGlvIFRhbmdlbnNpIChNYWtzaW11bSBTaGFycGUgUmF0aW8pIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiApDQoNCmdncGxvdGx5KHApDQpgYGANCg0KRGFyaSBvdW90cHV0IGRpYXRhcyBkYXBhdCBkaWxpaGF0IGJhaHdhIA0KDQojIyBCYXRhcyBFZmlzaWVuIFBvcnRvZm9saW8NCg0KYGBge3J9DQpwIDwtIHBvcnRmb2xpb192YWx1ZXMgJT4lDQogIGdncGxvdChhZXMoeCA9IFJpc2ssIHkgPSBSZXR1cm4sIGNvbG9yID0gU2hhcnBlUmF0aW8pKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBsYWJzKHggPSAnUmlzaWtvIFRhaHVuYW4nLA0KICAgICAgIHkgPSAnUGVuZ2VtYmFsaWFuIFRhaHVuYW4nLA0KICAgICAgIHRpdGxlID0gIk9wdGltYXNpIFBvcnRvZm9saW8gJiBQZXJiYXRhc2FuIHlhbmcgRWZpc2llbiIpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IFJpc2ssIHkgPSBSZXR1cm4pLCBkYXRhID0gbWluX3ZhciwgY29sb3IgPSAncmVkJykgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gUmlzaywgeSA9IFJldHVybiksIGRhdGEgPSBtYXhfc3IsIGNvbG9yID0gJ3JlZCcpICsNCiAgYW5ub3RhdGUoJ3RleHQnLCB4ID0gMC4zMSwgeSA9IDAuMzEsIGxhYmVsID0gIlBvcnRvZm9saW8gVGFuZ2Vuc2kiKSArDQogIGFubm90YXRlKCd0ZXh0JywgeCA9IDAuMjQsIHkgPSAwLjExLCBsYWJlbCA9ICJQb3J0b2ZvbGlvIFZhcmlhbnMgbWluaW11bSIpICsNCiAgYW5ub3RhdGUoZ2VvbSA9ICdzZWdtZW50JywgeCA9IDAuMzAyMywgeGVuZCA9IDAuMzAyMywgIHkgPSAwLjIzLCANCiAgICAgICAgICAgeWVuZCA9IDAuMjksIGNvbG9yID0gJ3JlZCcsIGFycm93ID0gYXJyb3codHlwZSA9ICJvcGVuIikpICsNCiAgYW5ub3RhdGUoZ2VvbSA9ICdzZWdtZW50JywgeCA9IDAuMjUsIHhlbmQgPSAwLjI1LCAgeSA9IDAuMDE1LCANCiAgICAgICAgICAgeWVuZCA9IDAuMTAsIGNvbG9yID0gJ3JlZCcsIGFycm93ID0gYXJyb3codHlwZSA9ICJvcGVuIikpDQogIA0KZ2dwbG90bHkocCkNCmBgYA0KDQoNCg0KDQo=