A post from data.visualisation.free.fr
What is radar plot?
Radar plots or charts, also called Spider or Web charts are very popular tools for representing individuals scores of brands, firms, NBA players recorded or evaluated for different variables, different activities or dimensions.
A radar plot is a sort parallel coordinates plot but using polar coordinates. The axis start from the center of the view and diverge from there to form equi-angular spoke. Each observation (individual) is represented by a line connecting values on each spoke (axis). The global performance is visualized by the total area delimited by the line. People use these representation to compare performances attributed to individuals in a multidimensional space (the categories).
Let’s take the example of Thom, Johnny, Colin and Ed who have been graded in 4 categories (A, B, C and D). We may think of musician with different skills regarding Accoustic guitar, Bass, Chorus and Drums. The data looks like this:
library (fmsb)
library(ggplot2)
library(ggthemes)
library(dplyr)
Thom = c(5,1,4,2)
Johnny = c(5,4,2,1)
Colin = c(2,2,3,4)
Ed = c( 4,3,2,1)
Radio.Table <- rbind(Thom,Johnny, Colin, Ed)
Radio.Table <- as.data.frame(Radio.Table)
colnames(Radio.Table) = list("A","B", "C", "D")
rownames(Radio.Table) = list("Thom","Johnny" , "Colin", "Ed")
| | | | |
---|
Thom | 5 | 1 | 4 | 2 |
Johnny | 5 | 4 | 2 | 1 |
Colin | 2 | 2 | 3 | 4 |
Ed | 4 | 3 | 2 | 1 |
Min.R <- rep(0,4)
Max.R <- rep(5,4)
Radio.Table.Radar <- rbind(Max.R, Min.R,Radio.Table)
colnames(Radio.Table.Radar) = list("A","B", "C", "D")
rownames(Radio.Table.Radar) = list("max" , "min", "Thom","Johnny" , "Colin", "Ed")
Standard overlaid radar plot
Now, let us compare these guys using a Radar Plot (thanks to Christophe Regouby for his trick on zero axis).
library(RColorBrewer)
Mycol <-brewer.pal(n = 4, name = "Set2")
radarchart(Radio.Table.Radar,
axistype=0, pty=32, plty=1, plwd=2, axislabcol="grey", na.itp=FALSE,
pcol=Mycol,
cglty = 3, cglwd = 2, cglcol = "grey",
centerzero=TRUE ,
title="Scores of Thom, Johnny, Colin and Ed ")

Small multiples are more usefull
The overlapping of the curves on this graphic does not allow an easy comparison of the scores, so let us split this graph into 4 graphs (using a Small multiple approach), each graph representing the radar plot of a member of the band.
par(mar=c(1, 2, 2, 1))
layout(matrix(1:4, ncol=2))
lapply(1:4, function(i) {
radarchart(rbind(Max.R, Min.R, Radio.Table[i,]),
seg=4,
axistype=0, pty=32, plty=1, axislabcol="grey", na.itp=FALSE,
cglty = 3, cglwd = 1, cglcol = "grey",
pcol= Mycol[i],
pdensity=50, pfcol=Mycol[i],
centerzero=TRUE ,
title= paste("Score of", rownames(Radio.Table[i,]),""))
})

The Radar plot does not represent truthfully the data
Let us compute the area of the radar plot for each of the 4 guys here. Since we only have 4 categories here, the area is very simple. It is defined as half the area of the square containing the radar plot, or, denoting by (a, b, c, d) the length of each branch, that is the score for each variable, we have:
area=(a+c)∗(b+d)2 Another way of finding this result is to compute the area of the 4 triangles (rectangle in 0) forming the radar plot surface.
Score.Table <-Radio.Table %>%
mutate(
score.total = Radio.Table[,"A"]+ Radio.Table[,"B"] + Radio.Table[,"C"]+ Radio.Table[,"D"] ,
area = 0.5*(Radio.Table[,"A"]+ Radio.Table[,"C"])*(Radio.Table[,"B"]+ Radio.Table[,"D"])
)
colnames(Score.Table) = list("A","B", "C", "D", "Total", "area")
rownames(Score.Table) = list("Thom","Johnny" , "Colin", "Ed")
Score.Table
| | | | | | |
---|
Thom | 5 | 1 | 4 | 2 | 12 | 13.5 |
Johnny | 5 | 4 | 2 | 1 | 12 | 17.5 |
Colin | 2 | 2 | 3 | 4 | 11 | 15.0 |
Ed | 4 | 3 | 2 | 1 | 10 | 12.0 |
If we focus on Thom and Johnny, we clearly see that the sum of their scores is identical while there is a big difference in the area representing their scores. There is clearly a lying factor here (see Tufte for a definition of this factor). The ranking of the total scores is not preserved by the graph, since in terms of areas we have the order from best to lowest:
- Johnny,
- Colin
- Thom, and
- Ed,
with a huge difference in the area, not reflecting the real scores differences (only 2 points difference between highest and lowest).
Score.Table$Names <- rownames(Score.Table)
ggplot(data=Score.Table, aes(x= Names, y=area )) +
geom_bar(colour= "white", fill = rev(Mycol) , width=.5, stat="identity") +
xlab("Band") + ylab("Radar plot area") +
scale_x_discrete(limits=rev(rownames(Score.Table)))+
ggtitle("Radar plot area (order A, B, C, D) ") +
coord_flip()

Impact of the axis order
Now let us redefine the axis and switch B and C on the radar plot:
Radio.Table.New <- Radio.Table[c("A", "C", "B", "D")]
Radio.Table.New
| | | | |
---|
Thom | 5 | 4 | 1 | 2 |
Johnny | 5 | 2 | 4 | 1 |
Colin | 2 | 3 | 2 | 4 |
Ed | 4 | 2 | 3 | 1 |
And now let us see who seems to be the best.
par(mar=c(1, 2, 2, 1))
layout(matrix(1:4, ncol=2))
lapply(1:4, function(i) {
radarchart(rbind(Max.R, Min.R, Radio.Table.New[i,]),
seg=5,
axistype=0, pty=32, plty=1, axislabcol="grey", na.itp=FALSE,
cglty = 3, cglwd = 1, cglcol = "grey",
pcol= Mycol[i],
pdensity=50, pfcol=Mycol[i],
centerzero=TRUE ,
title= paste("Score of", rownames(Radio.Table.New[i,]),""))
})

The whole picture has changed
Now, it seems that the respective areas of each members have changed. Let us recompute the areas.
Score.Table.New <-Radio.Table.New %>%
mutate(
score.total = Radio.Table.New[,"A"]+ Radio.Table.New[,"B"] + Radio.Table.New[,"C"]+ Radio.Table.New[,"D"] ,
area = 0.5*(Radio.Table.New[,"A"]+ Radio.Table.New[,"B"])*(Radio.Table.New[,"C"]+ Radio.Table.New[,"D"])
)
colnames(Score.Table.New) = list("A","C", "B", "D", "Total", "area")
rownames(Score.Table.New) = list("Thom","Johnny" , "Colin", "Ed")
Score.Table.New
| | | | | | |
---|
Thom | 5 | 4 | 1 | 2 | 12 | 18.0 |
Johnny | 5 | 2 | 4 | 1 | 12 | 13.5 |
Colin | 2 | 3 | 2 | 4 | 11 | 14.0 |
Ed | 4 | 2 | 3 | 1 | 10 | 10.5 |
The area representing the scores of Thom has changed from 13.5 to 18, while Johnny’s area has shrunk from 17.5 down to 13.5. That is less than Colin. Ed is still last. The order has changed with the change of axis, now the ranking is:
- Thom
- Colin
- Johnny
- Ed
Look at the new values of radar plot areas
Score.Table.New$Names <- rownames(Score.Table.New)
ggplot(data=Score.Table.New, aes(x= Names, y=area, fill=Names )) +
geom_bar(colour= "white", fill=rev(Mycol), width=.5, stat="identity") +
scale_x_discrete(limits=rev(rownames(Score.Table)))+
xlab("Band") + ylab("Radar plot area") +
ggtitle("Radar plot area with the new axis order (A, C, B, D) ") +
coord_flip()

