setup - libaries & custom functions

# libraries 
library(tidyverse) # data wrangling & plotting
library(httr) # api get/post requests

# cnbc api function for later - pulls sector etfs
# data from this table [https://www.cnbc.com/sector-etfs/]
cnbc_api <- function(){
  request <- GET("https://quote.cnbc.com/quote-html-webservice/restQuote/symbolType/symbol?symbols=XLE%7CXLF%7CXLU%7CXLI%7CGDX%7CXLK%7CXLV%7CXLY%7CXLP%7CXLB%7CXOP%7CIYR%7CXHB%7CITB%7CVNQ%7CGDXJ%7CIYE%7COIH%7CXME%7CXRT%7CSMH%7CIBB%7CKBE%7CKRE%7CXTL&requestMethod=itv&noform=1&partnerId=2&fund=1&exthrs=1&output=json&events=1")
  
  if(status_code(request) == 200){
    contents <- content(request)
    cnbc_list <- contents[["FormattedQuoteResult"]][["FormattedQuote"]]
    cnbc_data <- lapply(1:length(cnbc_list), function(x){
      as.data.frame(cnbc_list[x])}) %>% 
      bind_rows(.)
    
    return(cnbc_data)
    
  } else {
    message(sprintf("Status Code %s - No Data!", status_code(request)))
    return()
  }
}

setup - downloading cleaned data from other markdown

# cleaned option data from orats
option_data <- readRDS(file = "data/clean_orats_core.rds")
# cleaned price data from yahoo
price_data <- readRDS(file = "data/clean_price_data.rds")

# samples of both tables
head(option_data, 3)
head(price_data, 3)

data prep - pulling sector etf tbl from cnbc

# pulling cnbc sector etf table, then displaying a sample
cnbc_tbl <- cnbc_api()

#sample
head(cnbc_tbl, 3)

# filtering for etfs whose data we have in our cleaned tables
etf_tbl <- cnbc_tbl %>%
  select("ticker" = symbol,
         name) %>%
  filter(ticker %in% unique(price_data$ticker))

# sample of final etf table
head(etf_tbl, 3)

data prep - calculating price rate-of-change & preparing to calc relative value table with energy tickers

# calculating the log rate-of-change of adjclose prices
price_returns <- price_data %>%
  group_by(ticker) %>%
  arrange(ticker, date) %>%
  mutate(price_change = round(log(adj_close/lag(adj_close)), 4)) %>%
  ungroup()

# sample
head(price_returns, 3)

# going to filter for tickers that has sector = "Energy" and see how much data for all
# if one ticker has too few - it will tamper with the correlation range since the whole table will remove the data to be equal
price_returns %>%
  filter(ticker %in% c(option_data[option_data$sector == "Energy",]$ticker, "XLE")) %>%
  count(ticker) %>%
  arrange(n)

# calculating pearson correlation with xle & all selected tickers
corr_tbl <- price_returns %>%
  filter(ticker %in% c(option_data[option_data$sector == "Energy",]$ticker, "XLE")) %>%
  pivot_wider(id_cols = date, names_from = ticker, values_from = price_change) %>%
  drop_na() %>%
  select(-date) %>%
  as.matrix(.) %>%
  cor(.) %>%
  data.frame(
    etf = "XLE",
    ticker = row.names(.),
    row.names = NULL) %>%
  select(etf, ticker, "correlation" = XLE) %>%
  arrange(desc(correlation))

# sample of correlation table
# etf = benchmark etf (xle)
# ticker = energy ticker
# correlation = pearson correlation between price log rate-of-change
head(corr_tbl, 3)

data prep - run simple linear regressions for coefficients of energy tickers ~ xle

# preparing energy price tbl for the model calculation
energy_price_tbl <- price_returns %>%
  filter(ticker %in% c(option_data[option_data$sector == "Energy",]$ticker, "XLE")) %>%
  pivot_wider(id_cols = date, names_from = ticker, values_from = price_change) %>%
  drop_na() 

# sample
head(energy_price_tbl, 3)

