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==