This is what we (The ARC Group) sees a the Beta that we attempting to capture, with Alpha being acheaved through assement of funtemential informatoin from grain carrying clients and those that wish to purchase that grain.
Get the data:
library(Quandl)
library("ggplot2")
library("ggthemes")
library(stringr)
library(TTR)
library(psych) #describe
require(PerformanceAnalytics)
Quandl.api_key("REz32KzJNzWYTQzqL-r3")
#############
#Get the data from Quandl()
###############
i=0
my_data <- list()
my_data2 <- list()
my_dataMar<-list()
years <- c(1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017)
#diffsPct<-list()
for (year in years){#c(1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2002,2001,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017)){
i<-i+1
cat(i)
#print(paste("The year is", year))
my_data[[i]] <- xts::last(Quandl(paste0("CME/CZ",year), type= "xts"),"1 year")
my_data2[[i]] <- xts::last(Quandl(paste0("CME/CZ",year), type= "xts"),"2 years")
my_dataMar[[i]] <- xts::last(Quandl(paste0("CME/CH",year+1), type= "xts"),"2 years")
thisDiff<-my_data[[i]]$High-my_data[[i]]$Settle
beginDate<- paste0(year,"-11")
endDate<- paste0(year+1,"-03")
marDates<-paste(beginDate,endDate, sep="::")
novDate<- paste0(year-1,"-11")
if(i==1){
rDiffs<-thisDiff
firstPrice<- as.numeric(head(my_data[[i]]$High,1))
diffs<-thisDiff
tsTotal<-my_data[[i]]
tsSeries<-my_data2[[i]][novDate]
tsMarTotal<-my_dataMar[[i]][marDates]
}
else{
diffs<-c(diffs,thisDiff)
rDiffs<-rbind(rDiffs,thisDiff)
tsTotal<-rbind(tsTotal,my_data[[i]])
tsSeries<-rbind(tsSeries,my_data2[[i]][novDate])
tsMarTotal<- rbind(tsMarTotal,my_dataMar[[i]][marDates])
}
}
1234567891011121314151617181920212223242526272829303132333435363738
#colnames(tsTotal)<-c("Open","High","Low","l","c","Close","Volume","OI")
Now that we have the data (and potentially agree on it… we can grab the data we want it….
j=0
performanceGroup<- tsTotal
performanceGroup$pos <- 0
for(year in years){
j= j+1
#print(j)
if(j== 1){
###AVG Sell Period Subgroup####
beginDate<- paste0(year,"-02")
endDate<- paste0(year,"-06")
dates<-paste(beginDate,endDate, sep="::")
subGroup<- tsTotal[dates]
k=1
for (processedDate in index(subGroup)){
r<- paste0(as.Date(processedDate))
pos<- as.numeric(k/ nrow(subGroup))
# print(pos)
performanceGroup[r,9]<-as.numeric(pos)
k<- k+1
}
###########
## placeholders so that we know when we are 'Full'
beginDate<- paste0(year,"-07")
endDate<- paste0(year,"-09")
dates<-paste(beginDate,endDate, sep="::")
performanceGroup[dates,9]<-1
###AVG Buy Period Subgroup####
endDate<- paste0(year,"-10")
subGroupBuy<- tsTotal[endDate]
###########
#############
##this is so we have the daily data availalble.... buy backs
k=1
for (processedDate in index(subGroupBuy)){
r<- paste0(as.Date(processedDate))
pos<- 1- (k/ nrow(subGroupBuy))
# print(pos)
performanceGroup[r,9]<-as.numeric(pos)
k<- k+1
}
###########
yearAvgSell <- mean(na.omit(subGroup$Settle))
maxSettle<- max(tsTotal[paste0(year)]$Settle)
maxHigh<- max(tsTotal[paste0(year)]$High)
#subGroupHigh<- tsTotal[paste0(year)]
#maxHighmonth<- index2char(subGroupHigh[which.max(subGroupHigh$High)])
buyAvg<- mean(na.omit(subGroupBuy$Settle))
lager<- log(lag(tsTotal[paste0(year)]$Settle))
current<- log(tsTotal[paste0(year)]$Settle)
ret <- lager - current
vol<-sd(na.omit(ret)) * sqrt(250) * 100
rollRet<- yearAvgSell - buyAvg
MaxAdverse<- yearAvgSell- maxHigh
MaxAdversePct <- MaxAdverse/yearAvgSell
ret<- rollRet/yearAvgSell
#optionPx<- optionPrice()
CornStats<-c(yearAvgSell, maxSettle,maxHigh,buyAvg,vol, rollRet,ret,MaxAdverse,MaxAdversePct)
} else{
###AVG Sell Period Subgroup####
beginDate<- paste0(year,"-02")
endDate<- paste0(year,"-06")
dates<-paste(beginDate,endDate, sep="::")
subGroup<- tsTotal[dates]
###########
##this is so we have the daily data availalble....
k=1
for (processedDate in index(subGroup)){
#print(nrow(subGroup))
#print(as.Date(index(processedDate)))
#print(performanceGroup[index(processedDate)])
r<- paste0(as.Date(processedDate))
pos<- k/ nrow(subGroup)
#print(pos)
performanceGroup[r,9]<-as.numeric(pos)
k<- k+1
}
#######
## place holders so that we know whne we are 'Full'
beginDate<- paste0(year,"-07")
endDate<- paste0(year,"-09")
dates<-paste(beginDate,endDate, sep="::")
performanceGroup[dates,9]<-1
###AVG Buy Period Subgroup####
endDate<- paste0(year,"-10")
#dates<-paste(beginDate,endDate, sep="::")
subGroupBuy<- tsTotal[endDate]
#############
##this is so we have the daily data availalble.... buy backs
k=1
for (processedDate in index(subGroupBuy)){
#print(nrow(subGroup))
#print(as.Date(index(processedDate)))
#print(performanceGroup[index(processedDate)])
r<- paste0(as.Date(processedDate))
pos<- 1- (k/ nrow(subGroupBuy))
#print(pos)
performanceGroup[r,9]<-as.numeric(pos)
k<- k+1
}
###output to grid ########
yearAvgSell <- mean(na.omit(subGroup$Settle))
maxSettle<- max(tsTotal[paste0(year)]$Settle)
maxHigh<- max(tsTotal[paste0(year)]$High)
buyAvg<- mean(na.omit(subGroupBuy$Settle))
ret <- log(lag(tsTotal[paste0(year)]$Settle)) - log(tsTotal[paste0(year)]$Settle)
#str(ret)
vol<-sd(na.omit(ret)) * sqrt(250) * 100
#str(vol)
# volatility(tsTotal[year])
rollRet<- yearAvgSell - buyAvg
MaxAdverse<- yearAvg- maxSettle
MaxAdversePct <- MaxAdverse/yearAvgSell
ret<- rollRet/yearAvgSell
CornStatsLoop <-c(yearAvgSell, maxSettle,maxHigh,buyAvg,vol, rollRet,ret,MaxAdverse,MaxAdversePct)
#CornStats<-mean(na.omit(tsTotal[dates]$Settle))
CornStats<-rbind(CornStats,CornStatsLoop)
#indexList<- rbindyear
}
}
colnames(CornStats)<- c("yearAvgSell", "maxSettle","maxHigh","buyAvg","vol", "rollRet","ret","MaxAdverse","MaxAdversePct")
cornZoo<- as.zoo(CornStats)
index(cornZoo)<-years
AND Now that the data is all organised and sub grouped…. we have the daily data from 1980 for the “Dumb” Factor: increase position from 2/1 thru 6/31 and unload during the month of Oct.
performanceGroup$ret<- dailyReturn(performanceGroup$Settle)
#negitive assignment to the $pos to be short..
performanceGroup$factorReturn<-performanceGroup$ret*-performanceGroup$pos
charts.PerformanceSummary(performanceGroup$factorReturn)

#plot(na.omit(cumsum(performanceGroup$ret * -performanceGroup$pos)), main ='Cummilative Sum of Corn Factor Returns')
table.CalendarReturns(na.omit(monthlyReturn(performanceGroup$Settle)* -performanceGroup$pos))
ARC… Some points of difference of existing ‘track record’ vs. benchmark… we also have soybeans and other assets (KC Wheat, MWE Wheat, canola) as well as options positons that introduce a tracking error…. and as we dig – what we did in 2012 may become more important…
ourTarget<- cbind(ARC$Return,performanceGroup$factorRet)
colnames(ourTarget)<- c('ARCExisting','factor')
ourTarget<- na.omit(ourTarget)
chart.CumReturns(ourTarget,legend.loc = 'bottomright')

TrackingError(ARC$Return,performanceGroup$factorRet)
[1] 0.1625832
and now some more indepth look at wiesner (1997,2015) …second chart shows relationship between this years carryout and next years returns… third and fourth charts are the last 6 obs. and follows from weisner’s “tight” to current ‘normal’
carryout <- read.csv("/Users/hamilton/Downloads/carryout.csv",na.strings=c("", "NA"),sep=",",stringsAsFactors =FALSE,header=FALSE)
carryoutXTS <- xts(as.numeric(carryout$V2),order.by = as.Date(carryout$V1, "%m/%d/%y"))
carryoutZOO <- as.zoo(head(carryout$V2,-1))
index(carryoutZOO)<-(years)
qplot(carryoutZOO, (cornZoo$ret))

qplot(lag(carryoutZOO), (cornZoo$ret))

qplot(tail(carryoutZOO), tail((cornZoo$ret)),geom = "path")
qplot(tail(lag(carryoutZOO)), tail((cornZoo$ret)),geom = "path")
qplot(index(cornZoo),cornZoo$ret,xlab = "Year", ylab = "Annualized Ret")

more….
qplot(index(cornZoo),cornZoo$vol,xlab = "Year", ylab = "Product annualized Vol")

qplot(cornZoo$ret,cornZoo$vol,xlab = "Annualized Ret", ylab = "Product annualized Vol")

….
qplot(index(cornZoo),cumsum(cornZoo$ret),xlab = "Year", ylab = "Product Cum Ret", geom = "line")

tail(cornZoo)
yearAvgSell maxSettle maxHigh buyAvg vol rollRet ret MaxAdverse MaxAdversePct
2012 548.4381 838.75 840.00 740.1071 26.76767 -191.66905 -0.34948164 -448.83095 -0.81838034
2013 549.1917 593.75 605.00 423.0000 24.32178 126.19175 0.22977721 -203.83095 -0.37114715
2014 476.4272 513.00 517.00 373.1711 21.25040 103.25613 0.21673014 -123.08095 -0.25834158
2015 396.1947 451.75 454.25 366.3125 22.40737 29.88221 0.07542304 -61.83095 -0.15606203
2016 393.7170 448.75 449.00 344.9762 22.30422 48.74079 0.12379652 -58.83095 -0.14942447
2017 389.9190 414.75 417.25 343.1786 17.15855 46.74048 0.11987226 -24.83095 -0.06368233
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).
ARC <- read.csv("/Users/hamilton/Downloads/portreturns.csv",na.strings=c("", "NA"),sep=",",stringsAsFactors =FALSE,header=TRUE)
ARC$X<- as.Date(as.character(ARC$X),"%m/%d/%y")
#ARC$X<- format(ARC$X,"%m/%d/%Y")
ARC<-xts(ARC[,-1],order.by = ARC[,1])
#ARC$Running.P.l<- as.integer(ARC$Running.P.l)
#index(ARC)<-ARC$
str(ARC)
An ‘xts’ object on 2014-01-07/2018-07-11 containing:
Data: num [1:1176, 1:4] 518000 514500 514500 504000 504000 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:4] "Maintainance.Margin" "Running.P.l" "Daily" "Value50M"
Indexed by objects of class: [Date] TZ: UTC
xts Attributes:
NULL
plot(ARC$Daily)