# lapply loop to calculate the model of each ticker ~ xle 
# binding data frame with their coefficients (alpha & beta)
model_tbl <- lapply(2:length(energy_price_tbl), function(x){
  ticker <- names(energy_price_tbl)[x]
  coefs <- coefficients(lm(energy_price_tbl[,ticker][[1]] ~ energy_price_tbl[,"XLE"][[1]]))
  
  df <- data.frame(
    etf = "XLE",
    ticker = ticker,
    alpha = coefs[1],
    beta = coefs[2],
    row.names = NULL)
  
  return(df)}) %>%
  bind_rows() %>%
  mutate(across(alpha:beta, function(x) round(x, 4)))

# sample
head(model_tbl, 3)

data visualization - joined all tables into an “energy table”

# joining all tables
# calculating forecast iv & difference between iv-forecast
energy_tbl <- left_join(corr_tbl, model_tbl, by = c("etf", "ticker")) %>%
  left_join(option_data, by = "ticker") %>%
  rename_all(~str_replace_all(., "atmivm", "iv")) %>%
  mutate(across(starts_with("iv"), function(x) round(first(x) * beta, 2), .names = "{.col}_forecast"),
         first_month = iv1 - iv1_forecast,
         second_month = iv2 - iv2_forecast,
         third_month = iv3 - iv3_forecast,
         fourth_month = iv4 - iv4_forecast)

# sample
head(energy_tbl, 3)

# flipped column chart of the **absolute** difference between iv & forecast iv
# in descending order, only displaying the front 2 monthlies
energy_tbl %>%
  pivot_longer(first_month:second_month) %>%
  select(ticker, correlation, name, value) %>%
  mutate(value = abs(value)) %>%
  ggplot(aes(fct_reorder(ticker, value), value, fill = correlation)) +
  geom_col() +
  coord_flip() +
  facet_wrap(~name, scales = "free") +
  labs(title = "energy tickers: current implied vol & forecast implied vol absolute difference",
       subtitle = "absolute difference between atm monthly iv & forecast iv (with xle beta 1year)",
       x = "energy tickers", y = "absolute implied volatility difference",
       caption = "the greater the difference, the hypothetically larger the inefficiency. compare the difference with the correlation to xle. only showcasing the front two monthly expiries.")

final table - energy table

