library(tidyverse)
library(tidyquant)
library(timetk)
library(tibbletime)
library(viridis)
library(highcharter)
library(ggthemes)
library(dygraphs)
library(knitr)
library(stringr)
library(plotly)
library(scales)

S&P 500 stock,Russell 3000, Stockholm 30 Index, NASDAQ Global Market Composite NYSE Composite,State Street Global Advisors launched the SPDR S&P 500 ETF (NYSE:SPY),the SPDR Dow Jones Industrial Average (NYSE:DIA)

# The symbols vector holds our tickers. 
tickers <- c( "SPX","NYA","SPY","DIA")
# The prices object will hold our raw price data throughout this book.
prices <- 
  getSymbols(tickers, src = 'yahoo', from = "2015-01-01", 
             auto.assign = TRUE, warnings = FALSE)
prices
[1] "SPX" "NYA" "SPY" "DIA"

^IXIC is Nasdaq symbol,RUSSELL 2000 INDEX (^RUT),Dow Jones Industrial Average (NYSE:DIA),State Street Global Advisors launched the SPDR S&P 500 ETF (NYSE:SPY)

prices1=tq_get(c( "SPY","DIA","^IXIC","^RUT"), from = "2012-01-01", get = 'stock.prices')
tail(prices1)
head(prices1)
prices2<-prices1%>%select(-c(open,high,low,close,volume))
prices2
#remove non alphabet characters
prices2$symbol<-gsub("[^[:alpha:]]", "", prices2$symbol)
head(prices2)
tail(prices2)
prices1$symbol = str_replace_all(prices1$symbol, pattern = "[^[:alpha:]]", "")
head(prices1)
tail(prices1)
prices1%>%
ggplot(aes(date, adjusted, color = symbol)) +
geom_line() +
labs(title = "Multi stock example",
xlab = "Date",
ylab = "Adjusted Close")+theme_economist_white()+
  
  geom_area(fill = "cyan", alpha = .1)

ggplotly()
# Get stock prices
stocks <- c("AAPL", "FB", "NFLX", "GOOG","AMZN") %>%
tq_get(from = "2012-01-01")
stocks
# Plot for stocks
stocks %>%
ggplot(aes(date, adjusted, color = symbol)) +
geom_line() +
labs(title = "Multi stock example",
xlab = "Date",
ylab = "Adjusted Close")+theme_economist_white()

Use quantmod periodReturn to Convert Prices to Returns

The quantmod::periodReturn() function generates returns by periodicity.

We want to use the adjusted closing prices column (adjusted for stock splits, which can make it appear that a stock is performing poorly if a split is included). We set select = adjusted. We research the periodReturn function, and we found that it accepts type = “arithmetic” and period = “yearly”, which returns the annual returns.

Annual_returns <- prices1 %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "yearly", 
                 type       = "arithmetic")
Annual_returns
#Annual_returns %>%
   # ggplot(aes(x = date, y = yearly.returns, fill = symbol))+stat_count(stat = "identity")
Annual_returns<- prices2 %>%tk_tbl()%>%
    group_by(symbol) %>%
    tq_transmute(mutate_fun = periodReturn, 
                 period     = "yearly", 
                 type       = "arithmetic")
Annual_returns%>%head()
Annual_returns %>%
    ggplot(aes(x = date, y = yearly.returns, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "Yearly Stock returns Prices",
         x = "", y = "Adjusted Prices", color = "") +
    #facet_wrap(~ symbol, ncol = 2, scales = "free_y") +
    scale_y_continuous(labels = scales::percent) +
    theme_tq() + 
    scale_color_tq()

#ggplotly()
Annual_returns %>%
 ggplot(aes(x = date, y = yearly.returns, fill = symbol)) +
    geom_bar(stat = "identity", width = 200) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = "Annual Returns",
         subtitle = "",
         y = "Annual Returns", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free_y") +
    theme_tq() + 
    scale_fill_tq()

Daily Log Returns

We want to use the adjusted closing prices column (adjusted for stock splits, which can make it appear that a stock is performing poorly if a split is included), so we set select = adjusted. We researched the periodReturn function, and we found that it accepts type = “log” and period = “daily”, which returns the daily log returns.

Daily_log_returns <- prices1 %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "daily", 
                 type       = "log",
                 col_rename = "monthly.returns")
Daily_log_returns %>%
    ggplot(aes(x = monthly.returns, fill = symbol)) +
    geom_density(alpha = 0.5) +
    labs(title = "Daily Log Returns",
         x = "Monthly Returns", y = "Density") +
    theme_tq() +
    scale_fill_tq() + 
    facet_wrap(~ symbol, ncol = 2,scales = "free_y")

#facet_grid(.~symbol,scales="free",space="free") 
  #scale_y_continuous(labels = scales::percent)
  #facet_wrap(~symbol, scales = "free_y", nrow = 2, strip.position = "bottom") 

Use xts to.period to Change the Periodicity from Daily to Monthly

The xts::to.period function is used for periodicity aggregation (converting from a lower level periodicity to a higher level such as minutes to hours or months to years). Because we are seeking a return structure that is on a different time scale than the input (daily versus weekly), we need to use a transmute function. We select tq_transmute() and pass the open, high, low, close and volume columns via select = open:volume. Looking at the documentation for to.period, we see that it accepts a period argument that we can set to “weeks”. The result is the OHLCV data returned with the dates changed to one day per week.

prices1 %>%
    group_by(symbol) %>%
    tq_transmute(select     = open:volume, 
                 mutate_fun = to.period, 
                 period     = "months")%>%head()

Without Periodicity Aggregation

Daily <- prices2 %>%
    group_by(symbol)
Daily %>%
    ggplot(aes(x = date, y = adjusted, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "Daily Stock Prices",
         x = "", y = "Adjusted Prices", color = "") +
    facet_wrap(~ symbol, ncol = 2, scales = "free_y") +
    scale_y_continuous(labels = scales::dollar) +
    theme_tq() + 
    scale_color_tq()

With Periodicity Aggregation

Monthly <- prices2%>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = to.period, 
                 period     = "months")
Monthly %>%
    ggplot(aes(x = date, y = adjusted, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "Monthly Stock Prices",
         x = "", y = "Adjusted Prices", color = "") +
    facet_wrap(~ symbol, ncol = 2, scales = "free_y") +
    scale_y_continuous(labels = scales::dollar) +
    theme_tq() + 
    scale_color_tq()

Use TTR runCor to Visualize Rolling Correlations of Returns

Return correlations are a common way to analyze how closely an asset or portfolio mimics a baseline index or fund. We will need a set of returns for both the stocks and baseline. The baseline will be the Spdr XLK technology sector.

# Asset Returns
returns_monthly <- prices1%>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn,
                 period     = "monthly")
# Baseline Returns
baseline_returns_monthly <- "XLK" %>%
    tq_get(get  = "stock.prices",
           from = "2012-01-01") %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn,
                 period     = "monthly")
returns_joined <-inner_join(returns_monthly, 
                            baseline_returns_monthly,
                            by = "date")
#alternatively
returns_joined2 <- merge(returns_monthly, 
                            baseline_returns_monthly,
                            by = "date")
returns_joined%>%dim()
[1] 275   4
returns_joined2%>%dim()
[1] 275   4
returns_joined%>%head()
returns_joined$symbol=factor(returns_joined$symbol)
str(returns_joined)
Classes ‘grouped_df’, ‘tbl_df’, ‘tbl’ and 'data.frame': 275 obs. of  4 variables:
 $ symbol           : Factor w/ 4 levels "DIA","IXIC","RUT",..: 4 4 4 4 4 4 4 4 4 4 ...
 $ date             : Date, format: "2012-01-31" "2012-02-29" "2012-03-30" ...
 $ monthly.returns.x: num  0.02996 0.04341 0.03216 -0.00668 -0.06006 ...
 $ monthly.returns.y: num  0.0473 0.071 0.0451 -0.0113 -0.0634 ...
 - attr(*, "vars")= chr "symbol"