require(PerformanceAnalytics)
ARC$Daily<-as.numeric(ARC$Daily)
ARC$Return<-CalculateReturns(ARC$Value50M)
charts.PerformanceSummary(ARC$Return)

#plot(cumsum(ARC$Return)
#charts.PerformanceSummary(CalculateReturns(ARC$Running.P.l[,-2]))
and now some work with the ARC DATA
library(PerformanceAnalytics)
Package PerformanceAnalytics (1.4.3541) loaded.
Copyright (c) 2004-2014 Peter Carl and Brian G. Peterson, GPL-2 | GPL-3
http://r-forge.r-project.org/projects/returnanalytics/
Attaching package: ‘PerformanceAnalytics’
The following object is masked from ‘package:graphics’:
legend
table.CalendarReturns(monthlyReturn(na.omit(ARC$Value50M)))
Cor to the dumb benchmark…
library(devtools)
library(quantmod)
#install_github('systematicinvestor/SIT.date')
data <- new.env()
getSymbols("SHY",env=data)
[1] "SHY"
head(data$SHY<- Ad(data$SHY))
SHY.Adjusted
2007-01-03 68.23032
2007-01-04 68.29856
2007-01-05 68.25595
2007-01-08 68.21329
2007-01-09 68.23888
2007-01-10 68.22188
data$SHY$ARC<-ARC$Value50M
data$SHY$CORN<-cornZoo$rollRet
number of rows of result is not a multiple of vector length (arg 2)
head(data$SHY)
SHY.Adjusted ARC CORN
[1,] 68.23032 NA -81.41720
[2,] 68.29856 NA 93.04135
[3,] 68.25595 NA 55.79464
[4,] 68.21329 NA -57.88095
[5,] 68.23888 NA 24.39286
[6,] 68.22188 NA 23.88083
plota.matplot(scale.one(na.omit(data$SHY)),main='Asset Perfromance')
Error in y[, 1] : incorrect number of dimensions
data$universe = data$SHY > 0
prices = data$SHY #* data$universe
n = ncol(prices)
nperiods = nrow(prices)
period.ends = endpoints(prices, frequency)
period.ends = period.ends[period.ends > 0]
frequency = 'months'
# find period ends, can be 'weeks', 'months', 'quarters', 'years'
period.ends = endpoints(prices, frequency)
period.ends = period.ends[nrow(prices)< period.ends ]
ret = diff(log(na.omit(prices)))
colnames(ret)<-c("SHY.Close","ARC.Close")
hist.vol = bt.apply.matrix(na.omit(ret), runSD, n = 20)
# risk-parity
weight = 1 / na.omit(hist.vol)
rp.weight = weight / rowSums(weight, na.rm=T)
head(data$prices<-na.omit(prices))
SHY.Adjusted ARC
2014-01-07 81.63076 50000000
2014-01-08 81.55335 50119100
2014-01-09 81.57272 50190675
2014-01-10 81.65008 49915917
2014-01-13 81.66946 49899492
2014-01-14 81.65008 49939767
data$weight[] = NA
data$weight[period.ends,] = rp.weight[period.ends,]
models$rp = bt.run.share(data, clean.signal=F, commission = commission, trade.summary=T, silent=T)
Error in xts(rep(NA, length(index(x))), index(x)) :
order.by requires an appropriate time-based object
carryout <- read.csv("/Users/hamilton/Downloads/carryout.csv",na.strings=c("", "NA"),sep=",",stringsAsFactors =FALSE,header=FALSE)
carryoutXTS <- xts(as.numeric(carryout$V2),order.by = as.Date(carryout$V1, "%m/%d/%y"))
carryoutZOO <- as.zoo(head(carryout$V2,-1))
index(carryoutZOO)<-(years)
qplot(carryoutZOO, (cornZoo$ret))

