0.0.0.1 Exchange Traded Funds

A collection of securities for example stocks which usually tracks an underlying index is known as an Exchange - Traded Fund(ETF). ETF’s share some similarity with mutual funds although they are listed on exchanges and their share is traded like stocks throughout the day. ETF’s can be made up of various strategies and invest in diverse number of industry sectors.

The most popular index tracked by most ETF’s is the S&P 500. For example the SPDR S&P 500 ETF (SPY) tracks the S&P 500. ETFs can include different types of investments, including stocks, commodities, bonds, or a mixture of investment types. ETF’s is traded on financial markets as a security with a price at which it can be bought and sold. Most ETF’s are set up as Open-end funds meaning there is no cap on the number of investors allowed in on the product.

0.0.0.2 Types of ETFs

There are various types of ETFs available to investors that can be used for income generation, speculation, price increases, and to hedge or partly offset risk in an investor’s portfolio. Below are several examples of the types of ETFs.

  • Bond ETFs may include government bonds, corporate bonds, and state and local government bonds called municipal bonds.
  • Industry ETFs track a particular industry such as technology, banking, or the oil and gas sector.
  • Commodity ETFs invest in commodities including crude oil or gold.
  • Currency ETFs invest in foreign currencies such as the Euro or the British pound.
  • Inverse ETFs attempt to earn gains from stock declines by shorting stocks. Shorting is selling a stock, expecting a decline in value, and repurchasing it at a lower price. Many inverse ETFs are Exchange Traded Notes (ETNs) and not true ETFs. An ETN is a bond but trades like a stock and is backed by an issuer like a bank.

0.0.0.3 How to Buy and Sell ETFs

ETF’s are traded through licensed online and traditional broker dealers. Most of the poular ETF brokers like Vanguard also have robo-advisors which is a computer algorithm that attempts to mimic a human trader. Some ETF’s go a step further by offering commision free products. Examples of such brokers can easily be found online.

The following libraries required is loaded loaded here.

library(ggplot2)
library(plotly)
library(rvest)
library(pbapply)
library(TTR)
library(dygraphs)
library(lubridate)
library(tidyquant)
library(timetk)
pacman::p_load(dygraphs,DT,tidyverse,janitor,ggthemes,scales,ggpubr,viridis)

theme_set(theme_pubclean())

The table below shows some popular U.S. ETF brands and issuers.

library(rvest)
library(XML)
library(gt)
library(tidyverse)
library(glue)



webpage <- read_html("https://www.etf.com/sections/etf-league-tables/etf-league-table-2020-02-10")

tbls <- html_nodes(webpage, "table")

print(head(tbls))
## {xml_nodeset (2)}
## [1] <table border="0" cellpadding="2" cellspacing="0" class="IUtable" style=" ...
## [2] <table border="0" cellpadding="2" cellspacing="0" class="IUtable" style=" ...
tbls_ls <- webpage %>%
        html_nodes("table") %>%
        .[[1]] %>%
        html_table(fill = TRUE)



colnames(tbls_ls)  <-  c("Brand","AUM ($, mm)","Net Flows ($, mm)","% of AUM")

tbls_ls  <- tbls_ls %>% janitor::clean_names()


DT::datatable(tbls_ls, class = 'cell-border stripe')

We can download the following ETF’s some of which are actively managed and others which are passively managed from the yahoo API using the quantmod API.

#library("RSelenium")

tickers= c("QQQ","IVV","SPY","VOO","VTI","IWB","GLD","EEM","XLF",
           "GDX","ARKW")

actively_managed =c("ARKW")

