When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.S
##Extract Price Series Here we extract the index and the comparison equity We use the Quantmod Libraries standard getSymbols tool. We then pass symbols to Yahoo! Finance via the getSymbols() function from the quantmod package. This will return an object with the opening price, closing price, adjusted price, daily high, daily low and daily volume for each ticker. To isolate the adjusted price, we use the map() function from the purrr package and apply Ad(get(.)) to the imported prices. This will get() the adjusted price from each of our individual price series. If we wanted the closing price, we would run Cl(get(.)). That . refers to our initial object. We could stop here and have the right substance - daily prices for 2 ETFs - but the format would not be great as we would have a list of 2 xts objects. This is because the map() function returns a list by default. The reduce(merge) function will merge the 2 lists into one xts object. The merge() function looks for the date index shared by our objects and uses that index to align the data. After we set prices to daily we estimate returns with “asset_returns_xts <- na.omit(Return.calculate(prices_daily, method =”log“))” na.omit removes blanks, Return.Calculate calculates daily returns, throughout the rest of this we use the dailyReturn() function to achieve the same thing in a simpler fashion, method = log signifies log daily or geometric returns as opposed to the default arithmetic rate of change.
Finally, we want intuitive column names and use colnames<- to rename the columns according to the symbols object. In order to add technical indicators in a chart, Quantmod provides the add{IndicatorName)() function. We will use this function for plotting the Bollinger Band of SPY prices. Both indicators are plotted with the default parameters which are specified below: To add a second series on the same chart it is similar to adding and indicator in this case after you add the first chart series as normal, add this TA = “addTA(i_a.cls, on= 1)”, yrange = c(0, 380) where in the quote addTA in the brackets is the second series, the on = 1 signifies on the same chart not below,and you may need to adjust the y axis as yrange = or; the x axis as xrange =. The performance.Chart shows cumulative daily returns to compare the indices, the in the next band daily range of price returns, then below, the drawdowns, or biggest daily losses.
#startDate<- as.Date("2007-01-03")
ticker <-c("BAC","QQQ","IWM")
# getSymbols(ticker, from = "1993-01-01", auto.assign = TRUE)
# tidyQuant method in timeseries tibble
prices <-
getSymbols(ticker, src = 'yahoo',
from = "2000-01-01",
auto.assign = TRUE,
warnings = FALSE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(ticker)
prices_daily <- to.daily(prices, indexAt = "lastof", OHLC = FALSE)
asset_returns_xts <- na.omit(Return.calculate(prices_daily, method = "log"))
#standard quantmod method
getSymbols("BAC", from= "2000-01-01", auto.assign = TRUE)
getSymbols("IWM", from= "2000-01-01", auto.assign = TRUE)
chartSeries(QQQ)
chartSeries(BAC)
i_a.cls <- BAC$BAC.Adjusted
s_a.cls <- QQQ$QQQ.Adjusted
sht_series <- i_a.cls["2020"]
#sht_series
chartSeries(sht_series)
chartSeries(sht_series,
theme = chartTheme("white"),
TA = c(addBBands(n = 20, sd = 2, ma = "SMA", draw = 'bands', on = -1)))
chartSeries(s_a.cls,TA = "addTA(i_a.cls, on= 1)", yrange = c(0, 380))
charts.PerformanceSummary(asset_returns_xts)
THis small calculation shows how much of the total twenty years of the data the market has been down, it reflects the Hurst Index shown later
n_neg <- asset_returns_xts[asset_returns_xts$BAC<0]
neg <- n_neg$BAC
head(neg)
ndf <- as.data.frame(neg)
head(ndf)
count_neg <- count(ndf)
count_neg
neg_asset <- as.data.frame(asset_returns_xts$BAC)
count_asset <- count(neg_asset)
down <- count_neg/count_asset
down
up <- 1-down
up
Here we calculate a table of Capital Asset Pricing model Metrics such as Sharpe ratio , treynor ratio, beta, and alpha, etc. We also calculate a relative performance chart of IWM against the QQQ
head(asset_returns_xts)
chart.RelativePerformance(asset_returns_xts,asset_returns_xts$QQQ)
table.CAPM(asset_returns_xts,asset_returns_xts$QQQ,Rf = 0, scale = 252)
The probabilities and the expected range are really based on a snapshot in time. Recognition of what your expectations are for implied volatility in the future is therefore a necessary part of assessing the confidence and validity you place in the probability at which you arrive. Many traders do not even look at the historical distribution curve at all, and I think that is a huge mistake. We will talk more about that later, but for now, we will concentrate on our forwardlooking distribution curve as defined by the implied of the stocks. The original stock price model assumed that underlying assets moved randomly. After Merton got involved in the process, it was recognized that the curve was actually lognormal in shape. An asset’s value can theoretically go up infinitely but can never go to a negative value. One last facet of the distribution curve is its level of kurtosis. statistically speaking, a measure of the peakedness of the distribution curve. A statistical distribution where the points along the X‐axis are clustered, resulting in a higher peak (higher kurtosis) than the curvature found in a normal distribution. Th is high peak and corresponding fat tails means the distribution is more clustered around the mean than in a mesokurtic or platykurtic distribution, and will have a relatively smaller standard deviation. As we know, the standard deviation, as described in the definition, is synonymous with volatility. So, when we are in a relatively low volatility environment, the skew takes on a more leptokurtic shape. As a result, the more leptokurtic our distribution curves become, the greater the risk that traders will get caught with their pants down when the underlying has a tail risk–style event.
ts_r <- as.timeSeries(asset_returns_xts$BAC)
tb_r <- as.data.frame(asset_returns_xts$BAC)
histPlot(ts_r)
#chart.Histogram(ts_r,breaks= "FD",methods = c("add.rug","add.risk"),color ="blue", )
chart.Histogram(ts_r,main =" SPY Histogram",methods = c("add.density","add.centered","add.rug","add.risk"),color = bluemono)
library(stargazer)
out <- summary(ts_r)
stargazer(out, type = "text")
table.Stats(ts_r)
#out_rt <- t(table.CalendarReturns(ts_r))
#stargazer(out_rt, type = "text")
#
# layout(rbind(c(1,2),c(3,4)))
#chart.Histogram(asset_returns_xts, main = "Plain", methods = NULL)
#chart.Histogram(asset_returns_xts, main = "Density", breaks=40,
#methods = c("add.density", "add.normal"))
#chart.Histogram(asset_returns_xts, main = "Skew and Kurt", methods = c
#("add.centered", "add.rug"))
#chart.Histogram(asset_returns_xts, main = "Risk Measures", methods = c
#("add.risk"))
The below highlights the relative and cumulative frequency of the data as illustrated in the histograms in a data table. It is usefull for checking, given either the Implied volatility rank or percentile the likelihood a downside breach, using a rule of thumb heuristic based on the table stats.
factorx <- factor(cut(asset_returns_xts$BAC, breaks=nclass.Sturges(asset_returns_xts$BAC)))
#TSPYulate and turn into data.frame
xout <- as.data.frame(table(factorx))
#Add cumFreq and proportions
xout_r <- transform(xout, cumFreq = cumsum(Freq), relative = prop.table(Freq))
xout_r
tb_xout <- tibble(xout_r)
tb_xout
The conditional variance at risk is the variance at risk calculated using actual historical data, whereas the V.A.R. simply uses a z score to estimate risk.
CVaR(asset_returns_xts, alpha = .01, type ="sample")
CVaR(asset_returns_xts, alpha = .05, type ="sample")
Here we load the Pracma and fractal libraries for estimating various forms of the Hurst re scaled range statistic.
library(pracma)
# library(fractal)
library(quantmod)
getSymbols("BAC")
geom_return_BAC <- dailyReturn(BAC, type = "log")
x <- geom_return_BAC
Having estimated daily returns #(geom_return_BAC) and assigned to variable x, we then estimate the Hurst index for the stock at hand. first with Hurstexp(x) from the pracma libraries which gives the simple R/S statistic and some more experimental calculated variations.hurstexp(x) calculates the Hurst exponent of a time series x using R/S analysis, after Hurst, with slightly different approaches, or corrects it with small sample bias, see for example Weron.
These approaches are a corrected R/S method, an empirical and corrected empirical method, and a try at a theoretical Hurst exponent. It should be mentioned that the results are sometimes very different, so providing error estimates will be highly questionable.
Optimal sample sizes are automatically computed with a length that possesses the most divisors among series shorter than x by no more than 1 percent.
Hurstspec() form the fractal library is estimated next, it is estimated by spectral density function. Hurst Coefficient Estimation Via Spectral Regression Function to estimate the Hurst parameter H of a time series by linear regression of the log(spectrum) versus log(frequency) with frequency points accumulated into boxes of equal width on a logarithmic scale and spectrum values averaged over each box.We then look at a variation of this method, then 2 more; a simple user defined R/S H stat function, and a aggabs method of hurstblock function, which calculates greater scaled samples of data for their hurst exponent then averages them.The series is partitioned into m groups. Within each group, the first absolute moment about the mean of the entire series is evaluated. A measure of the variability of this statistic between groups is calculated. The number of groups, m, is increased and the process is repeated. The observed variability changes with increasing m in a way related by theory to the Hurst parameter H of the input series. For the methods used here, a log-log plot of variability versus number of groups is, ideally, linear, with a slope related to H, so H can be determined by linear regression.
hurstexp(x)
# hurstSpec(x)
#
# hurstSpec(x, method="robinson", sdf.method="multitaper")
# RoverS(geom_return_BAC)
#
# "aggAbs" <- hurstBlock(x, method="aggAbs", scale.min=8, scale.max=NULL,
# scale.ratio=8, weight=function(x) rep(1,length(x)), fit=lm)
#
# plot(aggAbs)
SimpleHurst <- function(y){
sd.y <- sd(y)
m <- mean(y)
y <- y - m
max.y <- max(cumsum(y))
min.y <- min(cumsum(y))
RS <- (max.y - min.y)/sd.y
H <- log(RS) / log(length(y))
return(H)
}
SimpleHurst(x)
# Alternate calculation
#hurst(nile.yr.ts)
#hurstexp(nile.yr.ts)
library(fPortfolio)
library(fExtremes)
library(PerformanceAnalytics)
rsk <- table.DownsideRisk(geom_return_BAC,Rf= 0,p = .99, digits = 4, ci = .99)
rsk
CVaR(geom_return_BAC, alpha = .01)
cvarRisk(geom_return_BAC, alpha = .01, weights = 1)
rslt_drw <- table.Drawdowns(geom_return_BAC)
rslt_drw
we will estimate from the law of small numbers the likelihood of left tail or downside events, one the mean likely drop or expected drop, and one the worst case scenario given the data. The next section uses the Peak over threshold method to estimate the extreme value distribution using a pareto curve fitted by maximum likelihood methods. It is often refer to as the law of small numbers, as extreme value theory after the GFC has come to replace VAR as the serious downside risk estimator for quants.
xt <- -geom_return_BAC
findThreshold(xt)
thrshd <- findThreshold(xt)
thrshd
findThreshold(xt,doplot = TRUE)
fit1 <- fitgpd(xt, thresh = .04, est = "mle")
fit <- fitgpd(xt, thresh = thrshd, est = "mle")
gpdfit <- gpd(xt,threshold =0.01)
names(gpdfit)
par(mfcol = c(2,2))
plot(gpdfit)
we estimate the pareto distribution then we forecast likely daily downside change, using GARCH metods on GARCH(1,1) , and ARMA(1,0) function.
#fit_dta <- geom_return_BAC[geom_return_BAC< .04]
fit_data_garch <- garchFit(formula=~ arma(1, 0) + garch(1, 1),
data=xt,
cond.dist="norm", trace=FALSE)
# Produce forecasts
model.forecast <- fGarch::predict(object=fit_data_garch, n.ahead=1)
cat("Forecasts for Extremes")
model.forecast
est <- model.forecast$meanForecast*last(BAC)
est
Here we fit the most likely extreme tail event given the data sample, with two distributions one at the 5% level of confidence and one at the 1% level of cofidence and we then calculate the maximum expected daily drop in an extreme event.
tp <- tailplot(gpdfit)
gpd.q(tp, pp = 0.999, ci.p = 0.95)
quantile(xt, probs = 0.999, type = 1)
gpd.sfall(tp, 0.99)
loss <- .09857*last(BAC$BAC.Adjusted)
loss
E
These are incomplete quantmod getOption functions not currently run.
library(quantmod)
getOptionChain("BAC", Exp = "2021-01")
#your list of expiration dates
Exp=c("2021-01", "2020-01-20")
x=list()
for(i in 1:length(exp)) x<-c(getOptionChain("BAC",exp[i]),x)
x
E
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuDQoNClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC5TDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQoNCg0KDQpsaWJyYXJ5KHF1YW50bW9kKQ0KbGlicmFyeShIbWlzYykNCg0KbGlicmFyeSh0aWR5cXVhbnQpDQpsaWJyYXJ5KGZCYXNpY3MpDQpsaWJyYXJ5KGZFeHRyZW1lcykNCmxpYnJhcnkoZlBvcnRmb2xpbykNCmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpDQpsaWJyYXJ5KHRzYm94KQ0KbGlicmFyeSh0aW1ldGspDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCg0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeSh2YXJzKQ0KbGlicmFyeShldmQpDQpsaWJyYXJ5KGV2aXIpDQpsaWJyYXJ5KFBPVCkNCg0KDQoNCmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpDQpsaWJyYXJ5KHJ1Z2FyY2gpDQpsaWJyYXJ5KG5vcnRlc3QpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KbGlicmFyeShwcmFjbWEpDQojbGlicmFyeShmcmFjdGFsKQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQpsaWJyYXJ5KHJ1Z2FyY2gpDQpsaWJyYXJ5KGZHYXJjaCkNCmBgYA0KIyNFeHRyYWN0IFByaWNlIFNlcmllcw0KSGVyZSB3ZSBleHRyYWN0IHRoZSBpbmRleCBhbmQgdGhlIGNvbXBhcmlzb24gZXF1aXR5DQpXZSB1c2UgdGhlIFF1YW50bW9kIExpYnJhcmllcyBzdGFuZGFyZCBnZXRTeW1ib2xzIHRvb2wuDQpXZSB0aGVuIHBhc3Mgc3ltYm9scyB0byBZYWhvbyEgRmluYW5jZSB2aWEgdGhlIGdldFN5bWJvbHMoKSBmdW5jdGlvbiBmcm9tDQp0aGUgcXVhbnRtb2QgcGFja2FnZS4gVGhpcyB3aWxsIHJldHVybiBhbiBvYmplY3Qgd2l0aCB0aGUgb3BlbmluZyBwcmljZSwNCmNsb3NpbmcgcHJpY2UsIGFkanVzdGVkIHByaWNlLCBkYWlseSBoaWdoLCBkYWlseSBsb3cgYW5kIGRhaWx5IHZvbHVtZSBmb3IgZWFjaA0KdGlja2VyLg0KVG8gaXNvbGF0ZSB0aGUgYWRqdXN0ZWQgcHJpY2UsIHdlIHVzZSB0aGUgbWFwKCkgZnVuY3Rpb24gZnJvbSB0aGUgcHVycnIgcGFja2FnZQ0KYW5kIGFwcGx5IEFkKGdldCguKSkgdG8gdGhlIGltcG9ydGVkIHByaWNlcy4gVGhpcyB3aWxsIGdldCgpIHRoZSBhZGp1c3RlZA0KcHJpY2UgZnJvbSBlYWNoIG9mIG91ciBpbmRpdmlkdWFsIHByaWNlIHNlcmllcy4gSWYgd2Ugd2FudGVkIHRoZSBjbG9zaW5nIHByaWNlLA0Kd2Ugd291bGQgcnVuIENsKGdldCguKSkuIFRoYXQgLiByZWZlcnMgdG8gb3VyIGluaXRpYWwgb2JqZWN0Lg0KV2UgY291bGQgc3RvcCBoZXJlIGFuZCBoYXZlIHRoZSByaWdodCBzdWJzdGFuY2UgLSBkYWlseSBwcmljZXMgZm9yIDIgRVRGcyAtDQpidXQgdGhlIGZvcm1hdCB3b3VsZCBub3QgYmUgZ3JlYXQgYXMgd2Ugd291bGQgaGF2ZSBhIGxpc3Qgb2YgMiB4dHMgb2JqZWN0cy4NClRoaXMgaXMgYmVjYXVzZSB0aGUgbWFwKCkgZnVuY3Rpb24gcmV0dXJucyBhIGxpc3QgYnkgZGVmYXVsdC4NClRoZSByZWR1Y2UobWVyZ2UpIGZ1bmN0aW9uIHdpbGwgbWVyZ2UgdGhlIDIgbGlzdHMgaW50byBvbmUgeHRzIG9iamVjdC4gVGhlDQptZXJnZSgpIGZ1bmN0aW9uIGxvb2tzIGZvciB0aGUgZGF0ZSBpbmRleCBzaGFyZWQgYnkgb3VyIG9iamVjdHMgYW5kIHVzZXMgdGhhdA0KaW5kZXggdG8gYWxpZ24gdGhlIGRhdGEuDQpBZnRlciB3ZSBzZXQgcHJpY2VzIHRvIGRhaWx5IHdlIGVzdGltYXRlIHJldHVybnMgd2l0aCAiYXNzZXRfcmV0dXJuc194dHMgPC0gbmEub21pdChSZXR1cm4uY2FsY3VsYXRlKHByaWNlc19kYWlseSwgbWV0aG9kID0gImxvZyIpKSIgbmEub21pdCByZW1vdmVzIGJsYW5rcywgUmV0dXJuLkNhbGN1bGF0ZSBjYWxjdWxhdGVzIGRhaWx5IHJldHVybnMsIHRocm91Z2hvdXQgdGhlIHJlc3Qgb2YgdGhpcyB3ZSB1c2UgdGhlIGRhaWx5UmV0dXJuKCkgZnVuY3Rpb24gdG8gYWNoaWV2ZSB0aGUgc2FtZSB0aGluZyBpbiBhIHNpbXBsZXIgZmFzaGlvbiwgbWV0aG9kID0gbG9nIHNpZ25pZmllcyBsb2cgZGFpbHkgb3IgZ2VvbWV0cmljIHJldHVybnMgYXMgb3Bwb3NlZCB0byB0aGUgZGVmYXVsdCBhcml0aG1ldGljIHJhdGUgb2YgY2hhbmdlLg0KDQpGaW5hbGx5LCB3ZSB3YW50IGludHVpdGl2ZSBjb2x1bW4gbmFtZXMgYW5kIHVzZSBjb2xuYW1lczwtIHRvIHJlbmFtZSB0aGUNCmNvbHVtbnMgYWNjb3JkaW5nIHRvIHRoZSBzeW1ib2xzIG9iamVjdC4NCkluIG9yZGVyIHRvIGFkZCB0ZWNobmljYWwgaW5kaWNhdG9ycyBpbiBhIGNoYXJ0LCBRdWFudG1vZCBwcm92aWRlcyB0aGUgYWRke0luZGljYXRvck5hbWUpKCkgZnVuY3Rpb24uIFdlIHdpbGwgdXNlIHRoaXMgZnVuY3Rpb24gZm9yIHBsb3R0aW5nIHRoZSBCb2xsaW5nZXIgQmFuZCBvZiBTUFkgcHJpY2VzLiBCb3RoIGluZGljYXRvcnMgYXJlIHBsb3R0ZWQgd2l0aCB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzIHdoaWNoIGFyZSBzcGVjaWZpZWQgYmVsb3c6DQpUbyBhZGQgYSBzZWNvbmQgc2VyaWVzIG9uIHRoZSBzYW1lIGNoYXJ0IGl0IGlzIHNpbWlsYXIgdG8gYWRkaW5nIGFuZCBpbmRpY2F0b3IgaW4gdGhpcyBjYXNlIGFmdGVyIHlvdSBhZGQgdGhlIGZpcnN0IGNoYXJ0IHNlcmllcyBhcyBub3JtYWwsIGFkZCB0aGlzIFRBID0gImFkZFRBKGlfYS5jbHMsIG9uPSAxKSIsIHlyYW5nZSA9IGMoMCwgMzgwKSB3aGVyZSBpbiB0aGUgcXVvdGUgYWRkVEEgaW4gdGhlIGJyYWNrZXRzIGlzIHRoZSBzZWNvbmQgc2VyaWVzLCB0aGUgb24gPSAxIHNpZ25pZmllcyBvbiB0aGUgc2FtZSBjaGFydCBub3QgYmVsb3csYW5kIHlvdSBtYXkgbmVlZCB0byBhZGp1c3QgdGhlIHkgYXhpcyBhcyB5cmFuZ2UgPSBvcjsgdGhlIHggYXhpcyBhcyB4cmFuZ2UgPS4NClRoZSBwZXJmb3JtYW5jZS5DaGFydCBzaG93cyBjdW11bGF0aXZlIGRhaWx5IHJldHVybnMgdG8gY29tcGFyZSB0aGUgaW5kaWNlcywgdGhlIGluIHRoZSBuZXh0IGJhbmQgZGFpbHkgcmFuZ2Ugb2YgcHJpY2UgcmV0dXJucywgdGhlbiBiZWxvdywgdGhlIGRyYXdkb3ducywgb3IgYmlnZ2VzdCBkYWlseSBsb3NzZXMuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQoNCg0KI3N0YXJ0RGF0ZTwtIGFzLkRhdGUoIjIwMDctMDEtMDMiKQ0KDQp0aWNrZXIgPC1jKCJCQUMiLCJRUVEiLCJJV00iKQ0KDQojIGdldFN5bWJvbHModGlja2VyLCBmcm9tID0gIjE5OTMtMDEtMDEiLCBhdXRvLmFzc2lnbiA9IFRSVUUpDQojIHRpZHlRdWFudCBtZXRob2QgaW4gdGltZXNlcmllcyB0aWJibGUNCnByaWNlcyA8LSANCiAgZ2V0U3ltYm9scyh0aWNrZXIsIHNyYyA9ICd5YWhvbycsIA0KICAgICAgICAgICAgIGZyb20gPSAiMjAwMC0wMS0wMSIsIA0KICAgICAgICAgICAgIGF1dG8uYXNzaWduID0gVFJVRSwgDQogICAgICAgICAgICAgd2FybmluZ3MgPSBGQUxTRSkgJT4lIA0KICBtYXAofkFkKGdldCguKSkpICU+JSANCiAgcmVkdWNlKG1lcmdlKSAlPiUNCiAgYGNvbG5hbWVzPC1gKHRpY2tlcikNCg0KDQoNCnByaWNlc19kYWlseSA8LSB0by5kYWlseShwcmljZXMsIGluZGV4QXQgPSAibGFzdG9mIiwgT0hMQyA9IEZBTFNFKQ0KDQphc3NldF9yZXR1cm5zX3h0cyA8LSBuYS5vbWl0KFJldHVybi5jYWxjdWxhdGUocHJpY2VzX2RhaWx5LCBtZXRob2QgPSAibG9nIikpDQoNCg0KI3N0YW5kYXJkIHF1YW50bW9kIG1ldGhvZA0KZ2V0U3ltYm9scygiQkFDIiwgZnJvbT0gIjIwMDAtMDEtMDEiLCBhdXRvLmFzc2lnbiA9IFRSVUUpDQoNCmdldFN5bWJvbHMoIklXTSIsIGZyb209ICIyMDAwLTAxLTAxIiwgYXV0by5hc3NpZ24gPSBUUlVFKQ0KDQpjaGFydFNlcmllcyhRUVEpDQpjaGFydFNlcmllcyhCQUMpDQppX2EuY2xzIDwtIEJBQyRCQUMuQWRqdXN0ZWQNCnNfYS5jbHMgPC0gUVFRJFFRUS5BZGp1c3RlZA0KDQpzaHRfc2VyaWVzIDwtIGlfYS5jbHNbIjIwMjAiXQ0KI3NodF9zZXJpZXMNCg0KY2hhcnRTZXJpZXMoc2h0X3NlcmllcykNCmNoYXJ0U2VyaWVzKHNodF9zZXJpZXMsDQogICAgICAgICAgICB0aGVtZSA9IGNoYXJ0VGhlbWUoIndoaXRlIiksDQogICAgICAgICAgICBUQSA9IGMoYWRkQkJhbmRzKG4gPSAyMCwgc2QgPSAyLCBtYSA9ICJTTUEiLCBkcmF3ID0gJ2JhbmRzJywgb24gPSAtMSkpKSANCg0KDQoNCmNoYXJ0U2VyaWVzKHNfYS5jbHMsVEEgPSAiYWRkVEEoaV9hLmNscywgb249IDEpIiwgeXJhbmdlID0gYygwLCAzODApKQ0KDQoNCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoYXNzZXRfcmV0dXJuc194dHMpDQoNCmBgYA0KDQoNClRIaXMgc21hbGwgY2FsY3VsYXRpb24gc2hvd3MgaG93IG11Y2ggb2YgdGhlIHRvdGFsIHR3ZW50eSB5ZWFycyBvZiB0aGUgZGF0YSB0aGUgbWFya2V0IGhhcyBiZWVuIGRvd24sIGl0IHJlZmxlY3RzIHRoZSBIdXJzdCBJbmRleCBzaG93biBsYXRlcg0KDQpgYGB7cn0NCm5fbmVnIDwtIGFzc2V0X3JldHVybnNfeHRzW2Fzc2V0X3JldHVybnNfeHRzJEJBQzwwXQ0KDQoNCm5lZyA8LSBuX25lZyRCQUMNCmhlYWQobmVnKQ0KbmRmIDwtIGFzLmRhdGEuZnJhbWUobmVnKQ0KaGVhZChuZGYpDQoNCmNvdW50X25lZyA8LSBjb3VudChuZGYpDQpjb3VudF9uZWcNCm5lZ19hc3NldCA8LSBhcy5kYXRhLmZyYW1lKGFzc2V0X3JldHVybnNfeHRzJEJBQykNCmNvdW50X2Fzc2V0IDwtIGNvdW50KG5lZ19hc3NldCkNCmRvd24gPC0gY291bnRfbmVnL2NvdW50X2Fzc2V0DQpkb3duDQp1cCA8LSAxLWRvd24NCnVwDQpgYGANCg0KSGVyZSB3ZSBjYWxjdWxhdGUgYSB0YWJsZSBvZiBDYXBpdGFsIEFzc2V0IFByaWNpbmcgbW9kZWwgTWV0cmljcyBzdWNoIGFzIFNoYXJwZSByYXRpbyAsIHRyZXlub3IgcmF0aW8sIGJldGEsIGFuZCBhbHBoYSwgZXRjLg0KV2UgYWxzbyBjYWxjdWxhdGUgYSByZWxhdGl2ZSBwZXJmb3JtYW5jZSBjaGFydCBvZiBJV00gYWdhaW5zdCB0aGUgUVFRDQoNCg0KYGBge3J9DQoNCg0KDQoNCmhlYWQoYXNzZXRfcmV0dXJuc194dHMpDQoNCg0KDQoNCmNoYXJ0LlJlbGF0aXZlUGVyZm9ybWFuY2UoYXNzZXRfcmV0dXJuc194dHMsYXNzZXRfcmV0dXJuc194dHMkUVFRKQ0KdGFibGUuQ0FQTShhc3NldF9yZXR1cm5zX3h0cyxhc3NldF9yZXR1cm5zX3h0cyRRUVEsUmYgPSAwLCBzY2FsZSA9IDI1MikNCg0KYGBgDQpUaGUgcHJvYmFiaWxpdGllcyBhbmQgdGhlIGV4cGVjdGVkIHJhbmdlIGFyZSByZWFsbHkgYmFzZWQgb24gYSBzbmFwc2hvdCBpbiB0aW1lLiBSZWNvZ25pdGlvbiBvZiB3aGF0IHlvdXIgZXhwZWN0YXRpb25zIGFyZSBmb3IgaW1wbGllZCB2b2xhdGlsaXR5IGluIHRoZSBmdXR1cmUgaXMgdGhlcmVmb3JlIGEgbmVjZXNzYXJ5IHBhcnQgb2YgYXNzZXNzaW5nIHRoZSBjb25maWRlbmNlIGFuZCB2YWxpZGl0eSB5b3UgcGxhY2UgaW4gdGhlIHByb2JhYmlsaXR5IGF0IHdoaWNoIHlvdSBhcnJpdmUuDQpNYW55IHRyYWRlcnMgZG8gbm90IGV2ZW4gbG9vayBhdCB0aGUgaGlzdG9yaWNhbCBkaXN0cmlidXRpb24gY3VydmUgYXQgYWxsLCBhbmQgSSB0aGluayB0aGF0IGlzIGEgaHVnZSBtaXN0YWtlLiBXZSB3aWxsIHRhbGsgbW9yZSBhYm91dCB0aGF0IGxhdGVyLCBidXQgZm9yIG5vdywgd2Ugd2lsbCBjb25jZW50cmF0ZSBvbiBvdXIgZm9yd2FyZGxvb2tpbmcgZGlzdHJpYnV0aW9uIGN1cnZlIGFzIGRlZmluZWQgYnkgdGhlIGltcGxpZWQgIG9mIHRoZSBzdG9ja3MuIA0KVGhlIG9yaWdpbmFsIHN0b2NrIHByaWNlIG1vZGVsICBhc3N1bWVkIHRoYXQgdW5kZXJseWluZyBhc3NldHMgbW92ZWQgcmFuZG9tbHkuIEFmdGVyIE1lcnRvbiBnb3QgaW52b2x2ZWQgaW4gdGhlIHByb2Nlc3MsIGl0IHdhcyByZWNvZ25pemVkIHRoYXQgdGhlIGN1cnZlIHdhcyBhY3R1YWxseSBsb2dub3JtYWwgaW4gc2hhcGUuIEFuIGFzc2V04oCZcyB2YWx1ZSBjYW4gdGhlb3JldGljYWxseSBnbyB1cCBpbmZpbml0ZWx5IGJ1dCBjYW4gbmV2ZXIgZ28gdG8gYSBuZWdhdGl2ZSB2YWx1ZS4NCk9uZSBsYXN0IGZhY2V0IG9mIHRoZSBkaXN0cmlidXRpb24gY3VydmUgaXMgaXRzIGxldmVsIG9mIGt1cnRvc2lzLiBzdGF0aXN0aWNhbGx5IHNwZWFraW5nLCBhIG1lYXN1cmUgb2YgdGhlIHBlYWtlZG5lc3Mgb2YgdGhlIGRpc3RyaWJ1dGlvbiBjdXJ2ZS4gQSBzdGF0aXN0aWNhbCBkaXN0cmlidXRpb24gd2hlcmUgdGhlIHBvaW50cyBhbG9uZyB0aGUgWOKAkGF4aXMgYXJlIGNsdXN0ZXJlZCwgcmVzdWx0aW5nIGluIGEgaGlnaGVyIHBlYWsgKGhpZ2hlciBrdXJ0b3NpcykgdGhhbiB0aGUgY3VydmF0dXJlIGZvdW5kIGluIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGggaXMgaGlnaCBwZWFrIGFuZCBjb3JyZXNwb25kaW5nIGZhdCB0YWlscyBtZWFucyB0aGUgZGlzdHJpYnV0aW9uIGlzIG1vcmUgY2x1c3RlcmVkIGFyb3VuZCB0aGUgbWVhbiB0aGFuIGluIGEgbWVzb2t1cnRpYyBvciBwbGF0eWt1cnRpYyBkaXN0cmlidXRpb24sIGFuZCB3aWxsIGhhdmUgYSByZWxhdGl2ZWx5IHNtYWxsZXIgc3RhbmRhcmQgZGV2aWF0aW9uLiBBcyB3ZSBrbm93LCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uLCBhcyBkZXNjcmliZWQgaW4gdGhlIGRlZmluaXRpb24sIGlzIHN5bm9ueW1vdXMgd2l0aCB2b2xhdGlsaXR5LiBTbywgd2hlbiB3ZSBhcmUgaW4gYSByZWxhdGl2ZWx5IGxvdyB2b2xhdGlsaXR5IGVudmlyb25tZW50LCB0aGUgc2tldyB0YWtlcyBvbiBhIG1vcmUgbGVwdG9rdXJ0aWMgc2hhcGUuIEFzIGEgcmVzdWx0LCB0aGUgbW9yZSBsZXB0b2t1cnRpYyBvdXIgZGlzdHJpYnV0aW9uIGN1cnZlcyBiZWNvbWUsIHRoZSBncmVhdGVyIHRoZSByaXNrIHRoYXQgdHJhZGVycyB3aWxsIGdldCBjYXVnaHQgd2l0aCB0aGVpciBwYW50cyBkb3duIHdoZW4gdGhlIHVuZGVybHlpbmcgaGFzIGEgdGFpbCByaXNr4oCTc3R5bGUgZXZlbnQuDQoNCg0KDQoNCg0KDQoNCg0KYGBge3IsIG1lc3NhZ2U9RmFsc2Usd2FybmluZz1GQUxTRX0NCg0KdHNfciA8LSBhcy50aW1lU2VyaWVzKGFzc2V0X3JldHVybnNfeHRzJEJBQykNCnRiX3IgPC0gYXMuZGF0YS5mcmFtZShhc3NldF9yZXR1cm5zX3h0cyRCQUMpDQpoaXN0UGxvdCh0c19yKQ0KI2NoYXJ0Lkhpc3RvZ3JhbSh0c19yLGJyZWFrcz0gIkZEIixtZXRob2RzID0gYygiYWRkLnJ1ZyIsImFkZC5yaXNrIiksY29sb3IgPSJibHVlIiwgKQ0KY2hhcnQuSGlzdG9ncmFtKHRzX3IsbWFpbiA9IiBTUFkgSGlzdG9ncmFtIixtZXRob2RzID0gYygiYWRkLmRlbnNpdHkiLCJhZGQuY2VudGVyZWQiLCJhZGQucnVnIiwiYWRkLnJpc2siKSxjb2xvciA9IGJsdWVtb25vKQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQpvdXQgPC0gc3VtbWFyeSh0c19yKQ0Kc3RhcmdhemVyKG91dCwgdHlwZSA9ICJ0ZXh0IikNCnRhYmxlLlN0YXRzKHRzX3IpDQojb3V0X3J0IDwtIHQodGFibGUuQ2FsZW5kYXJSZXR1cm5zKHRzX3IpKQ0KI3N0YXJnYXplcihvdXRfcnQsIHR5cGUgPSAidGV4dCIpDQojDQojIGxheW91dChyYmluZChjKDEsMiksYygzLDQpKSkNCiNjaGFydC5IaXN0b2dyYW0oYXNzZXRfcmV0dXJuc194dHMsIG1haW4gPSAiUGxhaW4iLCBtZXRob2RzID0gTlVMTCkNCiAjY2hhcnQuSGlzdG9ncmFtKGFzc2V0X3JldHVybnNfeHRzLCBtYWluID0gIkRlbnNpdHkiLCBicmVha3M9NDAsDQogI21ldGhvZHMgPSBjKCJhZGQuZGVuc2l0eSIsICJhZGQubm9ybWFsIikpDQogI2NoYXJ0Lkhpc3RvZ3JhbShhc3NldF9yZXR1cm5zX3h0cywgbWFpbiA9ICJTa2V3IGFuZCBLdXJ0IiwgbWV0aG9kcyA9IGMNCiAjKCJhZGQuY2VudGVyZWQiLCAiYWRkLnJ1ZyIpKQ0KICNjaGFydC5IaXN0b2dyYW0oYXNzZXRfcmV0dXJuc194dHMsIG1haW4gPSAiUmlzayBNZWFzdXJlcyIsIG1ldGhvZHMgPSBjDQogIygiYWRkLnJpc2siKSkNCmBgYA0KVGhlIGJlbG93IGhpZ2hsaWdodHMgdGhlIHJlbGF0aXZlIGFuZCBjdW11bGF0aXZlIGZyZXF1ZW5jeSBvZiB0aGUgZGF0YSBhcyBpbGx1c3RyYXRlZCBpbiB0aGUgaGlzdG9ncmFtcyBpbiBhIGRhdGEgdGFibGUuIEl0IGlzIHVzZWZ1bGwgZm9yIGNoZWNraW5nLCBnaXZlbiBlaXRoZXIgdGhlIEltcGxpZWQgdm9sYXRpbGl0eSByYW5rIG9yIHBlcmNlbnRpbGUgdGhlIGxpa2VsaWhvb2QgYSBkb3duc2lkZSBicmVhY2gsIHVzaW5nIGEgcnVsZSBvZiB0aHVtYiBoZXVyaXN0aWMgYmFzZWQgb24gdGhlIHRhYmxlIHN0YXRzLg0KYGBge3J9DQpmYWN0b3J4IDwtIGZhY3RvcihjdXQoYXNzZXRfcmV0dXJuc194dHMkQkFDLCBicmVha3M9bmNsYXNzLlN0dXJnZXMoYXNzZXRfcmV0dXJuc194dHMkQkFDKSkpDQojVFNQWXVsYXRlIGFuZCB0dXJuIGludG8gZGF0YS5mcmFtZQ0KeG91dCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGZhY3RvcngpKQ0KI0FkZCBjdW1GcmVxIGFuZCBwcm9wb3J0aW9ucw0KeG91dF9yIDwtIHRyYW5zZm9ybSh4b3V0LCBjdW1GcmVxID0gY3Vtc3VtKEZyZXEpLCByZWxhdGl2ZSA9IHByb3AudGFibGUoRnJlcSkpDQoNCnhvdXRfcg0KdGJfeG91dCA8LSB0aWJibGUoeG91dF9yKQ0KDQoNCnRiX3hvdXQNCmBgYA0KVGhlIGNvbmRpdGlvbmFsIHZhcmlhbmNlIGF0IHJpc2sgaXMgdGhlIHZhcmlhbmNlIGF0IHJpc2sgY2FsY3VsYXRlZCB1c2luZyBhY3R1YWwgaGlzdG9yaWNhbCBkYXRhLCB3aGVyZWFzIHRoZSBWLkEuUi4gc2ltcGx5IHVzZXMgYSB6IHNjb3JlIHRvIGVzdGltYXRlIHJpc2suDQoNCg0KYGBge3J9DQpDVmFSKGFzc2V0X3JldHVybnNfeHRzLCBhbHBoYSA9IC4wMSwgdHlwZSA9InNhbXBsZSIpDQpDVmFSKGFzc2V0X3JldHVybnNfeHRzLCBhbHBoYSA9IC4wNSwgdHlwZSA9InNhbXBsZSIpDQpgYGANCg0KDQoNCg0KDQoNCg0KSGVyZSB3ZSBsb2FkIHRoZSBQcmFjbWEgYW5kIGZyYWN0YWwgbGlicmFyaWVzIGZvciBlc3RpbWF0aW5nIHZhcmlvdXMgZm9ybXMgb2YgdGhlIEh1cnN0IHJlIHNjYWxlZCByYW5nZSBzdGF0aXN0aWMuDQoNCg0KDQoNCg0KDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFIH0NCg0KDQpsaWJyYXJ5KHByYWNtYSkNCiMgbGlicmFyeShmcmFjdGFsKQ0KbGlicmFyeShxdWFudG1vZCkNCmdldFN5bWJvbHMoIkJBQyIpDQoNCmdlb21fcmV0dXJuX0JBQyA8LSBkYWlseVJldHVybihCQUMsIHR5cGUgPSAibG9nIikNCg0KeCA8LSBnZW9tX3JldHVybl9CQUMNCg0KYGBgDQpIYXZpbmcgZXN0aW1hdGVkIGRhaWx5IHJldHVybnMNCiMoZ2VvbV9yZXR1cm5fQkFDKQ0KYW5kIGFzc2lnbmVkIHRvIHZhcmlhYmxlIHgsIHdlIHRoZW4gZXN0aW1hdGUgdGhlIEh1cnN0IGluZGV4IGZvciB0aGUgc3RvY2sgYXQgaGFuZC4gZmlyc3Qgd2l0aCBIdXJzdGV4cCh4KSBmcm9tIHRoZSBwcmFjbWEgbGlicmFyaWVzIHdoaWNoIGdpdmVzIHRoZSBzaW1wbGUgUi9TIHN0YXRpc3RpYyBhbmQgc29tZSBtb3JlIGV4cGVyaW1lbnRhbCBjYWxjdWxhdGVkIHZhcmlhdGlvbnMuaHVyc3RleHAoeCkgY2FsY3VsYXRlcyB0aGUgSHVyc3QgZXhwb25lbnQgb2YgYSB0aW1lIHNlcmllcyB4IHVzaW5nIFIvUyBhbmFseXNpcywgYWZ0ZXIgSHVyc3QsIHdpdGggc2xpZ2h0bHkgZGlmZmVyZW50IGFwcHJvYWNoZXMsIG9yIGNvcnJlY3RzIGl0IHdpdGggc21hbGwgc2FtcGxlIGJpYXMsIHNlZSBmb3IgZXhhbXBsZSBXZXJvbi4NCg0KVGhlc2UgYXBwcm9hY2hlcyBhcmUgYSBjb3JyZWN0ZWQgUi9TIG1ldGhvZCwgYW4gZW1waXJpY2FsIGFuZCBjb3JyZWN0ZWQgZW1waXJpY2FsIG1ldGhvZCwgYW5kIGEgdHJ5IGF0IGEgdGhlb3JldGljYWwgSHVyc3QgZXhwb25lbnQuIEl0IHNob3VsZCBiZSBtZW50aW9uZWQgdGhhdCB0aGUgcmVzdWx0cyBhcmUgc29tZXRpbWVzIHZlcnkgZGlmZmVyZW50LCBzbyBwcm92aWRpbmcgZXJyb3IgZXN0aW1hdGVzIHdpbGwgYmUgaGlnaGx5IHF1ZXN0aW9uYWJsZS4NCg0KT3B0aW1hbCBzYW1wbGUgc2l6ZXMgYXJlIGF1dG9tYXRpY2FsbHkgY29tcHV0ZWQgd2l0aCBhIGxlbmd0aCB0aGF0IHBvc3Nlc3NlcyB0aGUgbW9zdCBkaXZpc29ycyBhbW9uZyBzZXJpZXMgc2hvcnRlciB0aGFuIHggYnkgbm8gbW9yZSB0aGFuIDEgcGVyY2VudC4NCg0KSHVyc3RzcGVjKCkgZm9ybSB0aGUgZnJhY3RhbCBsaWJyYXJ5IGlzIGVzdGltYXRlZCBuZXh0LCBpdCBpcyBlc3RpbWF0ZWQgYnkgc3BlY3RyYWwgZGVuc2l0eSBmdW5jdGlvbi4gSHVyc3QgQ29lZmZpY2llbnQgRXN0aW1hdGlvbiBWaWEgU3BlY3RyYWwgUmVncmVzc2lvbg0KRnVuY3Rpb24gdG8gZXN0aW1hdGUgdGhlIEh1cnN0IHBhcmFtZXRlciBIIG9mIGEgdGltZSBzZXJpZXMgYnkgbGluZWFyIHJlZ3Jlc3Npb24gb2YgdGhlIGxvZyhzcGVjdHJ1bSkgdmVyc3VzIGxvZyhmcmVxdWVuY3kpIHdpdGggZnJlcXVlbmN5IHBvaW50cyBhY2N1bXVsYXRlZCBpbnRvIGJveGVzIG9mIGVxdWFsIHdpZHRoIG9uIGEgbG9nYXJpdGhtaWMgc2NhbGUgYW5kIHNwZWN0cnVtIHZhbHVlcyBhdmVyYWdlZCBvdmVyIGVhY2ggYm94LldlIHRoZW4gbG9vayBhdCBhIHZhcmlhdGlvbiBvZiB0aGlzIG1ldGhvZCwgdGhlbiAyIG1vcmU7IGEgc2ltcGxlIHVzZXIgZGVmaW5lZCBSL1MgSCBzdGF0IGZ1bmN0aW9uLCBhbmQgYSBhZ2dhYnMgbWV0aG9kIG9mIGh1cnN0YmxvY2sgZnVuY3Rpb24sIHdoaWNoIGNhbGN1bGF0ZXMgZ3JlYXRlciBzY2FsZWQgc2FtcGxlcyBvZiBkYXRhIGZvciB0aGVpciBodXJzdCBleHBvbmVudCB0aGVuIGF2ZXJhZ2VzIHRoZW0uVGhlIHNlcmllcyBpcyBwYXJ0aXRpb25lZCBpbnRvIG0gZ3JvdXBzLiBXaXRoaW4gZWFjaCBncm91cCwgdGhlIGZpcnN0IGFic29sdXRlIG1vbWVudCBhYm91dCB0aGUgbWVhbiBvZiB0aGUgZW50aXJlIHNlcmllcyBpcyBldmFsdWF0ZWQuIEEgbWVhc3VyZSBvZiB0aGUgdmFyaWFiaWxpdHkgb2YgdGhpcyBzdGF0aXN0aWMgYmV0d2VlbiBncm91cHMgaXMgY2FsY3VsYXRlZC4gVGhlIG51bWJlciBvZiBncm91cHMsIG0sIGlzIGluY3JlYXNlZCBhbmQgdGhlIHByb2Nlc3MgaXMgcmVwZWF0ZWQuIFRoZSBvYnNlcnZlZCB2YXJpYWJpbGl0eSBjaGFuZ2VzIHdpdGggaW5jcmVhc2luZyBtIGluIGEgd2F5IHJlbGF0ZWQgYnkgdGhlb3J5IHRvIHRoZSBIdXJzdCBwYXJhbWV0ZXIgSCBvZiB0aGUgaW5wdXQgc2VyaWVzLiBGb3IgdGhlIG1ldGhvZHMgdXNlZCBoZXJlLCBhIGxvZy1sb2cgcGxvdCBvZiB2YXJpYWJpbGl0eSB2ZXJzdXMgbnVtYmVyIG9mIGdyb3VwcyBpcywgaWRlYWxseSwgbGluZWFyLCB3aXRoIGEgc2xvcGUgcmVsYXRlZCB0byBILCBzbyBIIGNhbiBiZSBkZXRlcm1pbmVkIGJ5IGxpbmVhciByZWdyZXNzaW9uLg0KDQoNCg0KDQpgYGB7cn0NCg0KDQoNCg0KaHVyc3RleHAoeCkNCg0KIyBodXJzdFNwZWMoeCkNCiMgDQojIGh1cnN0U3BlYyh4LCBtZXRob2Q9InJvYmluc29uIiwgc2RmLm1ldGhvZD0ibXVsdGl0YXBlciIpDQojIFJvdmVyUyhnZW9tX3JldHVybl9CQUMpDQojIA0KIyAiYWdnQWJzIiA8LSBodXJzdEJsb2NrKHgsIG1ldGhvZD0iYWdnQWJzIiwgc2NhbGUubWluPTgsIHNjYWxlLm1heD1OVUxMLA0KIyAgICAgc2NhbGUucmF0aW89OCwgd2VpZ2h0PWZ1bmN0aW9uKHgpIHJlcCgxLGxlbmd0aCh4KSksIGZpdD1sbSkNCiMgDQojIHBsb3QoYWdnQWJzKQ0KDQoNClNpbXBsZUh1cnN0IDwtIGZ1bmN0aW9uKHkpew0KICAgICAgc2QueSA8LSBzZCh5KQ0KICAgICAgbSA8LSBtZWFuKHkpDQogICAgICB5IDwtIHkgLSBtDQogICAgICBtYXgueSA8LSBtYXgoY3Vtc3VtKHkpKQ0KICAgICAgbWluLnkgPC0gbWluKGN1bXN1bSh5KSkNCiAgICAgIFJTIDwtIChtYXgueSAtIG1pbi55KS9zZC55DQogICAgICBIIDwtIGxvZyhSUykgLyBsb2cobGVuZ3RoKHkpKQ0KICAgICAgcmV0dXJuKEgpDQp9DQpTaW1wbGVIdXJzdCh4KQ0KDQojIEFsdGVybmF0ZSBjYWxjdWxhdGlvbg0KI2h1cnN0KG5pbGUueXIudHMpDQojaHVyc3RleHAobmlsZS55ci50cykNCmBgYA0KDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShmUG9ydGZvbGlvKQ0KbGlicmFyeShmRXh0cmVtZXMpDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KcnNrIDwtIHRhYmxlLkRvd25zaWRlUmlzayhnZW9tX3JldHVybl9CQUMsUmY9IDAscCA9IC45OSwgZGlnaXRzID0gNCwgY2kgPSAuOTkpDQpyc2sNCkNWYVIoZ2VvbV9yZXR1cm5fQkFDLCBhbHBoYSA9IC4wMSkNCmN2YXJSaXNrKGdlb21fcmV0dXJuX0JBQywgYWxwaGEgPSAuMDEsIHdlaWdodHMgPSAxKQ0KcnNsdF9kcncgPC0gdGFibGUuRHJhd2Rvd25zKGdlb21fcmV0dXJuX0JBQykNCnJzbHRfZHJ3DQpgYGANCg0Kd2Ugd2lsbCBlc3RpbWF0ZSBmcm9tIHRoZSBsYXcgb2Ygc21hbGwgbnVtYmVycyB0aGUgbGlrZWxpaG9vZCBvZiBsZWZ0IHRhaWwgb3IgZG93bnNpZGUgZXZlbnRzLCBvbmUgdGhlIG1lYW4gbGlrZWx5IGRyb3Agb3IgZXhwZWN0ZWQgZHJvcCwgYW5kIG9uZSB0aGUgd29yc3QgY2FzZSBzY2VuYXJpbyBnaXZlbiB0aGUgZGF0YS4NClRoZSBuZXh0IHNlY3Rpb24gdXNlcyB0aGUgUGVhayBvdmVyIHRocmVzaG9sZCBtZXRob2QgdG8gZXN0aW1hdGUgdGhlIGV4dHJlbWUgdmFsdWUgZGlzdHJpYnV0aW9uIHVzaW5nIGEgcGFyZXRvIGN1cnZlIGZpdHRlZCBieSBtYXhpbXVtIGxpa2VsaWhvb2QgbWV0aG9kcy4NCkl0IGlzIG9mdGVuIHJlZmVyIHRvIGFzIHRoZSBsYXcgb2Ygc21hbGwgbnVtYmVycywgYXMgIGV4dHJlbWUgdmFsdWUgdGhlb3J5ICBhZnRlciB0aGUgR0ZDIGhhcyBjb21lIHRvIHJlcGxhY2UgVkFSIGFzIHRoZSBzZXJpb3VzIGRvd25zaWRlIHJpc2sgZXN0aW1hdG9yIGZvciBxdWFudHMuIA0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCg0KeHQgPC0gIC1nZW9tX3JldHVybl9CQUMNCg0KZmluZFRocmVzaG9sZCh4dCkNCnRocnNoZCA8LSBmaW5kVGhyZXNob2xkKHh0KQ0KdGhyc2hkDQpmaW5kVGhyZXNob2xkKHh0LGRvcGxvdCA9IFRSVUUpDQoNCmZpdDEgPC0gZml0Z3BkKHh0LCB0aHJlc2ggPSAuMDQsIGVzdCA9ICJtbGUiKQ0KZml0IDwtIGZpdGdwZCh4dCwgdGhyZXNoID0gdGhyc2hkLCBlc3QgPSAibWxlIikNCg0KDQoNCg0KDQoNCg0KDQpncGRmaXQgPC0gZ3BkKHh0LHRocmVzaG9sZCA9MC4wMSkNCg0KDQpuYW1lcyhncGRmaXQpDQpwYXIobWZjb2wgPSBjKDIsMikpDQpwbG90KGdwZGZpdCkNCg0KDQoNCg0KYGBgDQogd2UgZXN0aW1hdGUgdGhlIHBhcmV0byBkaXN0cmlidXRpb24gdGhlbiB3ZSBmb3JlY2FzdCBsaWtlbHkgZGFpbHkgZG93bnNpZGUgY2hhbmdlLCB1c2luZyBHQVJDSCBtZXRvZHMgb24gR0FSQ0goMSwxKSAsIGFuZCBBUk1BKDEsMCkgZnVuY3Rpb24uDQpgYGB7cn0NCg0KI2ZpdF9kdGEgPC0gZ2VvbV9yZXR1cm5fQkFDW2dlb21fcmV0dXJuX0JBQzwgLjA0XQ0KDQoNCg0KDQoNCmZpdF9kYXRhX2dhcmNoIDwtIGdhcmNoRml0KGZvcm11bGE9fiBhcm1hKDEsIDApICsgZ2FyY2goMSwgMSksDQogICAgICAgICBkYXRhPXh0LA0KICAgICAgICAgY29uZC5kaXN0PSJub3JtIiwgdHJhY2U9RkFMU0UpDQoNCiMgUHJvZHVjZSBmb3JlY2FzdHMNCm1vZGVsLmZvcmVjYXN0IDwtIGZHYXJjaDo6cHJlZGljdChvYmplY3Q9Zml0X2RhdGFfZ2FyY2gsIG4uYWhlYWQ9MSkNCg0KY2F0KCJGb3JlY2FzdHMgZm9yIEV4dHJlbWVzIikNCm1vZGVsLmZvcmVjYXN0DQpgYGANCg0KYGBge3J9DQoNCmVzdCA8LSBtb2RlbC5mb3JlY2FzdCRtZWFuRm9yZWNhc3QqbGFzdChCQUMpDQoNCmVzdA0KYGBgDQpIZXJlIHdlIGZpdCB0aGUgbW9zdCBsaWtlbHkgZXh0cmVtZSB0YWlsIGV2ZW50IGdpdmVuIHRoZSBkYXRhIHNhbXBsZSwgd2l0aCB0d28gZGlzdHJpYnV0aW9ucyBvbmUgYXQgdGhlIDUlIGxldmVsIG9mIGNvbmZpZGVuY2UgYW5kIG9uZSBhdCB0aGUgMSUgbGV2ZWwgb2YgY29maWRlbmNlIGFuZCB3ZSB0aGVuIGNhbGN1bGF0ZSB0aGUgbWF4aW11bSBleHBlY3RlZCBkYWlseSBkcm9wIGluIGFuIGV4dHJlbWUgZXZlbnQuDQoNCmBgYHtyfQ0KdHAgPC0gdGFpbHBsb3QoZ3BkZml0KQ0KZ3BkLnEodHAsIHBwID0gMC45OTksIGNpLnAgPSAwLjk1KQ0KcXVhbnRpbGUoeHQsIHByb2JzID0gMC45OTksIHR5cGUgPSAxKQ0KZ3BkLnNmYWxsKHRwLCAwLjk5KQ0KDQpsb3NzIDwtIC4wOTg1NypsYXN0KEJBQyRCQUMuQWRqdXN0ZWQpDQpsb3NzDQpgYGANCg0KDQpFDQoNCg0KDQoNClRoZXNlIGFyZSBpbmNvbXBsZXRlIHF1YW50bW9kICBnZXRPcHRpb24gZnVuY3Rpb25zIG5vdCBjdXJyZW50bHkgcnVuLg0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpnZXRPcHRpb25DaGFpbigiQkFDIiwgRXhwID0gIjIwMjEtMDEiKQ0KDQoNCg0KYGBgDQojIyMNCiN5b3VyIGxpc3Qgb2YgZXhwaXJhdGlvbiBkYXRlcw0KYGBge3J9DQpFeHA9YygiMjAyMS0wMSIsICIyMDIwLTAxLTIwIikNCg0KeD1saXN0KCkNCmZvcihpIGluIDE6bGVuZ3RoKGV4cCkpIHg8LWMoZ2V0T3B0aW9uQ2hhaW4oIkJBQyIsZXhwW2ldKSx4KQ0KDQpgYGANCmBgYHtyfQ0KeA0KYGBgYGANCg0KDQpFDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==