library(MASS)
library(dplyr)

The following variable screening method is called stepwise regression. This type of model selection adds and drops variables in the model until it finds the one with the most significant variables in it. The measure it uses to predict significance of the chosen variables is the AIC, this number gets smaller and smaller as more significant variables are added and then also penalizes the models for having too many variables in it.

We wanted to predict a teams post-season conference ranking with pre-season statistics, aquired from a large dataset being used for a senior thesis.

X_CFBRversionSEC <- X_CFBRversion %>%
  filter(SEC == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionSEC), direction = c("both"))
X_CFBRversionACC <- X_CFBRversion %>%
  filter(ACC == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionACC), direction = c("both"))
X_CFBRversionBigTen <- X_CFBRversion %>%
  filter(BigTen == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionBigTen), direction = c("both"))
X_CFBRversionPacTen <- X_CFBRversion %>%
  filter(PacTen == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionPacTen), direction = c("both"))
X_CFBRversionBigTwelve <- X_CFBRversion %>%
  filter(BigTwelve == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionBigTwelve), direction = c("both"))

So through this process, we found that different variables were deemed significant in different conferences. Essentially it means that different things are necessary to be successful relative to the other teams in your conference, based on a given conference.

SEC: “Fr5star”,“Fr4star”,“So4star”,“Soavg”,“Jrnbrrecruits”,“Jr5star”,“Jr4star”,“Rssr5star”,“Rssr4star”,“z_lysagarin”,“coachexp_school”,“coachexp_total”

ACC:“FrNbrRecruits” , “Fr4star” , “Sonbrrecruits”, “Jrnbrrecruits”, “Jr5star”, “Jr4star”, “Jr3star”, “Jravg”, “Rssr4star”, “z_lysagarin”,“retoff”, “bowl” ,“coachexp_total”

BigTen: “FrNbrRecruits”,“Fr3star”,“So4star”,“Jrnbrrecruits”,“Jr5star”,“Jr4star”,“Jr3star”,“Jravg”,“Srnbrrecruits”,“Sr3star”,“z_lysagarin”,“coachexp_total”

PacTen:“FrNbrRecruits” , “Fr4star” , “Sonbrrecruits”, “So4star”, “Soavg”, “Jrnbrrecruits” , “Jravg” , “Sr3star” , “Rssrnbrrecruits” , “Rssr5star” , “Rssr4star” , “Rssr3star” , “Rssravg” , “z_lysagarin” , “z_tyasagarin” , “retdef” , “qbret” , “coachexp_school” , “coachexp_total” , “Sravg”

BigTwelve:“FrNbrRecruits”, “Fr4star”, “Fr3star”, “Fravg”, “Sonbrrecruits”,“Soavg” , “Jrnbrrecruits” , “Jr5star” , “Srnbrrecruits” , “Rssrnbrrecruits” , “Rssravg” , “z_lysagarin” , “coachexp_school” , “coachexp_total”

Next, we subsetted the data for each conference so it only contained the variables that were deemed important in the variable screening process.

This facilitated the process of creating a function that will take in a string as a conference (i.e. “SEC”) and a year and outputs that conference’s rankings for that year

The function subsets the data into the conference you specify, and then subsets it into 2 datasets: one that contains all the data from every year except the year you specified (this is your training data), and one that is solely the data of year you specified (this is your test data). The multliple linear regression model is fit based on the training data, and then you use that model to predict the test data.

SECsubset <- as.data.frame(X_CFBRversion[,c(1,2,3,7,8,14,16,18,19,20,31,32,38,46,47,50)])
 SECsubset<- SECsubset %>%
   filter(SEC == 1)
ACCsubset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,12,18,19,20,21,22,32,38,41,44,47,52)])
 ACCsubset<- ACCsubset %>%
   filter(ACC == 1)
PAC10subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,12,14,16,18,22,27,30,31,32,33,34,38,40,42,43,46,47,28,53)]) 
PAC10subset<- PAC10subset %>%
   filter(PacTen == 1)
Big10subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,9,14,18,19,20,21,22,24,27,38,47,49)])
 Big10subset<- Big10subset %>%
   filter(BigTen == 1)
Big12subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,9,10,12,16,18,19,24,30,34,38,46,47,51)])
 Big12subset<- Big12subset %>%
   filter(BigTwelve == 1)