6-month rolling correlation

When something is said to be rolling it’s tracking a certain amount of time in the past, and then rolls forward as time progresses. So the the 30 day rolling correlation would be the correlation between the basket of assets for the past 30 days. Tomorrow we add one more day and subtract the first day, to maintain 30 days.

The TTR::runCor function can be used to evaluate rolling correlations using the xy pattern. Because the scale is monthly, we’ll go with n = 6 for a 6-month rolling correlation. The col_rename argument enables easy renaming of the output column(s).

rolling_corr <- returns_joined %>%
    tq_transmute_xy(x          = monthly.returns.x, 
                    y          = monthly.returns.y,
                    mutate_fun = runCor,
                    n          = 6,
                    col_rename = "rolling.corr.6")
rolling_corr %>%
    ggplot(aes(x = date, y = rolling.corr.6, color = symbol)) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    geom_line(size = 1) +
    labs(title = " Six Month Rolling Correlation to XLK",
         x = "", y = "Correlation", color = "") +
    facet_wrap(~ symbol, ncol = 2) +
    theme_tq() + 
    scale_color_tq()

Use TTR MACD to Visualize Moving Average Convergence Divergence

In reviewing the available options in the TTR package, we see that MACD will get us the Moving Average Convergence Divergence (MACD). In researching the documentation, the return is in the same periodicity as the input and the functions work with OHLC functions, so we can use tq_mutate(). MACD requires a price, so we select close.

macd <- prices1 %>%
    group_by(symbol) %>%
    tq_mutate(select     = close, 
              mutate_fun = MACD, 
              nFast      = 12, 
              nSlow      = 26, 
              nSig       = 9, 
              maType     = DEMA) %>%
    mutate(diff = macd - signal) %>%
    select(-(open:volume))
macd%>%head()
macd %>%
    filter(date >= as_date("2012-03-15")) %>%
    ggplot(aes(x = date)) + 
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    geom_line(aes(y = macd, col = symbol)) +
    geom_line(aes(y = signal), color = "blue", linetype = 2) +
    geom_bar(aes(y = diff), stat = "identity", color = palette_light()[[1]]) +
    facet_wrap(~ symbol, ncol = 2, scale = "free_y") +
    labs(title = "FANG: Moving Average Convergence Divergence",
         y = "MACD", x = "", color = "") +
    theme_tq() +
    scale_color_tq()

Use xts apply.quarterly to Get the Max and Min Price for Each Quarter

The xts::apply.quarterly() function that is part of the period apply group can be used to apply functions by quarterly time segments. Because we are seeking a return structure that is on a different time scale than the input (quarterly versus daily), we need to use a transmute function. We select tq_transmute and pass the close price using select, and we send this subset of the data to the apply.quarterly function via the mutate_fun argument. Looking at the documentation for apply.quarterly, we see that we can pass a function to the argument, FUN. We want the maximum values, so we set FUN = max. The result is the quarters returned as a date and the maximum closing price during the quarter returned as a double.

max_by_qtr <- prices1 %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = apply.quarterly, 
                 FUN        = max, 
                 col_rename = "max.close") %>%
    mutate(year.qtr = paste0(year(date), "-Q", quarter(date))) %>%
    select(-date)
max_by_qtr%>%head()

The minimum each quarter can be retrieved in much the same way. The data frames can be joined using left_join to get the max and min by quarter.

min_by_qtr <- FANG %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = apply.quarterly, 
                 FUN        = min, 
                 col_rename = "min.close") %>%
    mutate(year.qtr = paste0(year(date), "-Q", quarter(date))) %>%
    select(-date)
by_qtr <- left_join(max_by_qtr, min_by_qtr,
                         by = c("symbol"   = "symbol",
                                "year.qtr" = "year.qtr"))
by_qtr%>%head()
by_qtr %>%
    ggplot(aes(x = year.qtr, color = symbol)) +
    geom_segment(aes(xend = year.qtr, y = min.close, yend = max.close),
                 size = 2) +
    geom_point(aes(y = max.close), size = 2) +
    geom_point(aes(y = min.close), size = 2) +
    facet_wrap(~ symbol, ncol = 2, scale = "free_y") +
    labs(title = " Min/Max Price By Quarter",
         y = "Stock Price", color = "") +
    theme_tq() +
    scale_color_tq() +
    scale_y_continuous(labels = scales::dollar) +
    theme(axis.text.x = element_text(angle = 90, hjust = 1),
          axis.title.x = element_blank())

Use zoo rollapply to visualize a rolling regression

A good way to analyze relationships over time is using rolling calculations that compare two assets. Pairs trading is a common mechanism for similar assets. In this example we will analyze two similar assets, Ford(F) and General Motors(GM) to show the relationship via regression.

# Get stock pairs
stock_prices <- c("F", "GM") %>%
    tq_get(get  = "stock.prices",
           from = "2012-01-01") %>%
    group_by(symbol) 
stock_pairs <- stock_prices %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "daily",
                 type       = "log",
                 col_rename = "returns") %>%
    spread(key = symbol, value = returns)
stock_prices%>%head()
stock_pairs %>%
    ggplot(aes(x = F, y = GM)) +
    geom_point(color = palette_light()[[1]], alpha = 0.5) +
    geom_smooth(method = "lm") +
    labs(title = "Visualizing Returns Relationship of Stock Pairs") +
    theme_tq()

We can get statistcs on the relationship from the lm function. The model is highly correlated with a p-value of essential zero. The coefficient estimate for GM (Coefficient 1) is 0.63 indicating a positive relationship, meaning as F increases GM also tends to increase.

lm(F ~ GM, data = stock_pairs) %>%
    broom::tidy()

The data will be passed to the regression function as an xts object. The timetk::tk_tbl function takes care of converting to a data frame.

regr_fun <- function(data) {
    coef(lm(F ~ GM, data = timetk::tk_tbl(data, silent = TRUE)))
}

We can use tq_mutate() to apply the custom regression function over a rolling window using rollapply from the zoo package. Internally, the returns_combined data frame is being passed automatically to the data argument of the rollapply function. All you need to specify is the mutate_fun = rollapply and any additional arguments necessary to apply the rollapply function. We’ll specify a 90 day window via width = 90. The FUN argument is our custom regression function, regr_fun. It’s extremely important to specify by.column = FALSE, which tells rollapply to perform the computation using the data as a whole rather than apply the function to each column independently. The col_rename argument is used to rename the added columns.

stock_pairs <- stock_pairs %>%
         tq_mutate(mutate_fun = rollapply,
                   width      = 90,
                   FUN        = regr_fun,
                   by.column  = FALSE,
                   col_rename = c("coef.0", "coef.1"))
stock_pairs%>%head()
stock_pairs %>%
    ggplot(aes(x = date, y = coef.1)) +
    geom_line(size = 1, color = palette_light()[[1]]) +
    geom_hline(yintercept = 0.8134, size = 1, color = palette_light()[[2]]) +
    labs(title = "F ~ GM: Visualizing Rolling Regression Coefficient", x = "") +
    theme_tq()

Stock returns during this time period.