energy_tbl
LS0tDQp0aXRsZTogInJlbGF0aXZlIHZhbHVlIHNjYW5uZXIgZXhlcmNpc2UiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgc2V0dXAgLSBsaWJhcmllcyAmIGN1c3RvbSBmdW5jdGlvbnMNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCiMgbGlicmFyaWVzIA0KbGlicmFyeSh0aWR5dmVyc2UpICMgZGF0YSB3cmFuZ2xpbmcgJiBwbG90dGluZw0KbGlicmFyeShodHRyKSAjIGFwaSBnZXQvcG9zdCByZXF1ZXN0cw0KDQojIGNuYmMgYXBpIGZ1bmN0aW9uIGZvciBsYXRlciAtIHB1bGxzIHNlY3RvciBldGZzDQojIGRhdGEgZnJvbSB0aGlzIHRhYmxlIFtodHRwczovL3d3dy5jbmJjLmNvbS9zZWN0b3ItZXRmcy9dDQpjbmJjX2FwaSA8LSBmdW5jdGlvbigpew0KICByZXF1ZXN0IDwtIEdFVCgiaHR0cHM6Ly9xdW90ZS5jbmJjLmNvbS9xdW90ZS1odG1sLXdlYnNlcnZpY2UvcmVzdFF1b3RlL3N5bWJvbFR5cGUvc3ltYm9sP3N5bWJvbHM9WExFJTdDWExGJTdDWExVJTdDWExJJTdDR0RYJTdDWExLJTdDWExWJTdDWExZJTdDWExQJTdDWExCJTdDWE9QJTdDSVlSJTdDWEhCJTdDSVRCJTdDVk5RJTdDR0RYSiU3Q0lZRSU3Q09JSCU3Q1hNRSU3Q1hSVCU3Q1NNSCU3Q0lCQiU3Q0tCRSU3Q0tSRSU3Q1hUTCZyZXF1ZXN0TWV0aG9kPWl0diZub2Zvcm09MSZwYXJ0bmVySWQ9MiZmdW5kPTEmZXh0aHJzPTEmb3V0cHV0PWpzb24mZXZlbnRzPTEiKQ0KICANCiAgaWYoc3RhdHVzX2NvZGUocmVxdWVzdCkgPT0gMjAwKXsNCiAgICBjb250ZW50cyA8LSBjb250ZW50KHJlcXVlc3QpDQogICAgY25iY19saXN0IDwtIGNvbnRlbnRzW1siRm9ybWF0dGVkUXVvdGVSZXN1bHQiXV1bWyJGb3JtYXR0ZWRRdW90ZSJdXQ0KICAgIGNuYmNfZGF0YSA8LSBsYXBwbHkoMTpsZW5ndGgoY25iY19saXN0KSwgZnVuY3Rpb24oeCl7DQogICAgICBhcy5kYXRhLmZyYW1lKGNuYmNfbGlzdFt4XSl9KSAlPiUgDQogICAgICBiaW5kX3Jvd3MoLikNCiAgICANCiAgICByZXR1cm4oY25iY19kYXRhKQ0KICAgIA0KICB9IGVsc2Ugew0KICAgIG1lc3NhZ2Uoc3ByaW50ZigiU3RhdHVzIENvZGUgJXMgLSBObyBEYXRhISIsIHN0YXR1c19jb2RlKHJlcXVlc3QpKSkNCiAgICByZXR1cm4oKQ0KICB9DQp9DQpgYGANCg0KIyMjIHNldHVwIC0gZG93bmxvYWRpbmcgY2xlYW5lZCBkYXRhIGZyb20gb3RoZXIgbWFya2Rvd24NCi0gb3B0aW9uIGRhdGEgKGZyb20gb3JhdHMpLCBpbnRlbmRlZCB0byBiZSBiYXJlLWJvbmVzIHNvIHRoaXMgY2FuIGJlIGRvbmUgd2l0aCBhbnkgYXBpIHdpdGggb3B0aW9uIGNvbnRyYWN0IGRhdGENCi0gcHJpY2UgZGF0YSAoZnJvbSB5YWhvbykNCg0KYGBge3J9DQojIGNsZWFuZWQgb3B0aW9uIGRhdGEgZnJvbSBvcmF0cw0Kb3B0aW9uX2RhdGEgPC0gcmVhZFJEUyhmaWxlID0gImRhdGEvY2xlYW5fb3JhdHNfY29yZS5yZHMiKQ0KIyBjbGVhbmVkIHByaWNlIGRhdGEgZnJvbSB5YWhvbw0KcHJpY2VfZGF0YSA8LSByZWFkUkRTKGZpbGUgPSAiZGF0YS9jbGVhbl9wcmljZV9kYXRhLnJkcyIpDQoNCiMgc2FtcGxlcyBvZiBib3RoIHRhYmxlcw0KaGVhZChvcHRpb25fZGF0YSwgMykNCmhlYWQocHJpY2VfZGF0YSwgMykNCmBgYA0KDQojIyMgZGF0YSBwcmVwIC0gcHVsbGluZyBzZWN0b3IgZXRmIHRibCBmcm9tIGNuYmMNCi0gd2lsbCBiZSB1c2luZyB0aGVzZSBldGZzIGFzIGJlbmNobWFya3MgZm9yIHRoZSByZWxhdGl2ZSB2YWx1ZSB0YWJsZQ0KDQpgYGB7cn0NCiMgcHVsbGluZyBjbmJjIHNlY3RvciBldGYgdGFibGUsIHRoZW4gZGlzcGxheWluZyBhIHNhbXBsZQ0KY25iY190YmwgPC0gY25iY19hcGkoKQ0KDQojc2FtcGxlDQpoZWFkKGNuYmNfdGJsLCAzKQ0KDQojIGZpbHRlcmluZyBmb3IgZXRmcyB3aG9zZSBkYXRhIHdlIGhhdmUgaW4gb3VyIGNsZWFuZWQgdGFibGVzDQpldGZfdGJsIDwtIGNuYmNfdGJsICU+JQ0KICBzZWxlY3QoInRpY2tlciIgPSBzeW1ib2wsDQogICAgICAgICBuYW1lKSAlPiUNCiAgZmlsdGVyKHRpY2tlciAlaW4lIHVuaXF1ZShwcmljZV9kYXRhJHRpY2tlcikpDQoNCiMgc2FtcGxlIG9mIGZpbmFsIGV0ZiB0YWJsZQ0KaGVhZChldGZfdGJsLCAzKQ0KYGBgDQoNCiMjIyBkYXRhIHByZXAgLSBjYWxjdWxhdGluZyBwcmljZSByYXRlLW9mLWNoYW5nZSAmIHByZXBhcmluZyB0byBjYWxjIHJlbGF0aXZlIHZhbHVlIHRhYmxlIHdpdGggKiplbmVyZ3kqKiB0aWNrZXJzDQotIGdvaW5nIHRvIGNhbGN1bGF0ZSBhIHBlYXJzb24gY29ycmVsYXRpb24gdGFibGUgKHdpdGggZW5lcmd5IHRpY2tlcnMgJiB4bGUpDQoNCmBgYHtyfQ0KIyBjYWxjdWxhdGluZyB0aGUgbG9nIHJhdGUtb2YtY2hhbmdlIG9mIGFkamNsb3NlIHByaWNlcw0KcHJpY2VfcmV0dXJucyA8LSBwcmljZV9kYXRhICU+JQ0KICBncm91cF9ieSh0aWNrZXIpICU+JQ0KICBhcnJhbmdlKHRpY2tlciwgZGF0ZSkgJT4lDQogIG11dGF0ZShwcmljZV9jaGFuZ2UgPSByb3VuZChsb2coYWRqX2Nsb3NlL2xhZyhhZGpfY2xvc2UpKSwgNCkpICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBzYW1wbGUNCmhlYWQocHJpY2VfcmV0dXJucywgMykNCg0KIyBnb2luZyB0byBmaWx0ZXIgZm9yIHRpY2tlcnMgdGhhdCBoYXMgc2VjdG9yID0gIkVuZXJneSIgYW5kIHNlZSBob3cgbXVjaCBkYXRhIGZvciBhbGwNCiMgaWYgb25lIHRpY2tlciBoYXMgdG9vIGZldyAtIGl0IHdpbGwgdGFtcGVyIHdpdGggdGhlIGNvcnJlbGF0aW9uIHJhbmdlIHNpbmNlIHRoZSB3aG9sZSB0YWJsZSB3aWxsIHJlbW92ZSB0aGUgZGF0YSB0byBiZSBlcXVhbA0KcHJpY2VfcmV0dXJucyAlPiUNCiAgZmlsdGVyKHRpY2tlciAlaW4lIGMob3B0aW9uX2RhdGFbb3B0aW9uX2RhdGEkc2VjdG9yID09ICJFbmVyZ3kiLF0kdGlja2VyLCAiWExFIikpICU+JQ0KICBjb3VudCh0aWNrZXIpICU+JQ0KICBhcnJhbmdlKG4pDQoNCiMgY2FsY3VsYXRpbmcgcGVhcnNvbiBjb3JyZWxhdGlvbiB3aXRoIHhsZSAmIGFsbCBzZWxlY3RlZCB0aWNrZXJzDQpjb3JyX3RibCA8LSBwcmljZV9yZXR1cm5zICU+JQ0KICBmaWx0ZXIodGlja2VyICVpbiUgYyhvcHRpb25fZGF0YVtvcHRpb25fZGF0YSRzZWN0b3IgPT0gIkVuZXJneSIsXSR0aWNrZXIsICJYTEUiKSkgJT4lDQogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBkYXRlLCBuYW1lc19mcm9tID0gdGlja2VyLCB2YWx1ZXNfZnJvbSA9IHByaWNlX2NoYW5nZSkgJT4lDQogIGRyb3BfbmEoKSAlPiUNCiAgc2VsZWN0KC1kYXRlKSAlPiUNCiAgYXMubWF0cml4KC4pICU+JQ0KICBjb3IoLikgJT4lDQogIGRhdGEuZnJhbWUoDQogICAgZXRmID0gIlhMRSIsDQogICAgdGlja2VyID0gcm93Lm5hbWVzKC4pLA0KICAgIHJvdy5uYW1lcyA9IE5VTEwpICU+JQ0KICBzZWxlY3QoZXRmLCB0aWNrZXIsICJjb3JyZWxhdGlvbiIgPSBYTEUpICU+JQ0KICBhcnJhbmdlKGRlc2MoY29ycmVsYXRpb24pKQ0KDQojIHNhbXBsZSBvZiBjb3JyZWxhdGlvbiB0YWJsZQ0KIyBldGYgPSBiZW5jaG1hcmsgZXRmICh4bGUpDQojIHRpY2tlciA9IGVuZXJneSB0aWNrZXINCiMgY29ycmVsYXRpb24gPSBwZWFyc29uIGNvcnJlbGF0aW9uIGJldHdlZW4gcHJpY2UgbG9nIHJhdGUtb2YtY2hhbmdlDQpoZWFkKGNvcnJfdGJsLCAzKQ0KYGBgDQoNCiMjIyBkYXRhIHByZXAgLSBydW4gc2ltcGxlIGxpbmVhciByZWdyZXNzaW9ucyBmb3IgY29lZmZpY2llbnRzIG9mIGVuZXJneSB0aWNrZXJzIH4geGxlDQotIGNyZWF0aW5nICJtb2RlbCB0YWJsZSIgd2l0aCBhbHBoYSAmIGJldGEgdmFsdWVzDQoNCmBgYHtyfQ0KIyBwcmVwYXJpbmcgZW5lcmd5IHByaWNlIHRibCBmb3IgdGhlIG1vZGVsIGNhbGN1bGF0aW9uDQplbmVyZ3lfcHJpY2VfdGJsIDwtIHByaWNlX3JldHVybnMgJT4lDQogIGZpbHRlcih0aWNrZXIgJWluJSBjKG9wdGlvbl9kYXRhW29wdGlvbl9kYXRhJHNlY3RvciA9PSAiRW5lcmd5IixdJHRpY2tlciwgIlhMRSIpKSAlPiUNCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGRhdGUsIG5hbWVzX2Zyb20gPSB0aWNrZXIsIHZhbHVlc19mcm9tID0gcHJpY2VfY2hhbmdlKSAlPiUNCiAgZHJvcF9uYSgpIA0KDQojIHNhbXBsZQ0KaGVhZChlbmVyZ3lfcHJpY2VfdGJsLCAzKQ0KDQojIGxhcHBseSBsb29wIHRvIGNhbGN1bGF0ZSB0aGUgbW9kZWwgb2YgZWFjaCB0aWNrZXIgfiB4bGUgDQojIGJpbmRpbmcgZGF0YSBmcmFtZSB3aXRoIHRoZWlyIGNvZWZmaWNpZW50cyAoYWxwaGEgJiBiZXRhKQ0KbW9kZWxfdGJsIDwtIGxhcHBseSgyOmxlbmd0aChlbmVyZ3lfcHJpY2VfdGJsKSwgZnVuY3Rpb24oeCl7DQogIHRpY2tlciA8LSBuYW1lcyhlbmVyZ3lfcHJpY2VfdGJsKVt4XQ0KICBjb2VmcyA8LSBjb2VmZmljaWVudHMobG0oZW5lcmd5X3ByaWNlX3RibFssdGlja2VyXVtbMV1dIH4gZW5lcmd5X3ByaWNlX3RibFssIlhMRSJdW1sxXV0pKQ0KICANCiAgZGYgPC0gZGF0YS5mcmFtZSgNCiAgICBldGYgPSAiWExFIiwNCiAgICB0aWNrZXIgPSB0aWNrZXIsDQogICAgYWxwaGEgPSBjb2Vmc1sxXSwNCiAgICBiZXRhID0gY29lZnNbMl0sDQogICAgcm93Lm5hbWVzID0gTlVMTCkNCiAgDQogIHJldHVybihkZil9KSAlPiUNCiAgYmluZF9yb3dzKCkgJT4lDQogIG11dGF0ZShhY3Jvc3MoYWxwaGE6YmV0YSwgZnVuY3Rpb24oeCkgcm91bmQoeCwgNCkpKQ0KDQojIHNhbXBsZQ0KaGVhZChtb2RlbF90YmwsIDMpDQpgYGANCg0KIyMjIGRhdGEgdmlzdWFsaXphdGlvbiAtIGpvaW5lZCBhbGwgdGFibGVzIGludG8gYW4gImVuZXJneSB0YWJsZSINCi0gam9pbmVkIGNvcnJlbGF0aW9uLCBtb2RlbCAmIG9wdGlvbiBkYXRhIHRhYmxlcw0KLSBjYWxjdWxhdGVkIHRoZSAiaXYgZm9yZWNhc3QiIHdpdGggeGxlIDF5ciBiZXRhDQotIGNhbGN1bGF0ZWQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdGlja2VycyBjdXJyZW50IGltcGxpZWQgdm9sICYgZm9yZWNhc3QgYWNyb3NzIGVhY2ggbW9udGhseSBleHBpcnkNCi0gZ3JhcGhlZCBhIHZpc3VhbGl6YXRpb24gb2YgdGhlICoqYWJzb2x1dGUqKiBkaWZmZXJlbmNlIGJldHdlZW4gaW1wbGllZCB2b2wgJiBmb3JlY2FzdCB2b2wNCiAgLSBhcnJhbmdlZCBkaWZmZXJlbmNlZCB2YWx1ZXMgaW4gZGVzY2VuZGluZyBvcmRlcg0KICAtIGZhY2V0ZWQgdGhlIGRhdGEgaW50byB0d28gcGxvdHMsICJmcm9udCBtb250aCIgJiAic2Vjb25kIG1vbnRoIg0KICAtIGZpbGxlZCB0aGUgY29sdW1uIGNoYXJ0cyBieSBjb3JyZWxhdGlvbiB2YWx1ZSB0byB4bGUgKHRoZSBicmlnaHRlciBibHVlIHRoZSBjb2x1bW4sIHRoZSBncmVhdGVyIHRoZSBjb3JyZWxhdGlvbiB0byB4bGUpDQogIC0gYXMgZXhwZWN0ZWQsIHRpY2tlcnMgbGVhc3QgY29ycmVsYXRpb24gdG8geGxlIHdpbGwgaGF2ZSBhIGdyZWF0ZXIgc3ByZWFkIHRvIG91ciBmb3JlY2FzdCBpdg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9DQojIGpvaW5pbmcgYWxsIHRhYmxlcw0KIyBjYWxjdWxhdGluZyBmb3JlY2FzdCBpdiAmIGRpZmZlcmVuY2UgYmV0d2VlbiBpdi1mb3JlY2FzdA0KZW5lcmd5X3RibCA8LSBsZWZ0X2pvaW4oY29ycl90YmwsIG1vZGVsX3RibCwgYnkgPSBjKCJldGYiLCAidGlja2VyIikpICU+JQ0KICBsZWZ0X2pvaW4ob3B0aW9uX2RhdGEsIGJ5ID0gInRpY2tlciIpICU+JQ0KICByZW5hbWVfYWxsKH5zdHJfcmVwbGFjZV9hbGwoLiwgImF0bWl2bSIsICJpdiIpKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiaXYiKSwgZnVuY3Rpb24oeCkgcm91bmQoZmlyc3QoeCkgKiBiZXRhLCAyKSwgLm5hbWVzID0gInsuY29sfV9mb3JlY2FzdCIpLA0KICAgICAgICAgZmlyc3RfbW9udGggPSBpdjEgLSBpdjFfZm9yZWNhc3QsDQogICAgICAgICBzZWNvbmRfbW9udGggPSBpdjIgLSBpdjJfZm9yZWNhc3QsDQogICAgICAgICB0aGlyZF9tb250aCA9IGl2MyAtIGl2M19mb3JlY2FzdCwNCiAgICAgICAgIGZvdXJ0aF9tb250aCA9IGl2NCAtIGl2NF9mb3JlY2FzdCkNCg0KIyBzYW1wbGUNCmhlYWQoZW5lcmd5X3RibCwgMykNCg0KIyBmbGlwcGVkIGNvbHVtbiBjaGFydCBvZiB0aGUgKiphYnNvbHV0ZSoqIGRpZmZlcmVuY2UgYmV0d2VlbiBpdiAmIGZvcmVjYXN0IGl2DQojIGluIGRlc2NlbmRpbmcgb3JkZXIsIG9ubHkgZGlzcGxheWluZyB0aGUgZnJvbnQgMiBtb250aGxpZXMNCmVuZXJneV90YmwgJT4lDQogIHBpdm90X2xvbmdlcihmaXJzdF9tb250aDpzZWNvbmRfbW9udGgpICU+JQ0KICBzZWxlY3QodGlja2VyLCBjb3JyZWxhdGlvbiwgbmFtZSwgdmFsdWUpICU+JQ0KICBtdXRhdGUodmFsdWUgPSBhYnModmFsdWUpKSAlPiUNCiAgZ2dwbG90KGFlcyhmY3RfcmVvcmRlcih0aWNrZXIsIHZhbHVlKSwgdmFsdWUsIGZpbGwgPSBjb3JyZWxhdGlvbikpICsNCiAgZ2VvbV9jb2woKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGZhY2V0X3dyYXAofm5hbWUsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBsYWJzKHRpdGxlID0gImVuZXJneSB0aWNrZXJzOiBjdXJyZW50IGltcGxpZWQgdm9sICYgZm9yZWNhc3QgaW1wbGllZCB2b2wgYWJzb2x1dGUgZGlmZmVyZW5jZSIsDQogICAgICAgc3VidGl0bGUgPSAiYWJzb2x1dGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGF0bSBtb250aGx5IGl2ICYgZm9yZWNhc3QgaXYgKHdpdGggeGxlIGJldGEgMXllYXIpIiwNCiAgICAgICB4ID0gImVuZXJneSB0aWNrZXJzIiwgeSA9ICJhYnNvbHV0ZSBpbXBsaWVkIHZvbGF0aWxpdHkgZGlmZmVyZW5jZSIsDQogICAgICAgY2FwdGlvbiA9ICJ0aGUgZ3JlYXRlciB0aGUgZGlmZmVyZW5jZSwgdGhlIGh5cG90aGV0aWNhbGx5IGxhcmdlciB0aGUgaW5lZmZpY2llbmN5LiBjb21wYXJlIHRoZSBkaWZmZXJlbmNlIHdpdGggdGhlIGNvcnJlbGF0aW9uIHRvIHhsZS4gb25seSBzaG93Y2FzaW5nIHRoZSBmcm9udCB0d28gbW9udGhseSBleHBpcmllcy4iKQ0KYGBgDQoNCiMjIyBmaW5hbCB0YWJsZSAtIGVuZXJneSB0YWJsZQ0KLSBmaW5hbCB0YWJsZSB3aXRoIGFsbCBjYWxjdWxhdGlvbnMgZnJvbSB0aGlzIGV4ZXJjaXNlIHdpdGggdGlja2VycyBmcm9tIHRoZSBlbmVyZ3kgc2VjdG9yDQotIGFnYWluLCB0aGVyZSB3ZXJlIHByZS1maWx0ZXJpbmcgZG9uZSB3aGVuIGNsZWFuaW5nIGRhdGEgaW4gYW5vdGhlciBtYXJrZG93biwgcmVmZXIgdG8gdGhhdCBmb3IgZGV0YWlscw0KDQpgYGB7cn0NCmVuZXJneV90YmwNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K