predRank<- function(x,y)
{
  dat<-subset(SECsubset, SECsubset$Year != y)
  newdat<-subset(SECsubset, SECsubset$Year == y)
  if(x=="SEC") {
    colnames(dat) <- c("Team","Year","EPSNrank","Fr5star","Fr4star","So4star","Soavg","Jrnbrrecruits","Jr5star","Jr4star","Rssr5star","Rssr4star","z_lysagarin","coachexp_school","coachexp_total")
    sw<- lm(EPSNrank ~ Fr5star + Fr4star + So4star + Soavg + Jrnbrrecruits + 
    Jr5star + Jr4star + Rssr5star + Rssr4star + z_lysagarin + 
    coachexp_school + coachexp_total, data = dat)
    preds<-predict(sw, newdata = newdat)
    predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
     preddf<-as.data.frame(predset)
  }
  if(x=="ACC") {
    dat<-subset(ACCsubset, ACCsubset$Year != y)
    newdat<-subset(ACCsubset, ACCsubset$Year == y)
    colnames(dat) <- c("Team","Year","EPSNrank", "FrNbrRecruits" , "Fr4star" , "Sonbrrecruits", "Jrnbrrecruits", "Jr5star", "Jr4star", "Jr3star", "Jravg", "Rssr4star", "z_lysagarin","retoff", "bowl" ,"coachexp_total")
  
    fw<- lm(EPSNrank ~ FrNbrRecruits + Fr4star + Sonbrrecruits + Jrnbrrecruits + 
    Jr5star + Jr4star + Jr3star + Jravg + Rssr4star + z_lysagarin + 
    retoff + bowl + coachexp_total, data = dat)
    
  preds<-predict(fw, newdata = newdat)
  predset<-t(rbind(newdat$Team, newdat$EPSNrank,preds))
   preddf<-as.data.frame(predset)
  }
  if(x=="BigTen"){
    dat<-subset(Big10subset, Big10subset$Year != y)
    newdat<-subset(Big10subset, Big10subset$Year == y)
  colnames(dat) <- c("Team","Year","EPSNrank","FrNbrRecruits","Fr3star","So4star","Jrnbrrecruits","Jr5star","Jr4star","Jr3star","Jravg","Srnbrrecruits","Sr3star","z_lysagarin","coachexp_total")
  bw <- lm(EPSNrank ~ FrNbrRecruits + Fr3star + So4star + Jrnbrrecruits + 
    Jr5star + Jr4star + Jr3star + Jravg + Srnbrrecruits + Sr3star + 
    z_lysagarin + coachexp_total, data = dat)
  preds<-predict(bw, newdata = newdat)
  predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
  preddf<-as.data.frame(predset)
  }
  if(x=="PacTen"){
    dat<-subset(PAC10subset, PAC10subset$Year != y)
    newdat<-subset(PAC10subset, PAC10subset$Year == y)
  colnames(dat) <- c("Team","Year","EPSNrank", "FrNbrRecruits" , "Fr4star" , "Sonbrrecruits", "So4star", "Soavg", "Jrnbrrecruits" , "Jravg" , "Sr3star" , "Rssrnbrrecruits" , "Rssr5star" , "Rssr4star" , "Rssr3star" , "Rssravg" , "z_lysagarin" , "z_tyasagarin" , "retdef" , "qbret" , "coachexp_school" , "coachexp_total" , 
    "Sravg")
  bw <- lm(EPSNrank ~ FrNbrRecruits + Fr4star + Sonbrrecruits + So4star + 
    Soavg + Jrnbrrecruits + Jravg + Sr3star + Rssrnbrrecruits + 
    Rssr5star + Rssr4star + Rssr3star + Rssravg + z_lysagarin + 
    z_tyasagarin + retdef + qbret + coachexp_school + coachexp_total + 
    Sravg, data = dat)
  preds<-predict(bw, newdata = newdat)
  predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
  preddf<-as.data.frame(predset)
  }
  if(x =="BigTwelve"){
    dat<-subset(Big12subset, Big12subset$Year != y)
    newdat<-subset(Big12subset, Big12subset$Year == y)
    colnames(dat) <- c("Team","Year","EPSNrank","FrNbrRecruits", "Fr4star", "Fr3star", "Fravg", "Sonbrrecruits","Soavg" , "Jrnbrrecruits" , "Jr5star" , "Srnbrrecruits" , "Rssrnbrrecruits" , "Rssravg" , "z_lysagarin" , "coachexp_school" , "coachexp_total")
  
    fw<-lm(EPSNrank ~ FrNbrRecruits + Fr4star + Fr3star + Fravg + Sonbrrecruits + 
    Soavg + Jrnbrrecruits + Jr5star + Srnbrrecruits + Rssrnbrrecruits + 
    Rssravg + z_lysagarin + coachexp_school + coachexp_total, data = dat)
    
  preds<-predict(fw, newdata = newdat)
  predset<-t(rbind(newdat$Team, newdat$EPSNrank,preds))
   preddf<-as.data.frame(predset)
  }
   preddf$V2<-as.numeric(as.character(preddf$V2))
  preddf$preds<-as.numeric(as.character(preddf$preds))
  
 return(preddf)
}

Next, we predicted the conference rankings for the 2018 season using the function we created above. The results are below. One limitation is that the function predicted the rankings as doubles instead of integers. Therefore, we just ordered the predictions least to greatest, as you can see below.

SEC<-predRank("SEC",2018)
ACC<-predRank("ACC",2018)
BigTen<-predRank("BigTen",2018)
PacTen<-predRank("PacTen",2018)
BigTwelve<-predRank("BigTwelve",2018)
SEC<-SEC[order(SEC$preds),]
SEC
                   V1 V2      preds
149           Georgia  2  0.7483953
151               LSU  4  3.8811658
145           Alabama  1  5.6032631
150          Kentucky  5  5.8993797
157         Texas A&M  6  7.1220021
154          Ole Miss 13  7.3828862
155    South Carolina  9  7.4111542
147            Auburn 10  7.8791257
153          Missouri  7  8.3805134
152 Mississippi State  8  9.0233377
156         Tennessee 12  9.3217204
146          Arkansas 14 10.2480061
158        Vanderbilt 11 10.4361920
148           Florida  3 11.4028449
ACC<-ACC[order(ACC$preds),]
ACC
                V1 V2     preds
149       Miami-FL  8  1.834273
146  Florida State 12  1.880734
155  Virginia Tech  9  3.276114
150       NC State  4  4.534099
148     Louisville 14  4.671640
156    Wake Forest 11  4.825418
154       Virginia  7  4.908386
144        Clemson  1  4.975559
143 Boston College  6  5.566071
145           Duke 10  8.241210
147   Georgia Tech  5  9.086959
153       Syracuse  2  9.579264
151 North Carolina 13 10.772782
152     Pittsburgh  3 12.379287
BigTen<-BigTen[order(BigTen$preds),]
BigTen
                V1 V2      preds
147     Penn State  4 -0.4226229
142 Michigan State  7  2.9731629
146     Ohio State  1  4.0818182
141       Michigan  2  5.3926006
139           Iowa  5  5.5232166
144       Nebraska 11  7.4059580
148         Purdue  8  8.8154271
145   Northwestern  3  8.9978007
143      Minnesota  9  9.5228485
137       Illinois 13  9.8637852
138        Indiana 12 10.1719705
140       Maryland 10 10.5101409
149        Rutgers 14 12.1588026
150      Wisconsin  6         NA
PacTen<-PacTen[order(PacTen$preds),]
PacTen
                V1 V2    preds
135     Washington  2 4.498936
126  Arizona State  6 5.861611
125        Arizona  8 6.033062
131   Southern Cal  9 6.131612
127     California  7 6.304335
132       Stanford  4 7.533845
129         Oregon  5 7.898436
128       Colorado 11 8.350038
130   Oregon State 12 8.539411
136 Washington St.  1 8.610382
133           UCLA 10 8.979491
134           Utah  3 9.280296
BigTwelve<-BigTwelve[order(BigTwelve$preds),]
BigTwelve
                V1 V2     preds
123       Oklahoma  1  3.572277
122   Kansas State  9  3.915932
124 Oklahoma State  7  4.489035
126          Texas  2  4.738465
120     Iowa State  4  5.826364
128  West Virginia  3  6.952349
127     Texas Tech  8  7.402782
125            TCU  6  8.590376
119         Baylor  5  9.810153
121         Kansas 10 10.416551

Our predictions weren’t very accuarate, however usually the predicted top ranked team is in the top 5 (ish).

We also used another method of predicting, decision trees. We wrote a very similar function to predict a given seasons conference rankings for each conference. The function takes in a string as a conference (i.e. “SEC”) and a year and predicts that conference’s rankings for that year, just like the one above but based on the decision tree model.