qplot(lag(carryoutZOO), (cornZoo$ret))

qplot(tail(carryoutZOO), tail((cornZoo$ret)),geom = "path")

qplot(tail(lag(carryoutZOO)), tail((cornZoo$ret)),geom = "path")

qplot(carryoutZOO, (cornZoo$ret))

tail(cornZoo$ret,10)
2008 2009 2010 2011 2012 2013 2014
0.330584263 0.118356042 -0.413623548 0.006752839 -0.367737894 0.200346609 0.266597174
2015 2016 2017
0.033160194 0.112336750 0.103951536
tail((carryoutZOO),10)
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017
0.14 0.13 0.09 0.08 0.07 0.09 0.13 0.13 0.16 0.13
tail(lag(carryoutZOO),10)
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017
0.13 0.14 0.13 0.09 0.08 0.07 0.09 0.13 0.13 0.16
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgpUaGlzIGlzIHdoYXQgd2UgKFRoZSBBUkMgR3JvdXApIHNlZXMgYSB0aGUgQmV0YSB0aGF0IHdlIGF0dGVtcHRpbmcgdG8gY2FwdHVyZSwgd2l0aCBBbHBoYSBiZWluZyBhY2hlYXZlZCB0aHJvdWdoIGFzc2VtZW50IG9mIGZ1bnRlbWVudGlhbCBpbmZvcm1hdG9pbiBmcm9tIGdyYWluIGNhcnJ5aW5nIGNsaWVudHMgYW5kIHRob3NlIHRoYXQgd2lzaCB0byBwdXJjaGFzZSB0aGF0IGdyYWluLgoKR2V0IHRoZSBkYXRhOgpgYGB7cn0KCgpsaWJyYXJ5KFF1YW5kbCkKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoImdndGhlbWVzIikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KFRUUikKbGlicmFyeShwc3ljaCkgI2Rlc2NyaWJlCnJlcXVpcmUoUGVyZm9ybWFuY2VBbmFseXRpY3MpCgoKUXVhbmRsLmFwaV9rZXkoIlJFejMyS3pKTnpXWVRRenFMLXIzIikKCiMjIyMjIyMjIyMjIyMKI0dldCB0aGUgZGF0YSBmcm9tIFF1YW5kbCgpCiMjIyMjIyMjIyMjIyMjIwoKaT0wCm15X2RhdGEgPC0gbGlzdCgpCm15X2RhdGEyIDwtIGxpc3QoKQpteV9kYXRhTWFyPC1saXN0KCkKeWVhcnMgPC0gYygxOTgwLDE5ODEsMTk4MiwxOTgzLDE5ODQsMTk4NSwxOTg2LDE5ODcsMTk4OCwxOTg5LDE5OTAsMTk5MSwxOTkyLDE5OTMsMTk5NCwxOTk1LDE5OTYsMTk5NywxOTk4LDE5OTksMjAwMCwyMDAxLDIwMDIsMjAwMywyMDA0LDIwMDUsMjAwNiwyMDA3LDIwMDgsMjAwOSwyMDEwLDIwMTEsMjAxMiwyMDEzLDIwMTQsMjAxNSwyMDE2LDIwMTcpCiNkaWZmc1BjdDwtbGlzdCgpCmZvciAoeWVhciBpbiB5ZWFycyl7I2MoMTk5MCwxOTkxLDE5OTIsMTk5MywxOTk0LDE5OTUsMTk5NiwxOTk3LDE5OTgsMTk5OSwyMDAwLDIwMDIsMjAwMSwyMDAzLDIwMDQsMjAwNSwyMDA2LDIwMDcsMjAwOCwyMDA5LDIwMTAsMjAxMSwyMDEyLDIwMTMsMjAxNCwyMDE1LDIwMTYsMjAxNykpewogICAgaTwtaSsxCiAgICBjYXQoaSkKICAgICNwcmludChwYXN0ZSgiVGhlIHllYXIgaXMiLCB5ZWFyKSkKICAgIG15X2RhdGFbW2ldXSA8LSB4dHM6Omxhc3QoUXVhbmRsKHBhc3RlMCgiQ01FL0NaIix5ZWFyKSwgdHlwZT0gInh0cyIpLCIxIHllYXIiKQogICAgbXlfZGF0YTJbW2ldXSA8LSB4dHM6Omxhc3QoUXVhbmRsKHBhc3RlMCgiQ01FL0NaIix5ZWFyKSwgdHlwZT0gInh0cyIpLCIyIHllYXJzIikKICAgIG15X2RhdGFNYXJbW2ldXSA8LSB4dHM6Omxhc3QoUXVhbmRsKHBhc3RlMCgiQ01FL0NIIix5ZWFyKzEpLCB0eXBlPSAieHRzIiksIjIgeWVhcnMiKQoKICAgIHRoaXNEaWZmPC1teV9kYXRhW1tpXV0kSGlnaC1teV9kYXRhW1tpXV0kU2V0dGxlCiAgICBiZWdpbkRhdGU8LSBwYXN0ZTAoeWVhciwiLTExIikKICAgIGVuZERhdGU8LSBwYXN0ZTAoeWVhcisxLCItMDMiKQogICAgbWFyRGF0ZXM8LXBhc3RlKGJlZ2luRGF0ZSxlbmREYXRlLCBzZXA9Ijo6IikKICAgIAogICAgbm92RGF0ZTwtIHBhc3RlMCh5ZWFyLTEsIi0xMSIpCiAgICAKICAgIAogICAgaWYoaT09MSl7CiAgICAgIAogICAgICByRGlmZnM8LXRoaXNEaWZmCiAgICAgIGZpcnN0UHJpY2U8LSBhcy5udW1lcmljKGhlYWQobXlfZGF0YVtbaV1dJEhpZ2gsMSkpCiAgICAgIGRpZmZzPC10aGlzRGlmZgogICAgICB0c1RvdGFsPC1teV9kYXRhW1tpXV0KICAgICAgdHNTZXJpZXM8LW15X2RhdGEyW1tpXV1bbm92RGF0ZV0KICAgICAgCiAgICAgCiAgICAgIHRzTWFyVG90YWw8LW15X2RhdGFNYXJbW2ldXVttYXJEYXRlc10KICAgIH0KICAgIGVsc2V7CiAgICAgZGlmZnM8LWMoZGlmZnMsdGhpc0RpZmYpCiAgICAgckRpZmZzPC1yYmluZChyRGlmZnMsdGhpc0RpZmYpCiAgICAgdHNUb3RhbDwtcmJpbmQodHNUb3RhbCxteV9kYXRhW1tpXV0pCiAgICAgdHNTZXJpZXM8LXJiaW5kKHRzU2VyaWVzLG15X2RhdGEyW1tpXV1bbm92RGF0ZV0pCiAgICAgdHNNYXJUb3RhbDwtIHJiaW5kKHRzTWFyVG90YWwsbXlfZGF0YU1hcltbaV1dW21hckRhdGVzXSkKICAgIH0KfQoKI2NvbG5hbWVzKHRzVG90YWwpPC1jKCJPcGVuIiwiSGlnaCIsIkxvdyIsImwiLCJjIiwiQ2xvc2UiLCJWb2x1bWUiLCJPSSIpCgoKYGBgCgoKTm93IHRoYXQgd2UgaGF2ZSB0aGUgZGF0YSAoYW5kIHBvdGVudGlhbGx5IGFncmVlIG9uIGl0Li4uIHdlIGNhbiBncmFiIHRoZSBkYXRhIHdlIHdhbnQgaXQuLi4uCgpgYGB7cn0Kaj0wCnBlcmZvcm1hbmNlR3JvdXA8LSB0c1RvdGFsCnBlcmZvcm1hbmNlR3JvdXAkcG9zIDwtIDAKCmZvcih5ZWFyIGluIHllYXJzKXsKICBqPSBqKzEKICAjcHJpbnQoaikKICBpZihqPT0gMSl7CiAgICAjIyNBVkcgU2VsbCBQZXJpb2QgU3ViZ3JvdXAjIyMjCiAgICBiZWdpbkRhdGU8LSBwYXN0ZTAoeWVhciwiLTAyIikKICAgIGVuZERhdGU8LSBwYXN0ZTAoeWVhciwiLTA2IikKICAgIGRhdGVzPC1wYXN0ZShiZWdpbkRhdGUsZW5kRGF0ZSwgc2VwPSI6OiIpCiAgICBzdWJHcm91cDwtIHRzVG90YWxbZGF0ZXNdCiAgICBrPTEKICAgIGZvciAocHJvY2Vzc2VkRGF0ZSBpbiBpbmRleChzdWJHcm91cCkpewogcjwtIHBhc3RlMChhcy5EYXRlKHByb2Nlc3NlZERhdGUpKQogICAgICAKICAgICAgcG9zPC0gYXMubnVtZXJpYyhrLyBucm93KHN1Ykdyb3VwKSkKICAgICAjIHByaW50KHBvcykKICAgICAgcGVyZm9ybWFuY2VHcm91cFtyLDldPC1hcy5udW1lcmljKHBvcykgIAogICAgICBrPC0gaysxCiAgICB9CiAgICAjIyMjIyMjIyMjIwogICAgCiAgICAgIyMgcGxhY2Vob2xkZXJzIHNvIHRoYXQgd2Uga25vdyB3aGVuIHdlIGFyZSAnRnVsbCcKICAgIAogICAgYmVnaW5EYXRlPC0gcGFzdGUwKHllYXIsIi0wNyIpCiAgICBlbmREYXRlPC0gcGFzdGUwKHllYXIsIi0wOSIpCiAgICBkYXRlczwtcGFzdGUoYmVnaW5EYXRlLGVuZERhdGUsIHNlcD0iOjoiKSAgICAKICAgIHBlcmZvcm1hbmNlR3JvdXBbZGF0ZXMsOV08LTEgCiAgICAKICAgICMjI0FWRyBCdXkgUGVyaW9kIFN1Ymdyb3VwIyMjIwogICAgZW5kRGF0ZTwtIHBhc3RlMCh5ZWFyLCItMTAiKQogICAgc3ViR3JvdXBCdXk8LSB0c1RvdGFsW2VuZERhdGVdCiAgICAKICAgICMjIyMjIyMjIyMjCiAgICAjIyMjIyMjIyMjIyMjCiAgICAjI3RoaXMgaXMgc28gd2UgaGF2ZSB0aGUgZGFpbHkgZGF0YSBhdmFpbGFsYmxlLi4uLiBidXkgYmFja3MKICAgIGs9MQogICAgZm9yIChwcm9jZXNzZWREYXRlIGluIGluZGV4KHN1Ykdyb3VwQnV5KSl7CiAgICByPC0gcGFzdGUwKGFzLkRhdGUocHJvY2Vzc2VkRGF0ZSkpCiAgICAgIHBvczwtIDEtIChrLyBucm93KHN1Ykdyb3VwQnV5KSkKICAgICAjIHByaW50KHBvcykKICAgICAgcGVyZm9ybWFuY2VHcm91cFtyLDldPC1hcy5udW1lcmljKHBvcykgCiAgICAgIGs8LSBrKzEKICAgIH0KICAgICMjIyMjIyMjIyMjCiAgICB5ZWFyQXZnU2VsbCA8LSBtZWFuKG5hLm9taXQoc3ViR3JvdXAkU2V0dGxlKSkKICAgIG1heFNldHRsZTwtICBtYXgodHNUb3RhbFtwYXN0ZTAoeWVhcildJFNldHRsZSkKICAgIG1heEhpZ2g8LSBtYXgodHNUb3RhbFtwYXN0ZTAoeWVhcildJEhpZ2gpCiAgICAjc3ViR3JvdXBIaWdoPC0gdHNUb3RhbFtwYXN0ZTAoeWVhcildCiAgICAjbWF4SGlnaG1vbnRoPC0gaW5kZXgyY2hhcihzdWJHcm91cEhpZ2hbd2hpY2gubWF4KHN1Ykdyb3VwSGlnaCRIaWdoKV0pCiAgICAKICAgIGJ1eUF2ZzwtIG1lYW4obmEub21pdChzdWJHcm91cEJ1eSRTZXR0bGUpKQogICAgbGFnZXI8LSBsb2cobGFnKHRzVG90YWxbcGFzdGUwKHllYXIpXSRTZXR0bGUpKQogICAgY3VycmVudDwtIGxvZyh0c1RvdGFsW3Bhc3RlMCh5ZWFyKV0kU2V0dGxlKQogICAgcmV0IDwtIGxhZ2VyIC0gY3VycmVudAogICAgdm9sPC1zZChuYS5vbWl0KHJldCkpICogc3FydCgyNTApICogMTAwCiAgICAKICAgIHJvbGxSZXQ8LSB5ZWFyQXZnU2VsbCAtIGJ1eUF2ZwogICAgCiAgICBNYXhBZHZlcnNlPC0geWVhckF2Z1NlbGwtIG1heEhpZ2gKICAgIE1heEFkdmVyc2VQY3QgPC0gTWF4QWR2ZXJzZS95ZWFyQXZnU2VsbAogICAgcmV0PC0gcm9sbFJldC95ZWFyQXZnU2VsbAogICAgI29wdGlvblB4PC0gb3B0aW9uUHJpY2UoKQogIENvcm5TdGF0czwtYyh5ZWFyQXZnU2VsbCwgbWF4U2V0dGxlLG1heEhpZ2gsYnV5QXZnLHZvbCwgcm9sbFJldCxyZXQsTWF4QWR2ZXJzZSxNYXhBZHZlcnNlUGN0KQogICAKICB9IGVsc2V7CiAgICAjIyNBVkcgU2VsbCBQZXJpb2QgU3ViZ3JvdXAjIyMjCiAgICBiZWdpbkRhdGU8LSBwYXN0ZTAoeWVhciwiLTAyIikKICAgIGVuZERhdGU8LSBwYXN0ZTAoeWVhciwiLTA2IikKICAgIGRhdGVzPC1wYXN0ZShiZWdpbkRhdGUsZW5kRGF0ZSwgc2VwPSI6OiIpCiAgICBzdWJHcm91cDwtIHRzVG90YWxbZGF0ZXNdCiAgICAjIyMjIyMjIyMjIwogICAgIyN0aGlzIGlzIHNvIHdlIGhhdmUgdGhlIGRhaWx5IGRhdGEgYXZhaWxhbGJsZS4uLi4gCiAgICBrPTEKICAgIGZvciAocHJvY2Vzc2VkRGF0ZSBpbiBpbmRleChzdWJHcm91cCkpewogICAgICAjcHJpbnQobnJvdyhzdWJHcm91cCkpCiAgICAgICNwcmludChhcy5EYXRlKGluZGV4KHByb2Nlc3NlZERhdGUpKSkKICAgICAgI3ByaW50KHBlcmZvcm1hbmNlR3JvdXBbaW5kZXgocHJvY2Vzc2VkRGF0ZSldKQogICAgICByPC0gcGFzdGUwKGFzLkRhdGUocHJvY2Vzc2VkRGF0ZSkpCiAgICAgIHBvczwtIGsvIG5yb3coc3ViR3JvdXApCiAgICAgICNwcmludChwb3MpCiAgICAgIHBlcmZvcm1hbmNlR3JvdXBbciw5XTwtYXMubnVtZXJpYyhwb3MpIAogICAgICBrPC0gaysxCiAgICB9CiAgICAjIyMjIyMjCiAgICAjIyBwbGFjZSBob2xkZXJzIHNvIHRoYXQgd2Uga25vdyB3aG5lIHdlIGFyZSAnRnVsbCcKICAgIApiZWdpbkRhdGU8LSBwYXN0ZTAoeWVhciwiLTA3IikKICAgIGVuZERhdGU8LSBwYXN0ZTAoeWVhciwiLTA5IikKICAgIGRhdGVzPC1wYXN0ZShiZWdpbkRhdGUsZW5kRGF0ZSwgc2VwPSI6OiIpICAgIAogICAgcGVyZm9ybWFuY2VHcm91cFtkYXRlcyw5XTwtMSAKICAgICMjI0FWRyBCdXkgUGVyaW9kIFN1Ymdyb3VwIyMjIwogICAgZW5kRGF0ZTwtIHBhc3RlMCh5ZWFyLCItMTAiKQogICAgI2RhdGVzPC1wYXN0ZShiZWdpbkRhdGUsZW5kRGF0ZSwgc2VwPSI6OiIpCiAgICBzdWJHcm91cEJ1eTwtIHRzVG90YWxbZW5kRGF0ZV0KCiAgICAjIyMjIyMjIyMjIyMjCiAgICAjI3RoaXMgaXMgc28gd2UgaGF2ZSB0aGUgZGFpbHkgZGF0YSBhdmFpbGFsYmxlLi4uLiBidXkgYmFja3MKICAgIGs9MQogICAgZm9yIChwcm9jZXNzZWREYXRlIGluIGluZGV4KHN1Ykdyb3VwQnV5KSl7CiAgICAgICNwcmludChucm93KHN1Ykdyb3VwKSkKICAgICAgI3ByaW50KGFzLkRhdGUoaW5kZXgocHJvY2Vzc2VkRGF0ZSkpKQogICAgICAjcHJpbnQocGVyZm9ybWFuY2VHcm91cFtpbmRleChwcm9jZXNzZWREYXRlKV0pCiAgICAgIHI8LSBwYXN0ZTAoYXMuRGF0ZShwcm9jZXNzZWREYXRlKSkKICAgICAgcG9zPC0gMS0gKGsvIG5yb3coc3ViR3JvdXBCdXkpKQogICAgICAjcHJpbnQocG9zKQogICAgICBwZXJmb3JtYW5jZUdyb3VwW3IsOV08LWFzLm51bWVyaWMocG9zKSAKICAgICAgazwtIGsrMQogICAgfQogICAgCiAgICAjIyNvdXRwdXQgdG8gZ3JpZCAjIyMjIyMjIwogICAgeWVhckF2Z1NlbGwgPC0gbWVhbihuYS5vbWl0KHN1Ykdyb3VwJFNldHRsZSkpCiAgICBtYXhTZXR0bGU8LSAgbWF4KHRzVG90YWxbcGFzdGUwKHllYXIpXSRTZXR0bGUpCiAgICBtYXhIaWdoPC0gbWF4KHRzVG90YWxbcGFzdGUwKHllYXIpXSRIaWdoKQoKICAgIGJ1eUF2ZzwtIG1lYW4obmEub21pdChzdWJHcm91cEJ1eSRTZXR0bGUpKQogICAgcmV0IDwtIGxvZyhsYWcodHNUb3RhbFtwYXN0ZTAoeWVhcildJFNldHRsZSkpIC0gbG9nKHRzVG90YWxbcGFzdGUwKHllYXIpXSRTZXR0bGUpCiAgICAjc3RyKHJldCkKICAgIHZvbDwtc2QobmEub21pdChyZXQpKSAqIHNxcnQoMjUwKSAqIDEwMAogICAgI3N0cih2b2wpCiAgICAjIHZvbGF0aWxpdHkodHNUb3RhbFt5ZWFyXSkKICAgIHJvbGxSZXQ8LSB5ZWFyQXZnU2VsbCAtIGJ1eUF2ZwogICAgTWF4QWR2ZXJzZTwtIHllYXJBdmctIG1heFNldHRsZQogICAgTWF4QWR2ZXJzZVBjdCA8LSBNYXhBZHZlcnNlL3llYXJBdmdTZWxsCiAgICByZXQ8LSByb2xsUmV0L3llYXJBdmdTZWxsCiAgICBDb3JuU3RhdHNMb29wIDwtYyh5ZWFyQXZnU2VsbCwgbWF4U2V0dGxlLG1heEhpZ2gsYnV5QXZnLHZvbCwgcm9sbFJldCxyZXQsTWF4QWR2ZXJzZSxNYXhBZHZlcnNlUGN0KQogICAgICNDb3JuU3RhdHM8LW1lYW4obmEub21pdCh0c1RvdGFsW2RhdGVzXSRTZXR0bGUpKQogICAgQ29yblN0YXRzPC1yYmluZChDb3JuU3RhdHMsQ29yblN0YXRzTG9vcCkKCiAgICAjaW5kZXhMaXN0PC0gcmJpbmR5ZWFyCgogIH0KICAKfQpjb2xuYW1lcyhDb3JuU3RhdHMpPC0gYygieWVhckF2Z1NlbGwiLCAibWF4U2V0dGxlIiwibWF4SGlnaCIsImJ1eUF2ZyIsInZvbCIsICJyb2xsUmV0IiwicmV0IiwiTWF4QWR2ZXJzZSIsIk1heEFkdmVyc2VQY3QiKQpjb3JuWm9vPC0gYXMuem9vKENvcm5TdGF0cykKaW5kZXgoY29yblpvbyk8LXllYXJzCgpgYGAKCgoKCkFORCBOb3cgdGhhdCB0aGUgZGF0YSBpcyBhbGwgb3JnYW5pc2VkIGFuZCBzdWIgZ3JvdXBlZC4uLi4gd2UgaGF2ZSB0aGUgZGFpbHkgZGF0YSBmcm9tIDE5ODAgZm9yIHRoZSAiRHVtYiIgRmFjdG9yOgppbmNyZWFzZSBwb3NpdGlvbiBmcm9tIDIvMSB0aHJ1IDYvMzEgYW5kIHVubG9hZCBkdXJpbmcgdGhlIG1vbnRoIG9mIE9jdC4KCgpgYGB7cn0KCnBlcmZvcm1hbmNlR3JvdXAkcmV0PC0gZGFpbHlSZXR1cm4ocGVyZm9ybWFuY2VHcm91cCRTZXR0bGUpCiNuZWdpdGl2ZSBhc3NpZ25tZW50IHRvIHRoZSAkcG9zIHRvIGJlIHNob3J0Li4KcGVyZm9ybWFuY2VHcm91cCRmYWN0b3JSZXR1cm48LXBlcmZvcm1hbmNlR3JvdXAkcmV0Ki1wZXJmb3JtYW5jZUdyb3VwJHBvcwpjaGFydHMuUGVyZm9ybWFuY2VTdW1tYXJ5KHBlcmZvcm1hbmNlR3JvdXAkZmFjdG9yUmV0dXJuKQojcGxvdChuYS5vbWl0KGN1bXN1bShwZXJmb3JtYW5jZUdyb3VwJHJldCAqIC1wZXJmb3JtYW5jZUdyb3VwJHBvcykpLCBtYWluID0nQ3VtbWlsYXRpdmUgU3VtIG9mIENvcm4gRmFjdG9yIFJldHVybnMnKQp0YWJsZS5DYWxlbmRhclJldHVybnMobmEub21pdChtb250aGx5UmV0dXJuKHBlcmZvcm1hbmNlR3JvdXAkU2V0dGxlKSogLXBlcmZvcm1hbmNlR3JvdXAkcG9zKSkKYGBgCgpBUkMuLi4gU29tZSBwb2ludHMgb2YgZGlmZmVyZW5jZSBvZiBleGlzdGluZyAndHJhY2sgcmVjb3JkJyB2cy4gYmVuY2htYXJrLi4uIHdlIGFsc28gaGF2ZSBzb3liZWFucyBhbmQgb3RoZXIgYXNzZXRzIChLQyBXaGVhdCwgTVdFIFdoZWF0LCBjYW5vbGEpIGFzIHdlbGwgYXMgb3B0aW9ucyBwb3NpdG9ucyB0aGF0IGludHJvZHVjZSBhIHRyYWNraW5nIGVycm9yLi4uLiBhbmQgYXMgd2UgZGlnIC0tICAgd2hhdCB3ZSBkaWQgaW4gMjAxMiBtYXkgYmVjb21lIG1vcmUgaW1wb3J0YW50Li4uIAoKYGBge3J9CgpvdXJUYXJnZXQ8LSBjYmluZChBUkMkUmV0dXJuLHBlcmZvcm1hbmNlR3JvdXAkZmFjdG9yUmV0KQpjb2xuYW1lcyhvdXJUYXJnZXQpPC0gYygnQVJDRXhpc3RpbmcnLCdmYWN0b3InKQpvdXJUYXJnZXQ8LSBuYS5vbWl0KG91clRhcmdldCkKY2hhcnQuQ3VtUmV0dXJucyhvdXJUYXJnZXQsbGVnZW5kLmxvYyA9ICdib3R0b21yaWdodCcpClRyYWNraW5nRXJyb3IoQVJDJFJldHVybixwZXJmb3JtYW5jZUdyb3VwJGZhY3RvclJldCkKCmBgYAoKYW5kIG5vdyBzb21lIG1vcmUgaW5kZXB0aCBsb29rIGF0IHdpZXNuZXIgKDE5OTcsMjAxNSkgLi4uc2Vjb25kIGNoYXJ0IHNob3dzIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoaXMgeWVhcnMgY2FycnlvdXQgYW5kIG5leHQgeWVhcnMgcmV0dXJucy4uLiB0aGlyZCBhbmQgZm91cnRoIGNoYXJ0cyBhcmUgdGhlIGxhc3QgNiBvYnMuIGFuZCBmb2xsb3dzIGZyb20gd2Vpc25lcidzICJ0aWdodCIgdG8gY3VycmVudCAnbm9ybWFsJwoKYGBge3J9CmNhcnJ5b3V0IDwtIHJlYWQuY3N2KCIvVXNlcnMvaGFtaWx0b24vRG93bmxvYWRzL2NhcnJ5b3V0LmNzdiIsbmEuc3RyaW5ncz1jKCIiLCAiTkEiKSxzZXA9IiwiLHN0cmluZ3NBc0ZhY3RvcnMgPUZBTFNFLGhlYWRlcj1GQUxTRSkKY2FycnlvdXRYVFMgPC0geHRzKGFzLm51bWVyaWMoY2FycnlvdXQkVjIpLG9yZGVyLmJ5ID0gYXMuRGF0ZShjYXJyeW91dCRWMSwgIiVtLyVkLyV5IikpCmNhcnJ5b3V0Wk9PIDwtIGFzLnpvbyhoZWFkKGNhcnJ5b3V0JFYyLC0xKSkKaW5kZXgoY2FycnlvdXRaT08pPC0oeWVhcnMpCnFwbG90KGNhcnJ5b3V0Wk9PLCAoY29yblpvbyRyZXQpKQpxcGxvdChsYWcoY2FycnlvdXRaT08pLCAoY29yblpvbyRyZXQpKQpxcGxvdCh0YWlsKGNhcnJ5b3V0Wk9PKSwgdGFpbCgoY29yblpvbyRyZXQpKSxnZW9tID0gInBhdGgiKQpxcGxvdCh0YWlsKGxhZyhjYXJyeW91dFpPTykpLCB0YWlsKChjb3JuWm9vJHJldCkpLGdlb20gPSAicGF0aCIpCgoKYGBgCgoKCmBgYHtyfQpxcGxvdChpbmRleChjb3JuWm9vKSxjb3JuWm9vJHJldCx4bGFiID0gIlllYXIiLCB5bGFiID0gIkFubnVhbGl6ZWQgUmV0IikKCmBgYAoKbW9yZS4uLi4KCgpgYGB7cn0KcXBsb3QoaW5kZXgoY29yblpvbyksY29yblpvbyR2b2wseGxhYiA9ICJZZWFyIiwgeWxhYiA9ICJQcm9kdWN0IGFubnVhbGl6ZWQgVm9sIikKcXBsb3QoY29yblpvbyRyZXQsY29yblpvbyR2b2wseGxhYiA9ICJBbm51YWxpemVkIFJldCIsIHlsYWIgPSAiUHJvZHVjdCBhbm51YWxpemVkIFZvbCIpCgpgYGAKLi4uLgoKCgpgYGB7cn0KcXBsb3QoaW5kZXgoY29yblpvbyksY3Vtc3VtKGNvcm5ab28kcmV0KSx4bGFiID0gIlllYXIiLCB5bGFiID0gIlByb2R1Y3QgQ3VtIFJldCIsIGdlb20gPSAibGluZSIpCgpgYGAKCgoKYGBge3J9CnRhaWwoY29yblpvbykKYGBgCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ21kK09wdGlvbitJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuCmBgYHtyfQpBUkMgPC0gcmVhZC5jc3YoIi9Vc2Vycy9oYW1pbHRvbi9Eb3dubG9hZHMvcG9ydHJldHVybnMuY3N2IixuYS5zdHJpbmdzPWMoIiIsICJOQSIpLHNlcD0iLCIsc3RyaW5nc0FzRmFjdG9ycyA9RkFMU0UsaGVhZGVyPVRSVUUpCgpBUkMkWDwtIGFzLkRhdGUoYXMuY2hhcmFjdGVyKEFSQyRYKSwiJW0vJWQvJXkiKQojQVJDJFg8LSBmb3JtYXQoQVJDJFgsIiVtLyVkLyVZIikKCkFSQzwteHRzKEFSQ1ssLTFdLG9yZGVyLmJ5ID0gQVJDWywxXSkKI0FSQyRSdW5uaW5nLlAubDwtIGFzLmludGVnZXIoQVJDJFJ1bm5pbmcuUC5sKQojaW5kZXgoQVJDKTwtQVJDJApzdHIoQVJDKQpwbG90KEFSQyREYWlseSkKcmVxdWlyZShQZXJmb3JtYW5jZUFuYWx5dGljcykKQVJDJERhaWx5PC1hcy5udW1lcmljKEFSQyREYWlseSkKQVJDJFJldHVybjwtQ2FsY3VsYXRlUmV0dXJucyhBUkMkVmFsdWU1ME0pCmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoQVJDJFJldHVybikKQVJDJFJldHVybgojcGxvdChjdW1zdW0oQVJDJFJldHVybikKI2NoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoQ2FsY3VsYXRlUmV0dXJucyhBUkMkUnVubmluZy5QLmxbLC0yXSkpCgpgYGAKYW5kIG5vdyBzb21lIHdvcmsgd2l0aCB0aGUgQVJDIERBVEEKCmBgYHtyfQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQp0YWJsZS5DYWxlbmRhclJldHVybnMobW9udGhseVJldHVybihuYS5vbWl0KEFSQyRWYWx1ZTUwTSkpKQoKYGBgCgpDb3IgdG8gdGhlIGR1bWIgYmVuY2htYXJrLi4uIAoKCgoKCmBgYHtyfQpsaWJyYXJ5KGRldnRvb2xzKQpsaWJyYXJ5KHF1YW50bW9kKQojaW5zdGFsbF9naXRodWIoJ3N5c3RlbWF0aWNpbnZlc3Rvci9TSVQuZGF0ZScpCgoKZGF0YSA8LSBuZXcuZW52KCkKZ2V0U3ltYm9scygiU0hZIixlbnY9ZGF0YSkKaGVhZChkYXRhJFNIWTwtIEFkKGRhdGEkU0hZKSkKZGF0YSRTSFkkQVJDPC1BUkMkVmFsdWU1ME0KZGF0YSRTSFkkQ09STjwtY29yblpvbyRyb2xsUmV0CmhlYWQobmEub21pdChkYXRhJFNIWSkKCnBsb3RhLm1hdHBsb3Qoc2NhbGUub25lKG5hLm9taXQoZGF0YSRTSFkpKSxtYWluPSdBc3NldCBQZXJmcm9tYW5jZScpCgoKYGBgCgpgYGB7cn0KZGF0YSR1bml2ZXJzZSA9IGRhdGEkU0hZID4gMApwcmljZXMgPSBkYXRhJFNIWSAjKiBkYXRhJHVuaXZlcnNlCm4gPSBuY29sKHByaWNlcykKbnBlcmlvZHMgPSBucm93KHByaWNlcykKCnBlcmlvZC5lbmRzID0gZW5kcG9pbnRzKHByaWNlcywgZnJlcXVlbmN5KQpwZXJpb2QuZW5kcyA9IHBlcmlvZC5lbmRzW3BlcmlvZC5lbmRzID4gMF0KCmBgYAoKCgoKYGBge3J9CmZyZXF1ZW5jeSA9ICdtb250aHMnCiMgZmluZCBwZXJpb2QgZW5kcywgY2FuIGJlICd3ZWVrcycsICdtb250aHMnLCAncXVhcnRlcnMnLCAneWVhcnMnCnBlcmlvZC5lbmRzID0gZW5kcG9pbnRzKHByaWNlcywgZnJlcXVlbmN5KQpwZXJpb2QuZW5kcyA9IHBlcmlvZC5lbmRzW25yb3cocHJpY2VzKTwgcGVyaW9kLmVuZHMgXQoKCgpyZXQgPSBkaWZmKGxvZyhuYS5vbWl0KHByaWNlcykpKQpjb2xuYW1lcyhyZXQpPC1jKCJTSFkuQ2xvc2UiLCJBUkMuQ2xvc2UiKQpoaXN0LnZvbCA9IGJ0LmFwcGx5Lm1hdHJpeChuYS5vbWl0KHJldCksIHJ1blNELCBuID0gMjApCiMgcmlzay1wYXJpdHkKd2VpZ2h0ID0gMSAvIG5hLm9taXQoaGlzdC52b2wpCnJwLndlaWdodCA9IHdlaWdodCAvIHJvd1N1bXMod2VpZ2h0LCBuYS5ybT1UKQpoZWFkKGRhdGEkcHJpY2VzPC1uYS5vbWl0KHByaWNlcykpCmRhdGEkd2VpZ2h0W10gPSBOQQpkYXRhJHdlaWdodFtwZXJpb2QuZW5kcyxdID0gcnAud2VpZ2h0W3BlcmlvZC5lbmRzLF0KbW9kZWxzJHJwID0gYnQucnVuLnNoYXJlKGRhdGEsIGNsZWFuLnNpZ25hbD1GLCBjb21taXNzaW9uID0gY29tbWlzc2lvbiwgdHJhZGUuc3VtbWFyeT1ULCBzaWxlbnQ9VCkKCgpgYGAKCmBgYHtyfQpjYXJyeW91dCA8LSByZWFkLmNzdigiL1VzZXJzL2hhbWlsdG9uL0Rvd25sb2Fkcy9jYXJyeW91dC5jc3YiLG5hLnN0cmluZ3M9YygiIiwgIk5BIiksc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzID1GQUxTRSxoZWFkZXI9RkFMU0UpCmNhcnJ5b3V0WFRTIDwtIHh0cyhhcy5udW1lcmljKGNhcnJ5b3V0JFYyKSxvcmRlci5ieSA9IGFzLkRhdGUoY2FycnlvdXQkVjEsICIlbS8lZC8leSIpKQpjYXJyeW91dFpPTyA8LSBhcy56b28oaGVhZChjYXJyeW91dCRWMiwtMSkpCmluZGV4KGNhcnJ5b3V0Wk9PKTwtKHllYXJzKQogcXBsb3QoY2FycnlvdXRaT08sIChjb3JuWm9vJHJldCkpCiBxcGxvdChsYWcoY2FycnlvdXRaT08pLCAoY29yblpvbyRyZXQpKQogcXBsb3QodGFpbChjYXJyeW91dFpPTyksIHRhaWwoKGNvcm5ab28kcmV0KSksZ2VvbSA9ICJwYXRoIikKIHFwbG90KHRhaWwobGFnKGNhcnJ5b3V0Wk9PKSksIHRhaWwoKGNvcm5ab28kcmV0KSksZ2VvbSA9ICJwYXRoIikKICBxcGxvdChjYXJyeW91dFpPTywgKGNvcm5ab28kcmV0KSkKCiB0YWlsKGNvcm5ab28kcmV0LDEwKQogIHRhaWwoKGNhcnJ5b3V0Wk9PKSwxMCkKIHRhaWwobGFnKGNhcnJ5b3V0Wk9PKSwxMCkKYGBgCgoKCgoKCgoKCg==