stock_prices %>%
    tq_transmute(adjusted, 
                 periodReturn, 
                 period = "daily", 
                 type = "log", 
                 col_rename = "returns") %>%
    mutate(wealth.index = 100 * cumprod(1 + returns)) %>%
    ggplot(aes(x = date, y = wealth.index, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "F and GM: Stock Prices") +
    theme_tq() + 
    scale_color_tq()

Use Return.clean and Return.excess to clean and calculate excess returns

We use several of the PerformanceAnalytics functions to clean and format returns. The example uses three progressive applications of tq_transmute to apply various quant functions to the grouped stock prices from the initial data set. First, we calculate daily returns using quantmod::periodReturn. Next, we use Return.clean to clean outliers from the return data. The alpha parameter is the percentage of oultiers to be cleaned. Finally, the excess returns are calculated using a risk-free rate of 3% (divided by 252 for 252 trade days in one year).

prices1 %>%
    group_by(symbol) %>%
    tq_transmute(adjusted, periodReturn, period = "daily") %>%
    tq_transmute(daily.returns, Return.clean, alpha = 0.05) %>%
    tq_transmute(daily.returns, Return.excess, Rf = 0.03 / 252)
LS0tCnRpdGxlOiAiU29tZSBNYWpvciBTdG9jayBJbmRpY2VzIGFuZCAgVmlzdWFsaXphdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogTmFuYSBCb2F0ZW5nCmRmX3ByaW50OiBwYWdlZApUaW1lOiAnYHIgU3lzLnRpbWUoKWAnCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKLS0tCgogCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHlxdWFudCkKbGlicmFyeSh0aW1ldGspCmxpYnJhcnkodGliYmxldGltZSkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGR5Z3JhcGhzKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KHNjYWxlcykKYGBgCgoKCgpTJlAgNTAwIHN0b2NrLFJ1c3NlbGwgMzAwMCwgU3RvY2tob2xtIDMwIEluZGV4LApOQVNEQVEgR2xvYmFsIE1hcmtldCBDb21wb3NpdGUKTllTRSBDb21wb3NpdGUsU3RhdGUgU3RyZWV0IEdsb2JhbCBBZHZpc29ycyBsYXVuY2hlZCB0aGUgU1BEUiBTJlAgNTAwIEVURiAoTllTRTpTUFkpLHRoZSBTUERSIERvdyBKb25lcyBJbmR1c3RyaWFsIEF2ZXJhZ2UgKE5ZU0U6RElBKQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CiMgVGhlIHN5bWJvbHMgdmVjdG9yIGhvbGRzIG91ciB0aWNrZXJzLiAKdGlja2VycyA8LSBjKCAiU1BYIiwiTllBIiwiU1BZIiwiRElBIikKCiMgVGhlIHByaWNlcyBvYmplY3Qgd2lsbCBob2xkIG91ciByYXcgcHJpY2UgZGF0YSB0aHJvdWdob3V0IHRoaXMgYm9vay4KcHJpY2VzIDwtIAogIGdldFN5bWJvbHModGlja2Vycywgc3JjID0gJ3lhaG9vJywgZnJvbSA9ICIyMDE1LTAxLTAxIiwgCiAgICAgICAgICAgICBhdXRvLmFzc2lnbiA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UpCgpwcmljZXMKCmBgYAoKXklYSUMgaXMgTmFzZGFxIHN5bWJvbCxSVVNTRUxMIDIwMDAgSU5ERVggKF5SVVQpLERvdyBKb25lcyBJbmR1c3RyaWFsIEF2ZXJhZ2UgKE5ZU0U6RElBKSxTdGF0ZSBTdHJlZXQgR2xvYmFsIEFkdmlzb3JzIGxhdW5jaGVkIHRoZSBTUERSIFMmUCA1MDAgRVRGIChOWVNFOlNQWSkKYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQoKCnByaWNlczE9dHFfZ2V0KGMoICJTUFkiLCJESUEiLCJeSVhJQyIsIl5SVVQiKSwgZnJvbSA9ICIyMDEyLTAxLTAxIiwgZ2V0ID0gJ3N0b2NrLnByaWNlcycpCgoKCgp0YWlsKHByaWNlczEpCgpoZWFkKHByaWNlczEpCgpwcmljZXMyPC1wcmljZXMxJT4lc2VsZWN0KC1jKG9wZW4saGlnaCxsb3csY2xvc2Usdm9sdW1lKSkKcHJpY2VzMgoKCmBgYAoKCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CiNyZW1vdmUgbm9uIGFscGhhYmV0IGNoYXJhY3RlcnMKCnByaWNlczIkc3ltYm9sPC1nc3ViKCJbXls6YWxwaGE6XV0iLCAiIiwgcHJpY2VzMiRzeW1ib2wpCgpoZWFkKHByaWNlczIpCgp0YWlsKHByaWNlczIpCgoKcHJpY2VzMSRzeW1ib2wgPSBzdHJfcmVwbGFjZV9hbGwocHJpY2VzMSRzeW1ib2wsIHBhdHRlcm4gPSAiW15bOmFscGhhOl1dIiwgIiIpCgpoZWFkKHByaWNlczEpCgp0YWlsKHByaWNlczEpCgpwcmljZXMxJT4lCmdncGxvdChhZXMoZGF0ZSwgYWRqdXN0ZWQsIGNvbG9yID0gc3ltYm9sKSkgKwpnZW9tX2xpbmUoKSArCmxhYnModGl0bGUgPSAiTXVsdGkgc3RvY2sgZXhhbXBsZSIsCnhsYWIgPSAiRGF0ZSIsCnlsYWIgPSAiQWRqdXN0ZWQgQ2xvc2UiKSt0aGVtZV9lY29ub21pc3Rfd2hpdGUoKSsKICAKICBnZW9tX2FyZWEoZmlsbCA9ICJjeWFuIiwgYWxwaGEgPSAuMSkKCmdncGxvdGx5KCkKCmBgYAoKCgoKCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0KIyBHZXQgc3RvY2sgcHJpY2VzCnN0b2NrcyA8LSBjKCJBQVBMIiwgIkZCIiwgIk5GTFgiLCAiR09PRyIsIkFNWk4iKSAlPiUKdHFfZ2V0KGZyb20gPSAiMjAxMi0wMS0wMSIpCgpzdG9ja3MKCgojIFBsb3QgZm9yIHN0b2NrcwpzdG9ja3MgJT4lCmdncGxvdChhZXMoZGF0ZSwgYWRqdXN0ZWQsIGNvbG9yID0gc3ltYm9sKSkgKwpnZW9tX2xpbmUoKSArCmxhYnModGl0bGUgPSAiTXVsdGkgc3RvY2sgZXhhbXBsZSIsCnhsYWIgPSAiRGF0ZSIsCnlsYWIgPSAiQWRqdXN0ZWQgQ2xvc2UiKSt0aGVtZV9lY29ub21pc3Rfd2hpdGUoKQoKYGBgCgoKIyMjIyBVc2UgcXVhbnRtb2QgcGVyaW9kUmV0dXJuIHRvIENvbnZlcnQgUHJpY2VzIHRvIFJldHVybnMKClRoZSBxdWFudG1vZDo6cGVyaW9kUmV0dXJuKCkgZnVuY3Rpb24gZ2VuZXJhdGVzIHJldHVybnMgYnkgcGVyaW9kaWNpdHkuIAoKV2Ugd2FudCB0byB1c2UgdGhlIGFkanVzdGVkIGNsb3NpbmcgcHJpY2VzIGNvbHVtbiAoYWRqdXN0ZWQgZm9yIHN0b2NrIHNwbGl0cywgd2hpY2ggY2FuIG1ha2UgaXQgYXBwZWFyIHRoYXQgYSBzdG9jayBpcyBwZXJmb3JtaW5nIHBvb3JseSBpZiBhIHNwbGl0IGlzIGluY2x1ZGVkKS4gV2Ugc2V0IHNlbGVjdCA9IGFkanVzdGVkLiBXZSByZXNlYXJjaCB0aGUgcGVyaW9kUmV0dXJuIGZ1bmN0aW9uLCBhbmQgd2UgZm91bmQgdGhhdCBpdCBhY2NlcHRzIHR5cGUgPSAiYXJpdGhtZXRpYyIgYW5kIHBlcmlvZCA9ICJ5ZWFybHkiLCB3aGljaCByZXR1cm5zIHRoZSBhbm51YWwgcmV0dXJucy4KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQpBbm51YWxfcmV0dXJucyA8LSBwcmljZXMxICU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsIAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sIAogICAgICAgICAgICAgICAgIHBlcmlvZCAgICAgPSAieWVhcmx5IiwgCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJhcml0aG1ldGljIikKQW5udWFsX3JldHVybnMKYGBgCgoKCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CiNBbm51YWxfcmV0dXJucyAlPiUKICAgIyBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0geWVhcmx5LnJldHVybnMsIGZpbGwgPSBzeW1ib2wpKStzdGF0X2NvdW50KHN0YXQgPSAiaWRlbnRpdHkiKQoKCkFubnVhbF9yZXR1cm5zPC0gcHJpY2VzMiAlPiV0a190YmwoKSU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUKICAgIHRxX3RyYW5zbXV0ZShtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLCAKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gInllYXJseSIsIAogICAgICAgICAgICAgICAgIHR5cGUgICAgICAgPSAiYXJpdGhtZXRpYyIpCkFubnVhbF9yZXR1cm5zJT4laGVhZCgpCgoKQW5udWFsX3JldHVybnMgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0geWVhcmx5LnJldHVybnMsIGNvbG9yID0gc3ltYm9sKSkgKwogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgICBsYWJzKHRpdGxlID0gIlllYXJseSBTdG9jayByZXR1cm5zIFByaWNlcyIsCiAgICAgICAgIHggPSAiIiwgeSA9ICJBZGp1c3RlZCBQcmljZXMiLCBjb2xvciA9ICIiKSArCiAgICAjZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9jb2xvcl90cSgpCgojZ2dwbG90bHkoKQoKCmBgYAoKCgoKYGBge3J9CkFubnVhbF9yZXR1cm5zICU+JQogZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHllYXJseS5yZXR1cm5zLCBmaWxsID0gc3ltYm9sKSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMjAwKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9IHBhbGV0dGVfbGlnaHQoKVtbMV1dKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgICBsYWJzKHRpdGxlID0gIkFubnVhbCBSZXR1cm5zIiwKICAgICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgICAgeSA9ICJBbm51YWwgUmV0dXJucyIsIHggPSAiIikgKyAKICAgIGZhY2V0X3dyYXAofiBzeW1ib2wsIG5jb2wgPSAyLHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9maWxsX3RxKCkKYGBgCgoKIyMjIyAgRGFpbHkgTG9nIFJldHVybnMKCiBXZSB3YW50IHRvIHVzZSB0aGUgYWRqdXN0ZWQgY2xvc2luZyBwcmljZXMgY29sdW1uIChhZGp1c3RlZCBmb3Igc3RvY2sgc3BsaXRzLCB3aGljaCBjYW4gbWFrZSBpdCBhcHBlYXIgdGhhdCBhIHN0b2NrIGlzIHBlcmZvcm1pbmcgcG9vcmx5IGlmIGEgc3BsaXQgaXMgaW5jbHVkZWQpLCBzbyB3ZSBzZXQgc2VsZWN0ID0gYWRqdXN0ZWQuIFdlIHJlc2VhcmNoZWQgdGhlIHBlcmlvZFJldHVybiBmdW5jdGlvbiwgYW5kIHdlIGZvdW5kIHRoYXQgaXQgYWNjZXB0cyB0eXBlID0gImxvZyIgYW5kIHBlcmlvZCA9ICJkYWlseSIsIHdoaWNoIHJldHVybnMgdGhlIGRhaWx5IGxvZyByZXR1cm5zLgogCiAKYGBge3J9CkRhaWx5X2xvZ19yZXR1cm5zIDwtIHByaWNlczEgJT4lCiAgICBncm91cF9ieShzeW1ib2wpICU+JQogICAgdHFfdHJhbnNtdXRlKHNlbGVjdCAgICAgPSBhZGp1c3RlZCwgCiAgICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwgCiAgICAgICAgICAgICAgICAgcGVyaW9kICAgICA9ICJkYWlseSIsIAogICAgICAgICAgICAgICAgIHR5cGUgICAgICAgPSAibG9nIiwKICAgICAgICAgICAgICAgICBjb2xfcmVuYW1lID0gIm1vbnRobHkucmV0dXJucyIpCmBgYAogCiAKYGBge3J9CkRhaWx5X2xvZ19yZXR1cm5zICU+JQogICAgZ2dwbG90KGFlcyh4ID0gbW9udGhseS5yZXR1cm5zLCBmaWxsID0gc3ltYm9sKSkgKwogICAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArCiAgICBsYWJzKHRpdGxlID0gIkRhaWx5IExvZyBSZXR1cm5zIiwKICAgICAgICAgeCA9ICJNb250aGx5IFJldHVybnMiLCB5ID0gIkRlbnNpdHkiKSArCiAgICB0aGVtZV90cSgpICsKICAgIHNjYWxlX2ZpbGxfdHEoKSArIAogICAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsc2NhbGVzID0gImZyZWVfeSIpCiNmYWNldF9ncmlkKC5+c3ltYm9sLHNjYWxlcz0iZnJlZSIsc3BhY2U9ImZyZWUiKSAKICAjc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkKICAjZmFjZXRfd3JhcCh+c3ltYm9sLCBzY2FsZXMgPSAiZnJlZV95IiwgbnJvdyA9IDIsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIpIAoKYGBgCiAKIAogCiAKIyMjIyBVc2UgeHRzIHRvLnBlcmlvZCB0byBDaGFuZ2UgdGhlIFBlcmlvZGljaXR5IGZyb20gRGFpbHkgdG8gTW9udGhseQoKVGhlIHh0czo6dG8ucGVyaW9kIGZ1bmN0aW9uIGlzIHVzZWQgZm9yIHBlcmlvZGljaXR5IGFnZ3JlZ2F0aW9uIChjb252ZXJ0aW5nIGZyb20gYSBsb3dlciBsZXZlbCBwZXJpb2RpY2l0eSB0byBhIGhpZ2hlciBsZXZlbCBzdWNoIGFzIG1pbnV0ZXMgdG8gaG91cnMgb3IgbW9udGhzIHRvIHllYXJzKS4gQmVjYXVzZSB3ZSBhcmUgc2Vla2luZyBhIHJldHVybiBzdHJ1Y3R1cmUgdGhhdCBpcyBvbiBhIGRpZmZlcmVudCB0aW1lIHNjYWxlIHRoYW4gdGhlIGlucHV0IChkYWlseSB2ZXJzdXMgd2Vla2x5KSwgd2UgbmVlZCB0byB1c2UgYSB0cmFuc211dGUgZnVuY3Rpb24uIFdlIHNlbGVjdCB0cV90cmFuc211dGUoKSBhbmQgcGFzcyB0aGUgb3BlbiwgaGlnaCwgbG93LCBjbG9zZSBhbmQgdm9sdW1lIGNvbHVtbnMgdmlhIHNlbGVjdCA9IG9wZW46dm9sdW1lLiBMb29raW5nIGF0IHRoZSBkb2N1bWVudGF0aW9uIGZvciB0by5wZXJpb2QsIHdlIHNlZSB0aGF0IGl0IGFjY2VwdHMgYSBwZXJpb2QgYXJndW1lbnQgdGhhdCB3ZSBjYW4gc2V0IHRvICJ3ZWVrcyIuIFRoZSByZXN1bHQgaXMgdGhlIE9ITENWIGRhdGEgcmV0dXJuZWQgd2l0aCB0aGUgZGF0ZXMgY2hhbmdlZCB0byBvbmUgZGF5IHBlciB3ZWVrLiAKCmBgYHtyfQpwcmljZXMxICU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gb3Blbjp2b2x1bWUsIAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSB0by5wZXJpb2QsIAogICAgICAgICAgICAgICAgIHBlcmlvZCAgICAgPSAibW9udGhzIiklPiVoZWFkKCkKYGBgCgoKCiMjIyMgV2l0aG91dCBQZXJpb2RpY2l0eSBBZ2dyZWdhdGlvbgoKYGBge3J9CkRhaWx5IDwtIHByaWNlczIgJT4lCiAgICBncm91cF9ieShzeW1ib2wpCgpEYWlseSAlPiUKICAgIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBhZGp1c3RlZCwgY29sb3IgPSBzeW1ib2wpKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsKICAgIGxhYnModGl0bGUgPSAiRGFpbHkgU3RvY2sgUHJpY2VzIiwKICAgICAgICAgeCA9ICIiLCB5ID0gIkFkanVzdGVkIFByaWNlcyIsIGNvbG9yID0gIiIpICsKICAgIGZhY2V0X3dyYXAofiBzeW1ib2wsIG5jb2wgPSAyLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9jb2xvcl90cSgpCmBgYAoKCgojIyMjIFdpdGggUGVyaW9kaWNpdHkgQWdncmVnYXRpb24KCmBgYHtyfQpNb250aGx5IDwtIHByaWNlczIlPiUKICAgIGdyb3VwX2J5KHN5bWJvbCkgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLCAKICAgICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gdG8ucGVyaW9kLCAKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRocyIpCgpNb250aGx5ICU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGFkanVzdGVkLCBjb2xvciA9IHN5bWJvbCkpICsKICAgIGdlb21fbGluZShzaXplID0gMSkgKwogICAgbGFicyh0aXRsZSA9ICJNb250aGx5IFN0b2NrIFByaWNlcyIsCiAgICAgICAgIHggPSAiIiwgeSA9ICJBZGp1c3RlZCBQcmljZXMiLCBjb2xvciA9ICIiKSArCiAgICBmYWNldF93cmFwKH4gc3ltYm9sLCBuY29sID0gMiwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcikgKwogICAgdGhlbWVfdHEoKSArIAogICAgc2NhbGVfY29sb3JfdHEoKQpgYGAKCgojIyMjIFVzZSBUVFIgcnVuQ29yIHRvIFZpc3VhbGl6ZSBSb2xsaW5nIENvcnJlbGF0aW9ucyBvZiBSZXR1cm5zCgpSZXR1cm4gY29ycmVsYXRpb25zIGFyZSBhIGNvbW1vbiB3YXkgdG8gYW5hbHl6ZSBob3cgY2xvc2VseSBhbiBhc3NldCBvciBwb3J0Zm9saW8gbWltaWNzIGEgYmFzZWxpbmUgaW5kZXggb3IgZnVuZC4gV2Ugd2lsbCBuZWVkIGEgc2V0IG9mIHJldHVybnMgZm9yIGJvdGggdGhlIHN0b2NrcyBhbmQgYmFzZWxpbmUuIFRoZSAgYmFzZWxpbmUgd2lsbCBiZSB0aGUgU3BkciBYTEsgdGVjaG5vbG9neSBzZWN0b3IuCgpgYGB7cn0KIyBBc3NldCBSZXR1cm5zCnJldHVybnNfbW9udGhseSA8LSBwcmljZXMxJT4lCiAgICBncm91cF9ieShzeW1ib2wpICU+JQogICAgdHFfdHJhbnNtdXRlKHNlbGVjdCAgICAgPSBhZGp1c3RlZCwgCiAgICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRobHkiKQoKIyBCYXNlbGluZSBSZXR1cm5zCmJhc2VsaW5lX3JldHVybnNfbW9udGhseSA8LSAiWExLIiAlPiUKICAgIHRxX2dldChnZXQgID0gInN0b2NrLnByaWNlcyIsCiAgICAgICAgICAgZnJvbSA9ICIyMDEyLTAxLTAxIikgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLCAKICAgICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLAogICAgICAgICAgICAgICAgIHBlcmlvZCAgICAgPSAibW9udGhseSIpCmBgYAoKCgpgYGB7cn0KcmV0dXJuc19qb2luZWQgPC1pbm5lcl9qb2luKHJldHVybnNfbW9udGhseSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlbGluZV9yZXR1cm5zX21vbnRobHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJkYXRlIikKI2FsdGVybmF0aXZlbHkKcmV0dXJuc19qb2luZWQyIDwtIG1lcmdlKHJldHVybnNfbW9udGhseSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlbGluZV9yZXR1cm5zX21vbnRobHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJkYXRlIikKcmV0dXJuc19qb2luZWQlPiVkaW0oKQpyZXR1cm5zX2pvaW5lZDIlPiVkaW0oKQpyZXR1cm5zX2pvaW5lZCU+JWhlYWQoKQoKCgpyZXR1cm5zX2pvaW5lZCRzeW1ib2w9ZmFjdG9yKHJldHVybnNfam9pbmVkJHN5bWJvbCkKCgpzdHIocmV0dXJuc19qb2luZWQpCgpgYGAKCiMjIyMgNi1tb250aCByb2xsaW5nIGNvcnJlbGF0aW9uCiBXaGVuIHNvbWV0aGluZyBpcyBzYWlkIHRvIGJlIHJvbGxpbmcgaXQncyB0cmFja2luZyBhIGNlcnRhaW4gYW1vdW50IG9mIHRpbWUgaW4gdGhlIHBhc3QsIGFuZCB0aGVuIHJvbGxzIGZvcndhcmQgYXMgdGltZSBwcm9ncmVzc2VzLiBTbyB0aGUgdGhlIDMwIGRheSByb2xsaW5nIGNvcnJlbGF0aW9uIHdvdWxkIGJlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBiYXNrZXQgb2YgYXNzZXRzIGZvciB0aGUgcGFzdCAzMCBkYXlzLiBUb21vcnJvdyB3ZSBhZGQgb25lIG1vcmUgZGF5IGFuZCBzdWJ0cmFjdCB0aGUgZmlyc3QgZGF5LCB0byBtYWludGFpbiAzMCBkYXlzLgogClRoZSBUVFI6OnJ1bkNvciBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBldmFsdWF0ZSByb2xsaW5nIGNvcnJlbGF0aW9ucyB1c2luZyB0aGUgeHkgcGF0dGVybi4gQmVjYXVzZSB0aGUgc2NhbGUgaXMgbW9udGhseSwgd2XigJlsbCBnbyB3aXRoIG4gPSA2IGZvciBhIDYtbW9udGggcm9sbGluZyBjb3JyZWxhdGlvbi4gVGhlIGNvbF9yZW5hbWUgYXJndW1lbnQgZW5hYmxlcyBlYXN5IHJlbmFtaW5nIG9mIHRoZSBvdXRwdXQgY29sdW1uKHMpLgoKYGBge3J9CnJvbGxpbmdfY29yciA8LSByZXR1cm5zX2pvaW5lZCAlPiUKICAgIHRxX3RyYW5zbXV0ZV94eSh4ICAgICAgICAgID0gbW9udGhseS5yZXR1cm5zLngsIAogICAgICAgICAgICAgICAgICAgIHkgICAgICAgICAgPSBtb250aGx5LnJldHVybnMueSwKICAgICAgICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gcnVuQ29yLAogICAgICAgICAgICAgICAgICAgIG4gICAgICAgICAgPSA2LAogICAgICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAicm9sbGluZy5jb3JyLjYiKQpgYGAKCgoKYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQpyb2xsaW5nX2NvcnIgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gcm9sbGluZy5jb3JyLjYsIGNvbG9yID0gc3ltYm9sKSkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSBwYWxldHRlX2xpZ2h0KClbWzFdXSkgKwogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgICBsYWJzKHRpdGxlID0gIiBTaXggTW9udGggUm9sbGluZyBDb3JyZWxhdGlvbiB0byBYTEsiLAogICAgICAgICB4ID0gIiIsIHkgPSAiQ29ycmVsYXRpb24iLCBjb2xvciA9ICIiKSArCiAgICBmYWNldF93cmFwKH4gc3ltYm9sLCBuY29sID0gMikgKwogICAgdGhlbWVfdHEoKSArIAogICAgc2NhbGVfY29sb3JfdHEoKQpgYGAKCgoKIyMjIyBVc2UgVFRSIE1BQ0QgdG8gVmlzdWFsaXplIE1vdmluZyBBdmVyYWdlIENvbnZlcmdlbmNlIERpdmVyZ2VuY2UKCkluIHJldmlld2luZyB0aGUgYXZhaWxhYmxlIG9wdGlvbnMgaW4gdGhlIFRUUiBwYWNrYWdlLCB3ZSBzZWUgdGhhdCBNQUNEIHdpbGwgZ2V0IHVzIHRoZSBNb3ZpbmcgQXZlcmFnZSBDb252ZXJnZW5jZSBEaXZlcmdlbmNlIChNQUNEKS4gSW4gcmVzZWFyY2hpbmcgdGhlIGRvY3VtZW50YXRpb24sIHRoZSByZXR1cm4gaXMgaW4gdGhlIHNhbWUgcGVyaW9kaWNpdHkgYXMgdGhlIGlucHV0IGFuZCB0aGUgZnVuY3Rpb25zIHdvcmsgd2l0aCBPSExDIGZ1bmN0aW9ucywgc28gd2UgY2FuIHVzZSB0cV9tdXRhdGUoKS4gTUFDRCByZXF1aXJlcyBhIHByaWNlLCBzbyB3ZSBzZWxlY3QgY2xvc2UuCgoKYGBge3J9Cm1hY2QgPC0gcHJpY2VzMSAlPiUKICAgIGdyb3VwX2J5KHN5bWJvbCkgJT4lCiAgICB0cV9tdXRhdGUoc2VsZWN0ICAgICA9IGNsb3NlLCAKICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gTUFDRCwgCiAgICAgICAgICAgICAgbkZhc3QgICAgICA9IDEyLCAKICAgICAgICAgICAgICBuU2xvdyAgICAgID0gMjYsIAogICAgICAgICAgICAgIG5TaWcgICAgICAgPSA5LCAKICAgICAgICAgICAgICBtYVR5cGUgICAgID0gREVNQSkgJT4lCiAgICBtdXRhdGUoZGlmZiA9IG1hY2QgLSBzaWduYWwpICU+JQogICAgc2VsZWN0KC0ob3Blbjp2b2x1bWUpKQptYWNkJT4laGVhZCgpCmBgYAoKCgoKYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQptYWNkICU+JQogICAgZmlsdGVyKGRhdGUgPj0gYXNfZGF0ZSgiMjAxMi0wMy0xNSIpKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IGRhdGUpKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSBwYWxldHRlX2xpZ2h0KClbWzFdXSkgKwogICAgZ2VvbV9saW5lKGFlcyh5ID0gbWFjZCwgY29sID0gc3ltYm9sKSkgKwogICAgZ2VvbV9saW5lKGFlcyh5ID0gc2lnbmFsKSwgY29sb3IgPSAiYmx1ZSIsIGxpbmV0eXBlID0gMikgKwogICAgZ2VvbV9iYXIoYWVzKHkgPSBkaWZmKSwgc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gcGFsZXR0ZV9saWdodCgpW1sxXV0pICsKICAgIGZhY2V0X3dyYXAofiBzeW1ib2wsIG5jb2wgPSAyLCBzY2FsZSA9ICJmcmVlX3kiKSArCiAgICBsYWJzKHRpdGxlID0gIkZBTkc6IE1vdmluZyBBdmVyYWdlIENvbnZlcmdlbmNlIERpdmVyZ2VuY2UiLAogICAgICAgICB5ID0gIk1BQ0QiLCB4ID0gIiIsIGNvbG9yID0gIiIpICsKICAgIHRoZW1lX3RxKCkgKwogICAgc2NhbGVfY29sb3JfdHEoKQpgYGAKCgoKIyMjIyBVc2UgeHRzIGFwcGx5LnF1YXJ0ZXJseSB0byBHZXQgdGhlIE1heCBhbmQgTWluIFByaWNlIGZvciBFYWNoIFF1YXJ0ZXIKClRoZSB4dHM6OmFwcGx5LnF1YXJ0ZXJseSgpIGZ1bmN0aW9uIHRoYXQgaXMgcGFydCBvZiB0aGUgcGVyaW9kIGFwcGx5IGdyb3VwIGNhbiBiZSB1c2VkIHRvIGFwcGx5IGZ1bmN0aW9ucyBieSBxdWFydGVybHkgdGltZSBzZWdtZW50cy4gQmVjYXVzZSB3ZSBhcmUgc2Vla2luZyBhIHJldHVybiBzdHJ1Y3R1cmUgdGhhdCBpcyBvbiBhIGRpZmZlcmVudCB0aW1lIHNjYWxlIHRoYW4gdGhlIGlucHV0IChxdWFydGVybHkgdmVyc3VzIGRhaWx5KSwgd2UgbmVlZCB0byB1c2UgYSB0cmFuc211dGUgZnVuY3Rpb24uIFdlIHNlbGVjdCB0cV90cmFuc211dGUgYW5kIHBhc3MgdGhlIGNsb3NlIHByaWNlIHVzaW5nIHNlbGVjdCwgYW5kIHdlIHNlbmQgdGhpcyBzdWJzZXQgb2YgdGhlIGRhdGEgdG8gdGhlIGFwcGx5LnF1YXJ0ZXJseSBmdW5jdGlvbiB2aWEgdGhlIG11dGF0ZV9mdW4gYXJndW1lbnQuIExvb2tpbmcgYXQgdGhlIGRvY3VtZW50YXRpb24gZm9yIGFwcGx5LnF1YXJ0ZXJseSwgd2Ugc2VlIHRoYXQgd2UgY2FuIHBhc3MgYSBmdW5jdGlvbiB0byB0aGUgYXJndW1lbnQsIEZVTi4gV2Ugd2FudCB0aGUgbWF4aW11bSB2YWx1ZXMsIHNvIHdlIHNldCBGVU4gPSBtYXguIFRoZSByZXN1bHQgaXMgdGhlIHF1YXJ0ZXJzIHJldHVybmVkIGFzIGEgZGF0ZSBhbmQgdGhlIG1heGltdW0gY2xvc2luZyBwcmljZSBkdXJpbmcgdGhlIHF1YXJ0ZXIgcmV0dXJuZWQgYXMgYSBkb3VibGUuCgpgYGB7cn0KbWF4X2J5X3F0ciA8LSBwcmljZXMxICU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsIAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBhcHBseS5xdWFydGVybHksIAogICAgICAgICAgICAgICAgIEZVTiAgICAgICAgPSBtYXgsIAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAibWF4LmNsb3NlIikgJT4lCiAgICBtdXRhdGUoeWVhci5xdHIgPSBwYXN0ZTAoeWVhcihkYXRlKSwgIi1RIiwgcXVhcnRlcihkYXRlKSkpICU+JQogICAgc2VsZWN0KC1kYXRlKQptYXhfYnlfcXRyJT4laGVhZCgpCmBgYAoKVGhlIG1pbmltdW0gZWFjaCBxdWFydGVyIGNhbiBiZSByZXRyaWV2ZWQgaW4gbXVjaCB0aGUgc2FtZSB3YXkuIFRoZSBkYXRhIGZyYW1lcyBjYW4gYmUgam9pbmVkIHVzaW5nIGxlZnRfam9pbiB0byBnZXQgdGhlIG1heCBhbmQgbWluIGJ5IHF1YXJ0ZXIuCgpgYGB7cn0KbWluX2J5X3F0ciA8LSBGQU5HICU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsIAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBhcHBseS5xdWFydGVybHksIAogICAgICAgICAgICAgICAgIEZVTiAgICAgICAgPSBtaW4sIAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAibWluLmNsb3NlIikgJT4lCiAgICBtdXRhdGUoeWVhci5xdHIgPSBwYXN0ZTAoeWVhcihkYXRlKSwgIi1RIiwgcXVhcnRlcihkYXRlKSkpICU+JQogICAgc2VsZWN0KC1kYXRlKQoKYnlfcXRyIDwtIGxlZnRfam9pbihtYXhfYnlfcXRyLCBtaW5fYnlfcXRyLAogICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJzeW1ib2wiICAgPSAic3ltYm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieWVhci5xdHIiID0gInllYXIucXRyIikpCmJ5X3F0ciU+JWhlYWQoKQoKYGBgCgoKCgpgYGB7cixtZXNzYWdlPVRSVUUsd2FybmluZz1GQUxTRX0KYnlfcXRyICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhci5xdHIsIGNvbG9yID0gc3ltYm9sKSkgKwogICAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0geWVhci5xdHIsIHkgPSBtaW4uY2xvc2UsIHllbmQgPSBtYXguY2xvc2UpLAogICAgICAgICAgICAgICAgIHNpemUgPSAyKSArCiAgICBnZW9tX3BvaW50KGFlcyh5ID0gbWF4LmNsb3NlKSwgc2l6ZSA9IDIpICsKICAgIGdlb21fcG9pbnQoYWVzKHkgPSBtaW4uY2xvc2UpLCBzaXplID0gMikgKwogICAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsIHNjYWxlID0gImZyZWVfeSIpICsKICAgIGxhYnModGl0bGUgPSAiIE1pbi9NYXggUHJpY2UgQnkgUXVhcnRlciIsCiAgICAgICAgIHkgPSAiU3RvY2sgUHJpY2UiLCBjb2xvciA9ICIiKSArCiAgICB0aGVtZV90cSgpICsKICAgIHNjYWxlX2NvbG9yX3RxKCkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCgoKIyMjIyBVc2Ugem9vIHJvbGxhcHBseSB0byB2aXN1YWxpemUgYSByb2xsaW5nIHJlZ3Jlc3Npb24KCkEgZ29vZCB3YXkgdG8gYW5hbHl6ZSByZWxhdGlvbnNoaXBzIG92ZXIgdGltZSBpcyB1c2luZyByb2xsaW5nIGNhbGN1bGF0aW9ucyB0aGF0IGNvbXBhcmUgdHdvIGFzc2V0cy4gUGFpcnMgdHJhZGluZyBpcyBhIGNvbW1vbiBtZWNoYW5pc20gZm9yIHNpbWlsYXIgYXNzZXRzLiBJbiB0aGlzIGV4YW1wbGUgd2Ugd2lsbCBhbmFseXplIHR3byBzaW1pbGFyIGFzc2V0cywgRm9yZChGKSBhbmQgR2VuZXJhbCBNb3RvcnMoR00pIHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcCB2aWEgcmVncmVzc2lvbi4KCmBgYHtyLG1lc3NhZ2U9VFJVRSx3YXJuaW5nPUZBTFNFfQojIEdldCBzdG9jayBwYWlycwpzdG9ja19wcmljZXMgPC0gYygiRiIsICJHTSIpICU+JQogICAgdHFfZ2V0KGdldCAgPSAic3RvY2sucHJpY2VzIiwKICAgICAgICAgICBmcm9tID0gIjIwMTItMDEtMDEiKSAlPiUKICAgIGdyb3VwX2J5KHN5bWJvbCkgCgpzdG9ja19wYWlycyA8LSBzdG9ja19wcmljZXMgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sCiAgICAgICAgICAgICAgICAgcGVyaW9kICAgICA9ICJkYWlseSIsCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJsb2ciLAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAicmV0dXJucyIpICU+JQogICAgc3ByZWFkKGtleSA9IHN5bWJvbCwgdmFsdWUgPSByZXR1cm5zKQoKc3RvY2tfcHJpY2VzJT4laGVhZCgpCmBgYAoKCgpgYGB7cixtZXNzYWdlPVRSVUUsd2FybmluZz1GQUxTRX0Kc3RvY2tfcGFpcnMgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBGLCB5ID0gR00pKSArCiAgICBnZW9tX3BvaW50KGNvbG9yID0gcGFsZXR0ZV9saWdodCgpW1sxXV0sIGFscGhhID0gMC41KSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgICBsYWJzKHRpdGxlID0gIlZpc3VhbGl6aW5nIFJldHVybnMgUmVsYXRpb25zaGlwIG9mIFN0b2NrIFBhaXJzIikgKwogICAgdGhlbWVfdHEoKQpgYGAKCldlIGNhbiBnZXQgc3RhdGlzdGNzIG9uIHRoZSByZWxhdGlvbnNoaXAgZnJvbSB0aGUgbG0gZnVuY3Rpb24uIFRoZSBtb2RlbCBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIGEgcC12YWx1ZSBvZiBlc3NlbnRpYWwgemVyby4gVGhlIGNvZWZmaWNpZW50IGVzdGltYXRlIGZvciBHTSAoQ29lZmZpY2llbnQgMSkgaXMgMC42MyBpbmRpY2F0aW5nIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwLCBtZWFuaW5nIGFzIEYgaW5jcmVhc2VzIEdNIGFsc28gdGVuZHMgdG8gaW5jcmVhc2UuCgpgYGB7cn0KbG0oRiB+IEdNLCBkYXRhID0gc3RvY2tfcGFpcnMpICU+JQogICAgYnJvb206OnRpZHkoKQpgYGAKCgoKCgpUaGUgZGF0YSB3aWxsIGJlIHBhc3NlZCB0byB0aGUgcmVncmVzc2lvbiBmdW5jdGlvbiBhcyBhbiB4dHMgb2JqZWN0LiBUaGUgdGltZXRrOjp0a190YmwgZnVuY3Rpb24gdGFrZXMgY2FyZSBvZiBjb252ZXJ0aW5nIHRvIGEgZGF0YSBmcmFtZS4KCgpgYGB7cn0KcmVncl9mdW4gPC0gZnVuY3Rpb24oZGF0YSkgewogICAgY29lZihsbShGIH4gR00sIGRhdGEgPSB0aW1ldGs6OnRrX3RibChkYXRhLCBzaWxlbnQgPSBUUlVFKSkpCn0KYGBgCgpXZSBjYW4gdXNlIHRxX211dGF0ZSgpIHRvIGFwcGx5IHRoZSBjdXN0b20gcmVncmVzc2lvbiBmdW5jdGlvbiBvdmVyIGEgcm9sbGluZyB3aW5kb3cgdXNpbmcgcm9sbGFwcGx5IGZyb20gdGhlIHpvbyBwYWNrYWdlLiBJbnRlcm5hbGx5LCB0aGUgcmV0dXJuc19jb21iaW5lZCBkYXRhIGZyYW1lIGlzIGJlaW5nIHBhc3NlZCBhdXRvbWF0aWNhbGx5IHRvIHRoZSBkYXRhIGFyZ3VtZW50IG9mIHRoZSByb2xsYXBwbHkgZnVuY3Rpb24uIEFsbCB5b3UgbmVlZCB0byBzcGVjaWZ5IGlzIHRoZSBtdXRhdGVfZnVuID0gcm9sbGFwcGx5IGFuZCBhbnkgYWRkaXRpb25hbCBhcmd1bWVudHMgbmVjZXNzYXJ5IHRvIGFwcGx5IHRoZSByb2xsYXBwbHkgZnVuY3Rpb24uIFdl4oCZbGwgc3BlY2lmeSBhIDkwIGRheSB3aW5kb3cgdmlhIHdpZHRoID0gOTAuIFRoZSBGVU4gYXJndW1lbnQgaXMgb3VyIGN1c3RvbSByZWdyZXNzaW9uIGZ1bmN0aW9uLCByZWdyX2Z1bi4gSXTigJlzIGV4dHJlbWVseSBpbXBvcnRhbnQgdG8gc3BlY2lmeSBieS5jb2x1bW4gPSBGQUxTRSwgd2hpY2ggdGVsbHMgcm9sbGFwcGx5IHRvIHBlcmZvcm0gdGhlIGNvbXB1dGF0aW9uIHVzaW5nIHRoZSBkYXRhIGFzIGEgd2hvbGUgcmF0aGVyIHRoYW4gYXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVhY2ggY29sdW1uIGluZGVwZW5kZW50bHkuIFRoZSBjb2xfcmVuYW1lIGFyZ3VtZW50IGlzIHVzZWQgdG8gcmVuYW1lIHRoZSBhZGRlZCBjb2x1bW5zLgoKYGBge3J9CnN0b2NrX3BhaXJzIDwtIHN0b2NrX3BhaXJzICU+JQogICAgICAgICB0cV9tdXRhdGUobXV0YXRlX2Z1biA9IHJvbGxhcHBseSwKICAgICAgICAgICAgICAgICAgIHdpZHRoICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgIEZVTiAgICAgICAgPSByZWdyX2Z1biwKICAgICAgICAgICAgICAgICAgIGJ5LmNvbHVtbiAgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSBjKCJjb2VmLjAiLCAiY29lZi4xIikpCnN0b2NrX3BhaXJzJT4laGVhZCgpCmBgYAoKCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CnN0b2NrX3BhaXJzICU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGNvZWYuMSkpICsKICAgIGdlb21fbGluZShzaXplID0gMSwgY29sb3IgPSBwYWxldHRlX2xpZ2h0KClbWzFdXSkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC44MTM0LCBzaXplID0gMSwgY29sb3IgPSBwYWxldHRlX2xpZ2h0KClbWzJdXSkgKwogICAgbGFicyh0aXRsZSA9ICJGIH4gR006IFZpc3VhbGl6aW5nIFJvbGxpbmcgUmVncmVzc2lvbiBDb2VmZmljaWVudCIsIHggPSAiIikgKwogICAgdGhlbWVfdHEoKQpgYGAKCgoKU3RvY2sgcmV0dXJucyBkdXJpbmcgdGhpcyB0aW1lIHBlcmlvZC4KCmBgYHtyfQpzdG9ja19wcmljZXMgJT4lCiAgICB0cV90cmFuc211dGUoYWRqdXN0ZWQsIAogICAgICAgICAgICAgICAgIHBlcmlvZFJldHVybiwgCiAgICAgICAgICAgICAgICAgcGVyaW9kID0gImRhaWx5IiwgCiAgICAgICAgICAgICAgICAgdHlwZSA9ICJsb2ciLCAKICAgICAgICAgICAgICAgICBjb2xfcmVuYW1lID0gInJldHVybnMiKSAlPiUKICAgIG11dGF0ZSh3ZWFsdGguaW5kZXggPSAxMDAgKiBjdW1wcm9kKDEgKyByZXR1cm5zKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gd2VhbHRoLmluZGV4LCBjb2xvciA9IHN5bWJvbCkpICsKICAgIGdlb21fbGluZShzaXplID0gMSkgKwogICAgbGFicyh0aXRsZSA9ICJGIGFuZCBHTTogU3RvY2sgUHJpY2VzIikgKwogICAgdGhlbWVfdHEoKSArIAogICAgc2NhbGVfY29sb3JfdHEoKQpgYGAKCgojIyMjIFVzZSBSZXR1cm4uY2xlYW4gYW5kIFJldHVybi5leGNlc3MgdG8gY2xlYW4gYW5kIGNhbGN1bGF0ZSBleGNlc3MgcmV0dXJucwoKV2UgdXNlIHNldmVyYWwgb2YgdGhlIFBlcmZvcm1hbmNlQW5hbHl0aWNzIGZ1bmN0aW9ucyB0byBjbGVhbiBhbmQgZm9ybWF0IHJldHVybnMuIFRoZSBleGFtcGxlIHVzZXMgdGhyZWUgcHJvZ3Jlc3NpdmUgYXBwbGljYXRpb25zIG9mIHRxX3RyYW5zbXV0ZSB0byBhcHBseSB2YXJpb3VzIHF1YW50IGZ1bmN0aW9ucyB0byB0aGUgZ3JvdXBlZCBzdG9jayBwcmljZXMgZnJvbSB0aGUgaW5pdGlhbCBkYXRhIHNldC4gRmlyc3QsIHdlIGNhbGN1bGF0ZSBkYWlseSByZXR1cm5zIHVzaW5nIHF1YW50bW9kOjpwZXJpb2RSZXR1cm4uIE5leHQsIHdlIHVzZSBSZXR1cm4uY2xlYW4gdG8gY2xlYW4gb3V0bGllcnMgZnJvbSB0aGUgcmV0dXJuIGRhdGEuIFRoZSBhbHBoYSBwYXJhbWV0ZXIgaXMgdGhlIHBlcmNlbnRhZ2Ugb2Ygb3VsdGllcnMgdG8gYmUgY2xlYW5lZC4gRmluYWxseSwgdGhlIGV4Y2VzcyByZXR1cm5zIGFyZSBjYWxjdWxhdGVkIHVzaW5nIGEgcmlzay1mcmVlIHJhdGUgb2YgMyUgKGRpdmlkZWQgYnkgMjUyIGZvciAyNTIgdHJhZGUgZGF5cyBpbiBvbmUgeWVhcikuCgoKYGBge3J9CnByaWNlczEgJT4lCiAgICBncm91cF9ieShzeW1ib2wpICU+JQogICAgdHFfdHJhbnNtdXRlKGFkanVzdGVkLCBwZXJpb2RSZXR1cm4sIHBlcmlvZCA9ICJkYWlseSIpICU+JQogICAgdHFfdHJhbnNtdXRlKGRhaWx5LnJldHVybnMsIFJldHVybi5jbGVhbiwgYWxwaGEgPSAwLjA1KSAlPiUKICAgIHRxX3RyYW5zbXV0ZShkYWlseS5yZXR1cm5zLCBSZXR1cm4uZXhjZXNzLCBSZiA9IDAuMDMgLyAyNTIpCmBgYAoK