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}")
)
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")
LS0tDQp0aXRsZTogRXhoYW5nZSBUcmFkZWQgRnVuZHMgUGVyZm9yYW5jZQ0Kc3VidGl0bGU6IA0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGtlZXBfbWQ6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICAjdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogdHJ1ZSAjIHRhYmxlIG9mIGNvbnRlbnQgdHJ1ZQ0KICAgIHRvY19kZXB0aDogMyAgIyB1cHRvIHRocmVlIGRlcHRocyBvZiBoZWFkaW5ncyAoc3BlY2lmaWVkIGJ5ICMsICMjIGFuZCAjIyMpDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAjIyBpZiB5b3Ugd2FudCBudW1iZXIgc2VjdGlvbnMgYXQgZWFjaCB0YWJsZSBoZWFkZXINCiAgICB0aGVtZTogdW5pdGVkICAjIG1hbnkgb3B0aW9ucyBmb3IgdGhlbWUsIHRoaXMgb25lIGlzIG15IGZhdm9yaXRlLg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmF1dGhvcjogTmFuYSBCb2F0ZW5nDQpUaW1lOiAnYHIgU3lzLnRpbWUoKWAnDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiDQpwYXJhbXM6DQogIHNlcmllczogJzInDQp0YWdzOiBFVEYsIFF1YW50aXRhdGl2ZSBGaW5hbmNlLCBBc3NldCBSZXR1cm4sICANCiAgDQotLS0NCg0KDQoNCiMjIyMgRXhjaGFuZ2UgVHJhZGVkIEZ1bmRzDQoNCkEgY29sbGVjdGlvbiBvZiBzZWN1cml0aWVzICBmb3IgZXhhbXBsZSBzdG9ja3Mgd2hpY2ggdXN1YWxseSB0cmFja3MgYW4gdW5kZXJseWluZyBpbmRleCAgaXMga25vd24gYXMgYW4gICAgRXhjaGFuZ2UgLSBUcmFkZWQgRnVuZChFVEYpLiBFVEYncyBzaGFyZSBzb21lIHNpbWlsYXJpdHkgd2l0aCBtdXR1YWwgZnVuZHMgYWx0aG91Z2ggdGhleSBhcmUgbGlzdGVkIG9uIGV4Y2hhbmdlcyBhbmQgdGhlaXIgc2hhcmUgaXMgdHJhZGVkIGxpa2Ugc3RvY2tzIHRocm91Z2hvdXQgdGhlIGRheS4gRVRGJ3MgY2FuIGJlIG1hZGUgdXAgb2YgdmFyaW91cyBzdHJhdGVnaWVzIGFuZCBpbnZlc3QgaW4gZGl2ZXJzZSBudW1iZXIgb2YgaW5kdXN0cnkgc2VjdG9ycy4NCg0KVGhlIG1vc3QgcG9wdWxhciBpbmRleCB0cmFja2VkIGJ5IG1vc3QgRVRGJ3MgaXMgdGhlIFMmUCA1MDAuIEZvciBleGFtcGxlIHRoZSBTUERSIFMmUCA1MDAgRVRGIChTUFkpIHRyYWNrcyB0aGUgUyZQIDUwMC4gRVRGcyBjYW4gaW5jbHVkZSBkaWZmZXJlbnQgdHlwZXMgb2YgaW52ZXN0bWVudHMsIGluY2x1ZGluZyBzdG9ja3MsIGNvbW1vZGl0aWVzLCBib25kcywgb3IgYSBtaXh0dXJlIG9mIGludmVzdG1lbnQgdHlwZXMuIEVURidzICBpcyB0cmFkZWQgb24gZmluYW5jaWFsIG1hcmtldHMgYXMgYSBzZWN1cml0eSB3aXRoIGEgcHJpY2UgYXQgd2hpY2ggaXQgY2FuIGJlIGJvdWdodCBhbmQgc29sZC4gTW9zdCBFVEYncyBhcmUgc2V0IHVwIGFzIE9wZW4tZW5kIGZ1bmRzIG1lYW5pbmcgIHRoZXJlIGlzIG5vIGNhcCBvbiB0aGUgbnVtYmVyIG9mIGludmVzdG9ycyBhbGxvd2VkIGluIG9uIHRoZSBwcm9kdWN0Lg0KDQoNCg0KIyMjIyBUeXBlcyBvZiBFVEZzDQoNCg0KVGhlcmUgYXJlIHZhcmlvdXMgdHlwZXMgb2YgRVRGcyBhdmFpbGFibGUgdG8gaW52ZXN0b3JzIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGluY29tZSBnZW5lcmF0aW9uLCBzcGVjdWxhdGlvbiwgcHJpY2UgaW5jcmVhc2VzLCBhbmQgdG8gaGVkZ2Ugb3IgcGFydGx5IG9mZnNldCByaXNrIGluIGFuIGludmVzdG9yJ3MgcG9ydGZvbGlvLiBCZWxvdyBhcmUgc2V2ZXJhbCBleGFtcGxlcyBvZiB0aGUgdHlwZXMgb2YgRVRGcy4NCg0KLSBCb25kIEVURnMgbWF5IGluY2x1ZGUgZ292ZXJubWVudCBib25kcywgY29ycG9yYXRlIGJvbmRzLCBhbmQgc3RhdGUgYW5kIGxvY2FsIGdvdmVybm1lbnQgYm9uZHMgY2FsbGVkIG11bmljaXBhbCBib25kcy4NCi0gSW5kdXN0cnkgRVRGcyB0cmFjayBhIHBhcnRpY3VsYXIgaW5kdXN0cnkgc3VjaCBhcyB0ZWNobm9sb2d5LCBiYW5raW5nLCBvciB0aGUgb2lsIGFuZCBnYXMgc2VjdG9yLg0KLSBDb21tb2RpdHkgRVRGcyBpbnZlc3QgaW4gY29tbW9kaXRpZXMgaW5jbHVkaW5nIGNydWRlIG9pbCBvciBnb2xkLg0KLSBDdXJyZW5jeSBFVEZzIGludmVzdCBpbiBmb3JlaWduIGN1cnJlbmNpZXMgc3VjaCBhcyB0aGUgRXVybyBvciB0aGUgQnJpdGlzaCBwb3VuZC4NCi0gSW52ZXJzZSBFVEZzIGF0dGVtcHQgdG8gZWFybiBnYWlucyBmcm9tIHN0b2NrIGRlY2xpbmVzIGJ5IHNob3J0aW5nIHN0b2Nrcy4gU2hvcnRpbmcgaXMgc2VsbGluZyBhIHN0b2NrLCBleHBlY3RpbmcgYSBkZWNsaW5lIGluIHZhbHVlLCBhbmQgcmVwdXJjaGFzaW5nIGl0IGF0IGEgbG93ZXIgcHJpY2UuIE1hbnkgaW52ZXJzZSBFVEZzIGFyZSBFeGNoYW5nZSBUcmFkZWQgTm90ZXMgKEVUTnMpIGFuZCBub3QgdHJ1ZSBFVEZzLiBBbiBFVE4gaXMgYSBib25kIGJ1dCB0cmFkZXMgbGlrZSBhIHN0b2NrIGFuZCBpcyBiYWNrZWQgYnkgYW4gaXNzdWVyIGxpa2UgYSBiYW5rLg0KDQojIyMjIEhvdyB0byBCdXkgYW5kIFNlbGwgRVRGcw0KRVRGJ3MgYXJlIHRyYWRlZCB0aHJvdWdoIGxpY2Vuc2VkIG9ubGluZSBhbmQgdHJhZGl0aW9uYWwgYnJva2VyICBkZWFsZXJzLiBNb3N0IG9mIHRoZSBwb3VsYXIgRVRGIGJyb2tlcnMgbGlrZSBWYW5ndWFyZCAgYWxzbyBoYXZlIHJvYm8tYWR2aXNvcnMgd2hpY2ggaXMgYSBjb21wdXRlciBhbGdvcml0aG0gdGhhdCBhdHRlbXB0cyB0byBtaW1pYyBhIGh1bWFuIHRyYWRlci4gU29tZSBFVEYncyBnbyBhIHN0ZXAgZnVydGhlciBieSBvZmZlcmluZyBjb21taXNpb24gZnJlZSBwcm9kdWN0cy4gRXhhbXBsZXMgb2YgIHN1Y2ggYnJva2VycyBjYW4gZWFzaWx5IGJlIGZvdW5kIG9ubGluZS4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgICAgICAgICAgICAgICAgIGVjaG8gICAgICAgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgZXZhbCAgICAgICA9IFRSVUUsDQogICAgICAgICAgICAgICAgICB3YXJuaW5nICAgID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBtZXNzYWdlICAgID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBkcGkgICAgICAgID0gMzAwLA0KICAgICAgICAgICAgICAgICAgZmlnLmFsaWduICA9ICJjZW50ZXIiKQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgbGlicmFyaWVzIHJlcXVpcmVkIGlzIGxvYWRlZCBsb2FkZWQgaGVyZS4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkocnZlc3QpDQpsaWJyYXJ5KHBiYXBwbHkpDQpsaWJyYXJ5KFRUUikNCmxpYnJhcnkoZHlncmFwaHMpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkodGlkeXF1YW50KQ0KbGlicmFyeSh0aW1ldGspDQpwYWNtYW46OnBfbG9hZChkeWdyYXBocyxEVCx0aWR5dmVyc2UsamFuaXRvcixnZ3RoZW1lcyxzY2FsZXMsZ2dwdWJyLHZpcmlkaXMpDQoNCnRoZW1lX3NldCh0aGVtZV9wdWJjbGVhbigpKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNClRoZSB0YWJsZSBiZWxvdyBzaG93cyBzb21lIHBvcHVsYXIgVS5TLiBFVEYgYnJhbmRzIGFuZCBpc3N1ZXJzLiANCg0KYGBge3J9DQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShYTUwpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdsdWUpDQoNCg0KDQp3ZWJwYWdlIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuZXRmLmNvbS9zZWN0aW9ucy9ldGYtbGVhZ3VlLXRhYmxlcy9ldGYtbGVhZ3VlLXRhYmxlLTIwMjAtMDItMTAiKQ0KDQp0YmxzIDwtIGh0bWxfbm9kZXMod2VicGFnZSwgInRhYmxlIikNCg0KcHJpbnQoaGVhZCh0YmxzKSkNCg0KdGJsc19scyA8LSB3ZWJwYWdlICU+JQ0KICAgICAgICBodG1sX25vZGVzKCJ0YWJsZSIpICU+JQ0KICAgICAgICAuW1sxXV0gJT4lDQogICAgICAgIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpDQoNCg0KDQpjb2xuYW1lcyh0YmxzX2xzKSAgPC0gIGMoIkJyYW5kIiwiQVVNICgkLCBtbSkiLCJOZXQgRmxvd3MgKCQsIG1tKSIsIiUgb2YgQVVNIikNCg0KdGJsc19scyAgPC0gdGJsc19scyAlPiUgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQ0KDQoNCkRUOjpkYXRhdGFibGUodGJsc19scywgY2xhc3MgPSAnY2VsbC1ib3JkZXIgc3RyaXBlJykNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQpXZSBjYW4gZG93bmxvYWQgdGhlIGZvbGxvd2luZyBFVEYncyBzb21lIG9mIHdoaWNoIGFyZSBhY3RpdmVseSBtYW5hZ2VkIGFuZCBvdGhlcnMgd2hpY2ggYXJlIHBhc3NpdmVseSBtYW5hZ2VkIGZyb20gdGhlIHlhaG9vIEFQSSB1c2luZyB0aGUgcXVhbnRtb2QgQVBJLg0KDQpgYGB7cn0NCg0KI2xpYnJhcnkoIlJTZWxlbml1bSIpDQoNCnRpY2tlcnM9IGMoIlFRUSIsIklWViIsIlNQWSIsIlZPTyIsIlZUSSIsIklXQiIsIkdMRCIsIkVFTSIsIlhMRiIsDQogICAgICAgICAgICJHRFgiLCJBUktXIikNCg0KYWN0aXZlbHlfbWFuYWdlZCA9YygiQVJLVyIpDQoNCnBhc3NpdmVseV9tYW5hZ2VkIDwtICBjKCJBR1oiLCJJSEkiLCJJRVVTIiwiRkNPTSIsIlZHVC5JViIsIg0KVlVHLklWIikNCg0KdmFuZ3VhcmQgPC0gYygiTUdLLklWIiwiTUdDLklWIiwiVkdULklWIiwiDQpWVUcuSVYiLCJWT05HLklWIikNCg0KIyBUaGUgc3ltYm9scyB2ZWN0b3IgaG9sZHMgb3VyIHRpY2tlcnMuIA0Kc3ltYm9scyA8LSBjKCJTUFkiLCJFRkEiLCAiSUpTIiwgIkVFTSIsIkFHRyIpDQoNCiMgVGhlIHByaWNlcyBvYmplY3Qgd2lsbCBob2xkIG91ciByYXcgcHJpY2UgZGF0YSANCnByaWNlcyA8LSANCiAgcXVhbnRtb2Q6OmdldFN5bWJvbHModGlja2Vycywgc3JjID0gJ3lhaG9vJywgZnJvbSA9ICIyMDEwLTAxLTAxIiwgDQogICAgICAgICAgICAgYXV0by5hc3NpZ24gPSBUUlVFLCB3YXJuaW5ncyA9IEZBTFNFKSAlPiUgDQogZnVycnI6OmZ1dHVyZV9tYXAofkFkKGdldCguKSkpICU+JSAgIA0KICByZWR1Y2UobWVyZ2UpICU+JSAgICNyZWR1Y2UoKSBjb21iaW5lcyBmcm9tIHRoZSBsZWZ0LCByZWR1Y2VfcmlnaHQoKSBjb21iaW5lcyBmcm9tIHRoZSByaWdodA0KICBgY29sbmFtZXM8LWAodGlja2VycykNCg0KDQoNCkRUOjpkYXRhdGFibGUoZGF0YS5mcmFtZShoZWFkKHByaWNlcykpKQ0KDQpgYGANCg0KDQpUaGUgcHJpY2VzIG9mIHRoZXNlIEVURidzIGNhbiBiZSB2aXN1YWxpemVkIHdpdGggZHlncmFwaCBwYWNrYWdlLCBpdCBhbGxvd3MgYSB1c2VyIHRvIHNldCBhIGRhdGUgd2luZG93IHdoaWNoIGxldHMgeW91IGV4cGFuZCBhbmQgbmFycm93IHRoZSB3aW5kb3dzIHRvIGZvY3VzIG9uIGRldGFpbCB2aXN1YWxpemF0aW9uIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KDQoNCmRhdGVXaW5kb3cgPC0gYygiMjAxNS0wMS0wMSIsICIyMDIwLTAyLTIwIikNCg0KZHlncmFwaChwcmljZXMsIG1haW4gPSAiVmFsdWUiLCBncm91cCA9ICJzdG9jayIsDQogICAgICAgIHhsYWIgPSAiVGltZSIseWxhYiA9ICJBZGp1c3RlZCBQcmljZXMiKSAlPiUNCiAgZHlSZWJhc2UodmFsdWUgPSAxMDApICU+JQ0KICBkeVJhbmdlU2VsZWN0b3IoZGF0ZVdpbmRvdyA9IGRhdGVXaW5kb3cpDQpgYGANCg0KDQoNCg0KQ29udmVydCBkYWlseSBwcmljZXMgdG8gbW9udGhseSBwcmljZXMgdXNpbmcgYSBjYWxsIHRvIHRvLm1vbnRobHkocHJpY2VzLCBpbmRleEF0ID0g4oCcbGFzdOKAnSwgT0hMQyA9IEZBTFNFKSBmcm9tIHF1YW50bW9kLiBUaGUgYXJndW1lbnQgaW5kZXggPSDigJxsYXN04oCdIHRlbGxzIHRoZSBmdW5jdGlvbiB3aGV0aGVyIHdlIHdhbnQgdG8gaW5kZXggdG8gdGhlIGZpcnN0IGRheSBvZiB0aGUgbW9udGggb3IgdGhlIGxhc3QgZGF5Lg0KDQoNCmBgYHtyfQ0KDQoNCg0KcHJpY2VzX21vbnRobHkgPC0gdG8ubW9udGhseShwcmljZXMsIGluZGV4QXQgPSAibGFzdCIsIE9ITEMgPSBGQUxTRSklPiV0a190YmwoKSU+JSByZW5hbWUoZGF0ZT1pbmRleCkgDQoNCg0Kc3RhcnRfZGF0ZSA8LWZpcnN0KGluZGV4KHByaWNlc19tb250aGx5KSkNCmVuZF9kYXRlIDwtIGxhc3QoaW5kZXgocHJpY2VzX21vbnRobHkpKSANCg0KcHJpY2VzX21vbnRobHkgICU+JSBoZWFkKCkgICAlPiUgIGd0KCkgJT4lDQogIHRhYl9oZWFkZXIoDQogICAgdGl0bGUgPSAiIE1vbnRobHkgUHJpY2VzIGZvciBFVEYncyIsDQogICAgc3VidGl0bGUgPSBnbHVlOjpnbHVlKCJ7c3RhcnRfZGF0ZX0gdG8ge2VuZF9kYXRlfSIpDQogICkNCg0KYGBgDQoNCg0KDQpXZSBub3cgaGF2ZSBhbiB4dHMgb2JqZWN0LCBhbmQgd2UgaGF2ZSBtb3ZlZCBmcm9tIGRhaWx5IHByaWNlcyB0byBtb250aGx5IHByaWNlcy4NCg0KUmV0dXJuLmNhbGN1bGF0ZShwcmljZXNfbW9udGhseSwgbWV0aG9kID0g4oCcbG9n4oCdKSB0byBjb252ZXJ0IHRvIHJldHVybnMgYW5kIHNhdmUgYXMgYW4gb2JqZWN0IGNhbGxlZCBhc3NlZF9yZXR1cm5zX3h0cy4gTm90ZSB0aGlzIHdpbGwgZ2l2ZSB1cyBsb2cgcmV0dXJucyBieSB0aGUgbWV0aG9kID0g4oCcbG9n4oCdIGFyZ3VtZW50LiBXZSBjb3VsZCBoYXZlIHVzZWQgbWV0aG9kID0g4oCcZGlzY3JldGXigJ0gdG8gZ2V0IHNpbXBsZSByZXR1cm5zLiBUaGUgZGFpbHkgcGVyY2VudGFnZSAgcmV0dXJuIG9uIGEgc3RvY2sgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcHJldmlvdXMgZGF5J3MgcHJpY2UgYW5kIHRoZSBjdXJyZW50IGRheSdzIHByaWNlIHJlbGF0aXZlIHRvIHRoZSBwcmV2aW91cyBkYXkncyBwcmljZS4gVGhlIG1vbnRobHkgcGVyZW50YWdlIHJldHVybiBmb2xsb3dzIGFzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHByZXZpb3VzIG1vbnRoIGFuZCB0aGUgY3VycmVudCBtb250aCdzIHByaWNlIGRpdmlkZWQgYnkgdGhlIHByZXZpb3VzIG1vbnRocyBwcmljZS4NCg0KJFx0ZXh0e1BlcmNlbnRhZ2UgUmV0dXJuIH0gPSBcZnJhY3tcbGVmdChQX3sxfS1QX3swfVxyaWdodCkrRH17UF97MH19JA0KV2hlcmUNCg0KJFBfezB9JCBJbml0aWFsIEFzc2V0IFByaWNlDQokUF97MX0kIEVuZGluZyBBc3NldCBQcmljZQ0KJEQkIGlzIHRoZSBkaXZpZGVuZHMNCg0KVGhlIGFjdHVhbCBhc3NldCByZXR1cm4gaXMgZ2l2ZW4gYXMNCiRcdGV4dHsgUmV0dXJuIH0gPSBcbGVmdChQX3sxfS1QX3swfVxyaWdodCkrRCQNCg0KYGBge3J9DQojYXNzZXRfcmV0dXJuc194dHMgPC0gbmEub21pdChSZXR1cm4uY2FsY3VsYXRlKHByaWNlc19tb250aGx5LCBtZXRob2QgPSAiZGlzY3JlZXQiKSkNCnByaWNlc19tb250aGx5IDwtIHRvLm1vbnRobHkocHJpY2VzLCBpbmRleEF0ID0gImxhc3QiLCBPSExDID0gRkFMU0UpDQphc3NldF9yZXR1cm5zX3F1YW50bW9kIDwtIG5hLm9taXQoQ2FsY3VsYXRlUmV0dXJucyhwcmljZXNfbW9udGhseSwgbWV0aG9kID0gImxvZyIpKQ0KaGVhZChhc3NldF9yZXR1cm5zX3F1YW50bW9kKSU+JXRrX3RibCgpJT4lICBndCgpDQoNCmBgYA0KDQoNCg0KDQoNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoa2FibGUsa2FibGVFeHRyYSkNCg0KRVRGX3JldHVybnMgPC0gcHJpY2VzICU+JQ0KICB0a190YmwocHJlc2VydmVfaW5kZXggPSBUUlVFLCByZW5hbWVfaW5kZXggPSAiZGF0ZSIpICU+JQ0KICANCiAgcGl2b3RfbG9uZ2VyKC1kYXRlICwgbmFtZXNfdG8gPSAic3ltYm9sIix2YWx1ZXNfdG8gPSAiQWRqdXN0ZWRfUHJpY2VzIiklPiUNCiAgDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lDQogIHRxX3RyYW5zbXV0ZShtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLCBwZXJpb2QgPSAibW9udGhseSIsIHR5cGUgPSAibG9nIikgJT4lDQogIA0KICBhcnJhbmdlKGRlc2MobW9udGhseS5yZXR1cm5zKSkNCiANCg0KDQpFVEZfcmV0dXJucyU+JWhlYWQoKSU+JQ0KICBrYWJsZShlc2NhcGUgPSBGLCBhbGlnbiA9ICJjIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYygic3RyaXBlZCIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpDQoNCg0KYGBgDQoNCg0KDQpBbiBpbnRlcmFjdGl2ZSAgdmlzdWFsaWF0aW9uIGZvciB0aGUgbW9udGhseSByZXR1cm5zIGZvciB0aGUgRVRGJ3Mgc2VsZWN0ZWQgaXMgZGlzcGxheWVkIGJlbG93Lg0KDQpgYGB7cn0NCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KDQpFVEZfcmV0dXJucyA8LSAgRVRGX3JldHVybnMgJT4lICB1bmdyb3VwKHN5bWJvbCkNCg0KDQpkIDwtIA0KICBTaGFyZWREYXRhJG5ldyhFVEZfcmV0dXJucywgfnN5bWJvbCkNCnAgPC0gZ2dwbG90KGQsIGFlcyhkYXRlLG1vbnRobHkucmV0dXJucyxjb2xvcj1zeW1ib2wpKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzeW1ib2wpKSsNCiAgDQogIA0KI3NjYWxlX3lfY29udGludW91cyh0cmFucyA9IGxvZzEwX3RyYW5zKCksIGxhYmVscyA9ICBzY2FsZXM6OmNvbW1hKSsNCiAgDQogICNzY2FsZV9maWxsX3ZpcmlkaXNfZCgpKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uPSJEIikgKw0KICANCiAgIyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTo2ICkgICsNCiAgDQogIyAgIHRoZW1lX2Vjb25vbWlzdCgpICsNCiAgDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJWQtJW0tJVkiKSxkYXRlX2JyZWFrcyA9ICIxIHllYXIiKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgIGxhYnModGl0bGUgPSAiTW9udGhseSBSZXR1cm5zIFBlcmZvcm1hbmNlIG9mIEV4aGNhbmdlIFRyYWRlZCBGdW5kcyIsDQogICAgICAgc3VidGl0bGUgPSAiIDIwMTAgLSAyMDIwIiwNCiAgICAgICBjYXB0aW9uID0gInd3dy5yZXN0c2FuYWx5dGljcy5jb20iLCANCiAgICAgICB4ID0gIlRpbWUiLCB5ID0gIlJldHVybnMiKQ0KDQoNCihnZyA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gInN5bWJvbCIpKQ0KDQpoaWdobGlnaHQoZ2csICJwbG90bHlfaG92ZXIiKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQpFVEZfcmV0dXJucyAlPiUgbXV0YXRlKFllYXI9IGZvcm1hdChkYXRlLCIlWSIpKSAlPiUgIGdyb3VwX2J5KHN5bWJvbCxZZWFyKSAlPiUgIA0KICAgICAgICAgICAgICAgIHN1bW1hcml6ZShtZWFucmV0dXJuID1tZWFuKG1vbnRobHkucmV0dXJucyxuYS5ybSA9IFRSVUUpKSU+JQ0KICANCiAgZ2dwbG90KGFlcyh4PVllYXIseT1tZWFucmV0dXJuLGZpbGw9c3ltYm9sKSkrDQogIGdlb21fY29sKCkrDQogI3NjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGU9VFJVRSxvcHRpb24gPSAiQSIpDQpzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGU9VFJVRSxvcHRpb24gPSAiRCIpKw0KICAgIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwNCiAgICBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT04LCAgZmFtaWx5PSJDb21pYyBTYW5zIE1TIiksDQogICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEsc2l6ZSA9IDkpLA0KICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KQ0KKSsNCiAgIGxhYnMoeT0iTWVhbiBZZWFybHkgUmV0dXJuIix4PSJZZWFyIix0aXRsZT0iIikNCiAjIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMSB5ZWFyIiksbGFiZWxzPWRhdGVfZm9ybWF0KCIlYiAlWSIpICkNCg0KYGBgDQoNCg0KDQpUaGUgYW5hbHlzaXMgYWJvdmUgaW4gd2hpY2ggdGhlIGRhdGEgd2FzIGRvd25sb2FkZWQgd2l0aCB0aGUgcXVhbnRtb2QgcGFja2FnZSwgY2FuIGJlIHJlcGxpY2F0ZWQgd2l0aCB0aGUgdGlkeXF1YW50IHBhY2thZ2UuIFRoZSB0aWR5cXVhbnQgcGFja2FnZSBidWlsZHMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgcXVhbnRtb2QgYW5kIGNvbnZlcnRzIHRoZSBkYXRhIGZyb20geHRzIGZvcm1hdCB0byB0aWJibGUgZGF0YWZyYW1lcy4NCmBgYHtyfQ0KZW5kPC1TeXMuRGF0ZSgpDQpzdGFydDwtYXMuRGF0ZSgiMjAxMC0wMS0xMCIpDQoNCg0KUHJpY2VzICA8LSB0cV9nZXQodGlja2VycyAsIGdldCA9ICJzdG9jay5wcmljZXMiLCBmcm9tID0gc3RhcnQsdG89ZW5kKQ0KUHJpY2VzJT4laGVhZCgpICU+JSBEVDo6ZGF0YXRhYmxlKCkNCg0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQoNCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KZCA8LSBTaGFyZWREYXRhJG5ldyhQcmljZXMsIH5zeW1ib2wpDQpwIDwtIGdncGxvdChkLCBhZXMoZGF0ZSwgYWRqdXN0ZWQsY29sb3I9c3ltYm9sKSkgKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3ltYm9sKSkrDQogIA0KICANCiNzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSBsb2cxMF90cmFucygpLCBsYWJlbHMgPSAgc2NhbGVzOjpjb21tYSkrDQogIA0KICAjc2NhbGVfZmlsbF92aXJpZGlzX2QoKSsNCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbj0iRCIpICsNCiAgDQogICMgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDE6NiApICArDQogIA0KICMgICB0aGVtZV9lY29ub21pc3QoKSArDQogIA0KICBzY2FsZV94X2RhdGUobGFiZWxzID0gZGF0ZV9mb3JtYXQoIiVkLSVtLSVZIiksZGF0ZV9icmVha3MgPSAiMSB5ZWFyIikgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogICBsYWJzKHRpdGxlID0gIlBlcmZvcm1hbmNlIG9mIEV4aGNhbmdlIFRyYWRlZCBGdW5kcyIsDQogICAgICAgc3VidGl0bGUgPSAiIDIwMTAgLSAyMDIwIiwNCiAgICAgICBjYXB0aW9uID0gInd3dy5yZXN0c2FuYWx5dGljcy5jb20iLCANCiAgICAgICB4ID0gIlRpbWUiLCB5ID0gIkFkanVzdGVkIFByaWNlcyIpDQoNCg0KKGdnIDwtIGdncGxvdGx5KHAsIHRvb2x0aXAgPSAic3ltYm9sIikpDQoNCmhpZ2hsaWdodChnZywgInBsb3RseV9ob3ZlciIpDQoNCg0KDQpgYGANCg0KDQoNCiMjIyMgUmV0dXJucw0KDQpgYGB7cn0NCg0KbW9udGhseXJldHVybnMgPC1QcmljZXMlPiUgc2VsZWN0KHN5bWJvbCxkYXRlLGFkanVzdGVkKSU+JQ0KICBncm91cF9ieShzeW1ib2wpJT4lDQogIHRxX3RyYW5zbXV0ZSggDQogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sIA0KICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRobHkiLCANCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJhcml0aG1ldGljIiklPiVoZWFkKCkNCg0KDQoNCm1vbnRobHlyZXR1cm5zJT4laGVhZCgpICU+JSBndCgpDQogIA0KICANCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KYGBge3J9DQpFVEZfcmV0dXJucyAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gbW9udGhseS5yZXR1cm5zLCBncm91cCA9IHN5bWJvbCkpICsNCiAgICBnZW9tX2FyZWEoYWVzKGZpbGwgPSBzeW1ib2wpLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgICBsYWJzKHRpdGxlID0gIlF1YW50aXR5IFNvbGQ6IE1vbnRoIFBsb3QiLCB4ID0gIiIsIHkgPSAiU2FsZXMiLA0KICAgICAgICAgc3VidGl0bGUgPSAiTWFyY2ggdGhyb3VnaCBKdWx5IHRlbmQgdG8gYmUgbW9zdCBhY3RpdmUiKSArDQogICAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uPSJ0b3AiLA0KICAgIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgsICBmYW1pbHk9IkNvbWljIFNhbnMgTVMiKSwNCiAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSxzaXplID0gOSksDQogICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemUgPSA4KSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgpDQopKw0KICAgIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlX2JyZWFrcygiMTIgbW9udGgiKSxsYWJlbHM9ZGF0ZV9mb3JtYXQoIiViICVZIikgKSArDQogICAjIHRoZW1lX3RxKCkrDQogICNzY2FsZV9jb2xvcl92aXJpZGlzKCkNCiAjc2NhbGVfY29sb3JfY29udGludW91c190YWJsZWF1KCkNCiAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFQsb3B0aW9uPSJCIikNCiAgICNzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSANCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==