An alternative: Parallel Coordinate Plot
We may use a different type of graph to have a better view of this difficult case. One example is the Parallel Coordinate Plot proposed in the MASS library in R. Radar plot and Parallel Coordinate Plot are quite similar in spirit. The advantage of the latter lies in its simplicity and in the absence of artificial area representation spoiling the perception of the global performance. Contrary to the radar plot, the comparison of each individual is done on vertical axis, the connecting lines showing some evolution of the scores from on axis to the other. So, here again, the order of the axis may change the view, and can help detect patterns, but will not affect the comparison.
Note that this standard graph propose different scales for each axis, ranging from min to max. In our case, the second axis (“B”) has a maximum of 4, while the first ranges from 1 to 5. So, the global comparison is still far from obvious.
So who is the best?
We see that the orange line (Johnny) strictly dominates the pink line (Ed). This something easy to see in the table, whatever the ranking of columns, Johnny has always a score greater than Ed. We couldn’t easily see that striking result in the radar plot.
The blue (Colin) and orange (Johnny) lines have opposite results. We also see that it is difficult to compare the green (Thom) and orange (Johnny) lines, since the corresponding band members have exactly the same scores, but not for the same variables. Contrary to what the radar plot showed, none is globally better. That’s also a result clearly emphasized by this (imperfect) graph.
parcoord(Radio.Table[1:4,], col=Mycol, lwd=3, var.label=TRUE)

Or even Better, we could use small multiples
toto <- c(6,6,6,6)
Radio.Table2 <- rbind(Radio.Table, toto)
par(mfrow=c(2,2))
parcoord(Radio.Table[c(1,3),], col=c(Mycol[1], "white"), lwd=3, var.label=TRUE)
parcoord(Radio.Table[2:3,], col=c(Mycol[2], "white"), lwd=3, var.label=TRUE)
parcoord(Radio.Table[3:4,], col=c(Mycol[3], "white"), lwd=3, var.label=TRUE)
parcoord(Radio.Table[3:4,], col=c("white", Mycol[4]), lwd=3, var.label=TRUE)

Conclusion: Comparison is still difficult…
But we have a more faithful comparison of the 4 guys here, and we do not rely on false global measure implicitly over- or under-representing the values used for comparison.
That’s why I suggest to avoid using radar plots!
Even more missleading: Same example with 5 axis
We can redo the example of Thom, Johnny, Colin and Ed who have been graded now in 5 categories (A, B, C, D and E). The data are exactly the same, except that we gave a score of 2 for a fifth variable.
library (fmsb)
library(ggplot2)
library(ggthemes)
Thom = c(5,1,4,2, 2)
Johnny = c(5,4,2,1,2)
Colin = c(2,2,3,4,2)
Ed = c( 4,3,2,1,2)
Radio.Table5 <- rbind(Thom,Johnny, Colin, Ed)
Radio.Table5 <- as.data.frame(Radio.Table5)
colnames(Radio.Table5) = list("A","B", "C", "D", "E")
rownames(Radio.Table5) = list("Thom","Johnny" , "Colin", "Ed")
Radio.Table5
| | | | | |
---|
Thom | 5 | 1 | 4 | 2 | 2 |
Johnny | 5 | 4 | 2 | 1 | 2 |
Colin | 2 | 2 | 3 | 4 | 2 |
Ed | 4 | 3 | 2 | 1 | 2 |
Min.R <- rep(0,5)
Max.R <- rep(5,5)
Radio.Table5 <- rbind(Max.R, Min.R,Radio.Table5)
colnames(Radio.Table5) = list("A","B", "C", "D", "E")
rownames(Radio.Table5) = list("max" , "min", "Thom","Johnny" , "Colin", "Ed")
Again, comparing the performance of these guys using a Radar Plot provides a very biased visual comparison, since the areas do not reflect the overall scores.

par(mar=c(1, 2, 2, 1))
layout(matrix(1:4, ncol=2))
lapply(1:4, function(i) {
radarchart(rbind(Max.R, Min.R, Radio.Table5[i+2,]),
seg=5,
axistype=0, pty=32, plty=1, axislabcol="grey", na.itp=FALSE,
cglty = 3, cglwd = 1, cglcol = "grey",
pcol= Mycol[i],
pdensity =50, pfcol=Mycol[i],
centerzero=TRUE ,
title= paste("Score of", rownames(Radio.Table5[i+2,]),""))
})

Now let us redefine the axis so that axis B and D do not have the position on the radar plot:
Radio.Table5.New <- Radio.Table5[c("A", "D", "C", "B", "E")]
Radio.Table5.New[3:6,]
| | | | | |
---|
Thom | 5 | 2 | 4 | 1 | 2 |
Johnny | 5 | 1 | 2 | 4 | 2 |
Colin | 2 | 4 | 3 | 2 | 2 |
Ed | 4 | 1 | 2 | 3 | 2 |
And now let us see who seems to be the best.
par(mar=c(1, 2, 2, 1))
layout(matrix(1:4, ncol=2))
lapply(1:4, function(i) {
radarchart(rbind(Max.R, Min.R, Radio.Table5.New[i+2,]),
seg=5,
axistype=0, pty=32, plty=1, axislabcol="grey", na.itp=FALSE,
cglty = 3, cglwd = 1, cglcol = "grey",
pcol= Mycol[i],
pdensity =50, pfcol=Mycol[i],
centerzero=TRUE ,
title= paste("Score of", rownames(Radio.Table5.New[i+2,]),""))
})