passively_managed <-  c("AGZ","IHI","IEUS","FCOM","VGT.IV","
VUG.IV")

vanguard <- c("MGK.IV","MGC.IV","VGT.IV","
VUG.IV","VONG.IV")

# The symbols vector holds our tickers. 
symbols <- c("SPY","EFA", "IJS", "EEM","AGG")

# The prices object will hold our raw price data 
prices <- 
  quantmod::getSymbols(tickers, src = 'yahoo', from = "2010-01-01", 
             auto.assign = TRUE, warnings = FALSE) %>% 
 furrr::future_map(~Ad(get(.))) %>%   
  reduce(merge) %>%   #reduce() combines from the left, reduce_right() combines from the right
  `colnames<-`(tickers)



DT::datatable(data.frame(head(prices)))

The prices of these ETF’s can be visualized with dygraph package, it allows a user to set a date window which lets you expand and narrow the windows to focus on detail visualization within the range of interest.

dateWindow <- c("2015-01-01", "2020-02-20")

dygraph(prices, main = "Value", group = "stock",
        xlab = "Time",ylab = "Adjusted Prices") %>%
  dyRebase(value = 100) %>%
  dyRangeSelector(dateWindow = dateWindow)

Convert daily prices to monthly prices using a call to to.monthly(prices, indexAt = “last”, OHLC = FALSE) from quantmod. The argument index = “last” tells the function whether we want to index to the first day of the month or the last day.

prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)%>%tk_tbl()%>% rename(date=index) 


start_date <-first(index(prices_monthly))
end_date <- last(index(prices_monthly)) 

prices_monthly  %>% head()   %>%  gt() %>%
  tab_header(
    title = " Monthly Prices for ETF's",
    subtitle = glue::glue("{start_date} to {end_date}")
  )
Monthly Prices for ETF's
1 to 69
date QQQ IVV SPY VOO VTI IWB GLD EEM XLF GDX ARKW
2014-09-30 93.71915 176.6444 176.5203 161.6403 91.02445 98.94495 116.21 36.63364 12.99660 20.55621 16.92123
2014-10-31 96.19518 180.8587 180.6775 165.5249 93.52393 101.31341 112.66 37.15370 13.37242 16.56238 17.20904
2014-11-28 100.56856 185.8393 185.6411 170.0898 95.84360 104.06014 112.11 36.58075 13.68653 17.66910 17.52985
2014-12-31 98.31519 185.2874 185.1702 169.5703 95.80689 103.75922 113.58 35.13086 13.94251 17.80461 17.37833
2015-01-30 96.26794 179.9134 179.6837 164.7011 93.18576 100.97132 123.45 34.88944 12.97279 21.59221 17.32754
2015-02-27 103.21903 190.0703 189.7828 173.8906 98.53648 106.68292 116.16 36.42736 13.72827 20.61383 18.75810

We now have an xts object, and we have moved from daily prices to monthly prices.

Return.calculate(prices_monthly, method = “log”) to convert to returns and save as an object called assed_returns_xts. Note this will give us log returns by the method = “log” argument. We could have used method = “discrete” to get simple returns. The daily percentage return on a stock is the difference between the previous day’s price and the current day’s price relative to the previous day’s price. The monthly perentage return follows as the difference between the previous month and the current month’s price divided by the previous months price.

\(\text{Percentage Return } = \frac{\left(P_{1}-P_{0}\right)+D}{P_{0}}\) Where

\(P_{0}\) Initial Asset Price \(P_{1}\) Ending Asset Price \(D\) is the dividends

The actual asset return is given as \(\text{ Return } = \left(P_{1}-P_{0}\right)+D\)

#asset_returns_xts <- na.omit(Return.calculate(prices_monthly, method = "discreet"))
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)
asset_returns_quantmod <- na.omit(CalculateReturns(prices_monthly, method = "log"))
head(asset_returns_quantmod)%>%tk_tbl()%>%  gt()
index QQQ IVV SPY VOO VTI IWB GLD EEM XLF GDX ARKW
2014-10-31 0.02607669 0.023577611 0.023277427 0.023748307 0.027089275 0.023655167 -0.031024422 0.014096472 0.028506520 -0.216029614 0.016865430
2014-11-28 0.04446046 0.027165955 0.027101615 0.027204324 0.024500294 0.026750191 -0.004893928 -0.015541380 0.023218202 0.064683848 0.018470776
2014-12-31 -0.02266116 -0.002974243 -0.002539849 -0.003058407 -0.000383041 -0.002895892 0.013026911 -0.040442204 0.018529945 0.007640004 -0.008681112
2015-01-30 -0.02104319 -0.029432389 -0.030077047 -0.029135649 -0.027739704 -0.027236535 0.083328739 -0.006895657 -0.072088211 0.192875272 -0.002926942
2015-02-27 0.06971794 0.054918331 0.054681883 0.054294315 0.055831874 0.055024563 -0.060867606 0.043136074 0.056602901 -0.046370579 0.079328556
2015-03-31 -0.02387254 -0.016099672 -0.015830159 -0.015832690 -0.011696995 -0.013102059 -0.021757014 -0.015086285 -0.006179701 -0.154150526 -0.006792035
pacman::p_load(kable,kableExtra)

ETF_returns <- prices %>%
  tk_tbl(preserve_index = TRUE, rename_index = "date") %>%
  
  pivot_longer(-date , names_to = "symbol",values_to = "Adjusted_Prices")%>%
  
  group_by(symbol) %>%
  tq_transmute(mutate_fun = periodReturn, period = "monthly", type = "log") %>%
  
  arrange(desc(monthly.returns))
 


ETF_returns%>%head()%>%
  kable(escape = F, align = "c") %>%
  kable_styling(c("striped", "condensed"), full_width = F)
symbol date monthly.returns
GDX 2020-04-30 0.3365961
GDX 2016-02-29 0.3102956
GDX 2016-04-29 0.2573056
XLF 2016-09-30 0.2350068
ARKW 2020-04-30 0.2197622
GDX 2016-06-30 0.2047288

An interactive visualiation for the monthly returns for the ETF’s selected is displayed below.

library(crosstalk)

ETF_returns <-  ETF_returns %>%  ungroup(symbol)


d <- 
  SharedData$new(ETF_returns, ~symbol)
p <- ggplot(d, aes(date,monthly.returns,color=symbol)) +
  geom_line(aes(group = symbol))+
  
  
#scale_y_continuous(trans = log10_trans(), labels =  scales::comma)+
  
  #scale_fill_viridis_d()+
  scale_color_viridis_d(option="D") +
  
  # scale_shape_manual(values = 1:6 )  +
  
 #   theme_economist() +
  
  scale_x_date(labels = date_format("%d-%m-%Y"),date_breaks = "1 year") +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
   labs(title = "Monthly Returns Performance of Exhcange Traded Funds",
       subtitle = " 2010 - 2020",
       caption = "www.restsanalytics.com", 
       x = "Time", y = "Returns")


(gg <- ggplotly(p, tooltip = "symbol"))
highlight(gg, "plotly_hover")
ETF_returns %>% mutate(Year= format(date,"%Y")) %>%  group_by(symbol,Year) %>%  
                summarize(meanreturn =mean(monthly.returns,na.rm = TRUE))%>%
  
  ggplot(aes(x=Year,y=meanreturn,fill=symbol))+
  geom_col()+
 #scale_color_viridis(discrete=TRUE,option = "A")
scale_fill_viridis(discrete=TRUE,option = "D")+
    theme(
    legend.position="top",
    legend.direction="horizontal",
    legend.title = element_blank(),
    text=element_text(size=8,  family="Comic Sans MS"),
    axis.text.x=element_text(angle=45,hjust=1,size = 9),
    axis.text.y=element_text(size = 8),
    legend.text = element_text(size=8)
)+
   labs(y="Mean Yearly Return",x="Year",title="")

 # scale_x_date(breaks = date_breaks("1 year"),labels=date_format("%b %Y") )