There is a new decision tree created for each conference. The process for this function is essentially the exact same as the one above, except decision trees are used to predict.

One thing to note about the tree diagram is that it predicts the ranking in factors essentially. Therefore a lot of “ties” show up in the predictions, as you will see below.

SECTree<-treePredRank("SEC",2018)
ACCTree<-treePredRank("ACC",2018)

BigTenTree<-treePredRank("BigTen",2018)

PacTenTree<-treePredRank("PacTen",2018)

BigTwelveTree<-treePredRank("BigTwelve",2018)

These predicitions are also not very accurate. However, the ties are interesting because you can see how teams differ in the post-season that were predicted to perform the same.

Overall, preseason statistics dont seem to be a very good predictor of post-season conference rankings, whether you are using multilple linear regression and variable screening methods or decision trees.

An important result we attained was how different conferences yield different predictors of success.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyLCBtZXNzYWdlPVRSVUV9CmxpYnJhcnkoTUFTUykKbGlicmFyeShkcGx5cikKYGBgClRoZSBmb2xsb3dpbmcgdmFyaWFibGUgc2NyZWVuaW5nIG1ldGhvZCBpcyBjYWxsZWQgc3RlcHdpc2UgcmVncmVzc2lvbi4gVGhpcyB0eXBlIG9mIG1vZGVsIHNlbGVjdGlvbiBhZGRzIGFuZCBkcm9wcyB2YXJpYWJsZXMgaW4gdGhlIG1vZGVsIHVudGlsIGl0IGZpbmRzIHRoZSBvbmUgd2l0aCB0aGUgbW9zdCBzaWduaWZpY2FudCB2YXJpYWJsZXMgaW4gaXQuIFRoZSBtZWFzdXJlIGl0IHVzZXMgdG8gcHJlZGljdCBzaWduaWZpY2FuY2Ugb2YgdGhlIGNob3NlbiB2YXJpYWJsZXMgaXMgdGhlIEFJQywgdGhpcyBudW1iZXIgZ2V0cyBzbWFsbGVyIGFuZCBzbWFsbGVyIGFzIG1vcmUgc2lnbmlmaWNhbnQgdmFyaWFibGVzIGFyZSBhZGRlZCBhbmQgdGhlbiBhbHNvIHBlbmFsaXplcyB0aGUgbW9kZWxzIGZvciBoYXZpbmcgdG9vIG1hbnkgdmFyaWFibGVzIGluIGl0LgoKV2Ugd2FudGVkIHRvIHByZWRpY3QgYSB0ZWFtcyBwb3N0LXNlYXNvbiBjb25mZXJlbmNlIHJhbmtpbmcgd2l0aCBwcmUtc2Vhc29uIHN0YXRpc3RpY3MsIGFxdWlyZWQgZnJvbSBhIGxhcmdlIGRhdGFzZXQgYmVpbmcgdXNlZCBmb3IgYSBzZW5pb3IgdGhlc2lzLiAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uU0VDIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKFNFQyA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvblNFQyksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKCgpgYGAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uQUNDIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKEFDQyA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvbkFDQyksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKYGBgCgpgYGB7cn0KWF9DRkJSdmVyc2lvbkJpZ1RlbiA8LSBYX0NGQlJ2ZXJzaW9uICU+JQogIGZpbHRlcihCaWdUZW4gPT0gMSkKI1N0ZXB3aXNlIFJlZ3Jlc3Npb24Kc3c8LXN0ZXAobG0oRVBTTnJhbmt+RnJOYnJSZWNydWl0cytGcjVzdGFyK0ZyNHN0YXIrRnIzc3RhcitGcmF2ZytTb25icnJlY3J1aXRzK1NvNXN0YXIrU280c3RhcitTbzNzdGFyK1NvYXZnK0pybmJycmVjcnVpdHMrSnI1c3RhcitKcjRzdGFyK0pyM3N0YXIrSnJhdmcrU3JuYnJyZWNydWl0cytTcjVzdGFyK1NyNHN0YXIrU3Izc3RhcitTcmF2ZytSc3NybmJycmVjcnVpdHMrUnNzcjVzdGFyK1Jzc3I0c3RhcitSc3NyM3N0YXIrUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IFhfQ0ZCUnZlcnNpb25CaWdUZW4pLCBkaXJlY3Rpb24gPSBjKCJib3RoIikpCmBgYAoKYGBge3J9ClhfQ0ZCUnZlcnNpb25QYWNUZW4gPC0gWF9DRkJSdmVyc2lvbiAlPiUKICBmaWx0ZXIoUGFjVGVuID09IDEpCiNTdGVwd2lzZSBSZWdyZXNzaW9uCnN3PC1zdGVwKGxtKEVQU05yYW5rfkZyTmJyUmVjcnVpdHMrRnI1c3RhcitGcjRzdGFyK0ZyM3N0YXIrRnJhdmcrU29uYnJyZWNydWl0cytTbzVzdGFyK1NvNHN0YXIrU28zc3RhcitTb2F2ZytKcm5icnJlY3J1aXRzK0pyNXN0YXIrSnI0c3RhcitKcjNzdGFyK0pyYXZnK1NybmJycmVjcnVpdHMrU3I1c3RhcitTcjRzdGFyK1NyM3N0YXIrU3JhdmcrUnNzcm5icnJlY3J1aXRzK1Jzc3I1c3RhcitSc3NyNHN0YXIrUnNzcjNzdGFyK1Jzc3Jhdmcrel9seXNhZ2FyaW4rel90eWFzYWdhcmluK3JldG9mZityZXRkZWYrcWJyZXQrYm93bCtib3dsd2luK2NvYWNoZXhwX3NjaG9vbCtjb2FjaGV4cF90b3RhbCtCaWdUZW4rU0VDK0JpZ1R3ZWx2ZStBQ0MrUGFjVGVuK0JpZ2Vhc3QsIGRhdGEgPSBYX0NGQlJ2ZXJzaW9uUGFjVGVuKSwgZGlyZWN0aW9uID0gYygiYm90aCIpKQpgYGAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uQmlnVHdlbHZlIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKEJpZ1R3ZWx2ZSA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKYGBgCgoKU28gdGhyb3VnaCB0aGlzIHByb2Nlc3MsIHdlIGZvdW5kIHRoYXQgZGlmZmVyZW50IHZhcmlhYmxlcyB3ZXJlIGRlZW1lZCBzaWduaWZpY2FudCBpbiBkaWZmZXJlbnQgY29uZmVyZW5jZXMuIEVzc2VudGlhbGx5IGl0IG1lYW5zIHRoYXQgZGlmZmVyZW50IHRoaW5ncyBhcmUgbmVjZXNzYXJ5IHRvIGJlIHN1Y2Nlc3NmdWwgcmVsYXRpdmUgdG8gdGhlIG90aGVyIHRlYW1zIGluIHlvdXIgY29uZmVyZW5jZSwgYmFzZWQgb24gYSBnaXZlbiBjb25mZXJlbmNlLiAKClNFQzogIkZyNXN0YXIiLCJGcjRzdGFyIiwiU280c3RhciIsIlNvYXZnIiwiSnJuYnJyZWNydWl0cyIsIkpyNXN0YXIiLCJKcjRzdGFyIiwiUnNzcjVzdGFyIiwiUnNzcjRzdGFyIiwiel9seXNhZ2FyaW4iLCJjb2FjaGV4cF9zY2hvb2wiLCJjb2FjaGV4cF90b3RhbCIKCkFDQzoiRnJOYnJSZWNydWl0cyIgLCAiRnI0c3RhciIgLCAiU29uYnJyZWNydWl0cyIsICJKcm5icnJlY3J1aXRzIiwgIkpyNXN0YXIiLCAiSnI0c3RhciIsICJKcjNzdGFyIiwgIkpyYXZnIiwgIlJzc3I0c3RhciIsICJ6X2x5c2FnYXJpbiIsInJldG9mZiIsICJib3dsIiAsImNvYWNoZXhwX3RvdGFsIgoKQmlnVGVuOiAiRnJOYnJSZWNydWl0cyIsIkZyM3N0YXIiLCJTbzRzdGFyIiwiSnJuYnJyZWNydWl0cyIsIkpyNXN0YXIiLCJKcjRzdGFyIiwiSnIzc3RhciIsIkpyYXZnIiwiU3JuYnJyZWNydWl0cyIsIlNyM3N0YXIiLCJ6X2x5c2FnYXJpbiIsImNvYWNoZXhwX3RvdGFsIgoKUGFjVGVuOiJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIlNvNHN0YXIiLCAiU29hdmciLCAiSnJuYnJyZWNydWl0cyIgLCAiSnJhdmciICwgIlNyM3N0YXIiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcjVzdGFyIiAsICJSc3NyNHN0YXIiICwgIlJzc3Izc3RhciIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgInpfdHlhc2FnYXJpbiIgLCAicmV0ZGVmIiAsICJxYnJldCIgLCAiY29hY2hleHBfc2Nob29sIiAsICJjb2FjaGV4cF90b3RhbCIgLCAiU3JhdmciCiAgICAKQmlnVHdlbHZlOiJGck5iclJlY3J1aXRzIiwgIkZyNHN0YXIiLCAiRnIzc3RhciIsICJGcmF2ZyIsICJTb25icnJlY3J1aXRzIiwiU29hdmciICwgIkpybmJycmVjcnVpdHMiICwgIkpyNXN0YXIiICwgIlNybmJycmVjcnVpdHMiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgImNvYWNoZXhwX3NjaG9vbCIgLCAiY29hY2hleHBfdG90YWwiCgoKTmV4dCwgd2Ugc3Vic2V0dGVkIHRoZSBkYXRhIGZvciBlYWNoIGNvbmZlcmVuY2Ugc28gaXQgb25seSBjb250YWluZWQgdGhlIHZhcmlhYmxlcyB0aGF0IHdlcmUgZGVlbWVkIGltcG9ydGFudCBpbiB0aGUgdmFyaWFibGUgc2NyZWVuaW5nIHByb2Nlc3MuIAoKVGhpcyBmYWNpbGl0YXRlZCB0aGUgcHJvY2VzcyBvZiBjcmVhdGluZyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCB0YWtlIGluIGEgc3RyaW5nIGFzIGEgY29uZmVyZW5jZSAoaS5lLiAiU0VDIikgYW5kIGEgeWVhciBhbmQgb3V0cHV0cyB0aGF0IGNvbmZlcmVuY2UncyByYW5raW5ncyBmb3IgdGhhdCB5ZWFyIAoKVGhlIGZ1bmN0aW9uIHN1YnNldHMgdGhlIGRhdGEgaW50byB0aGUgY29uZmVyZW5jZSB5b3Ugc3BlY2lmeSwgYW5kIHRoZW4gc3Vic2V0cyBpdCBpbnRvIDIgZGF0YXNldHM6IG9uZSB0aGF0IGNvbnRhaW5zIGFsbCB0aGUgZGF0YSBmcm9tIGV2ZXJ5IHllYXIgZXhjZXB0IHRoZSB5ZWFyIHlvdSBzcGVjaWZpZWQgKHRoaXMgaXMgeW91ciB0cmFpbmluZyBkYXRhKSwgYW5kIG9uZSB0aGF0IGlzIHNvbGVseSB0aGUgZGF0YSBvZiB5ZWFyIHlvdSBzcGVjaWZpZWQgKHRoaXMgaXMgeW91ciB0ZXN0IGRhdGEpLiBUaGUgbXVsdGxpcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGlzIGZpdCBiYXNlZCBvbiB0aGUgdHJhaW5pbmcgZGF0YSwgYW5kIHRoZW4geW91IHVzZSB0aGF0IG1vZGVsIHRvIHByZWRpY3QgdGhlIHRlc3QgZGF0YS4gCgoKCmBgYHtyfQpTRUNzdWJzZXQgPC0gYXMuZGF0YS5mcmFtZShYX0NGQlJ2ZXJzaW9uWyxjKDEsMiwzLDcsOCwxNCwxNiwxOCwxOSwyMCwzMSwzMiwzOCw0Niw0Nyw1MCldKQogU0VDc3Vic2V0PC0gU0VDc3Vic2V0ICU+JQogICBmaWx0ZXIoU0VDID09IDEpCkFDQ3N1YnNldCA8LSBhcy5kYXRhLmZyYW1lKFhfQ0ZCUnZlcnNpb25bLGMoMSwyLDMsNiw4LDEyLDE4LDE5LDIwLDIxLDIyLDMyLDM4LDQxLDQ0LDQ3LDUyKV0pCiBBQ0NzdWJzZXQ8LSBBQ0NzdWJzZXQgJT4lCiAgIGZpbHRlcihBQ0MgPT0gMSkKUEFDMTBzdWJzZXQgPC0gYXMuZGF0YS5mcmFtZShYX0NGQlJ2ZXJzaW9uWyxjKDEsMiwzLDYsOCwxMiwxNCwxNiwxOCwyMiwyNywzMCwzMSwzMiwzMywzNCwzOCw0MCw0Miw0Myw0Niw0NywyOCw1MyldKSAKUEFDMTBzdWJzZXQ8LSBQQUMxMHN1YnNldCAlPiUKICAgZmlsdGVyKFBhY1RlbiA9PSAxKQpCaWcxMHN1YnNldCA8LSBhcy5kYXRhLmZyYW1lKFhfQ0ZCUnZlcnNpb25bLGMoMSwyLDMsNiw5LDE0LDE4LDE5LDIwLDIxLDIyLDI0LDI3LDM4LDQ3LDQ5KV0pCiBCaWcxMHN1YnNldDwtIEJpZzEwc3Vic2V0ICU+JQogICBmaWx0ZXIoQmlnVGVuID09IDEpCkJpZzEyc3Vic2V0IDwtIGFzLmRhdGEuZnJhbWUoWF9DRkJSdmVyc2lvblssYygxLDIsMyw2LDgsOSwxMCwxMiwxNiwxOCwxOSwyNCwzMCwzNCwzOCw0Niw0Nyw1MSldKQogQmlnMTJzdWJzZXQ8LSBCaWcxMnN1YnNldCAlPiUKICAgZmlsdGVyKEJpZ1R3ZWx2ZSA9PSAxKQoKcHJlZFJhbms8LSBmdW5jdGlvbih4LHkpCnsKICBkYXQ8LXN1YnNldChTRUNzdWJzZXQsIFNFQ3N1YnNldCRZZWFyICE9IHkpCiAgbmV3ZGF0PC1zdWJzZXQoU0VDc3Vic2V0LCBTRUNzdWJzZXQkWWVhciA9PSB5KQogIGlmKHg9PSJTRUMiKSB7CiAgICBjb2xuYW1lcyhkYXQpIDwtIGMoIlRlYW0iLCJZZWFyIiwiRVBTTnJhbmsiLCJGcjVzdGFyIiwiRnI0c3RhciIsIlNvNHN0YXIiLCJTb2F2ZyIsIkpybmJycmVjcnVpdHMiLCJKcjVzdGFyIiwiSnI0c3RhciIsIlJzc3I1c3RhciIsIlJzc3I0c3RhciIsInpfbHlzYWdhcmluIiwiY29hY2hleHBfc2Nob29sIiwiY29hY2hleHBfdG90YWwiKQogICAgc3c8LSBsbShFUFNOcmFuayB+IEZyNXN0YXIgKyBGcjRzdGFyICsgU280c3RhciArIFNvYXZnICsgSnJuYnJyZWNydWl0cyArIAogICAgSnI1c3RhciArIEpyNHN0YXIgKyBSc3NyNXN0YXIgKyBSc3NyNHN0YXIgKyB6X2x5c2FnYXJpbiArIAogICAgY29hY2hleHBfc2Nob29sICsgY29hY2hleHBfdG90YWwsIGRhdGEgPSBkYXQpCiAgICBwcmVkczwtcHJlZGljdChzdywgbmV3ZGF0YSA9IG5ld2RhdCkKICAgIHByZWRzZXQ8LXQocmJpbmQobmV3ZGF0JFRlYW0sbmV3ZGF0JEVQU05yYW5rLHByZWRzKSkKICAgICBwcmVkZGY8LWFzLmRhdGEuZnJhbWUocHJlZHNldCkKICB9CiAgaWYoeD09IkFDQyIpIHsKICAgIGRhdDwtc3Vic2V0KEFDQ3N1YnNldCwgQUNDc3Vic2V0JFllYXIgIT0geSkKICAgIG5ld2RhdDwtc3Vic2V0KEFDQ3N1YnNldCwgQUNDc3Vic2V0JFllYXIgPT0geSkKICAgIGNvbG5hbWVzKGRhdCkgPC0gYygiVGVhbSIsIlllYXIiLCJFUFNOcmFuayIsICJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIkpybmJycmVjcnVpdHMiLCAiSnI1c3RhciIsICJKcjRzdGFyIiwgIkpyM3N0YXIiLCAiSnJhdmciLCAiUnNzcjRzdGFyIiwgInpfbHlzYWdhcmluIiwicmV0b2ZmIiwgImJvd2wiICwiY29hY2hleHBfdG90YWwiKQogIAogICAgZnc8LSBsbShFUFNOcmFuayB+IEZyTmJyUmVjcnVpdHMgKyBGcjRzdGFyICsgU29uYnJyZWNydWl0cyArIEpybmJycmVjcnVpdHMgKyAKICAgIEpyNXN0YXIgKyBKcjRzdGFyICsgSnIzc3RhciArIEpyYXZnICsgUnNzcjRzdGFyICsgel9seXNhZ2FyaW4gKyAKICAgIHJldG9mZiArIGJvd2wgKyBjb2FjaGV4cF90b3RhbCwgZGF0YSA9IGRhdCkKICAgIAogIHByZWRzPC1wcmVkaWN0KGZ3LCBuZXdkYXRhID0gbmV3ZGF0KQogIHByZWRzZXQ8LXQocmJpbmQobmV3ZGF0JFRlYW0sIG5ld2RhdCRFUFNOcmFuayxwcmVkcykpCiAgIHByZWRkZjwtYXMuZGF0YS5mcmFtZShwcmVkc2V0KQogIH0KICBpZih4PT0iQmlnVGVuIil7CiAgICBkYXQ8LXN1YnNldChCaWcxMHN1YnNldCwgQmlnMTBzdWJzZXQkWWVhciAhPSB5KQogICAgbmV3ZGF0PC1zdWJzZXQoQmlnMTBzdWJzZXQsIEJpZzEwc3Vic2V0JFllYXIgPT0geSkKICBjb2xuYW1lcyhkYXQpIDwtIGMoIlRlYW0iLCJZZWFyIiwiRVBTTnJhbmsiLCJGck5iclJlY3J1aXRzIiwiRnIzc3RhciIsIlNvNHN0YXIiLCJKcm5icnJlY3J1aXRzIiwiSnI1c3RhciIsIkpyNHN0YXIiLCJKcjNzdGFyIiwiSnJhdmciLCJTcm5icnJlY3J1aXRzIiwiU3Izc3RhciIsInpfbHlzYWdhcmluIiwiY29hY2hleHBfdG90YWwiKQogIGJ3IDwtIGxtKEVQU05yYW5rIH4gRnJOYnJSZWNydWl0cyArIEZyM3N0YXIgKyBTbzRzdGFyICsgSnJuYnJyZWNydWl0cyArIAogICAgSnI1c3RhciArIEpyNHN0YXIgKyBKcjNzdGFyICsgSnJhdmcgKyBTcm5icnJlY3J1aXRzICsgU3Izc3RhciArIAogICAgel9seXNhZ2FyaW4gKyBjb2FjaGV4cF90b3RhbCwgZGF0YSA9IGRhdCkKICBwcmVkczwtcHJlZGljdChidywgbmV3ZGF0YSA9IG5ld2RhdCkKICBwcmVkc2V0PC10KHJiaW5kKG5ld2RhdCRUZWFtLG5ld2RhdCRFUFNOcmFuayxwcmVkcykpCiAgcHJlZGRmPC1hcy5kYXRhLmZyYW1lKHByZWRzZXQpCiAgfQogIGlmKHg9PSJQYWNUZW4iKXsKICAgIGRhdDwtc3Vic2V0KFBBQzEwc3Vic2V0LCBQQUMxMHN1YnNldCRZZWFyICE9IHkpCiAgICBuZXdkYXQ8LXN1YnNldChQQUMxMHN1YnNldCwgUEFDMTBzdWJzZXQkWWVhciA9PSB5KQogIGNvbG5hbWVzKGRhdCkgPC0gYygiVGVhbSIsIlllYXIiLCJFUFNOcmFuayIsICJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIlNvNHN0YXIiLCAiU29hdmciLCAiSnJuYnJyZWNydWl0cyIgLCAiSnJhdmciICwgIlNyM3N0YXIiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcjVzdGFyIiAsICJSc3NyNHN0YXIiICwgIlJzc3Izc3RhciIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgInpfdHlhc2FnYXJpbiIgLCAicmV0ZGVmIiAsICJxYnJldCIgLCAiY29hY2hleHBfc2Nob29sIiAsICJjb2FjaGV4cF90b3RhbCIgLCAKICAgICJTcmF2ZyIpCiAgYncgPC0gbG0oRVBTTnJhbmsgfiBGck5iclJlY3J1aXRzICsgRnI0c3RhciArIFNvbmJycmVjcnVpdHMgKyBTbzRzdGFyICsgCiAgICBTb2F2ZyArIEpybmJycmVjcnVpdHMgKyBKcmF2ZyArIFNyM3N0YXIgKyBSc3NybmJycmVjcnVpdHMgKyAKICAgIFJzc3I1c3RhciArIFJzc3I0c3RhciArIFJzc3Izc3RhciArIFJzc3JhdmcgKyB6X2x5c2FnYXJpbiArIAogICAgel90eWFzYWdhcmluICsgcmV0ZGVmICsgcWJyZXQgKyBjb2FjaGV4cF9zY2hvb2wgKyBjb2FjaGV4cF90b3RhbCArIAogICAgU3JhdmcsIGRhdGEgPSBkYXQpCiAgcHJlZHM8LXByZWRpY3QoYncsIG5ld2RhdGEgPSBuZXdkYXQpCiAgcHJlZHNldDwtdChyYmluZChuZXdkYXQkVGVhbSxuZXdkYXQkRVBTTnJhbmsscHJlZHMpKQogIHByZWRkZjwtYXMuZGF0YS5mcmFtZShwcmVkc2V0KQoKICB9CiAgaWYoeCA9PSJCaWdUd2VsdmUiKXsKICAgIGRhdDwtc3Vic2V0KEJpZzEyc3Vic2V0LCBCaWcxMnN1YnNldCRZZWFyICE9IHkpCiAgICBuZXdkYXQ8LXN1YnNldChCaWcxMnN1YnNldCwgQmlnMTJzdWJzZXQkWWVhciA9PSB5KQogICAgY29sbmFtZXMoZGF0KSA8LSBjKCJUZWFtIiwiWWVhciIsIkVQU05yYW5rIiwiRnJOYnJSZWNydWl0cyIsICJGcjRzdGFyIiwgIkZyM3N0YXIiLCAiRnJhdmciLCAiU29uYnJyZWNydWl0cyIsIlNvYXZnIiAsICJKcm5icnJlY3J1aXRzIiAsICJKcjVzdGFyIiAsICJTcm5icnJlY3J1aXRzIiAsICJSc3NybmJycmVjcnVpdHMiICwgIlJzc3JhdmciICwgInpfbHlzYWdhcmluIiAsICJjb2FjaGV4cF9zY2hvb2wiICwgImNvYWNoZXhwX3RvdGFsIikKICAKICAgIGZ3PC1sbShFUFNOcmFuayB+IEZyTmJyUmVjcnVpdHMgKyBGcjRzdGFyICsgRnIzc3RhciArIEZyYXZnICsgU29uYnJyZWNydWl0cyArIAogICAgU29hdmcgKyBKcm5icnJlY3J1aXRzICsgSnI1c3RhciArIFNybmJycmVjcnVpdHMgKyBSc3NybmJycmVjcnVpdHMgKyAKICAgIFJzc3JhdmcgKyB6X2x5c2FnYXJpbiArIGNvYWNoZXhwX3NjaG9vbCArIGNvYWNoZXhwX3RvdGFsLCBkYXRhID0gZGF0KQogICAgCiAgcHJlZHM8LXByZWRpY3QoZncsIG5ld2RhdGEgPSBuZXdkYXQpCiAgcHJlZHNldDwtdChyYmluZChuZXdkYXQkVGVhbSwgbmV3ZGF0JEVQU05yYW5rLHByZWRzKSkKICAgcHJlZGRmPC1hcy5kYXRhLmZyYW1lKHByZWRzZXQpCiAgfQogICBwcmVkZGYkVjI8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWRkZiRWMikpCiAgcHJlZGRmJHByZWRzPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkZGYkcHJlZHMpKQogIAogcmV0dXJuKHByZWRkZikKfQpgYGAKCk5leHQsIHdlIHByZWRpY3RlZCB0aGUgY29uZmVyZW5jZSByYW5raW5ncyBmb3IgdGhlIDIwMTggc2Vhc29uIHVzaW5nIHRoZSBmdW5jdGlvbiB3ZSBjcmVhdGVkIGFib3ZlLiBUaGUgcmVzdWx0cyBhcmUgYmVsb3cuIE9uZSBsaW1pdGF0aW9uIGlzIHRoYXQgdGhlIGZ1bmN0aW9uIHByZWRpY3RlZCB0aGUgcmFua2luZ3MgYXMgZG91YmxlcyBpbnN0ZWFkIG9mIGludGVnZXJzLiBUaGVyZWZvcmUsIHdlIGp1c3Qgb3JkZXJlZCB0aGUgcHJlZGljdGlvbnMgbGVhc3QgdG8gZ3JlYXRlc3QsIGFzIHlvdSBjYW4gc2VlIGJlbG93LiAKCgpgYGB7cn0KU0VDPC1wcmVkUmFuaygiU0VDIiwyMDE4KQpBQ0M8LXByZWRSYW5rKCJBQ0MiLDIwMTgpCkJpZ1RlbjwtcHJlZFJhbmsoIkJpZ1RlbiIsMjAxOCkKUGFjVGVuPC1wcmVkUmFuaygiUGFjVGVuIiwyMDE4KQpCaWdUd2VsdmU8LXByZWRSYW5rKCJCaWdUd2VsdmUiLDIwMTgpCgpTRUM8LVNFQ1tvcmRlcihTRUMkcHJlZHMpLF0KU0VDCkFDQzwtQUNDW29yZGVyKEFDQyRwcmVkcyksXQpBQ0MKQmlnVGVuPC1CaWdUZW5bb3JkZXIoQmlnVGVuJHByZWRzKSxdCkJpZ1RlbgpQYWNUZW48LVBhY1RlbltvcmRlcihQYWNUZW4kcHJlZHMpLF0KUGFjVGVuCkJpZ1R3ZWx2ZTwtQmlnVHdlbHZlW29yZGVyKEJpZ1R3ZWx2ZSRwcmVkcyksXQpCaWdUd2VsdmUKYGBgCk91ciBwcmVkaWN0aW9ucyB3ZXJlbid0IHZlcnkgYWNjdWFyYXRlLCBob3dldmVyIHVzdWFsbHkgdGhlIHByZWRpY3RlZCB0b3AgcmFua2VkIHRlYW0gaXMgaW4gdGhlIHRvcCA1IChpc2gpLiAKCldlIGFsc28gdXNlZCBhbm90aGVyIG1ldGhvZCBvZiBwcmVkaWN0aW5nLCBkZWNpc2lvbiB0cmVlcy4gV2Ugd3JvdGUgYSB2ZXJ5IHNpbWlsYXIgZnVuY3Rpb24gdG8gcHJlZGljdCBhIGdpdmVuIHNlYXNvbnMgY29uZmVyZW5jZSByYW5raW5ncyBmb3IgZWFjaCBjb25mZXJlbmNlLiBUaGUgZnVuY3Rpb24gdGFrZXMgaW4gYSBzdHJpbmcgYXMgYSBjb25mZXJlbmNlIChpLmUuICJTRUMiKSBhbmQgYSB5ZWFyIGFuZCBwcmVkaWN0cyB0aGF0IGNvbmZlcmVuY2UncyByYW5raW5ncyBmb3IgdGhhdCB5ZWFyLCBqdXN0IGxpa2UgdGhlIG9uZSBhYm92ZSBidXQgYmFzZWQgb24gdGhlIGRlY2lzaW9uIHRyZWUgbW9kZWwuCgpUaGVyZSBpcyBhIG5ldyBkZWNpc2lvbiB0cmVlIGNyZWF0ZWQgZm9yIGVhY2ggY29uZmVyZW5jZS4gVGhlIHByb2Nlc3MgZm9yIHRoaXMgZnVuY3Rpb24gaXMgZXNzZW50aWFsbHkgdGhlIGV4YWN0IHNhbWUgYXMgdGhlIG9uZSBhYm92ZSwgZXhjZXB0IGRlY2lzaW9uIHRyZWVzIGFyZSB1c2VkIHRvIHByZWRpY3QuIAoKT25lIHRoaW5nIHRvIG5vdGUgYWJvdXQgdGhlIHRyZWUgZGlhZ3JhbSBpcyB0aGF0IGl0IHByZWRpY3RzIHRoZSByYW5raW5nIGluIGZhY3RvcnMgZXNzZW50aWFsbHkuIFRoZXJlZm9yZSBhIGxvdCBvZiAidGllcyIgc2hvdyB1cCBpbiB0aGUgcHJlZGljdGlvbnMsIGFzIHlvdSB3aWxsIHNlZSBiZWxvdy4gCgoKYGBge3J9CnRyZWVQcmVkUmFuazwtIGZ1bmN0aW9uKHgseSkgewogIGlmKHggPT0gIlNFQyIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uU0VDLCBYX0NGQlJ2ZXJzaW9uU0VDJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25TRUMsIFhfQ0ZCUnZlcnNpb25TRUMkWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICB9CiAgIGlmKHggPT0gIkFDQyIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uQUNDLCBYX0NGQlJ2ZXJzaW9uQUNDJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25BQ0MsIFhfQ0ZCUnZlcnNpb25BQ0MkWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICAgfQogICBpZih4ID09ICJCaWdUZW4iKXsKICAgICB0cmFpbjwtICBzdWJzZXQoWF9DRkJSdmVyc2lvbkJpZ1RlbiwgWF9DRkJSdmVyc2lvbkJpZ1RlbiRZZWFyICE9IHkpCiAgICAgdGVzdDwtIHN1YnNldChYX0NGQlJ2ZXJzaW9uQmlnVGVuLCBYX0NGQlJ2ZXJzaW9uQmlnVGVuJFllYXIgPT0geSkKbW9kZWxfdHJlZSA8LXRyZWUoRVBTTnJhbmt+RnJOYnJSZWNydWl0cytGcjVzdGFyK0ZyNHN0YXIrRnIzc3RhcitGcmF2ZytTb25icnJlY3J1aXRzK1NvNXN0YXIrU280c3RhcitTbzNzdGFyK1NvYXZnK0pybmJycmVjcnVpdHMrSnI1c3RhcitKcjRzdGFyK0pyM3N0YXIrSnJhdmcrU3JuYnJyZWNydWl0cytTcjVzdGFyK1NyNHN0YXIrU3Izc3RhcitTcmF2ZytSc3NybmJycmVjcnVpdHMrUnNzcjVzdGFyK1Jzc3I0c3RhcitSc3NyM3N0YXIrIFJzc3Jhdmcrel9seXNhZ2FyaW4rel90eWFzYWdhcmluK3JldG9mZityZXRkZWYrcWJyZXQrYm93bCtib3dsd2luK2NvYWNoZXhwX3NjaG9vbCtjb2FjaGV4cF90b3RhbCtCaWdUZW4rU0VDK0JpZ1R3ZWx2ZStBQ0MrUGFjVGVuK0JpZ2Vhc3QsIGRhdGEgPSB0cmFpbikKcGxvdChtb2RlbF90cmVlKQp0ZXh0KG1vZGVsX3RyZWUsY2V4PS43KQpwcmVkIDwtIHByZWRpY3QobW9kZWxfdHJlZSxuZXdkYXRhID0gdGVzdCkKcHJlZHZzYWN0PC0gdChyYmluZChwcmVkLHRlc3QkRVBTTnJhbmssIHRlc3QkVGVhbSkpCnByZWR2c2FjdDwtYXMuZGF0YS5mcmFtZShwcmVkdnNhY3QpCnByZWR2c2FjdCRWMjwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JFYyKSkKcHJlZHZzYWN0JHByZWQ8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWR2c2FjdCRwcmVkKSkKCiAgIH0KICAgaWYoeCA9PSAiQmlnVHdlbHZlIil7CiAgICAgdHJhaW48LSAgc3Vic2V0KFhfQ0ZCUnZlcnNpb25CaWdUd2VsdmUsIFhfQ0ZCUnZlcnNpb25CaWdUd2VsdmUkWWVhciAhPSB5KQogICAgIHRlc3Q8LSBzdWJzZXQoWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSwgWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSRZZWFyID09IHkpCm1vZGVsX3RyZWUgPC10cmVlKEVQU05yYW5rfkZyTmJyUmVjcnVpdHMrRnI1c3RhcitGcjRzdGFyK0ZyM3N0YXIrRnJhdmcrU29uYnJyZWNydWl0cytTbzVzdGFyK1NvNHN0YXIrU28zc3RhcitTb2F2ZytKcm5icnJlY3J1aXRzK0pyNXN0YXIrSnI0c3RhcitKcjNzdGFyK0pyYXZnK1NybmJycmVjcnVpdHMrU3I1c3RhcitTcjRzdGFyK1NyM3N0YXIrU3JhdmcrUnNzcm5icnJlY3J1aXRzK1Jzc3I1c3RhcitSc3NyNHN0YXIrUnNzcjNzdGFyKyBSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gdHJhaW4pCnBsb3QobW9kZWxfdHJlZSkKdGV4dChtb2RlbF90cmVlLGNleD0uNykKcHJlZCA8LSBwcmVkaWN0KG1vZGVsX3RyZWUsbmV3ZGF0YSA9IHRlc3QpCnByZWR2c2FjdDwtIHQocmJpbmQocHJlZCx0ZXN0JEVQU05yYW5rLCB0ZXN0JFRlYW0pKQpwcmVkdnNhY3Q8LWFzLmRhdGEuZnJhbWUocHJlZHZzYWN0KQpwcmVkdnNhY3QkVjI8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWR2c2FjdCRWMikpCnByZWR2c2FjdCRwcmVkPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkcHJlZCkpCgogICB9CiAgIGlmKHggPT0gIlBhY1RlbiIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uUGFjVGVuLCBYX0NGQlJ2ZXJzaW9uUGFjVGVuJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25QYWNUZW4sIFhfQ0ZCUnZlcnNpb25QYWNUZW4kWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICB9CiAgcmV0dXJuKHByZWR2c2FjdCkKfQoKClNFQ1RyZWU8LXRyZWVQcmVkUmFuaygiU0VDIiwyMDE4KQpBQ0NUcmVlPC10cmVlUHJlZFJhbmsoIkFDQyIsMjAxOCkKQmlnVGVuVHJlZTwtdHJlZVByZWRSYW5rKCJCaWdUZW4iLDIwMTgpClBhY1RlblRyZWU8LXRyZWVQcmVkUmFuaygiUGFjVGVuIiwyMDE4KQpCaWdUd2VsdmVUcmVlPC10cmVlUHJlZFJhbmsoIkJpZ1R3ZWx2ZSIsMjAxOCkKClNFQ1RyZWU8LVNFQ1RyZWVbb3JkZXIoU0VDVHJlZSRwcmVkKSxdClNFQ1RyZWUKQUNDVHJlZTwtQUNDVHJlZVtvcmRlcihBQ0NUcmVlJHByZWQpLF0KQUNDVHJlZQpCaWdUZW5UcmVlPC1CaWdUZW5UcmVlW29yZGVyKEJpZ1RlblRyZWUkcHJlZCksXQpCaWdUZW5UcmVlClBhY1RlblRyZWU8LVBhY1RlblRyZWVbb3JkZXIoUGFjVGVuVHJlZSRwcmVkKSxdClBhY1RlblRyZWUKQmlnVHdlbHZlVHJlZTwtQmlnVHdlbHZlVHJlZVtvcmRlcihCaWdUd2VsdmVUcmVlJHByZWQpLF0KQmlnVHdlbHZlVHJlZQoKCgpgYGAKClRoZXNlIHByZWRpY2l0aW9ucyBhcmUgYWxzbyBub3QgdmVyeSBhY2N1cmF0ZS4gSG93ZXZlciwgdGhlIHRpZXMgYXJlIGludGVyZXN0aW5nIGJlY2F1c2UgeW91IGNhbiBzZWUgaG93IHRlYW1zIGRpZmZlciBpbiB0aGUgcG9zdC1zZWFzb24gdGhhdCB3ZXJlIHByZWRpY3RlZCB0byBwZXJmb3JtIHRoZSBzYW1lLiAKCk92ZXJhbGwsIHByZXNlYXNvbiBzdGF0aXN0aWNzIGRvbnQgc2VlbSB0byBiZSBhIHZlcnkgZ29vZCBwcmVkaWN0b3Igb2YgcG9zdC1zZWFzb24gY29uZmVyZW5jZSByYW5raW5ncywgd2hldGhlciB5b3UgYXJlIHVzaW5nIG11bHRpbHBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmQgdmFyaWFibGUgc2NyZWVuaW5nIG1ldGhvZHMgb3IgZGVjaXNpb24gdHJlZXMuCgpBbiBpbXBvcnRhbnQgcmVzdWx0IHdlIGF0dGFpbmVkIHdhcyBob3cgZGlmZmVyZW50IGNvbmZlcmVuY2VzIHlpZWxkIGRpZmZlcmVudCBwcmVkaWN0b3JzIG9mIHN1Y2Nlc3MuIAo=