So, ordering the members on the basis of these plots, comparing multidimensional scores, remains a very difficult task. The radar plot certainly does not help.
Done in Toulouse (France), by Xtophe. Usual citation policy and disclaimer apply. Comments on my twitter account are welcome
LS0tDQp0aXRsZTogJ1doeSB5b3Ugc2hvdWxkIG5ldmVyIHVzZSByYWRhciBwbG90cyAnDQphdXRob3I6ICJYdG9waGUgQm9udGVtcHMiDQpkYXRlOiAiTWFyY2gsIDIwMTciDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIHRoZW1lOiBqb3VybmFsDQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KKkEgcG9zdCBmcm9tIFtkYXRhLnZpc3VhbGlzYXRpb24uZnJlZS5mcl0oaHR0cDovL2RhdGEudmlzdWFsaXNhdGlvbi5mcmVlLmZyKSoNCg0KIyMjIFdoYXQgaXMgKnJhZGFyIHBsb3QqPw0KKlJhZGFyIHBsb3RzKiBvciAqY2hhcnRzKiwgYWxzbyBjYWxsZWQgKlNwaWRlciogb3IgKldlYiBjaGFydHMqICBhcmUgdmVyeSBwb3B1bGFyIHRvb2xzIGZvciByZXByZXNlbnRpbmcgaW5kaXZpZHVhbHMgc2NvcmVzIG9mIGJyYW5kcywgZmlybXMsIE5CQSBwbGF5ZXJzIHJlY29yZGVkIG9yIGV2YWx1YXRlZCBmb3IgZGlmZmVyZW50IHZhcmlhYmxlcywgZGlmZmVyZW50IGFjdGl2aXRpZXMgb3IgZGltZW5zaW9ucy4gDQoNCkEgcmFkYXIgcGxvdCBpcyBhIHNvcnQgKipwYXJhbGxlbCBjb29yZGluYXRlcyoqIHBsb3QgYnV0IHVzaW5nIHBvbGFyIGNvb3JkaW5hdGVzLiBUaGUgYXhpcyBzdGFydCBmcm9tIHRoZSBjZW50ZXIgb2YgdGhlIHZpZXcgYW5kIGRpdmVyZ2UgZnJvbSB0aGVyZSB0byBmb3JtIGVxdWktYW5ndWxhciBzcG9rZS4gRWFjaCBvYnNlcnZhdGlvbiAoaW5kaXZpZHVhbCkgaXMgcmVwcmVzZW50ZWQgYnkgYSBsaW5lIGNvbm5lY3RpbmcgdmFsdWVzIG9uIGVhY2ggc3Bva2UgKGF4aXMpLiBUaGUgZ2xvYmFsIHBlcmZvcm1hbmNlIGlzIHZpc3VhbGl6ZWQgYnkgdGhlIHRvdGFsIGFyZWEgZGVsaW1pdGVkIGJ5IHRoZSBsaW5lLiBQZW9wbGUgdXNlIHRoZXNlIHJlcHJlc2VudGF0aW9uIHRvIGNvbXBhcmUgcGVyZm9ybWFuY2VzIGF0dHJpYnV0ZWQgdG8gaW5kaXZpZHVhbHMgaW4gYSBtdWx0aWRpbWVuc2lvbmFsIHNwYWNlICh0aGUgY2F0ZWdvcmllcykuIA0KDQpMZXQncyB0YWtlIHRoZSBleGFtcGxlIG9mICpUaG9tLCBKb2hubnksIENvbGluKiBhbmQgKkVkKiB3aG8gaGF2ZSBiZWVuIGdyYWRlZCBpbiA0IGNhdGVnb3JpZXMgKCoqQSwgQiwgQyoqIGFuZCAqKkQqKikuIFdlIG1heSB0aGluayBvZiBtdXNpY2lhbiB3aXRoIGRpZmZlcmVudCBza2lsbHMgcmVnYXJkaW5nICoqQSoqY2NvdXN0aWMgZ3VpdGFyLCAqKkIqKmFzcywgKipDKipob3J1cyBhbmQgKipEKipydW1zLiBUaGUgZGF0YSBsb29rcyBsaWtlIHRoaXM6IA0KDQoNCmBgYGB7ciAsIHJlc3VsdHM9ICJoaWRlIn0NCmxpYnJhcnkgKGZtc2IpICAgICAgICMgVXNlZCBoZXJlIGZvciByYWRhciBwbG90cw0KbGlicmFyeShnZ3Bsb3QyKSAgICAgIyBNb2Rlcm4gcGxvdHRpbmcgaW4gUg0KbGlicmFyeShnZ3RoZW1lcykgICAgIyBJIGxpa2UgdG8gaGF2ZSBwbG90dGluZyB0aGVtZXMgKHN1Y2ggYXMgImNsYXNzaWMiIiwgb3IgIlR1ZnRlJyIpDQpsaWJyYXJ5KGRwbHlyKSAgICAgICAjIEZvciBlYXN5IGRhdGEgbWFuYWdlbWVudA0KDQpUaG9tID0gYyg1LDEsNCwyKQ0KSm9obm55ID0gYyg1LDQsMiwxKQ0KQ29saW4gPSBjKDIsMiwzLDQpDQpFZCA9ICBjKCA0LDMsMiwxKQ0KDQpSYWRpby5UYWJsZSA8LSByYmluZChUaG9tLEpvaG5ueSwgQ29saW4sIEVkKSAgDQpSYWRpby5UYWJsZSA8LSBhcy5kYXRhLmZyYW1lKFJhZGlvLlRhYmxlKQ0KDQpjb2xuYW1lcyhSYWRpby5UYWJsZSkgPSBsaXN0KCJBIiwiQiIsICJDIiwgIkQiKQ0Kcm93bmFtZXMoUmFkaW8uVGFibGUpID0gbGlzdCgiVGhvbSIsIkpvaG5ueSIgLCAiQ29saW4iLCAiRWQiKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQojc2hvdyB0YWJsZQ0KUmFkaW8uVGFibGUNCg0KYGBgDQoNCmBgYHtyfQ0KDQojRmlyc3QgdHdvIHJvd3MgbXVzdCBzaG93IG1heC1taW4NCiMgTWluLlIgPC0gYXBwbHkoUmFkaW8uVGFibGUsMixtaW4pDQojIE1heC5SIDwtIGFwcGx5KFJhZGlvLlRhYmxlLDIsbWF4KQ0KDQojT3IgZGVjaWRlIG9mIGEgZml4ZWQgc2NhbGUgKG1heD0gNSwgbWluPTApDQpNaW4uUiA8LSByZXAoMCw0KQ0KTWF4LlIgPC0gcmVwKDUsNCkNCg0KI0FkZCAyIGZpcnN0IHJvd3MgDQpSYWRpby5UYWJsZS5SYWRhciA8LSByYmluZChNYXguUiwgTWluLlIsUmFkaW8uVGFibGUpDQogICAgDQpjb2xuYW1lcyhSYWRpby5UYWJsZS5SYWRhcikgPSBsaXN0KCJBIiwiQiIsICJDIiwgIkQiKQ0Kcm93bmFtZXMoUmFkaW8uVGFibGUuUmFkYXIpID0gbGlzdCgibWF4IiAsICJtaW4iLCAiVGhvbSIsIkpvaG5ueSIgLCAiQ29saW4iLCAiRWQiKQ0KDQpgYGANCiMjIyBTdGFuZGFyZCBvdmVybGFpZCByYWRhciBwbG90DQoNCk5vdywgbGV0IHVzIGNvbXBhcmUgdGhlc2UgZ3V5cyB1c2luZyBhIFJhZGFyIFBsb3QgKCp0aGFua3MgdG8gQ2hyaXN0b3BoZSBSZWdvdWJ5IGZvciBoaXMgdHJpY2sgb24gemVybyBheGlzKikuIA0KDQpgYGBge3IgLCByZXN1bHRzPSAiaGlkZSJ9DQojSSBsaWtlIHRvIGNob29zZSBteSBjb2xvcnMhDQojbGlicmFyeSh3ZXNhbmRlcnNvbikNCiNNeWNvbCA8LXdlc19wYWxldHRlKG49NCwgbmFtZT0iRGFyamVlbGluZyIpDQoNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KTXljb2wgPC1icmV3ZXIucGFsKG4gPSA0LCBuYW1lID0gIlNldDIiKQ0KDQojdGhhbmtzIHRvIENocmlzdG9waGUgUmVnb3VieSBmb3IgaGlzIHRyaWNrIG9uIGNlbnRlcmluZyB0byB6ZXJvIQ0KcmFkYXJjaGFydChSYWRpby5UYWJsZS5SYWRhciwgDQogICAgICAgICAgIGF4aXN0eXBlPTAsIHB0eT0zMiwgcGx0eT0xLCAgcGx3ZD0yLCBheGlzbGFiY29sPSJncmV5IiwgbmEuaXRwPUZBTFNFLA0KICAgICAgICAgICBwY29sPU15Y29sLA0KICAgICAgICAgICBjZ2x0eSA9IDMsIGNnbHdkID0gMiwgY2dsY29sID0gImdyZXkiLCANCiAgICAgICAgICAgY2VudGVyemVybz1UUlVFICwNCiB0aXRsZT0iU2NvcmVzIG9mIFRob20sIEpvaG5ueSwgQ29saW4gYW5kIEVkICIpDQoNCmBgYGANCiMjIyBTbWFsbCBtdWx0aXBsZXMgYXJlIG1vcmUgdXNlZnVsbA0KVGhlIG92ZXJsYXBwaW5nIG9mIHRoZSBjdXJ2ZXMgb24gdGhpcyBncmFwaGljIGRvZXMgbm90IGFsbG93IGFuIGVhc3kgY29tcGFyaXNvbiBvZiB0aGUgc2NvcmVzLCBzbyBsZXQgdXMgc3BsaXQgdGhpcyBncmFwaCBpbnRvIDQgZ3JhcGhzICh1c2luZyBhICpTbWFsbCBtdWx0aXBsZSogYXBwcm9hY2gpLCBlYWNoIGdyYXBoIHJlcHJlc2VudGluZyB0aGUgcmFkYXIgcGxvdCBvZiBhIG1lbWJlciBvZiB0aGUgYmFuZC4gICANCg0KYGBge3IsIHJlc3VsdHM9ImhpZGUifQ0KcGFyKG1hcj1jKDEsIDIsIDIsIDEpKSAjZGVjcmVhc2UgZGVmYXVsdCBtYXJnaW4NCmxheW91dChtYXRyaXgoMTo0LCBuY29sPTIpKSAjZHJhdyA0IHBsb3RzIHRvIGRldmljZQ0KI2xvb3Agb3ZlciByb3dzIHRvIGRyYXcgdGhlbSwgYWRkIDEgYXMgbWF4IGFuZCAwIGFzIG1pbiBmb3IgZWFjaCB2YXINCmxhcHBseSgxOjQsIGZ1bmN0aW9uKGkpIHsgDQogICAgcmFkYXJjaGFydChyYmluZChNYXguUiwgTWluLlIsIFJhZGlvLlRhYmxlW2ksXSksIA0KICAgICAgICAgICAgICAgc2VnPTQsIA0KICAgICAgICAgICAgICAgYXhpc3R5cGU9MCwgcHR5PTMyLCBwbHR5PTEsIGF4aXNsYWJjb2w9ImdyZXkiLCBuYS5pdHA9RkFMU0UsDQogICAgICAgICAgICAgICBjZ2x0eSA9IDMsIGNnbHdkID0gMSwgY2dsY29sID0gImdyZXkiLCANCiAgICAgICAgICAgICAgIHBjb2w9IE15Y29sW2ldLA0KICAgICAgICAgICAgICAgcGRlbnNpdHk9NTAsIHBmY29sPU15Y29sW2ldLA0KICAgICAgICAgICAgICAgIGNlbnRlcnplcm89VFJVRSAsDQogICAgICAgICAgICAgICB0aXRsZT0gcGFzdGUoIlNjb3JlIG9mIiwgcm93bmFtZXMoUmFkaW8uVGFibGVbaSxdKSwiIikpDQogIH0pDQpgYGANCg0KIyMjIFRoZSBSYWRhciBwbG90IGRvZXMgbm90IHJlcHJlc2VudCB0cnV0aGZ1bGx5IHRoZSBkYXRhIA0KTGV0IHVzIGNvbXB1dGUgdGhlIGFyZWEgb2YgdGhlIHJhZGFyIHBsb3QgZm9yIGVhY2ggb2YgdGhlIDQgZ3V5cyBoZXJlLiAgU2luY2Ugd2Ugb25seSBoYXZlIDQgY2F0ZWdvcmllcyBoZXJlLCB0aGUgYXJlYSBpcyB2ZXJ5IHNpbXBsZS4gSXQgaXMgZGVmaW5lZCBhcyBoYWxmIHRoZSBhcmVhIG9mIHRoZSBzcXVhcmUgY29udGFpbmluZyB0aGUgcmFkYXIgcGxvdCwgb3IsIGRlbm90aW5nIGJ5IChhLCBiLCBjLCBkKSB0aGUgbGVuZ3RoIG9mIGVhY2ggYnJhbmNoLCB0aGF0IGlzIHRoZSBzY29yZSBmb3IgZWFjaCB2YXJpYWJsZSwgd2UgaGF2ZToNCg0KJCRhcmVhID0gXGZyYWN7KGErYykqKGIrZCl9ezJ9JCQNCkFub3RoZXIgd2F5IG9mIGZpbmRpbmcgdGhpcyByZXN1bHQgaXMgdG8gY29tcHV0ZSB0aGUgYXJlYSBvZiB0aGUgNCB0cmlhbmdsZXMgKHJlY3RhbmdsZSBpbiAwKSBmb3JtaW5nIHRoZSByYWRhciBwbG90IHN1cmZhY2UuDQoNCmBgYHtyfQ0KU2NvcmUuVGFibGUgPC1SYWRpby5UYWJsZSAlPiUNCiAgbXV0YXRlKA0KICAgIHNjb3JlLnRvdGFsID0gUmFkaW8uVGFibGVbLCJBIl0rIFJhZGlvLlRhYmxlWywiQiJdICsgUmFkaW8uVGFibGVbLCJDIl0rIFJhZGlvLlRhYmxlWywiRCJdICwgIA0KICAgIGFyZWEgPSAwLjUqKFJhZGlvLlRhYmxlWywiQSJdKyBSYWRpby5UYWJsZVssIkMiXSkqKFJhZGlvLlRhYmxlWywiQiJdKyBSYWRpby5UYWJsZVssIkQiXSkNCiAgKQ0KDQpjb2xuYW1lcyhTY29yZS5UYWJsZSkgPSBsaXN0KCJBIiwiQiIsICJDIiwgIkQiLCAiVG90YWwiLCAiYXJlYSIpDQpyb3duYW1lcyhTY29yZS5UYWJsZSkgPSBsaXN0KCJUaG9tIiwiSm9obm55IiAsICJDb2xpbiIsICJFZCIpDQoNClNjb3JlLlRhYmxlIA0KDQpgYGANCg0KSWYgd2UgZm9jdXMgb24gVGhvbSBhbmQgSm9obm55LCAgd2UgY2xlYXJseSBzZWUgdGhhdCB0aGUgc3VtIG9mIHRoZWlyIHNjb3JlcyBpcyBpZGVudGljYWwgd2hpbGUgdGhlcmUgaXMgYSBiaWcgZGlmZmVyZW5jZSBpbiB0aGUgYXJlYSByZXByZXNlbnRpbmcgdGhlaXIgc2NvcmVzLiBUaGVyZSBpcyBjbGVhcmx5IGEgKipseWluZyBmYWN0b3IqKiBoZXJlIChzZWUgW1R1ZnRlXShodHRwczovL3d3dy5lZHdhcmR0dWZ0ZS5jb20vYmJvYXJkL3EtYW5kLWEtZmV0Y2gtbXNnP21zZ19pZD0wMDAwMm8pIGZvciBhIGRlZmluaXRpb24gb2YgdGhpcyBmYWN0b3IpLiBUaGUgcmFua2luZyBvZiB0aGUgdG90YWwgc2NvcmVzIGlzIG5vdCBwcmVzZXJ2ZWQgYnkgdGhlIGdyYXBoLCBzaW5jZSBpbiB0ZXJtcyBvZiBhcmVhcyB3ZSBoYXZlIHRoZSBvcmRlciBmcm9tIGJlc3QgdG8gbG93ZXN0OiANCg0KMS4gSm9obm55LCANCjIuIENvbGluIA0KMy4gVGhvbSwgYW5kIA0KNC4gRWQsIA0KDQp3aXRoIGEgaHVnZSBkaWZmZXJlbmNlIGluIHRoZSBhcmVhLCBub3QgcmVmbGVjdGluZyB0aGUgcmVhbCBzY29yZXMgZGlmZmVyZW5jZXMgKG9ubHkgMiBwb2ludHMgZGlmZmVyZW5jZSBiZXR3ZWVuIGhpZ2hlc3QgYW5kIGxvd2VzdCkuIA0KDQpgYGB7cn0NClNjb3JlLlRhYmxlJE5hbWVzIDwtIHJvd25hbWVzKFNjb3JlLlRhYmxlKQ0KZ2dwbG90KGRhdGE9U2NvcmUuVGFibGUsIGFlcyh4PSBOYW1lcywgeT1hcmVhICkpICsgDQogICAgZ2VvbV9iYXIoY29sb3VyPSAid2hpdGUiLCAgZmlsbCA9IHJldihNeWNvbCkgLCB3aWR0aD0uNSwgc3RhdD0iaWRlbnRpdHkiKSArIA0KICAgIHhsYWIoIkJhbmQiKSArIHlsYWIoIlJhZGFyIHBsb3QgYXJlYSIpICsNCiAgICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cz1yZXYocm93bmFtZXMoU2NvcmUuVGFibGUpKSkrDQogICAgZ2d0aXRsZSgiUmFkYXIgcGxvdCBhcmVhIChvcmRlciBBLCBCLCBDLCBEKSAiKSArDQogICAgY29vcmRfZmxpcCgpDQpgYGANCg0KDQoNCiMjIyBJbXBhY3Qgb2YgdGhlIGF4aXMgb3JkZXINCk5vdyBsZXQgdXMgcmVkZWZpbmUgdGhlIGF4aXMgYW5kIHN3aXRjaCAgKipCKiogYW5kICoqQyoqIG9uIHRoZSByYWRhciBwbG90Og0KDQpgYGB7cn0NClJhZGlvLlRhYmxlLk5ldyA8LSBSYWRpby5UYWJsZVtjKCJBIiwgIkMiLCAiQiIsICJEIildDQpSYWRpby5UYWJsZS5OZXcNCg0KYGBgDQoNCkFuZCBub3cgbGV0IHVzIHNlZSB3aG8gc2VlbXMgdG8gYmUgdGhlIGJlc3QuDQoNCg0KYGBge3IsIHJlc3VsdHM9ICJoaWRlIn0NCnBhcihtYXI9YygxLCAyLCAyLCAxKSkgI2RlY3JlYXNlIGRlZmF1bHQgbWFyZ2luDQpsYXlvdXQobWF0cml4KDE6NCwgbmNvbD0yKSkgI2RyYXcgNCBwbG90cyB0byBkZXZpY2UNCiNsb29wIG92ZXIgcm93cyB0byBkcmF3IHRoZW0sIGFkZCAxIGFzIG1heCBhbmQgMCBhcyBtaW4gZm9yIGVhY2ggdmFyDQpsYXBwbHkoMTo0LCBmdW5jdGlvbihpKSB7IA0KICAgIHJhZGFyY2hhcnQocmJpbmQoTWF4LlIsIE1pbi5SLCBSYWRpby5UYWJsZS5OZXdbaSxdKSwgDQogICAgICAgICAgICAgICBzZWc9NSwgDQogICAgICAgICAgICAgICBheGlzdHlwZT0wLCBwdHk9MzIsIHBsdHk9MSwgYXhpc2xhYmNvbD0iZ3JleSIsIG5hLml0cD1GQUxTRSwNCiAgICAgICAgICAgICAgIGNnbHR5ID0gMywgY2dsd2QgPSAxLCBjZ2xjb2wgPSAiZ3JleSIsIA0KICAgICAgICAgICAgICAgcGNvbD0gTXljb2xbaV0sDQogICAgICAgICAgICAgICBwZGVuc2l0eT01MCwgcGZjb2w9TXljb2xbaV0sIA0KICAgICAgICAgICAgICAgY2VudGVyemVybz1UUlVFICwNCiAgICAgICAgICAgICAgIHRpdGxlPSBwYXN0ZSgiU2NvcmUgb2YiLCByb3duYW1lcyhSYWRpby5UYWJsZS5OZXdbaSxdKSwiIikpDQogIH0pDQpgYGANCg0KIyMjVGhlIHdob2xlIHBpY3R1cmUgaGFzIGNoYW5nZWQNCk5vdywgaXQgc2VlbXMgdGhhdCB0aGUgcmVzcGVjdGl2ZSBhcmVhcyBvZiBlYWNoIG1lbWJlcnMgaGF2ZSBjaGFuZ2VkLiBMZXQgdXMgcmVjb21wdXRlIHRoZSBhcmVhcy4gDQoNCg0KYGBge3J9DQpTY29yZS5UYWJsZS5OZXcgPC1SYWRpby5UYWJsZS5OZXcgJT4lDQogIG11dGF0ZSgNCiAgICBzY29yZS50b3RhbCA9IFJhZGlvLlRhYmxlLk5ld1ssIkEiXSsgUmFkaW8uVGFibGUuTmV3WywiQiJdICsgUmFkaW8uVGFibGUuTmV3WywiQyJdKyBSYWRpby5UYWJsZS5OZXdbLCJEIl0gLCAgDQogICAgYXJlYSA9IDAuNSooUmFkaW8uVGFibGUuTmV3WywiQSJdKyBSYWRpby5UYWJsZS5OZXdbLCJCIl0pKihSYWRpby5UYWJsZS5OZXdbLCJDIl0rIFJhZGlvLlRhYmxlLk5ld1ssIkQiXSkNCiAgKQ0KDQpjb2xuYW1lcyhTY29yZS5UYWJsZS5OZXcpID0gbGlzdCgiQSIsIkMiLCAiQiIsICJEIiwgIlRvdGFsIiwgImFyZWEiKQ0Kcm93bmFtZXMoU2NvcmUuVGFibGUuTmV3KSA9IGxpc3QoIlRob20iLCJKb2hubnkiICwgIkNvbGluIiwgIkVkIikNCg0KU2NvcmUuVGFibGUuTmV3DQoNCmBgYA0KDQpUaGUgYXJlYSByZXByZXNlbnRpbmcgdGhlIHNjb3JlcyBvZiBUaG9tIGhhcyBjaGFuZ2VkIGZyb20gMTMuNSB0byAxOCwgd2hpbGUgSm9obm55J3MgYXJlYSBoYXMgc2hydW5rIGZyb20gKioxNy41KiogZG93biB0byAqKjEzLjUqKi4gVGhhdCBpcyBsZXNzIHRoYW4gQ29saW4uIEVkIGlzIHN0aWxsIGxhc3QuIFRoZSBvcmRlciBoYXMgY2hhbmdlZCB3aXRoIHRoZSBjaGFuZ2Ugb2YgYXhpcywgbm93IHRoZSByYW5raW5nIGlzOiANCg0KMS4gVGhvbQ0KMi4gQ29saW4NCjMuIEpvaG5ueQ0KNC4gRWQNCg0KTG9vayBhdCB0aGUgbmV3IHZhbHVlcyBvZiByYWRhciBwbG90IGFyZWFzDQoNCmBgYHtyfQ0KI05COiBJIGhhdmUgdG8gcmV2ZXJzZSBjb2xvcnMgYmVjYXVzZSBvZiBjb29yZF9mbGlwDQpTY29yZS5UYWJsZS5OZXckTmFtZXMgPC0gcm93bmFtZXMoU2NvcmUuVGFibGUuTmV3KQ0KZ2dwbG90KGRhdGE9U2NvcmUuVGFibGUuTmV3LCBhZXMoeD0gTmFtZXMsIHk9YXJlYSwgZmlsbD1OYW1lcyApKSArIA0KICAgIGdlb21fYmFyKGNvbG91cj0gIndoaXRlIiwgZmlsbD1yZXYoTXljb2wpLCB3aWR0aD0uNSwgc3RhdD0iaWRlbnRpdHkiKSArDQogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHM9cmV2KHJvd25hbWVzKFNjb3JlLlRhYmxlKSkpKw0KICAgIHhsYWIoIkJhbmQiKSArIHlsYWIoIlJhZGFyIHBsb3QgYXJlYSIpICsNCiAgICBnZ3RpdGxlKCJSYWRhciBwbG90IGFyZWEgd2l0aCB0aGUgbmV3IGF4aXMgb3JkZXIgKEEsIEMsIEIsIEQpICIpICsNCiAgICBjb29yZF9mbGlwKCkNCmBgYA0KDQoNCg0KDQoNCiMjIyBBbiBhbHRlcm5hdGl2ZTogUGFyYWxsZWwgQ29vcmRpbmF0ZSBQbG90DQoNCldlIG1heSB1c2UgYSBkaWZmZXJlbnQgdHlwZSBvZiBncmFwaCB0byBoYXZlIGEgYmV0dGVyIHZpZXcgb2YgdGhpcyBkaWZmaWN1bHQgY2FzZS4gT25lIGV4YW1wbGUgaXMgdGhlICpQYXJhbGxlbCBDb29yZGluYXRlIFBsb3QqIHByb3Bvc2VkIGluIHRoZSAqTUFTUyogbGlicmFyeSBpbiBSLiBSYWRhciBwbG90IGFuZCBQYXJhbGxlbCBDb29yZGluYXRlIFBsb3QgYXJlIHF1aXRlIHNpbWlsYXIgaW4gc3Bpcml0LiBUaGUgYWR2YW50YWdlIG9mIHRoZSBsYXR0ZXIgbGllcyBpbiBpdHMgc2ltcGxpY2l0eSBhbmQgaW4gdGhlIGFic2VuY2Ugb2YgYXJ0aWZpY2lhbCBhcmVhIHJlcHJlc2VudGF0aW9uIHNwb2lsaW5nIHRoZSBwZXJjZXB0aW9uIG9mIHRoZSBnbG9iYWwgcGVyZm9ybWFuY2UuIENvbnRyYXJ5IHRvIHRoZSByYWRhciBwbG90LCB0aGUgY29tcGFyaXNvbiBvZiBlYWNoIGluZGl2aWR1YWwgaXMgZG9uZSAqb24gdmVydGljYWwgYXhpcyosIHRoZSBjb25uZWN0aW5nIGxpbmVzIHNob3dpbmcgc29tZSBldm9sdXRpb24gb2YgdGhlIHNjb3JlcyBmcm9tIG9uIGF4aXMgdG8gdGhlIG90aGVyLiAgU28sIGhlcmUgYWdhaW4sIHRoZSBvcmRlciBvZiB0aGUgYXhpcyBtYXkgY2hhbmdlIHRoZSB2aWV3LCBhbmQgY2FuIGhlbHAgZGV0ZWN0IHBhdHRlcm5zLCAgYnV0ICoqd2lsbCBub3QgYWZmZWN0IHRoZSBjb21wYXJpc29uKiouICANCg0KTm90ZSB0aGF0IHRoaXMgc3RhbmRhcmQgZ3JhcGggcHJvcG9zZSAqKmRpZmZlcmVudCBzY2FsZXMgZm9yIGVhY2ggYXhpcyoqLCByYW5naW5nIGZyb20gbWluIHRvIG1heC4gSW4gb3VyIGNhc2UsIHRoZSBzZWNvbmQgYXhpcyAoIkIiKSBoYXMgYSBtYXhpbXVtIG9mIDQsIHdoaWxlIHRoZSBmaXJzdCByYW5nZXMgZnJvbSAxIHRvIDUuIFNvLCB0aGUgZ2xvYmFsIGNvbXBhcmlzb24gaXMgc3RpbGwgZmFyIGZyb20gb2J2aW91cy4gDQoNCiMjIyBTbyB3aG8gaXMgdGhlIGJlc3Q/DQoNCldlIHNlZSB0aGF0IHRoZSBvcmFuZ2UgbGluZSAoKkpvaG5ueSopICAqKnN0cmljdGx5IGRvbWluYXRlcyoqIHRoZSBwaW5rIGxpbmUgKCpFZCopLiBUaGlzIHNvbWV0aGluZyBlYXN5IHRvIHNlZSBpbiB0aGUgdGFibGUsIHdoYXRldmVyIHRoZSByYW5raW5nIG9mIGNvbHVtbnMsICpKb2hubnkqIGhhcyBhbHdheXMgYSBzY29yZSBncmVhdGVyIHRoYW4gKkVkKi4gV2UgY291bGRuJ3QgZWFzaWx5IHNlZSB0aGF0IHN0cmlraW5nIHJlc3VsdCBpbiB0aGUgcmFkYXIgcGxvdC4gDQoNClRoZSBibHVlICAoKkNvbGluKikgYW5kIG9yYW5nZSAoKkpvaG5ueSopIGxpbmVzIGhhdmUgb3Bwb3NpdGUgcmVzdWx0cy4gV2UgYWxzbyBzZWUgdGhhdCBpdCBpcyBkaWZmaWN1bHQgdG8gY29tcGFyZSB0aGUgZ3JlZW4gKCpUaG9tKikgYW5kIG9yYW5nZSAoKkpvaG5ueSopIGxpbmVzLCBzaW5jZSB0aGUgY29ycmVzcG9uZGluZyBiYW5kIG1lbWJlcnMgKipoYXZlIGV4YWN0bHkgdGhlIHNhbWUgc2NvcmVzKiosIGJ1dCBub3QgZm9yIHRoZSBzYW1lIHZhcmlhYmxlcy4gQ29udHJhcnkgdG8gd2hhdCB0aGUgcmFkYXIgcGxvdCBzaG93ZWQsIG5vbmUgaXMgZ2xvYmFsbHkgYmV0dGVyLiBUaGF0J3MgYWxzbyBhIHJlc3VsdCBjbGVhcmx5IGVtcGhhc2l6ZWQgYnkgdGhpcyAoaW1wZXJmZWN0KSBncmFwaC4gDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzID0naGlkZScsIGVycm9yID1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZSA9IEZBTFNFfQ0KbGlicmFyeShNQVNTKQ0KYGBgDQoNCmBgYHtyfQ0KcGFyY29vcmQoUmFkaW8uVGFibGVbMTo0LF0sIGNvbD1NeWNvbCwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKQ0KDQpgYGANCj5PciBldmVuIEJldHRlciwgd2UgY291bGQgdXNlICpzbWFsbCBtdWx0aXBsZXMqDQoNCmBgYHtyfQ0KdG90byA8LSBjKDYsNiw2LDYpDQpSYWRpby5UYWJsZTIgPC0gcmJpbmQoUmFkaW8uVGFibGUsIHRvdG8pDQpwYXIobWZyb3c9YygyLDIpKQ0KcGFyY29vcmQoUmFkaW8uVGFibGVbYygxLDMpLF0sIGNvbD1jKE15Y29sWzFdLCAid2hpdGUiKSwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKQ0KcGFyY29vcmQoUmFkaW8uVGFibGVbMjozLF0sIGNvbD1jKE15Y29sWzJdLCAid2hpdGUiKSwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKQ0KcGFyY29vcmQoUmFkaW8uVGFibGVbMzo0LF0sIGNvbD1jKE15Y29sWzNdLCAid2hpdGUiKSwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKQ0KcGFyY29vcmQoUmFkaW8uVGFibGVbMzo0LF0sIGNvbD1jKCJ3aGl0ZSIsIE15Y29sWzRdKSwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKQ0KDQoNCmBgYA0KDQoNCiMjIyBDb25jbHVzaW9uOiBDb21wYXJpc29uIGlzIHN0aWxsIGRpZmZpY3VsdC4uLg0KDQpCdXQgd2UgaGF2ZSBhIG1vcmUgZmFpdGhmdWwgY29tcGFyaXNvbiBvZiB0aGUgNCBndXlzIGhlcmUsIGFuZCB3ZSBkbyBub3QgcmVseSBvbiBmYWxzZSBnbG9iYWwgbWVhc3VyZSBpbXBsaWNpdGx5IG92ZXItIG9yIHVuZGVyLXJlcHJlc2VudGluZyB0aGUgdmFsdWVzIHVzZWQgZm9yIGNvbXBhcmlzb24uIA0KDQpUaGF0J3Mgd2h5IEkgc3VnZ2VzdCB0byAqKmF2b2lkIHVzaW5nIHJhZGFyIHBsb3RzKiohDQoNCg0KPCEtLSBgYGB7cn0gLS0+DQo8IS0tICNBbHRlcm5hdGl2ZSB3YXkgb2YgcGxvdHRpbmcgdXNpbmcgZ2dwbG90IC0tPg0KPCEtLSBsaWJyYXJ5KEdHYWxseSkgLS0+DQo8IS0tIGdncGFyY29vcmQoZGF0YSA9IFJhZGlvLlRhYmxlLCBjb2x1bW5zID0gMTo0LCBzY2FsZSA9ICJnbG9iYWxtaW5tYXgiKSAtLT4NCg0KPCEtLSBgYGAgLS0+DQoNCioqKg0KDQojIyBFdmVuIG1vcmUgbWlzc2xlYWRpbmc6IFNhbWUgZXhhbXBsZSB3aXRoIDUgYXhpcw0KDQpXZSBjYW4gcmVkbyB0aGUgZXhhbXBsZSBvZiBUaG9tLCBKb2hubnksIENvbGluIGFuZCBFZCB3aG8gaGF2ZSBiZWVuIGdyYWRlZCBub3cgaW4gNSBjYXRlZ29yaWVzIChBLCBCLCBDLCBEIGFuZCBFKS4gVGhlIGRhdGEgYXJlIGV4YWN0bHkgdGhlIHNhbWUsIGV4Y2VwdCB0aGF0IHdlIGdhdmUgYSBzY29yZSBvZiAyIGZvciBhIGZpZnRoIHZhcmlhYmxlLiANCg0KDQpgYGB7cn0NCmxpYnJhcnkgKGZtc2IpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KDQpUaG9tID0gYyg1LDEsNCwyLCAyKQ0KSm9obm55ID0gYyg1LDQsMiwxLDIpDQpDb2xpbiA9IGMoMiwyLDMsNCwyKQ0KRWQgPSAgYyggNCwzLDIsMSwyKQ0KDQpSYWRpby5UYWJsZTUgPC0gcmJpbmQoVGhvbSxKb2hubnksIENvbGluLCBFZCkgIA0KUmFkaW8uVGFibGU1IDwtIGFzLmRhdGEuZnJhbWUoUmFkaW8uVGFibGU1KQ0KDQpjb2xuYW1lcyhSYWRpby5UYWJsZTUpID0gbGlzdCgiQSIsIkIiLCAiQyIsICJEIiwgIkUiKQ0Kcm93bmFtZXMoUmFkaW8uVGFibGU1KSA9IGxpc3QoIlRob20iLCJKb2hubnkiICwgIkNvbGluIiwgIkVkIikNCg0KI3Nob3cgdGFibGUNClJhZGlvLlRhYmxlNQ0KDQpgYGANCg0KYGBge3J9DQoNCiNGaXJzdCB0d28gcm93cyBtdXN0IHNob3cgbWF4LW1pbg0KIyBNaW4uUiA8LSBhcHBseShSYWRpby5UYWJsZTUsMixtaW4pDQojIE1heC5SIDwtIGFwcGx5KFJhZGlvLlRhYmxlNSwyLG1heCkNCg0KI09yIGRlY2lkZSBvZiBhIGZpeGVkIHNjYWxlIChtYXg9IDUsIG1pbj0wKQ0KTWluLlIgPC0gcmVwKDAsNSkNCk1heC5SIDwtIHJlcCg1LDUpDQoNCiNBZGQgMiBmaXJzdCByb3dzIA0KUmFkaW8uVGFibGU1IDwtIHJiaW5kKE1heC5SLCBNaW4uUixSYWRpby5UYWJsZTUpDQogICAgDQpjb2xuYW1lcyhSYWRpby5UYWJsZTUpID0gbGlzdCgiQSIsIkIiLCAiQyIsICJEIiwgIkUiKQ0Kcm93bmFtZXMoUmFkaW8uVGFibGU1KSA9IGxpc3QoIm1heCIgLCAibWluIiwgIlRob20iLCJKb2hubnkiICwgIkNvbGluIiwgIkVkIikNCg0KYGBgDQoNCkFnYWluLCBjb21wYXJpbmcgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZXNlIGd1eXMgdXNpbmcgYSBSYWRhciBQbG90IHByb3ZpZGVzIGEgdmVyeSBiaWFzZWQgdmlzdWFsIGNvbXBhcmlzb24sIHNpbmNlIHRoZSBhcmVhcyBkbyBub3QgcmVmbGVjdCB0aGUgb3ZlcmFsbCBzY29yZXMuICANCg0KYGBgYHtyICwgZWNobz1GQUxTRSwgcmVzdWx0cz0gImhpZGUifQ0KcmFkYXJjaGFydChSYWRpby5UYWJsZTUsIA0KICAgICAgICAgICBheGlzdHlwZT0wLCBwdHk9MzIsIHBsdHk9MSwgIHBsd2Q9MiwgYXhpc2xhYmNvbD0iZ3JleSIsIG5hLml0cD1GQUxTRSwNCiAgICAgICAgICAgY2dsdHkgPSAzLCBjZ2x3ZCA9IDIsIGNnbGNvbCA9ICJncmV5IiwgDQogICAgICAgICAgIHBjb2w9IE15Y29sLCANCiAgICAgICAgICAgIGNlbnRlcnplcm89VFJVRSAsDQogICAgICAgICAgIHRpdGxlPSJTY29yZXMgb2YgVGhvbSwgSm9obm55LCBDb2xpbiBhbmQgRWQgIikNCg0KYGBgYA0KDQoNCmBgYHtyLCByZXN1bHRzPSJoaWRlIn0NCnBhcihtYXI9YygxLCAyLCAyLCAxKSkgI2RlY3JlYXNlIGRlZmF1bHQgbWFyZ2luDQpsYXlvdXQobWF0cml4KDE6NCwgbmNvbD0yKSkgI2RyYXcgNCBwbG90cyB0byBkZXZpY2UNCiNsb29wIG92ZXIgcm93cyB0byBkcmF3IHRoZW0sIGFkZCAxIGFzIG1heCBhbmQgMCBhcyBtaW4gZm9yIGVhY2ggdmFyDQpsYXBwbHkoMTo0LCBmdW5jdGlvbihpKSB7IA0KICAgIHJhZGFyY2hhcnQocmJpbmQoTWF4LlIsIE1pbi5SLCBSYWRpby5UYWJsZTVbaSsyLF0pLCANCiAgICAgICAgICAgICAgIHNlZz01LCANCiAgICAgICAgICAgICAgIGF4aXN0eXBlPTAsIHB0eT0zMiwgcGx0eT0xLCBheGlzbGFiY29sPSJncmV5IiwgbmEuaXRwPUZBTFNFLA0KICAgICAgICAgICAgICAgY2dsdHkgPSAzLCBjZ2x3ZCA9IDEsIGNnbGNvbCA9ICJncmV5IiwgDQogICAgICAgICAgICAgICBwY29sPSBNeWNvbFtpXSwNCiAgICAgICAgICAgICAgIHBkZW5zaXR5ID01MCwgcGZjb2w9TXljb2xbaV0sIA0KICAgICAgICAgICAgICAgIGNlbnRlcnplcm89VFJVRSAsDQogICAgICAgICAgICAgICB0aXRsZT0gcGFzdGUoIlNjb3JlIG9mIiwgcm93bmFtZXMoUmFkaW8uVGFibGU1W2krMixdKSwiIikpDQogIH0pDQpgYGANCg0KDQoNCk5vdyBsZXQgdXMgcmVkZWZpbmUgdGhlIGF4aXMgc28gdGhhdCBheGlzIEIgYW5kIEQgZG8gbm90IGhhdmUgdGhlIHBvc2l0aW9uIG9uIHRoZSByYWRhciBwbG90Og0KDQpgYGB7cn0NClJhZGlvLlRhYmxlNS5OZXcgPC0gUmFkaW8uVGFibGU1W2MoIkEiLCAiRCIsICJDIiwgIkIiLCAiRSIpXQ0KUmFkaW8uVGFibGU1Lk5ld1szOjYsXQ0KDQpgYGANCg0KQW5kIG5vdyBsZXQgdXMgc2VlIHdobyBzZWVtcyB0byBiZSB0aGUgYmVzdC4NCg0KDQpgYGB7ciwgcmVzdWx0cz0gImhpZGUifQ0KcGFyKG1hcj1jKDEsIDIsIDIsIDEpKSAjZGVjcmVhc2UgZGVmYXVsdCBtYXJnaW4NCmxheW91dChtYXRyaXgoMTo0LCBuY29sPTIpKSAjZHJhdyA0IHBsb3RzIHRvIGRldmljZQ0KI2xvb3Agb3ZlciByb3dzIHRvIGRyYXcgdGhlbSwgYWRkIDEgYXMgbWF4IGFuZCAwIGFzIG1pbiBmb3IgZWFjaCB2YXINCmxhcHBseSgxOjQsIGZ1bmN0aW9uKGkpIHsgDQogICAgcmFkYXJjaGFydChyYmluZChNYXguUiwgTWluLlIsIFJhZGlvLlRhYmxlNS5OZXdbaSsyLF0pLCANCiAgICAgICAgICAgICAgIHNlZz01LCANCiAgICAgICAgICAgICAgIGF4aXN0eXBlPTAsIHB0eT0zMiwgcGx0eT0xLCBheGlzbGFiY29sPSJncmV5IiwgbmEuaXRwPUZBTFNFLA0KICAgICAgICAgICAgICAgY2dsdHkgPSAzLCBjZ2x3ZCA9IDEsIGNnbGNvbCA9ICJncmV5IiwgDQogICAgICAgICAgICAgICBwY29sPSBNeWNvbFtpXSwNCiAgICAgICAgICAgICAgIHBkZW5zaXR5ID01MCwgcGZjb2w9TXljb2xbaV0sIA0KICAgICAgICAgICAgICAgIGNlbnRlcnplcm89VFJVRSAsDQogICAgICAgICAgICAgICB0aXRsZT0gcGFzdGUoIlNjb3JlIG9mIiwgcm93bmFtZXMoUmFkaW8uVGFibGU1Lk5ld1tpKzIsXSksIiIpKQ0KICB9KQ0KYGBgDQoNClNvLCBvcmRlcmluZyB0aGUgbWVtYmVycyBvbiB0aGUgYmFzaXMgb2YgdGhlc2UgcGxvdHMsIGNvbXBhcmluZyBtdWx0aWRpbWVuc2lvbmFsIHNjb3JlcywgcmVtYWlucyBhIHZlcnkgZGlmZmljdWx0IHRhc2suIFRoZSByYWRhciBwbG90IGNlcnRhaW5seSBkb2VzIG5vdCBoZWxwLg0KDQoNCioqKg0KKkRvbmUgaW4gVG91bG91c2UgKEZyYW5jZSksIGJ5IFtYdG9waGVdKG1haWx0bzpYdG9waGUuQm9udGVtcHNAZnJlZS5mcikuIFVzdWFsIGNpdGF0aW9uIHBvbGljeSBhbmQgZGlzY2xhaW1lciBhcHBseS4gQ29tbWVudHMgb24gbXkgW3R3aXR0ZXIgYWNjb3VudF0oaHR0cHM6Ly90d2l0dGVyLmNvbS9YdG9waGVfQm9udGVtcHMpIGFyZSB3ZWxjb21lKiANCg0KDQoNCg0KPCEtLSBgYGB7cn0gLS0+DQo8IS0tIGxpYnJhcnkoTUFTUykgLS0+DQoNCjwhLS0gcGFyY29vcmQoUmFkaW8uVGFibGU1WzM6NixdLCBjb2w9YygxLCAyLCAzLCA0KSwgbHdkPTMsIHZhci5sYWJlbD1UUlVFKSAtLT4NCg0KPCEtLSBgYGAgLS0+DQoNCg0KDQoNCg0KDQo=