The analysis above in which the data was downloaded with the quantmod package, can be replicated with the tidyquant package. The tidyquant package builds a wrapper around the quantmod and converts the data from xts format to tibble dataframes.

end<-Sys.Date()
start<-as.Date("2010-01-10")


Prices  <- tq_get(tickers , get = "stock.prices", from = start,to=end)
Prices%>%head() %>% DT::datatable()
library(crosstalk)
d <- SharedData$new(Prices, ~symbol)
p <- ggplot(d, aes(date, adjusted,color=symbol)) +
  geom_line(aes(group = symbol))+
  
  
#scale_y_continuous(trans = log10_trans(), labels =  scales::comma)+
  
  #scale_fill_viridis_d()+
  scale_color_viridis_d(option="D") +
  
  # scale_shape_manual(values = 1:6 )  +
  
 #   theme_economist() +
  
  scale_x_date(labels = date_format("%d-%m-%Y"),date_breaks = "1 year") +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
   labs(title = "Performance of Exhcange Traded Funds",
       subtitle = " 2010 - 2020",
       caption = "www.restsanalytics.com", 
       x = "Time", y = "Adjusted Prices")


(gg <- ggplotly(p, tooltip = "symbol"))
highlight(gg, "plotly_hover")

0.0.0.4 Returns

monthlyreturns <-Prices%>% select(symbol,date,adjusted)%>%
  group_by(symbol)%>%
  tq_transmute( 
                 mutate_fun = periodReturn, 
                 period     = "monthly", 
                 type       = "arithmetic")%>%head()



monthlyreturns%>%head() %>% gt()
date monthly.returns
QQQ
2010-01-29 -0.07700585
2010-02-26 0.04603873
2010-03-31 0.07710888
2010-04-30 0.02242552
2010-05-28 -0.07392362
2010-06-30 -0.05975721
ETF_returns %>%
    ggplot(aes(x = date, y = monthly.returns, group = symbol)) +
    geom_area(aes(fill = symbol), position = "stack") +
    labs(title = "Quantity Sold: Month Plot", x = "", y = "Sales",
         subtitle = "March through July tend to be most active") +
    theme(
    legend.position="top",
    legend.direction="horizontal",
    legend.title = element_blank(),
    text=element_text(size=8,  family="Comic Sans MS"),
    axis.text.x=element_text(angle=45,hjust=1,size = 9),
    axis.text.y=element_text(size = 8),
    legend.text = element_text(size=8)
)+
    scale_x_date(breaks = date_breaks("12 month"),labels=date_format("%b %Y") ) +
   # theme_tq()+
  #scale_color_viridis()
 #scale_color_continuous_tableau()
   scale_fill_viridis(discrete = T,option="B")

   #scale_color_viridis_d() 
