To go back to the Home page, click here.
Data Description
The dataset contains the results for the men’s ATP tour date back to January 2000, including Grand Slams, Masters Series, Masters Cup and International Series competitions. All head to head matches are provided with rank of both opponents, the name of the winner, and the final score. A more detailled description of the data can be found here.
The data can be found here.
In this notebook, we will only be focused on the so-called BIG 3 that corresponds to the three best tennis players over the last 20 years, namely Roger Federer, Rafael Nadal and Novak Djokovic.
Study of head to head in the BIG 3
Players in the BIG 3 have really different game styles. In this first section, we want to test for each member of the BIG 3 if he has the same chances to win against one or the other of its greatest rivals.
# Selecting Head to Head matches
big3 = c('Federer R.','Nadal R.', 'Djokovic N.')
FvsN = ('Federer R.' == data$Winner[(data$Winner %in% big3[-3]) & (data$Loser %in% big3[-3])]);
FvsD = ('Federer R.' == data$Winner[(data$Winner %in% big3[-2]) & (data$Loser %in% big3[-2])]);
NvsD = ('Nadal R.' == data$Winner[(data$Winner %in% big3[-1]) & (data$Loser %in% big3[-1])]);
We will use a Z-Test to carry out our study.
Power comparison between the asymptotic Z-test and the exact Fisher test
The following functions compute the p-values resulting from the Fisher Test and the asymptotic Z-test.
# Exact Fisher Test
FisherTestStat <- function (seq1,seq2){
contingency = matrix(ncol=2,nrow=2);
contingency[1,1] = sum(seq1);
contingency[2,1] = length(seq1)-contingency[1,1];
contingency[1,2] = sum(seq2);
contingency[2,2] = length(seq2)-contingency[1,2];
Zstat <- fisher.test(contingency);
return (Zstat$p.value);
}
# Asymptotic Z-Test
computeAsymptoticZstat <- function (seq1,seq2) {
n1 = length(seq1);
n2 = length(seq2);
bar1 = mean(seq1);
bar2 = mean(seq2);
bar = (sum(seq1)+sum(seq2))/(n1+n2);
Zstat = sqrt(n1*n2/(n1+n2))*(bar1-bar2)/sqrt(bar*(1-bar));
pvalue = 2*pnorm(-abs(Zstat),mean=0,sd=1);
return (data.frame(stat=Zstat, pval=pvalue));
}
In our case, we will deal with sample sizes around 40. We propose to study the power of both tests for sample size of this order.
Let us first check that the above functions are working correctly by plotting the proportion of Type I errors for tests with level 0.05.
# Proportion of Type I error for both tests depending on the sample size (using a level = 0.05)
level = 0.05;
i = 1;
list_n <- seq(20,200,by=10);
fisher <- rep(0,length(list_n));
asymptoticZtest <- rep(0,length(list_n));
for (n in list_n){
for (k in 1:1000){
seq1 = rbinom(n,1,0.5);
seq2 = rbinom(n,1,0.5);
asymptoticZtest[i] = asymptoticZtest[i] + 1*(computeAsymptoticZstat(seq1,seq2)$pval < level)/1000;
fisher[i] = fisher[i] + 1*(FisherTestStat(seq1,seq2) < level)/1000;
}
i = i+1;
}
errorstype1 <- data.frame(list_n,fisher,asymptoticZtest);
ggplot(errorstype1, aes(list_n)) + # basic graphical object
geom_line(aes(y=fisher, colour="Fisher test")) + # first layer
geom_line(aes(y=asymptoticZtest, colour = "Asymptotic Z test")) + # second layer
scale_color_manual(name = "", values = c("Asymptotic Z test" = "green", "Fisher test" = "red")) +
labs(x = "Sample size") +
labs(y = "Proportion of Type I error")
As theoretically guaranteed, the Fisher leads to a proportion of Type I errors smaller than 0.05. Indeed, it is the opportunity to recall that Fisher test only provides an upper bound on the level of the test.
Regarding the asymptotic Z-test, the proportion of Type I errors is around 0.05 but may slightly above or below this value due to randomness but also due to the fact that the theoretical control of the level of the test holds only asymptotically.
Let us now dig into the power study. We consider two sequences of Bernoulli random variables with respective parameters p1 and p2 with 0.5-p1=p2-0.5.
level = 0.05;
list_n = seq(10,100,by=10);
list_gaps = seq(0.,0.2,by=0.02);
power_asymptoticZtest = matrix(0,ncol=length(list_n),nrow=length(list_gaps));
power_fisher = matrix(0,ncol=length(list_n),nrow=length(list_gaps));
i = 1;
for (n in list_n){
j = 1;
for (gap in list_gaps){
p1 = 0.5-gap;
p2 = 0.5+gap;
for (k in 1:300){
seq1 = rbinom(n,1,p1);
seq2 = rbinom(n,1,p2);
power_asymptoticZtest[j,i] = power_asymptoticZtest[j,i] + 1*(computeAsymptoticZstat(seq1,seq2)$pval < level)/300;
power_fisher[j,i] = power_fisher[j,i] + 1*(FisherTestStat(seq1,seq2) < level)/300;
}
j = j+1;
}
i = i+1;
}
heatmap <- expand.grid(X=list_gaps, Y=list_n);
heatmap$Z <- c(power_asymptoticZtest - power_fisher);
## Try it out
levelplot(Z ~ X*Y, data=heatmap ,xlab="p2-p1", ylab="Number of samples: n",
main="Power(Asymptotic Z test) - Power(Fisher Test)")
The heatmap shows that the power of asymptotic Z test is greater than the one of the Fisher test in the range of sample size of interest. Hence, in the following, we will use the asymptotic Z test.
Study for Federer
# We compute the p-value of the T-Test for Federer
resZtest <- computeAsymptoticZstat(FvsN,FvsD);
resZtest$pval
## [1] 0.1994286
The p-value is equal to 0.2 meaning that we do not reject the null hypothesis. Hence, the probability of victory of Federer over Nadal is not statistically different from the one of Federer over Djokovic.
Study for Nadal
# We compute the p-value of the T-Test for Nadal
resZtest <- computeAsymptoticZstat(1-FvsN,NvsD);
resZtest$pval;
## [1] 0.04057708
The p-value is equal to 0.04 meaning that we would tend to reject the null hypothesis. Hence, the probability of victory of Nadal over Federer is statistically different (in this case: larger) from the one of Nadal over Djokovic.
Study for Djokovic
# We compute the p-value of the T-Test for Djokovic
resZtest <- computeAsymptoticZstat(1-FvsD,1-NvsD);
resZtest$pval;
## [1] 0.8484067
The p-value is equal to 0.85 meaning that we do not reject the null hypothesis. Hence, the probability of victory of Djokovic over Federer is not statistically different from the one of Djokovic over Nadal.
Conclusion While Nadal and Djokovic have a probability of victory against the other members of the Big 3 that does not depend on the opponent, we showed that Nadal has significantly less chance of winning against Djokovic than against Federer.
Now we want to understand why Nadal performs better when facing Federer than Djokovic. In the following, we will be focused on the following questions.
Does this fact holds for every surfaces?
Was it true during the whole Nadal’s career?
We first investigate the influence of the surface.
Influence of the Surface
We take a closer look to matches between Nadal and tho others members of the BIG 3 depending on the different surfaces. We only focus on Clay and Hard Court since we do not have enough data for Carpet and Grass.
The R function presented below returns:
the probability of victory of Nadal over Federer or Djokovic on both surfaces
the p-value of the T-test of the previous section conducted on both surfaces separately
Nadal_study <- function(df){
list_surfaces = c("Clay","Hard");
pvals = list();
probasNadalvictory = data.frame(matrix(ncol=length(list_surfaces),nrow=2));
colnames(probasNadalvictory) <- list_surfaces;
rownames(probasNadalvictory) <- c('Federer R.', 'Djokovic N.');
for (surface in list_surfaces){
FvsNsurface = ('Federer R.' == df$Winner[(df$Winner %in% big3[-3]) & (df$Loser %in% big3[-3]) & (df$Surface == surface)]);
NvsDsurface = ('Nadal R.' == df$Winner[(df$Winner %in% big3[-1]) & (df$Loser %in% big3[-1]) & (df$Surface == surface)]);
resZtest <- computeAsymptoticZstat(1-FvsNsurface,NvsDsurface);
pvals = append(pvals, resZtest$pval);
probasNadalvictory['Federer R.',surface] <- mean(1-FvsNsurface);
probasNadalvictory['Djokovic N.',surface] <- mean(NvsDsurface);
}
names(pvals) <- list_surfaces;
return (list(pvals=pvals,probasvictory=probasNadalvictory));
}
Nadal_res <- Nadal_study(data);
Nadal_res$pvals
## $Clay
## [1] 0.1466762
##
## $Hard
## [1] 0.04550026
## Clay Hard
## Federer R. 0.8666667 0.5625
## Djokovic N. 0.6500000 0.2500
With a p-value=0.15 for Clay, we conclude that the difference between the probabilities of victory of Nadal against Federer or Djokovic are not statistically different (Nadal is known to be the King of Clay ;) Hence he often comes out with a victory on this surface regardless of the opponent).
However, on Hard courts the p-value is 0.045 and we can conclude that Nadal has greater chances to win against Federer rather than Djokovic.
Studying Nadal matches over time
Based on the previous section, we will still consider separately the different surfaces: Clay and Hard courts. We do the same tests as previously but focusing on matches played before 2010 or after 2010.
a) Before 2010
dates <- apply(select(data, Date), 1, function(x){ as.integer(substr(x,nchar(x)-3,nchar(x)));});
Nadal_res <- Nadal_study(data[dates <= 2010,]);
Nadal_res$pvals
## $Clay
## [1] 0.2235429
##
## $Hard
## [1] 0.7829351
## Clay Hard
## Federer R. 0.8333333 0.4285714
## Djokovic N. 1.0000000 0.3636364
We do not reject the null hypothesis for both Clay and Hard courts working with matches played before 2010. Hence, for matches played before 2010, the difference in probability of victory of Nadal over Federer or Djokovic is not statistically significant.
b) After 2010
Nadal_res <- Nadal_study(data[dates > 2010,]);
Nadal_res$pvals
## $Clay
## [1] 0.07007554
##
## $Hard
## [1] 0.01395398
## Clay Hard
## Federer R. 1.0000000 0.6666667
## Djokovic N. 0.4166667 0.1538462
Contrary to the previous paragraph, we again reach the conclusion that Nadal has significantly more chances to win over Federer than Djokovic on Hard courts if we focus only on matches played after 2010. Moreover, the p-value on Clay for matches played after 2010 is equal to 0.07, which is smaller compared to the previous section. If this result may be too weak to reject the null with conviction, it could lead us to think that the older Nadal was getting, the better it is for him to face Federer rather than Djokovic (regardless of the surface).
Conclusion
A distracted reader could think that the main reason explaining the results of this study is the age of Federer. One could easily think that after 2010, Federer was still a high level player but found difficulties to compete with the other members of the BIG 3.
But if it was the case, we should also find a difference between the probability of victory of Djokovic over Nadal or Federer for matches after 2010, which is not the case has shown below.
Djokovic_study <- function(df){
list_surfaces = c("Clay","Hard");
pvals = list();
probasDjokovicvictory = data.frame(matrix(ncol=length(list_surfaces),nrow=2));
colnames(probasDjokovicvictory) <- list_surfaces;
rownames(probasDjokovicvictory) <- c('Federer R.', 'Nadal R.');
for (surface in list_surfaces){
DvsNsurface = ('Djokovic N.' == df$Winner[(df$Winner %in% big3[-1]) & (df$Loser %in% big3[-1]) & (df$Surface == surface)]);
DvsFsurface = ('Djokovic N.' == df$Winner[(df$Winner %in% big3[-2]) & (df$Loser %in% big3[-2]) & (df$Surface == surface)]);
resZtest <- computeAsymptoticZstat(DvsNsurface,DvsFsurface);
pvals = append(pvals, resZtest$pval);
probasDjokovicvictory['Federer R.',surface] <- mean(DvsFsurface);
probasDjokovicvictory['Nadal R.',surface] <- mean(DvsNsurface);
}
names(pvals) <- list_surfaces;
return (list(pvals=pvals,probasvictory=probasDjokovicvictory));
}
Djokovic_res <- Djokovic_study(data[dates > 2010,]);
Djokovic_res$pvals
## $Clay
## [1] 0.9492721
##
## $Hard
## [1] 0.2987821
Hence saying that Federer level decayed after 2010 would be a hasty conclusion.
From my personal point of view (and as a tennis fan), the fact that Nadal had better chances to win against Federer rather than against Djokovic was mainly due to a psychological ascendant he hed on the Swiss. But everyone will make his own opinion !
LS0tDQp0aXRsZTogIlR3byBzYW1wbGUgaG9tb2dlbmVpdHkgdGVzdHM6IHRlbm5pcyBkYXRhc2V0Ig0Kb3V0cHV0Og0KICAgIGh0bWxfZG9jdW1lbnQ6DQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIA0KICAgICAgdGhlbWU6IGNvc21vDQogICAgICB0b2M6IHRydWUNCiAgICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQotLS0NCg0KVG8gZ28gYmFjayB0byB0aGUgSG9tZSBwYWdlLCBjbGljayBbaGVyZV0oaHR0cHM6Ly9xdWVudGluLWR1Y2hlbWluLmdpdGh1Yi5pby9FTlBDLVNEQS8pLg0KDQo8YnI+PC9icj4NCg0KDQojIERhdGEgRGVzY3JpcHRpb24NCg0KVGhlIGRhdGFzZXQgY29udGFpbnMgdGhlIHJlc3VsdHMgZm9yIHRoZSBtZW4ncyBBVFAgdG91ciBkYXRlIGJhY2sgdG8gSmFudWFyeSAyMDAwLCBpbmNsdWRpbmcgR3JhbmQgU2xhbXMsIE1hc3RlcnMgU2VyaWVzLCBNYXN0ZXJzIEN1cCBhbmQgSW50ZXJuYXRpb25hbCBTZXJpZXMgY29tcGV0aXRpb25zLiBBbGwgaGVhZCB0byBoZWFkIG1hdGNoZXMgYXJlIHByb3ZpZGVkIHdpdGggcmFuayBvZiBib3RoIG9wcG9uZW50cywgdGhlIG5hbWUgb2YgdGhlIHdpbm5lciwgYW5kIHRoZSBmaW5hbCBzY29yZS4gQSBtb3JlIGRldGFpbGxlZCBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YSBjYW4gYmUgZm91bmQgW2hlcmVdKCcuLi8uLi9kYXRhL21ldGFkYXRhL3Rlbm5pcy50eHQnKS4NCg0KVGhlIGRhdGEgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2pvcmRhbmdvYmxldC9hdHAtdG91ci0yMDAwMjAxNi92ZXJzaW9uLzI/c2VsZWN0PURhdGEuY3N2KS4NCg0KDQo8YnI+PC9icj4NCg0KSW4gdGhpcyBub3RlYm9vaywgd2Ugd2lsbCBvbmx5IGJlIGZvY3VzZWQgb24gdGhlIHNvLWNhbGxlZCBCSUcgMyB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSB0aHJlZSBiZXN0IHRlbm5pcyBwbGF5ZXJzIG92ZXIgdGhlIGxhc3QgMjAgeWVhcnMsIG5hbWVseSBSb2dlciBGZWRlcmVyLCBSYWZhZWwgTmFkYWwgYW5kIE5vdmFrIERqb2tvdmljLiANCg0KPGJyPjwvYnI+DQoNCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeSgndGlkeXZlcnNlJykNCmxpYnJhcnkoImxhdHRpY2UiKQ0KbGlicmFyeSgnZ2dwbG90MicpDQpkYXRhIDwtIHJlYWRfY3N2KCIuLi8uLi9kYXRhL3Rlbm5pcy5jc3YiKTsNCmBgYA0KDQojIFN0dWR5IG9mIGhlYWQgdG8gaGVhZCBpbiB0aGUgQklHIDMNCg0KUGxheWVycyBpbiB0aGUgQklHIDMgaGF2ZSByZWFsbHkgZGlmZmVyZW50IGdhbWUgc3R5bGVzLiBJbiB0aGlzIGZpcnN0IHNlY3Rpb24sIHdlIHdhbnQgdG8gdGVzdCBmb3IgZWFjaCBtZW1iZXIgb2YgdGhlIEJJRyAzIGlmIGhlIGhhcyB0aGUgc2FtZSBjaGFuY2VzIHRvIHdpbiBhZ2FpbnN0IG9uZSBvciB0aGUgb3RoZXIgb2YgaXRzIGdyZWF0ZXN0IHJpdmFscy4NCg0KYGBge3J9DQojIFNlbGVjdGluZyBIZWFkIHRvIEhlYWQgbWF0Y2hlcw0KYmlnMyA9ICBjKCdGZWRlcmVyIFIuJywnTmFkYWwgUi4nLCAnRGpva292aWMgTi4nKQ0KRnZzTiA9ICgnRmVkZXJlciBSLicgPT0gZGF0YSRXaW5uZXJbKGRhdGEkV2lubmVyICVpbiUgYmlnM1stM10pICYgKGRhdGEkTG9zZXIgJWluJSBiaWczWy0zXSldKTsNCkZ2c0QgPSAoJ0ZlZGVyZXIgUi4nID09IGRhdGEkV2lubmVyWyhkYXRhJFdpbm5lciAlaW4lIGJpZzNbLTJdKSAmIChkYXRhJExvc2VyICVpbiUgYmlnM1stMl0pXSk7DQpOdnNEID0gKCdOYWRhbCBSLicgPT0gZGF0YSRXaW5uZXJbKGRhdGEkV2lubmVyICVpbiUgYmlnM1stMV0pICYgKGRhdGEkTG9zZXIgJWluJSBiaWczWy0xXSldKTsNCmBgYA0KDQoNCldlIHdpbGwgdXNlIGEgWi1UZXN0IHRvIGNhcnJ5IG91dCBvdXIgc3R1ZHkuIA0KDQoNCiMjIFBvd2VyIGNvbXBhcmlzb24gYmV0d2VlbiB0aGUgYXN5bXB0b3RpYyBaLXRlc3QgYW5kIHRoZSBleGFjdCBGaXNoZXIgdGVzdA0KDQpUaGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBjb21wdXRlIHRoZSBwLXZhbHVlcyByZXN1bHRpbmcgZnJvbSB0aGUgRmlzaGVyIFRlc3QgYW5kIHRoZSBhc3ltcHRvdGljIFotdGVzdC4gDQoNCmBgYHtyfQ0KIyBFeGFjdCBGaXNoZXIgVGVzdA0KRmlzaGVyVGVzdFN0YXQgPC0gZnVuY3Rpb24gKHNlcTEsc2VxMil7DQogIGNvbnRpbmdlbmN5ID0gbWF0cml4KG5jb2w9Mixucm93PTIpOw0KICBjb250aW5nZW5jeVsxLDFdID0gc3VtKHNlcTEpOw0KICBjb250aW5nZW5jeVsyLDFdID0gbGVuZ3RoKHNlcTEpLWNvbnRpbmdlbmN5WzEsMV07DQogIGNvbnRpbmdlbmN5WzEsMl0gPSBzdW0oc2VxMik7DQogIGNvbnRpbmdlbmN5WzIsMl0gPSBsZW5ndGgoc2VxMiktY29udGluZ2VuY3lbMSwyXTsNCiAgWnN0YXQgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3kpOw0KICByZXR1cm4gKFpzdGF0JHAudmFsdWUpOw0KfQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBUUlVFfSANCiMgQXN5bXB0b3RpYyBaLVRlc3QNCmNvbXB1dGVBc3ltcHRvdGljWnN0YXQgPC0gZnVuY3Rpb24gKHNlcTEsc2VxMikgew0KICBuMSA9IGxlbmd0aChzZXExKTsNCiAgbjIgPSBsZW5ndGgoc2VxMik7DQogIGJhcjEgPSBtZWFuKHNlcTEpOw0KICBiYXIyID0gbWVhbihzZXEyKTsNCiAgYmFyID0gKHN1bShzZXExKStzdW0oc2VxMikpLyhuMStuMik7DQogIFpzdGF0ID0gc3FydChuMSpuMi8objErbjIpKSooYmFyMS1iYXIyKS9zcXJ0KGJhciooMS1iYXIpKTsNCiAgcHZhbHVlID0gMipwbm9ybSgtYWJzKFpzdGF0KSxtZWFuPTAsc2Q9MSk7DQogIHJldHVybiAoZGF0YS5mcmFtZShzdGF0PVpzdGF0LCBwdmFsPXB2YWx1ZSkpOw0KfQ0KYGBgDQoNCg0KSW4gb3VyIGNhc2UsIHdlIHdpbGwgZGVhbCB3aXRoIHNhbXBsZSBzaXplcyBhcm91bmQgNDAuIFdlIHByb3Bvc2UgdG8gc3R1ZHkgdGhlIHBvd2VyIG9mIGJvdGggdGVzdHMgZm9yIHNhbXBsZSBzaXplIG9mIHRoaXMgb3JkZXIuDQoNCkxldCB1cyBmaXJzdCBjaGVjayB0aGF0IHRoZSBhYm92ZSBmdW5jdGlvbnMgYXJlIHdvcmtpbmcgY29ycmVjdGx5IGJ5IHBsb3R0aW5nIHRoZSBwcm9wb3J0aW9uIG9mIFR5cGUgSSBlcnJvcnMgZm9yIHRlc3RzIHdpdGggbGV2ZWwgMC4wNS4NCg0KDQpgYGB7cn0NCiMgUHJvcG9ydGlvbiBvZiBUeXBlIEkgZXJyb3IgZm9yIGJvdGggdGVzdHMgZGVwZW5kaW5nIG9uIHRoZSBzYW1wbGUgc2l6ZSAodXNpbmcgYSBsZXZlbCA9IDAuMDUpDQpsZXZlbCA9IDAuMDU7DQppID0gMTsNCmxpc3RfbiA8LSBzZXEoMjAsMjAwLGJ5PTEwKTsNCmZpc2hlciA8LSByZXAoMCxsZW5ndGgobGlzdF9uKSk7DQoNCmFzeW1wdG90aWNadGVzdCA8LSByZXAoMCxsZW5ndGgobGlzdF9uKSk7DQpmb3IgKG4gaW4gbGlzdF9uKXsNCiAgZm9yIChrIGluIDE6MTAwMCl7DQogICAgICBzZXExID0gcmJpbm9tKG4sMSwwLjUpOw0KICAgICAgc2VxMiA9IHJiaW5vbShuLDEsMC41KTsNCiAgICAgIGFzeW1wdG90aWNadGVzdFtpXSA9IGFzeW1wdG90aWNadGVzdFtpXSArIDEqKGNvbXB1dGVBc3ltcHRvdGljWnN0YXQoc2VxMSxzZXEyKSRwdmFsIDwgbGV2ZWwpLzEwMDA7DQogICAgICBmaXNoZXJbaV0gPSBmaXNoZXJbaV0gKyAxKihGaXNoZXJUZXN0U3RhdChzZXExLHNlcTIpIDwgbGV2ZWwpLzEwMDA7DQogICAgfQ0KICBpID0gaSsxOw0KfQ0KZXJyb3JzdHlwZTEgPC0gZGF0YS5mcmFtZShsaXN0X24sZmlzaGVyLGFzeW1wdG90aWNadGVzdCk7DQpnZ3Bsb3QoZXJyb3JzdHlwZTEsIGFlcyhsaXN0X24pKSArICAgICAgICAgICAgICAgICAgICAjIGJhc2ljIGdyYXBoaWNhbCBvYmplY3QNCiAgZ2VvbV9saW5lKGFlcyh5PWZpc2hlciwgIGNvbG91cj0iRmlzaGVyIHRlc3QiKSkgKyAgIyBmaXJzdCBsYXllcg0KICBnZW9tX2xpbmUoYWVzKHk9YXN5bXB0b3RpY1p0ZXN0LCAgY29sb3VyID0gIkFzeW1wdG90aWMgWiB0ZXN0IikpICsgIyBzZWNvbmQgbGF5ZXINCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiIiwgdmFsdWVzID0gYygiQXN5bXB0b3RpYyBaIHRlc3QiID0gImdyZWVuIiwgIkZpc2hlciB0ZXN0IiA9ICJyZWQiKSkgKw0KICBsYWJzKHggPSAiU2FtcGxlIHNpemUiKSArDQogIGxhYnMoeSA9ICJQcm9wb3J0aW9uIG9mIFR5cGUgSSBlcnJvciIpDQoNCmBgYA0KDQpBcyB0aGVvcmV0aWNhbGx5IGd1YXJhbnRlZWQsIHRoZSBGaXNoZXIgbGVhZHMgdG8gYSBwcm9wb3J0aW9uIG9mIFR5cGUgSSBlcnJvcnMgc21hbGxlciB0aGFuIDAuMDUuIEluZGVlZCwgaXQgaXMgdGhlIG9wcG9ydHVuaXR5IHRvIHJlY2FsbCB0aGF0IEZpc2hlciB0ZXN0IG9ubHkgcHJvdmlkZXMgYW4gdXBwZXIgYm91bmQgb24gdGhlIGxldmVsIG9mIHRoZSB0ZXN0LiANCg0KUmVnYXJkaW5nIHRoZSBhc3ltcHRvdGljIFotdGVzdCwgdGhlIHByb3BvcnRpb24gb2YgVHlwZSBJIGVycm9ycyBpcyBhcm91bmQgMC4wNSBidXQgbWF5IHNsaWdodGx5IGFib3ZlIG9yIGJlbG93IHRoaXMgdmFsdWUgZHVlIHRvIHJhbmRvbW5lc3MgYnV0IGFsc28gZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlIHRoZW9yZXRpY2FsIGNvbnRyb2wgb2YgdGhlIGxldmVsIG9mIHRoZSB0ZXN0IGhvbGRzIG9ubHkgYXN5bXB0b3RpY2FsbHkuDQoNCkxldCB1cyBub3cgZGlnIGludG8gdGhlIHBvd2VyIHN0dWR5LiBXZSBjb25zaWRlciB0d28gc2VxdWVuY2VzIG9mIEJlcm5vdWxsaSByYW5kb20gdmFyaWFibGVzIHdpdGggcmVzcGVjdGl2ZSBwYXJhbWV0ZXJzIHAxIGFuZCBwMiB3aXRoIDAuNS1wMT1wMi0wLjUuDQoNCmBgYHtyfQ0KbGV2ZWwgPSAwLjA1Ow0KbGlzdF9uID0gc2VxKDEwLDEwMCxieT0xMCk7DQpsaXN0X2dhcHMgPSBzZXEoMC4sMC4yLGJ5PTAuMDIpOw0KcG93ZXJfYXN5bXB0b3RpY1p0ZXN0ID0gbWF0cml4KDAsbmNvbD1sZW5ndGgobGlzdF9uKSxucm93PWxlbmd0aChsaXN0X2dhcHMpKTsNCnBvd2VyX2Zpc2hlciA9IG1hdHJpeCgwLG5jb2w9bGVuZ3RoKGxpc3RfbiksbnJvdz1sZW5ndGgobGlzdF9nYXBzKSk7DQppID0gMTsNCmZvciAobiBpbiBsaXN0X24pew0KICBqID0gMTsNCiAgZm9yIChnYXAgaW4gbGlzdF9nYXBzKXsNCiAgICBwMSA9IDAuNS1nYXA7DQogICAgcDIgPSAwLjUrZ2FwOw0KICAgIGZvciAoayBpbiAxOjMwMCl7DQogICAgICBzZXExID0gcmJpbm9tKG4sMSxwMSk7DQogICAgICBzZXEyID0gcmJpbm9tKG4sMSxwMik7DQogICAgICANCiAgICAgIHBvd2VyX2FzeW1wdG90aWNadGVzdFtqLGldID0gcG93ZXJfYXN5bXB0b3RpY1p0ZXN0W2osaV0gKyAxKihjb21wdXRlQXN5bXB0b3RpY1pzdGF0KHNlcTEsc2VxMikkcHZhbCA8IGxldmVsKS8zMDA7DQogICAgICBwb3dlcl9maXNoZXJbaixpXSA9IHBvd2VyX2Zpc2hlcltqLGldICsgMSooRmlzaGVyVGVzdFN0YXQoc2VxMSxzZXEyKSA8IGxldmVsKS8zMDA7DQogICAgfQ0KICAgIGogPSBqKzE7DQogIH0NCiAgaSA9IGkrMTsNCn0NCmBgYA0KDQpgYGB7cn0NCmhlYXRtYXAgPC0gZXhwYW5kLmdyaWQoWD1saXN0X2dhcHMsIFk9bGlzdF9uKTsNCmhlYXRtYXAkWiA8LSBjKHBvd2VyX2FzeW1wdG90aWNadGVzdCAtIHBvd2VyX2Zpc2hlcik7DQoNCiMjIFRyeSBpdCBvdXQNCmxldmVscGxvdChaIH4gWCpZLCBkYXRhPWhlYXRtYXAgICx4bGFiPSJwMi1wMSIsIHlsYWI9Ik51bWJlciBvZiBzYW1wbGVzOiBuIiwNCiAgICAgICAgICBtYWluPSJQb3dlcihBc3ltcHRvdGljIFogdGVzdCkgLSBQb3dlcihGaXNoZXIgVGVzdCkiKQ0KYGBgDQoNClRoZSBoZWF0bWFwIHNob3dzIHRoYXQgdGhlIHBvd2VyIG9mIGFzeW1wdG90aWMgWiB0ZXN0IGlzIGdyZWF0ZXIgdGhhbiB0aGUgb25lIG9mIHRoZSBGaXNoZXIgdGVzdCBpbiB0aGUgcmFuZ2Ugb2Ygc2FtcGxlIHNpemUgb2YgaW50ZXJlc3QuIEhlbmNlLCBpbiB0aGUgZm9sbG93aW5nLCB3ZSB3aWxsIHVzZSB0aGUgYXN5bXB0b3RpYyBaIHRlc3QuDQoNCg0KIyMgU3R1ZHkgZm9yIEZlZGVyZXINCg0KYGBge3J9DQojIFdlIGNvbXB1dGUgdGhlIHAtdmFsdWUgb2YgdGhlIFQtVGVzdCBmb3IgRmVkZXJlcg0KcmVzWnRlc3QgPC0gY29tcHV0ZUFzeW1wdG90aWNac3RhdChGdnNOLEZ2c0QpOw0KcmVzWnRlc3QkcHZhbA0KYGBgDQoNClRoZSBwLXZhbHVlIGlzIGVxdWFsIHRvIDAuMiBtZWFuaW5nIHRoYXQgd2UgZG8gbm90IHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiBIZW5jZSwgdGhlIHByb2JhYmlsaXR5IG9mIHZpY3Rvcnkgb2YgRmVkZXJlciBvdmVyIE5hZGFsIGlzIG5vdCBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCBmcm9tIHRoZSBvbmUgb2YgRmVkZXJlciBvdmVyIERqb2tvdmljLg0KDQojIyBTdHVkeSBmb3IgTmFkYWwNCg0KYGBge3J9DQojIFdlIGNvbXB1dGUgdGhlIHAtdmFsdWUgb2YgdGhlIFQtVGVzdCBmb3IgTmFkYWwNCnJlc1p0ZXN0IDwtIGNvbXB1dGVBc3ltcHRvdGljWnN0YXQoMS1GdnNOLE52c0QpOw0KcmVzWnRlc3QkcHZhbDsNCmBgYA0KVGhlIHAtdmFsdWUgaXMgZXF1YWwgdG8gMC4wNCBtZWFuaW5nIHRoYXQgd2Ugd291bGQgdGVuZCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gSGVuY2UsIHRoZSBwcm9iYWJpbGl0eSBvZiB2aWN0b3J5IG9mIE5hZGFsIG92ZXIgRmVkZXJlciBpcyBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCAoaW4gdGhpcyBjYXNlOiBsYXJnZXIpIGZyb20gdGhlIG9uZSBvZiBOYWRhbCBvdmVyIERqb2tvdmljLg0KDQojIyBTdHVkeSBmb3IgRGpva292aWMNCg0KYGBge3J9DQojIFdlIGNvbXB1dGUgdGhlIHAtdmFsdWUgb2YgdGhlIFQtVGVzdCBmb3IgRGpva292aWMNCnJlc1p0ZXN0IDwtIGNvbXB1dGVBc3ltcHRvdGljWnN0YXQoMS1GdnNELDEtTnZzRCk7DQpyZXNadGVzdCRwdmFsOw0KYGBgDQpUaGUgcC12YWx1ZSBpcyBlcXVhbCB0byAwLjg1IG1lYW5pbmcgdGhhdCB3ZSBkbyBub3QgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuIEhlbmNlLCB0aGUgcHJvYmFiaWxpdHkgb2YgdmljdG9yeSBvZiBEam9rb3ZpYyBvdmVyIEZlZGVyZXIgaXMgbm90IHN0YXRpc3RpY2FsbHkgZGlmZmVyZW50IGZyb20gdGhlIG9uZSBvZiBEam9rb3ZpYyBvdmVyIE5hZGFsLg0KDQoqQ29uY2x1c2lvbioNCldoaWxlIE5hZGFsIGFuZCBEam9rb3ZpYyBoYXZlIGEgcHJvYmFiaWxpdHkgb2YgdmljdG9yeSBhZ2FpbnN0IHRoZSBvdGhlciBtZW1iZXJzIG9mIHRoZSBCaWcgMyB0aGF0IGRvZXMgbm90IGRlcGVuZCBvbiB0aGUgb3Bwb25lbnQsIHdlIHNob3dlZCB0aGF0IE5hZGFsIGhhcyBzaWduaWZpY2FudGx5IGxlc3MgY2hhbmNlIG9mIHdpbm5pbmcgYWdhaW5zdCBEam9rb3ZpYyB0aGFuIGFnYWluc3QgRmVkZXJlci4NCg0KPGJyPiA8L2JyPg0KDQpOb3cgd2Ugd2FudCB0byB1bmRlcnN0YW5kIHdoeSBOYWRhbCBwZXJmb3JtcyBiZXR0ZXIgd2hlbiBmYWNpbmcgRmVkZXJlciB0aGFuIERqb2tvdmljLiBJbiB0aGUgZm9sbG93aW5nLCB3ZSB3aWxsIGJlIGZvY3VzZWQgb24gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuDQoNCjEuIERvZXMgdGhpcyBmYWN0IGhvbGRzIGZvciBldmVyeSBzdXJmYWNlcz8NCg0KMi4gV2FzIGl0IHRydWUgZHVyaW5nIHRoZSB3aG9sZSBOYWRhbCdzIGNhcmVlcj8NCg0KV2UgZmlyc3QgaW52ZXN0aWdhdGUgdGhlIGluZmx1ZW5jZSBvZiB0aGUgc3VyZmFjZS4NCg0KIyBJbmZsdWVuY2Ugb2YgdGhlIFN1cmZhY2UNCg0KV2UgdGFrZSBhIGNsb3NlciBsb29rIHRvIG1hdGNoZXMgYmV0d2VlbiBOYWRhbCBhbmQgdGhvIG90aGVycyBtZW1iZXJzIG9mIHRoZSBCSUcgMyBkZXBlbmRpbmcgb24gdGhlIGRpZmZlcmVudCBzdXJmYWNlcy4gV2Ugb25seSBmb2N1cyBvbiBDbGF5IGFuZCBIYXJkIENvdXJ0IHNpbmNlIHdlIGRvIG5vdCBoYXZlIGVub3VnaCBkYXRhIGZvciBDYXJwZXQgYW5kIEdyYXNzLg0KDQpUaGUgUiBmdW5jdGlvbiBwcmVzZW50ZWQgYmVsb3cgcmV0dXJuczoNCg0KICAgMS4gdGhlIHByb2JhYmlsaXR5IG9mIHZpY3Rvcnkgb2YgTmFkYWwgb3ZlciBGZWRlcmVyIG9yIERqb2tvdmljIG9uIGJvdGggc3VyZmFjZXMNCg0KICAgMi4gdGhlIHAtdmFsdWUgb2YgdGhlIFQtdGVzdCBvZiB0aGUgcHJldmlvdXMgc2VjdGlvbiBjb25kdWN0ZWQgb24gYm90aCBzdXJmYWNlcyBzZXBhcmF0ZWx5DQoNCmBgYHtyfQ0KTmFkYWxfc3R1ZHkgPC0gZnVuY3Rpb24oZGYpew0KICAgIGxpc3Rfc3VyZmFjZXMgPSBjKCJDbGF5IiwiSGFyZCIpOw0KICAgIHB2YWxzID0gbGlzdCgpOw0KICAgIHByb2Jhc05hZGFsdmljdG9yeSA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bGVuZ3RoKGxpc3Rfc3VyZmFjZXMpLG5yb3c9MikpOw0KICAgIGNvbG5hbWVzKHByb2Jhc05hZGFsdmljdG9yeSkgPC0gbGlzdF9zdXJmYWNlczsNCiAgICByb3duYW1lcyhwcm9iYXNOYWRhbHZpY3RvcnkpIDwtIGMoJ0ZlZGVyZXIgUi4nLCAnRGpva292aWMgTi4nKTsNCiAgICBmb3IgKHN1cmZhY2UgaW4gbGlzdF9zdXJmYWNlcyl7DQogICAgICBGdnNOc3VyZmFjZSA9ICgnRmVkZXJlciBSLicgPT0gZGYkV2lubmVyWyhkZiRXaW5uZXIgJWluJSBiaWczWy0zXSkgJiAoZGYkTG9zZXIgJWluJSBiaWczWy0zXSkgJiAoZGYkU3VyZmFjZSA9PSBzdXJmYWNlKV0pOw0KICAgICAgTnZzRHN1cmZhY2UgPSAoJ05hZGFsIFIuJyA9PSBkZiRXaW5uZXJbKGRmJFdpbm5lciAlaW4lIGJpZzNbLTFdKSAmIChkZiRMb3NlciAlaW4lIGJpZzNbLTFdKSAmIChkZiRTdXJmYWNlID09IHN1cmZhY2UpXSk7DQogICAgICByZXNadGVzdCA8LSBjb21wdXRlQXN5bXB0b3RpY1pzdGF0KDEtRnZzTnN1cmZhY2UsTnZzRHN1cmZhY2UpOw0KICAgICAgcHZhbHMgPSBhcHBlbmQocHZhbHMsIHJlc1p0ZXN0JHB2YWwpOw0KICAgICAgcHJvYmFzTmFkYWx2aWN0b3J5WydGZWRlcmVyIFIuJyxzdXJmYWNlXSA8LSBtZWFuKDEtRnZzTnN1cmZhY2UpOw0KICAgICAgcHJvYmFzTmFkYWx2aWN0b3J5WydEam9rb3ZpYyBOLicsc3VyZmFjZV0gPC0gbWVhbihOdnNEc3VyZmFjZSk7DQogICAgfQ0KICAgIG5hbWVzKHB2YWxzKSA8LSBsaXN0X3N1cmZhY2VzOw0KICAgIHJldHVybiAobGlzdChwdmFscz1wdmFscyxwcm9iYXN2aWN0b3J5PXByb2Jhc05hZGFsdmljdG9yeSkpOw0KfQ0KYGBgDQoNCg0KYGBge3J9DQpOYWRhbF9yZXMgPC0gTmFkYWxfc3R1ZHkoZGF0YSk7DQpOYWRhbF9yZXMkcHZhbHMNCk5hZGFsX3JlcyRwcm9iYXN2aWN0b3J5DQpgYGANCg0KDQpXaXRoIGEgcC12YWx1ZT0wLjE1IGZvciBDbGF5LCB3ZSBjb25jbHVkZSB0aGF0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHByb2JhYmlsaXRpZXMgb2YgdmljdG9yeSBvZiBOYWRhbCBhZ2FpbnN0IEZlZGVyZXIgb3IgRGpva292aWMgYXJlIG5vdCBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCAoTmFkYWwgaXMga25vd24gdG8gYmUgdGhlIEtpbmcgb2YgQ2xheSA7KSBIZW5jZSBoZSBvZnRlbiBjb21lcyBvdXQgd2l0aCBhIHZpY3Rvcnkgb24gdGhpcyBzdXJmYWNlIHJlZ2FyZGxlc3Mgb2YgdGhlIG9wcG9uZW50KS4NCg0KSG93ZXZlciwgb24gSGFyZCBjb3VydHMgdGhlIHAtdmFsdWUgaXMgMC4wNDUgYW5kIHdlIGNhbiBjb25jbHVkZSB0aGF0IE5hZGFsIGhhcyBncmVhdGVyIGNoYW5jZXMgdG8gd2luIGFnYWluc3QgRmVkZXJlciByYXRoZXIgdGhhbiBEam9rb3ZpYy4NCg0KDQojIFN0dWR5aW5nIE5hZGFsIG1hdGNoZXMgb3ZlciB0aW1lDQoNCkJhc2VkIG9uIHRoZSBwcmV2aW91cyBzZWN0aW9uLCB3ZSB3aWxsIHN0aWxsIGNvbnNpZGVyIHNlcGFyYXRlbHkgdGhlIGRpZmZlcmVudCBzdXJmYWNlczogQ2xheSBhbmQgSGFyZCBjb3VydHMuIFdlIGRvIHRoZSBzYW1lIHRlc3RzIGFzIHByZXZpb3VzbHkgYnV0IGZvY3VzaW5nIG9uIG1hdGNoZXMgcGxheWVkIGJlZm9yZSAyMDEwIG9yIGFmdGVyIDIwMTAuDQoNCg0KIyMgYSkgQmVmb3JlIDIwMTANCg0KYGBge3J9DQpkYXRlcyA8LSBhcHBseShzZWxlY3QoZGF0YSwgRGF0ZSksIDEsIGZ1bmN0aW9uKHgpeyBhcy5pbnRlZ2VyKHN1YnN0cih4LG5jaGFyKHgpLTMsbmNoYXIoeCkpKTt9KTsNCk5hZGFsX3JlcyA8LSBOYWRhbF9zdHVkeShkYXRhW2RhdGVzIDw9IDIwMTAsXSk7DQpOYWRhbF9yZXMkcHZhbHMNCk5hZGFsX3JlcyRwcm9iYXN2aWN0b3J5DQpgYGANCldlIGRvIG5vdCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBmb3IgYm90aCBDbGF5IGFuZCBIYXJkIGNvdXJ0cyB3b3JraW5nIHdpdGggbWF0Y2hlcyBwbGF5ZWQgYmVmb3JlIDIwMTAuIEhlbmNlLCBmb3IgbWF0Y2hlcyBwbGF5ZWQgYmVmb3JlIDIwMTAsIHRoZSBkaWZmZXJlbmNlIGluIHByb2JhYmlsaXR5IG9mIHZpY3Rvcnkgb2YgTmFkYWwgb3ZlciBGZWRlcmVyIG9yIERqb2tvdmljIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50Lg0KDQojIyBiKSBBZnRlciAyMDEwDQpgYGB7cn0NCk5hZGFsX3JlcyA8LSBOYWRhbF9zdHVkeShkYXRhW2RhdGVzID4gMjAxMCxdKTsNCk5hZGFsX3JlcyRwdmFscw0KTmFkYWxfcmVzJHByb2Jhc3ZpY3RvcnkNCmBgYA0KDQpDb250cmFyeSB0byB0aGUgcHJldmlvdXMgcGFyYWdyYXBoLCB3ZSBhZ2FpbiByZWFjaCB0aGUgY29uY2x1c2lvbiB0aGF0IE5hZGFsIGhhcyBzaWduaWZpY2FudGx5IG1vcmUgY2hhbmNlcyB0byB3aW4gb3ZlciBGZWRlcmVyIHRoYW4gRGpva292aWMgb24gSGFyZCBjb3VydHMgaWYgd2UgZm9jdXMgb25seSBvbiBtYXRjaGVzIHBsYXllZCBhZnRlciAyMDEwLiBNb3Jlb3ZlciwgdGhlIHAtdmFsdWUgb24gQ2xheSBmb3IgbWF0Y2hlcyBwbGF5ZWQgYWZ0ZXIgMjAxMCBpcyBlcXVhbCB0byAwLjA3LCB3aGljaCBpcyBzbWFsbGVyIGNvbXBhcmVkIHRvIHRoZSBwcmV2aW91cyBzZWN0aW9uLiBJZiB0aGlzIHJlc3VsdCBtYXkgYmUgdG9vIHdlYWsgdG8gcmVqZWN0IHRoZSBudWxsIHdpdGggY29udmljdGlvbiwgaXQgY291bGQgbGVhZCB1cyB0byB0aGluayB0aGF0IHRoZSBvbGRlciBOYWRhbCB3YXMgZ2V0dGluZywgdGhlIGJldHRlciBpdCBpcyBmb3IgaGltIHRvIGZhY2UgRmVkZXJlciByYXRoZXIgdGhhbiBEam9rb3ZpYyAocmVnYXJkbGVzcyBvZiB0aGUgc3VyZmFjZSkuDQoNCjxicj4gPC9icj4NCg0KIyBDb25jbHVzaW9uDQoNCkEgZGlzdHJhY3RlZCByZWFkZXIgY291bGQgdGhpbmsgdGhhdCB0aGUgbWFpbiByZWFzb24gZXhwbGFpbmluZyB0aGUgcmVzdWx0cyBvZiB0aGlzIHN0dWR5IGlzIHRoZSBhZ2Ugb2YgRmVkZXJlci4gT25lIGNvdWxkIGVhc2lseSB0aGluayB0aGF0IGFmdGVyIDIwMTAsIEZlZGVyZXIgd2FzIHN0aWxsIGEgaGlnaCBsZXZlbCBwbGF5ZXIgYnV0IGZvdW5kIGRpZmZpY3VsdGllcyB0byBjb21wZXRlIHdpdGggdGhlIG90aGVyIG1lbWJlcnMgb2YgdGhlIEJJRyAzLg0KDQpCdXQgaWYgaXQgd2FzIHRoZSBjYXNlLCB3ZSBzaG91bGQgYWxzbyBmaW5kIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcm9iYWJpbGl0eSBvZiB2aWN0b3J5IG9mIERqb2tvdmljIG92ZXIgTmFkYWwgb3IgRmVkZXJlciBmb3IgbWF0Y2hlcyBhZnRlciAyMDEwLCB3aGljaCBpcyBub3QgdGhlIGNhc2UgaGFzIHNob3duIGJlbG93Lg0KDQpgYGB7cn0NCkRqb2tvdmljX3N0dWR5IDwtIGZ1bmN0aW9uKGRmKXsNCiAgICBsaXN0X3N1cmZhY2VzID0gYygiQ2xheSIsIkhhcmQiKTsNCiAgICBwdmFscyA9IGxpc3QoKTsNCiAgICBwcm9iYXNEam9rb3ZpY3ZpY3RvcnkgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPWxlbmd0aChsaXN0X3N1cmZhY2VzKSxucm93PTIpKTsNCiAgICBjb2xuYW1lcyhwcm9iYXNEam9rb3ZpY3ZpY3RvcnkpIDwtIGxpc3Rfc3VyZmFjZXM7DQogICAgcm93bmFtZXMocHJvYmFzRGpva292aWN2aWN0b3J5KSA8LSBjKCdGZWRlcmVyIFIuJywgJ05hZGFsIFIuJyk7DQogICAgZm9yIChzdXJmYWNlIGluIGxpc3Rfc3VyZmFjZXMpew0KICAgICAgRHZzTnN1cmZhY2UgPSAoJ0Rqb2tvdmljIE4uJyA9PSBkZiRXaW5uZXJbKGRmJFdpbm5lciAlaW4lIGJpZzNbLTFdKSAmIChkZiRMb3NlciAlaW4lIGJpZzNbLTFdKSAmIChkZiRTdXJmYWNlID09IHN1cmZhY2UpXSk7DQogICAgICBEdnNGc3VyZmFjZSA9ICgnRGpva292aWMgTi4nID09IGRmJFdpbm5lclsoZGYkV2lubmVyICVpbiUgYmlnM1stMl0pICYgKGRmJExvc2VyICVpbiUgYmlnM1stMl0pICYgKGRmJFN1cmZhY2UgPT0gc3VyZmFjZSldKTsNCiAgICAgIHJlc1p0ZXN0IDwtIGNvbXB1dGVBc3ltcHRvdGljWnN0YXQoRHZzTnN1cmZhY2UsRHZzRnN1cmZhY2UpOw0KICAgICAgcHZhbHMgPSBhcHBlbmQocHZhbHMsIHJlc1p0ZXN0JHB2YWwpOw0KICAgICAgcHJvYmFzRGpva292aWN2aWN0b3J5WydGZWRlcmVyIFIuJyxzdXJmYWNlXSA8LSBtZWFuKER2c0ZzdXJmYWNlKTsNCiAgICAgIHByb2Jhc0Rqb2tvdmljdmljdG9yeVsnTmFkYWwgUi4nLHN1cmZhY2VdIDwtIG1lYW4oRHZzTnN1cmZhY2UpOw0KICAgIH0NCiAgICBuYW1lcyhwdmFscykgPC0gbGlzdF9zdXJmYWNlczsNCiAgICByZXR1cm4gKGxpc3QocHZhbHM9cHZhbHMscHJvYmFzdmljdG9yeT1wcm9iYXNEam9rb3ZpY3ZpY3RvcnkpKTsNCn0NCmBgYA0KDQpgYGB7cn0NCkRqb2tvdmljX3JlcyA8LSBEam9rb3ZpY19zdHVkeShkYXRhW2RhdGVzID4gMjAxMCxdKTsNCkRqb2tvdmljX3JlcyRwdmFscw0KYGBgDQoNCkhlbmNlIHNheWluZyB0aGF0IEZlZGVyZXIgbGV2ZWwgZGVjYXllZCBhZnRlciAyMDEwIHdvdWxkIGJlIGEgaGFzdHkgY29uY2x1c2lvbi4gDQoNCkZyb20gbXkgcGVyc29uYWwgcG9pbnQgb2YgdmlldyAoYW5kIGFzIGEgdGVubmlzIGZhbiksIHRoZSBmYWN0IHRoYXQgTmFkYWwgaGFkIGJldHRlciBjaGFuY2VzIHRvIHdpbiBhZ2FpbnN0IEZlZGVyZXIgcmF0aGVyIHRoYW4gYWdhaW5zdCBEam9rb3ZpYyB3YXMgbWFpbmx5IGR1ZSB0byBhIHBzeWNob2xvZ2ljYWwgYXNjZW5kYW50IGhlIGhlZCBvbiB0aGUgU3dpc3MuIEJ1dCBldmVyeW9uZSB3aWxsIG1ha2UgaGlzIG93biBvcGluaW9uICE=