LS0tDQp0aXRsZTogRXhoYW5nZSBUcmFkZWQgRnVuZHMgUGVyZm9yYW5jZQ0Kc3VidGl0bGU6IA0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGtlZXBfbWQ6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICAjdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogdHJ1ZSAjIHRhYmxlIG9mIGNvbnRlbnQgdHJ1ZQ0KICAgIHRvY19kZXB0aDogMyAgIyB1cHRvIHRocmVlIGRlcHRocyBvZiBoZWFkaW5ncyAoc3BlY2lmaWVkIGJ5ICMsICMjIGFuZCAjIyMpDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAjIyBpZiB5b3Ugd2FudCBudW1iZXIgc2VjdGlvbnMgYXQgZWFjaCB0YWJsZSBoZWFkZXINCiAgICB0aGVtZTogdW5pdGVkICAjIG1hbnkgb3B0aW9ucyBmb3IgdGhlbWUsIHRoaXMgb25lIGlzIG15IGZhdm9yaXRlLg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmF1dGhvcjogTmFuYSBCb2F0ZW5nDQpUaW1lOiAnYHIgU3lzLnRpbWUoKWAnDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiDQpwYXJhbXM6DQogIHNlcmllczogJzInDQp0YWdzOiBFVEYsIFF1YW50aXRhdGl2ZSBGaW5hbmNlLCBBc3NldCBSZXR1cm4sICANCiAgDQotLS0NCg0KDQoNCiMjIyMgRXhjaGFuZ2UgVHJhZGVkIEZ1bmRzDQoNCkEgY29sbGVjdGlvbiBvZiBzZWN1cml0aWVzICBmb3IgZXhhbXBsZSBzdG9ja3Mgd2hpY2ggdXN1YWxseSB0cmFja3MgYW4gdW5kZXJseWluZyBpbmRleCAgaXMga25vd24gYXMgYW4gICAgRXhjaGFuZ2UgLSBUcmFkZWQgRnVuZChFVEYpLiBFVEYncyBzaGFyZSBzb21lIHNpbWlsYXJpdHkgd2l0aCBtdXR1YWwgZnVuZHMgYWx0aG91Z2ggdGhleSBhcmUgbGlzdGVkIG9uIGV4Y2hhbmdlcyBhbmQgdGhlaXIgc2hhcmUgaXMgdHJhZGVkIGxpa2Ugc3RvY2tzIHRocm91Z2hvdXQgdGhlIGRheS4gRVRGJ3MgY2FuIGJlIG1hZGUgdXAgb2YgdmFyaW91cyBzdHJhdGVnaWVzIGFuZCBpbnZlc3QgaW4gZGl2ZXJzZSBudW1iZXIgb2YgaW5kdXN0cnkgc2VjdG9ycy4NCg0KVGhlIG1vc3QgcG9wdWxhciBpbmRleCB0cmFja2VkIGJ5IG1vc3QgRVRGJ3MgaXMgdGhlIFMmUCA1MDAuIEZvciBleGFtcGxlIHRoZSBTUERSIFMmUCA1MDAgRVRGIChTUFkpIHRyYWNrcyB0aGUgUyZQIDUwMC4gRVRGcyBjYW4gaW5jbHVkZSBkaWZmZXJlbnQgdHlwZXMgb2YgaW52ZXN0bWVudHMsIGluY2x1ZGluZyBzdG9ja3MsIGNvbW1vZGl0aWVzLCBib25kcywgb3IgYSBtaXh0dXJlIG9mIGludmVzdG1lbnQgdHlwZXMuIEVURidzICBpcyB0cmFkZWQgb24gZmluYW5jaWFsIG1hcmtldHMgYXMgYSBzZWN1cml0eSB3aXRoIGEgcHJpY2UgYXQgd2hpY2ggaXQgY2FuIGJlIGJvdWdodCBhbmQgc29sZC4gTW9zdCBFVEYncyBhcmUgc2V0IHVwIGFzIE9wZW4tZW5kIGZ1bmRzIG1lYW5pbmcgIHRoZXJlIGlzIG5vIGNhcCBvbiB0aGUgbnVtYmVyIG9mIGludmVzdG9ycyBhbGxvd2VkIGluIG9uIHRoZSBwcm9kdWN0Lg0KDQoNCg0KIyMjIyBUeXBlcyBvZiBFVEZzDQoNCg0KVGhlcmUgYXJlIHZhcmlvdXMgdHlwZXMgb2YgRVRGcyBhdmFpbGFibGUgdG8gaW52ZXN0b3JzIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGluY29tZSBnZW5lcmF0aW9uLCBzcGVjdWxhdGlvbiwgcHJpY2UgaW5jcmVhc2VzLCBhbmQgdG8gaGVkZ2Ugb3IgcGFydGx5IG9mZnNldCByaXNrIGluIGFuIGludmVzdG9yJ3MgcG9ydGZvbGlvLiBCZWxvdyBhcmUgc2V2ZXJhbCBleGFtcGxlcyBvZiB0aGUgdHlwZXMgb2YgRVRGcy4NCg0KLSBCb25kIEVURnMgbWF5IGluY2x1ZGUgZ292ZXJubWVudCBib25kcywgY29ycG9yYXRlIGJvbmRzLCBhbmQgc3RhdGUgYW5kIGxvY2FsIGdvdmVybm1lbnQgYm9uZHMgY2FsbGVkIG11bmljaXBhbCBib25kcy4NCi0gSW5kdXN0cnkgRVRGcyB0cmFjayBhIHBhcnRpY3VsYXIgaW5kdXN0cnkgc3VjaCBhcyB0ZWNobm9sb2d5LCBiYW5raW5nLCBvciB0aGUgb2lsIGFuZCBnYXMgc2VjdG9yLg0KLSBDb21tb2RpdHkgRVRGcyBpbnZlc3QgaW4gY29tbW9kaXRpZXMgaW5jbHVkaW5nIGNydWRlIG9pbCBvciBnb2xkLg0KLSBDdXJyZW5jeSBFVEZzIGludmVzdCBpbiBmb3JlaWduIGN1cnJlbmNpZXMgc3VjaCBhcyB0aGUgRXVybyBvciB0aGUgQnJpdGlzaCBwb3VuZC4NCi0gSW52ZXJzZSBFVEZzIGF0dGVtcHQgdG8gZWFybiBnYWlucyBmcm9tIHN0b2NrIGRlY2xpbmVzIGJ5IHNob3J0aW5nIHN0b2Nrcy4gU2hvcnRpbmcgaXMgc2VsbGluZyBhIHN0b2NrLCBleHBlY3RpbmcgYSBkZWNsaW5lIGluIHZhbHVlLCBhbmQgcmVwdXJjaGFzaW5nIGl0IGF0IGEgbG93ZXIgcHJpY2UuIE1hbnkgaW52ZXJzZSBFVEZzIGFyZSBFeGNoYW5nZSBUcmFkZWQgTm90ZXMgKEVUTnMpIGFuZCBub3QgdHJ1ZSBFVEZzLiBBbiBFVE4gaXMgYSBib25kIGJ1dCB0cmFkZXMgbGlrZSBhIHN0b2NrIGFuZCBpcyBiYWNrZWQgYnkgYW4gaXNzdWVyIGxpa2UgYSBiYW5rLg0KDQojIyMjIEhvdyB0byBCdXkgYW5kIFNlbGwgRVRGcw0KRVRGJ3MgYXJlIHRyYWRlZCB0aHJvdWdoIGxpY2Vuc2VkIG9ubGluZSBhbmQgdHJhZGl0aW9uYWwgYnJva2VyICBkZWFsZXJzLiBNb3N0IG9mIHRoZSBwb3VsYXIgRVRGIGJyb2tlcnMgbGlrZSBWYW5ndWFyZCAgYWxzbyBoYXZlIHJvYm8tYWR2aXNvcnMgd2hpY2ggaXMgYSBjb21wdXRlciBhbGdvcml0aG0gdGhhdCBhdHRlbXB0cyB0byBtaW1pYyBhIGh1bWFuIHRyYWRlci4gU29tZSBFVEYncyBnbyBhIHN0ZXAgZnVydGhlciBieSBvZmZlcmluZyBjb21taXNpb24gZnJlZSBwcm9kdWN0cy4gRXhhbXBsZXMgb2YgIHN1Y2ggYnJva2VycyBjYW4gZWFzaWx5IGJlIGZvdW5kIG9ubGluZS4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgICAgICAgICAgICAgICAgIGVjaG8gICAgICAgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgZXZhbCAgICAgICA9IFRSVUUsDQogICAgICAgICAgICAgICAgICB3YXJuaW5nICAgID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBtZXNzYWdlICAgID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBkcGkgICAgICAgID0gMzAwLA0KICAgICAgICAgICAgICAgICAgZmlnLmFsaWduICA9ICJjZW50ZXIiKQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgbGlicmFyaWVzIHJlcXVpcmVkIGlzIGxvYWRlZCBsb2FkZWQgaGVyZS4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkocnZlc3QpDQpsaWJyYXJ5KHBiYXBwbHkpDQpsaWJyYXJ5KFRUUikNCmxpYnJhcnkoZHlncmFwaHMpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkodGlkeXF1YW50KQ0KbGlicmFyeSh0aW1ldGspDQpwYWNtYW46OnBfbG9hZChkeWdyYXBocyxEVCx0aWR5dmVyc2UsamFuaXRvcixnZ3RoZW1lcyxzY2FsZXMsZ2dwdWJyLHZpcmlkaXMpDQoNCnRoZW1lX3NldCh0aGVtZV9wdWJjbGVhbigpKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNClRoZSB0YWJsZSBiZWxvdyBzaG93cyBzb21lIHBvcHVsYXIgVS5TLiBFVEYgYnJhbmRzIGFuZCBpc3N1ZXJzLiANCg0KYGBge3J9DQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShYTUwpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdsdWUpDQoNCg0KDQp3ZWJwYWdlIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuZXRmLmNvbS9zZWN0aW9ucy9ldGYtbGVhZ3VlLXRhYmxlcy9ldGYtbGVhZ3VlLXRhYmxlLTIwMjAtMDItMTAiKQ0KDQp0YmxzIDwtIGh0bWxfbm9kZXMod2VicGFnZSwgInRhYmxlIikNCg0KcHJpbnQoaGVhZCh0YmxzKSkNCg0KdGJsc19scyA8LSB3ZWJwYWdlICU+JQ0KICAgICAgICBodG1sX25vZGVzKCJ0YWJsZSIpICU+JQ0KICAgICAgICAuW1sxXV0gJT4lDQogICAgICAgIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpDQoNCg0KDQpjb2xuYW1lcyh0YmxzX2xzKSAgPC0gIGMoIkJyYW5kIiwiQVVNICgkLCBtbSkiLCJOZXQgRmxvd3MgKCQsIG1tKSIsIiUgb2YgQVVNIikNCg0KdGJsc19scyAgPC0gdGJsc19scyAlPiUgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQ0KDQoNCkRUOjpkYXRhdGFibGUodGJsc19scywgY2xhc3MgPSAnY2VsbC1ib3JkZXIgc3RyaXBlJykNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQpXZSBjYW4gZG93bmxvYWQgdGhlIGZvbGxvd2luZyBFVEYncyBzb21lIG9mIHdoaWNoIGFyZSBhY3RpdmVseSBtYW5hZ2VkIGFuZCBvdGhlcnMgd2hpY2ggYXJlIHBhc3NpdmVseSBtYW5hZ2VkIGZyb20gdGhlIHlhaG9vIEFQSSB1c2luZyB0aGUgcXVhbnRtb2QgQVBJLg0KDQpgYGB7cn0NCg0KI2xpYnJhcnkoIlJTZWxlbml1bSIpDQoNCnRpY2tlcnM9IGMoIlFRUSIsIklWViIsIlNQWSIsIlZPTyIsIlZUSSIsIklXQiIsIkdMRCIsIkVFTSIsIlhMRiIsDQogICAgICAgICAgICJHRFgiLCJBUktXIikNCg0KYWN0aXZlbHlfbWFuYWdlZCA9YygiQVJLVyIpDQoNCnBhc3NpdmVseV9tYW5hZ2VkIDwtICBjKCJBR1oiLCJJSEkiLCJJRVVTIiwiRkNPTSIsIlZHVC5JViIsIg0KVlVHLklWIikNCg0KdmFuZ3VhcmQgPC0gYygiTUdLLklWIiwiTUdDLklWIiwiVkdULklWIiwiDQpWVUcuSVYiLCJWT05HLklWIikNCg0KIyBUaGUgc3ltYm9scyB2ZWN0b3IgaG9sZHMgb3VyIHRpY2tlcnMuIA0Kc3ltYm9scyA8LSBjKCJTUFkiLCJFRkEiLCAiSUpTIiwgIkVFTSIsIkFHRyIpDQoNCiMgVGhlIHByaWNlcyBvYmplY3Qgd2lsbCBob2xkIG91ciByYXcgcHJpY2UgZGF0YSANCnByaWNlcyA8LSANCiAgcXVhbnRtb2Q6OmdldFN5bWJvbHModGlja2Vycywgc3JjID0gJ3lhaG9vJywgZnJvbSA9ICIyMDEwLTAxLTAxIiwgDQogICAgICAgICAgICAgYXV0by5hc3NpZ24gPSBUUlVFLCB3YXJuaW5ncyA9IEZBTFNFKSAlPiUgDQogZnVycnI6OmZ1dHVyZV9tYXAofkFkKGdldCguKSkpICU+JSAgIA0KICByZWR1Y2UobWVyZ2UpICU+JSAgICNyZWR1Y2UoKSBjb21iaW5lcyBmcm9tIHRoZSBsZWZ0LCByZWR1Y2VfcmlnaHQoKSBjb21iaW5lcyBmcm9tIHRoZSByaWdodA0KICBgY29sbmFtZXM8LWAodGlja2VycykNCg0KDQoNCkRUOjpkYXRhdGFibGUoZGF0YS5mcmFtZShoZWFkKHByaWNlcykpKQ0KDQpgYGANCg0KDQpUaGUgcHJpY2VzIG9mIHRoZXNlIEVURidzIGNhbiBiZSB2aXN1YWxpemVkIHdpdGggZHlncmFwaCBwYWNrYWdlLCBpdCBhbGxvd3MgYSB1c2VyIHRvIHNldCBhIGRhdGUgd2luZG93IHdoaWNoIGxldHMgeW91IGV4cGFuZCBhbmQgbmFycm93IHRoZSB3aW5kb3dzIHRvIGZvY3VzIG9uIGRldGFpbCB2aXN1YWxpemF0aW9uIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KDQoNCmRhdGVXaW5kb3cgPC0gYygiMjAxNS0wMS0wMSIsICIyMDIwLTAyLTIwIikNCg0KZHlncmFwaChwcmljZXMsIG1haW4gPSAiVmFsdWUiLCBncm91cCA9ICJzdG9jayIsDQogICAgICAgIHhsYWIgPSAiVGltZSIseWxhYiA9ICJBZGp1c3RlZCBQcmljZXMiKSAlPiUNCiAgZHlSZWJhc2UodmFsdWUgPSAxMDApICU+JQ0KICBkeVJhbmdlU2VsZWN0b3IoZGF0ZVdpbmRvdyA9IGRhdGVXaW5kb3cpDQpgYGANCg0KDQoNCg0KQ29udmVydCBkYWlseSBwcmljZXMgdG8gbW9udGhseSBwcmljZXMgdXNpbmcgYSBjYWxsIHRvIHRvLm1vbnRobHkocHJpY2VzLCBpbmRleEF0ID0g4oCcbGFzdOKAnSwgT0hMQyA9IEZBTFNFKSBmcm9tIHF1YW50bW9kLiBUaGUgYXJndW1lbnQgaW5kZXggPSDigJxsYXN04oCdIHRlbGxzIHRoZSBmdW5jdGlvbiB3aGV0aGVyIHdlIHdhbnQgdG8gaW5kZXggdG8gdGhlIGZpcnN0IGRheSBvZiB0aGUgbW9udGggb3IgdGhlIGxhc3QgZGF5Lg0KDQoNCmBgYHtyfQ0KDQoNCg0KcHJpY2VzX21vbnRobHkgPC0gdG8ubW9udGhseShwcmljZXMsIGluZGV4QXQgPSAibGFzdCIsIE9ITEMgPSBGQUxTRSklPiV0a190YmwoKSU+JSByZW5hbWUoZGF0ZT1pbmRleCkgDQoNCg0Kc3RhcnRfZGF0ZSA8LWZpcnN0KGluZGV4KHByaWNlc19tb250aGx5KSkNCmVuZF9kYXRlIDwtIGxhc3QoaW5kZXgocHJpY2VzX21vbnRobHkpKSANCg0KcHJpY2VzX21vbnRobHkgICU+JSBoZWFkKCkgICAlPiUgIGd0KCkgJT4lDQogIHRhYl9oZWFkZXIoDQogICAgdGl0bGUgPSAiIE1vbnRobHkgUHJpY2VzIGZvciBFVEYncyIsDQogICAgc3VidGl0bGUgPSBnbHVlOjpnbHVlKCJ7c3RhcnRfZGF0ZX0gdG8ge2VuZF9kYXRlfSIpDQogICkNCg0KYGBgDQoNCg0KDQpXZSBub3cgaGF2ZSBhbiB4dHMgb2JqZWN0LCBhbmQgd2UgaGF2ZSBtb3ZlZCBmcm9tIGRhaWx5IHByaWNlcyB0byBtb250aGx5IHByaWNlcy4NCg0KUmV0dXJuLmNhbGN1bGF0ZShwcmljZXNfbW9udGhseSwgbWV0aG9kID0g4oCcbG9n4oCdKSB0byBjb252ZXJ0IHRvIHJldHVybnMgYW5kIHNhdmUgYXMgYW4gb2JqZWN0IGNhbGxlZCBhc3NlZF9yZXR1cm5zX3h0cy4gTm90ZSB0aGlzIHdpbGwgZ2l2ZSB1cyBsb2cgcmV0dXJucyBieSB0aGUgbWV0aG9kID0g4oCcbG9n4oCdIGFyZ3VtZW50LiBXZSBjb3VsZCBoYXZlIHVzZWQgbWV0aG9kID0g4oCcZGlzY3JldGXigJ0gdG8gZ2V0IHNpbXBsZSByZXR1cm5zLiBUaGUgZGFpbHkgcGVyY2VudGFnZSAgcmV0dXJuIG9uIGEgc3RvY2sgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcHJldmlvdXMgZGF5J3MgcHJpY2UgYW5kIHRoZSBjdXJyZW50IGRheSdzIHByaWNlIHJlbGF0aXZlIHRvIHRoZSBwcmV2aW91cyBkYXkncyBwcmljZS4gVGhlIG1vbnRobHkgcGVyZW50YWdlIHJldHVybiBmb2xsb3dzIGFzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHByZXZpb3VzIG1vbnRoIGFuZCB0aGUgY3VycmVudCBtb250aCdzIHByaWNlIGRpdmlkZWQgYnkgdGhlIHByZXZpb3VzIG1vbnRocyBwcmljZS4NCg0KJFx0ZXh0e1BlcmNlbnRhZ2UgUmV0dXJuIH0gPSBcZnJhY3tcbGVmdChQX3sxfS1QX3swfVxyaWdodCkrRH17UF97MH19JA0KV2hlcmUNCg0KJFBfezB9JCBJbml0aWFsIEFzc2V0IFByaWNlDQokUF97MX0kIEVuZGluZyBBc3NldCBQcmljZQ0KJEQkIGlzIHRoZSBkaXZpZGVuZHMNCg0KVGhlIGFjdHVhbCBhc3NldCByZXR1cm4gaXMgZ2l2ZW4gYXMNCiRcdGV4dHsgUmV0dXJuIH0gPSBcbGVmdChQX3sxfS1QX3swfVxyaWdodCkrRCQNCg0KYGBge3J9DQojYXNzZXRfcmV0dXJuc194dHMgPC0gbmEub21pdChSZXR1cm4uY2FsY3VsYXRlKHByaWNlc19tb250aGx5LCBtZXRob2QgPSAiZGlzY3JlZXQiKSkNCnByaWNlc19tb250aGx5IDwtIHRvLm1vbnRobHkocHJpY2VzLCBpbmRleEF0ID0gImxhc3QiLCBPSExDID0gRkFMU0UpDQphc3NldF9yZXR1cm5zX3F1YW50bW9kIDwtIG5hLm9taXQoQ2FsY3VsYXRlUmV0dXJucyhwcmljZXNfbW9udGhseSwgbWV0aG9kID0gImxvZyIpKQ0KaGVhZChhc3NldF9yZXR1cm5zX3F1YW50bW9kKSU+JXRrX3RibCgpJT4lICBndCgpDQoNCmBgYA0KDQoNCg0KDQoNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoa2FibGUsa2FibGVFeHRyYSkNCg0KRVRGX3JldHVybnMgPC0gcHJpY2VzICU+JQ0KICB0a190YmwocHJlc2VydmVfaW5kZXggPSBUUlVFLCByZW5hbWVfaW5kZXggPSAiZGF0ZSIpICU+JQ0KICANCiAgcGl2b3RfbG9uZ2VyKC1kYXRlICwgbmFtZXNfdG8gPSAic3ltYm9sIix2YWx1ZXNfdG8gPSAiQWRqdXN0ZWRfUHJpY2VzIiklPiUNCiAgDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lDQogIHRxX3RyYW5zbXV0ZShtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLCBwZXJpb2QgPSAibW9udGhseSIsIHR5cGUgPSAibG9nIikgJT4lDQogIA0KICBhcnJhbmdlKGRlc2MobW9udGhseS5yZXR1cm5zKSkNCiANCg0KDQpFVEZfcmV0dXJucyU+JWhlYWQoKSU+JQ0KICBrYWJsZShlc2NhcGUgPSBGLCBhbGlnbiA9ICJjIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYygic3RyaXBlZCIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpDQoNCg0KYGBgDQoNCg0KDQpBbiBpbnRlcmFjdGl2ZSAgdmlzdWFsaWF0aW9uIGZvciB0aGUgbW9udGhseSByZXR1cm5zIGZvciB0aGUgRVRGJ3Mgc2VsZWN0ZWQgaXMgZGlzcGxheWVkIGJlbG93Lg0KDQpgYGB7cn0NCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KDQpFVEZfcmV0dXJucyA8LSAgRVRGX3JldHVybnMgJT4lICB1bmdyb3VwKHN5bWJvbCkNCg0KDQpkIDwtIA0KICBTaGFyZWREYXRhJG5ldyhFVEZfcmV0dXJucywgfnN5bWJvbCkNCnAgPC0gZ2dwbG90KGQsIGFlcyhkYXRlLG1vbnRobHkucmV0dXJucyxjb2xvcj1zeW1ib2wpKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzeW1ib2wpKSsNCiAgDQogIA0KI3NjYWxlX3lfY29udGludW91cyh0cmFucyA9IGxvZzEwX3RyYW5zKCksIGxhYmVscyA9ICBzY2FsZXM6OmNvbW1hKSsNCiAgDQogICNzY2FsZV9maWxsX3ZpcmlkaXNfZCgpKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uPSJEIikgKw0KICANCiAgIyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTo2ICkgICsNCiAgDQogIyAgIHRoZW1lX2Vjb25vbWlzdCgpICsNCiAgDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJWQtJW0tJVkiKSxkYXRlX2JyZWFrcyA9ICIxIHllYXIiKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgIGxhYnModGl0bGUgPSAiTW9udGhseSBSZXR1cm5zIFBlcmZvcm1hbmNlIG9mIEV4aGNhbmdlIFRyYWRlZCBGdW5kcyIsDQogICAgICAgc3VidGl0bGUgPSAiIDIwMTAgLSAyMDIwIiwNCiAgICAgICBjYXB0aW9uID0gInd3dy5yZXN0c2FuYWx5dGljcy5jb20iLCANCiAgICAgICB4ID0gIlRpbWUiLCB5ID0gIlJldHVybnMiKQ0KDQoNCihnZyA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gInN5bWJvbCIpKQ0KDQpoaWdobGlnaHQoZ2csICJwbG90bHlfaG92ZXIiKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQpFVEZfcmV0dXJucyAlPiUgbXV0YXRlKFllYXI9IGZvcm1hdChkYXRlLCIlWSIpKSAlPiUgIGdyb3VwX2J5KHN5bWJvbCxZZWFyKSAlPiUgIA0KICAgICAgICAgICAgICAgIHN1bW1hcml6ZShtZWFucmV0dXJuID1tZWFuKG1vbnRobHkucmV0dXJucyxuYS5ybSA9IFRSVUUpKSU+JQ0KICANCiAgZ2dwbG90KGFlcyh4PVllYXIseT1tZWFucmV0dXJuLGZpbGw9c3ltYm9sKSkrDQogIGdlb21fY29sKCkrDQogI3NjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGU9VFJVRSxvcHRpb24gPSAiQSIpDQpzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGU9VFJVRSxvcHRpb24gPSAiRCIpKw0KICAgIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwNCiAgICBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT04LCAgZmFtaWx5PSJDb21pYyBTYW5zIE1TIiksDQogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEsc2l6ZSA9IDkpLA0KICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KQ0KKSsNCiAgIGxhYnMoeT0iTWVhbiBZZWFybHkgUmV0dXJuIix4PSJZZWFyIix0aXRsZT0iIikNCiAjIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMSB5ZWFyIiksbGFiZWxzPWRhdGVfZm9ybWF0KCIlYiAlWSIpICkNCg0KYGBgDQoNCg0KDQpUaGUgYW5hbHlzaXMgYWJvdmUgaW4gd2hpY2ggdGhlIGRhdGEgd2FzIGRvd25sb2FkZWQgd2l0aCB0aGUgcXVhbnRtb2QgcGFja2FnZSwgY2FuIGJlIHJlcGxpY2F0ZWQgd2l0aCB0aGUgdGlkeXF1YW50IHBhY2thZ2UuIFRoZSB0aWR5cXVhbnQgcGFja2FnZSBidWlsZHMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgcXVhbnRtb2QgYW5kIGNvbnZlcnRzIHRoZSBkYXRhIGZyb20geHRzIGZvcm1hdCB0byB0aWJibGUgZGF0YWZyYW1lcy4NCmBgYHtyfQ0KZW5kPC1TeXMuRGF0ZSgpDQpzdGFydDwtYXMuRGF0ZSgiMjAxMC0wMS0xMCIpDQoNCg0KUHJpY2VzICA8LSB0cV9nZXQodGlja2VycyAsIGdldCA9ICJzdG9jay5wcmljZXMiLCBmcm9tID0gc3RhcnQsdG89ZW5kKQ0KUHJpY2VzJT4laGVhZCgpICU+JSBEVDo6ZGF0YXRhYmxlKCkNCg0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQoNCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KZCA8LSBTaGFyZWREYXRhJG5ldyhQcmljZXMsIH5zeW1ib2wpDQpwIDwtIGdncGxvdChkLCBhZXMoZGF0ZSwgYWRqdXN0ZWQsY29sb3I9c3ltYm9sKSkgKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3ltYm9sKSkrDQogIA0KICANCiNzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSBsb2cxMF90cmFucygpLCBsYWJlbHMgPSAgc2NhbGVzOjpjb21tYSkrDQogIA0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2QoKSsNCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbj0iRCIpICsNCiAgDQogICMgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDE6NiApICArDQogIA0KICMgICB0aGVtZV9lY29ub21pc3QoKSArDQogIA0KICBzY2FsZV94X2RhdGUobGFiZWxzID0gZGF0ZV9mb3JtYXQoIiVkLSVtLSVZIiksZGF0ZV9icmVha3MgPSAiMSB5ZWFyIikgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogICBsYWJzKHRpdGxlID0gIlBlcmZvcm1hbmNlIG9mIEV4aGNhbmdlIFRyYWRlZCBGdW5kcyIsDQogICAgICAgc3VidGl0bGUgPSAiIDIwMTAgLSAyMDIwIiwNCiAgICAgICBjYXB0aW9uID0gInd3dy5yZXN0c2FuYWx5dGljcy5jb20iLCANCiAgICAgICB4ID0gIlRpbWUiLCB5ID0gIkFkanVzdGVkIFByaWNlcyIpDQoNCg0KKGdnIDwtIGdncGxvdGx5KHAsIHRvb2x0aXAgPSAic3ltYm9sIikpDQoNCmhpZ2hsaWdodChnZywgInBsb3RseV9ob3ZlciIpDQoNCg0KDQpgYGANCg0KDQoNCiMjIyMgUmV0dXJucw0KDQpgYGB7cn0NCg0KbW9udGhseXJldHVybnMgPC1QcmljZXMlPiUgc2VsZWN0KHN5bWJvbCxkYXRlLGFkanVzdGVkKSU+JQ0KICBncm91cF9ieShzeW1ib2wpJT4lDQogIHRxX3RyYW5zbXV0ZSggDQogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sIA0KICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRobHkiLCANCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJhcml0aG1ldGljIiklPiVoZWFkKCkNCg0KDQoNCm1vbnRobHlyZXR1cm5zJT4laGVhZCgpICU+JSBndCgpDQogIA0KICANCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KYGBge3J9DQpFVEZfcmV0dXJucyAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gbW9udGhseS5yZXR1cm5zLCBncm91cCA9IHN5bWJvbCkpICsNCiAgICBnZW9tX2FyZWEoYWVzKGZpbGwgPSBzeW1ib2wpLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgICBsYWJzKHRpdGxlID0gIlF1YW50aXR5IFNvbGQ6IE1vbnRoIFBsb3QiLCB4ID0gIiIsIHkgPSAiU2FsZXMiLA0KICAgICAgICAgc3VidGl0bGUgPSAiTWFyY2ggdGhyb3VnaCBKdWx5IHRlbmQgdG8gYmUgbW9zdCBhY3RpdmUiKSArDQogICAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uPSJ0b3AiLA0KICAgIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgsICBmYW1pbHk9IkNvbWljIFNhbnMgTVMiKSwNCiAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSxzaXplID0gOSksDQogICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemUgPSA4KSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgpDQopKw0KICAgIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMTIgbW9udGgiKSxsYWJlbHM9ZGF0ZV9mb3JtYXQoIiViICVZIikgKSArDQogICAjIHRoZW1lX3RxKCkrDQogICNzY2FsZV9jb2xvcl92aXJpZGlzKCkNCiAjc2NhbGVfY29sb3JfY29udGludW91c190YWJsZWF1KCkNCiAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFQsb3B0aW9uPSJCIikNCiAgICNzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSANCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==