3.3.1 Exercises
1. What’s gone wrong with this code? Why are the points not blue?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = "blue"))

aes
関数は引数をデータとして解釈するので、上記のコードは以下と同じような意味になる。
mpg %>% mutate(color = "blue") %>%
ggplot() + geom_point(aes(x = displ, y = hwy, color = color))

修正版
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), color = "blue")

3. Map a continuous variable to color
, size
, and shape
. How do these aesthetics behave differently for categorical vs. continuous variables?
shapeは連続だとダメ。
## myplot <- function(aes_name, var_name) {
## aes_name <- sym(aes_name)
## var_name <- sym(var_name)
## p <- ggplot(mpg, aes(displ, hwy)) +
## geom_point(mapping = aes(!!aes_name := !!var_name))
## print(p)
## }
myplot <- function(aes_name, var_name) {
aes_name <- sym(aes_name)
var_name <- sym(var_name)
ggplot(mpg) +
geom_point(mapping = aes(displ, hwy, !!aes_name := !!var_name))
}
var_names <- mpg %>% select_if(is.numeric) %>% names
aes_names <- c("color", "size", "shape")
plots <- crossing(aes_name = aes_names, var_name = var_names) %>% pmap(myplot)
plots %>% walk(safely(print))
4. What happens if you map the same variable to multiple aesthetics?
ggplot(mpg, aes(displ, hwy)) +
geom_point(aes(color = class, shape = class, size = class))
Warning: Using size for a discrete variable is not advised.
Warning: The shape palette can deal with a maximum of 6 discrete values
because more than 6 becomes difficult to discriminate; you have 7.
Consider specifying shapes manually if you must have them.
Warning: Removed 62 rows containing missing values (geom_point).

5. What does the stroke
aesthetic do? What shapes does it work with? (Hint: use ?geom_point
)
# For shapes that have a border (like 21), you can colour the inside and
# outside separately. Use the stroke aesthetic to modify the width of the
# border
ggplot(mtcars, aes(wt, mpg)) +
geom_point(shape = 21, colour = "black", fill = "white", size = 5, stroke = 5)

6. What happens if you map an aethetic to something other than a variable name, like aes(colour = displ < 5)
? Note, you’ll also need to specify x and y.
ggplot(mpg, aes(displ, hwy)) +
geom_point(aes(colour = displ < 5))

3.5.1 Exercises
1. What happens if you facet on a continuous variable?
たくさんでてくる。
ggplot(mpg, aes(hwy, cty)) +
geom_point() +
facet_wrap(~displ)

2. What do the empty cells in plot with facet_grid(drv ~ cyl)
mean? How do they relate to this plot?
そのようなcylとdrvの組み合わせを持つ車が存在しないことを意味する。
expand(mpg, cyl, drv) %>% left_join(count(mpg, cyl, drv))
3. What plots does the following code make? What does . do?
For compatibility with the classic interface, ‘rows’ can also be a formula with the rows (of the tabular display) on the LHS and the columns (of the tabular display) on the RHS; the dot in the formula is used to indicate there should be no faceting on this dimension (either row or column).
facet_grid
はformulaの左辺をrow、右辺をcolumnとして解釈する。.
は空を意味する。
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(drv ~ .)
## 上と同じ
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(rows = vars(drv))
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(. ~ cyl)
## 上と同じ
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(cols = vars(cyl))
4. Take the first faceted plot in this section:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_wrap(~ class, nrow = 2)
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = class))
What are the advantages to using faceting instead of the colour aesthetic? What are the disadvantages? How might the balance change if you had a larger dataset?
classがもっと多くなると、色での見分けは困難になる。少ないうちは色のほうが一目で理解しやすい。
5. Read ?facet_wrap. What does nrow do? What does ncol do? What other options control the layout of the individual panels? Why doesn’t facet_grid() have nrow and ncol arguments?
nrowとncolで表示する際の行数、列数を指定している。facet_grid
の場合、それらはデータによって決まるので指定する意味がない。
6. When using facet_grid() you should usually put the variable with more unique levels in the columns. Why?
問題の意味がよくわからなかった。 colsの値が一つしかなかったら意味がないということ?
mpg %>% mutate(x = 1) %>%
ggplot() +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(cols = vars(x))

3.6.1 Exercises
1. What geom would you use to draw a line chart? A boxplot? A histogram? An area chart?
geom_line
,geom_path
,geom_boxplot
,geom_histogram
,geom_area
2. Run this code in your head and predict what the output will look like. Then, run the code in R and check your predictions.
ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) +
geom_point() +
geom_smooth(se = FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

3. What does show.legend = FALSE
do? What happens if you remove it? Why do you think I used it earlier in the chapter?
他のプロットと表示を揃えるため。
ggplot(data = mpg) +
geom_smooth(
mapping = aes(x = displ, y = hwy, color = drv),
show.legend = FALSE
)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

4. What does the se argument to geom_smooth() do?
信頼区間を表示するかどうか。
5. Will these two graphs look different? Why/why not?
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_point() +
geom_smooth()
ggplot() +
geom_point(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_smooth(data = mpg, mapping = aes(x = displ, y = hwy))
同じ。ggplotでデフォルトのmappingを指定しているので。
6. Recreate the R code necessary to generate the following graphs.
p_base <- ggplot(mpg, aes(displ, hwy))
p_point <- p_base + geom_point()
p1 <- p_point + geom_smooth(se = FALSE)
p2 <- p_point + geom_smooth(aes(group = drv), se = FALSE)
p_color <- p_base + geom_point(aes(color = drv))
p3 <- p_color + geom_smooth(aes(color = drv), se = FALSE)
p4 <- p_color + geom_smooth(se = FALSE)
p5 <- p_color + geom_smooth(aes(linetype = drv), se = FALSE)
p6 <- p_base + geom_point(color = "white", size = 4) + geom_point(aes(color = drv))
p1 + p2 + p3 + p4 + p5 + p6 + plot_layout(ncol = 2)

3.7.1 Exercises
1. What is the default geom associated with stat_summary()
? How could you rewrite the previous plot to use that geom function instead of the stat function?
diamonds %>% group_by(cut) %>%
summarise(ymin = min(depth),
ymax = max(depth),
y = median(depth)) %>%
ggplot() +
geom_pointrange(aes(x = cut, y = y, ymin = ymin, ymax = ymax))

2. What does geom_col()
do? How is it different to geom_bar()
?
geom_bar
はstat_count
を使うが、geom_col
はidentity
を使っている。 カウント部分を自前で処理したデータを表示したいときに便利。
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut))
diamonds %>% count(cut) %>%
ggplot() +
geom_col(aes(x = cut, y = n))
diamonds %>% count(cut) %>%
ggplot() +
geom_bar(aes(x = cut, y = n), stat = "identity")
3. Most geoms and stats come in pairs that are almost always used in concert. Read through the documentation and make a list of all the pairs. What do they have in common?
面倒なのでパス
4. What variables does stat_smooth()
compute? What parameters control its behaviour?
y predicted value ymin lower pointwise confidence interval around the mean ymax upper pointwise confidence interval around the mean se standard error
Smoothing methodを変更すると変わる。
5. In our proportion bar chart, we need to set group = 1. Why? In other words what is the problem with these two graphs?
1
prop
はgroupごとに計算される。 デフォルトだとxがグループになるので(この場合cut)、全てを同じグループにするために1を渡す必要がある
p1 <- ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, y = ..prop..))
ggplot_build(p1)$data[[1]] %>% select(count, prop, x, group)
p2 <- ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, y = ..prop.., group = 1))
ggplot_build(p2)$data[[1]] %>% select(count, prop, x, group)
p1 + p2

2
groupをcutにすると上手くいかないのでcountした。
diamonds %>% count(cut, color) %>% mutate(prop = n/sum(n)) %>%
ggplot() +
geom_col(mapping = aes(x = cut, y = prop, fill = color))

3.8.1 Exercises
1. What is the problem with this plot? How could you improve it?
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point()

重なりが多いのでjitterしてみる。
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_jitter()

2. What parameters to geom_jitter() control the amount of jittering?
width
とheight
3. Compare and contrast geom_jitter()
with geom_count()
.
上でjitterしてみたものをcountしてみる。
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_count()

重なっている点の数にばらつきがあるならcountの方がいい。 重なっている点の数がだいたい同じようならjitterの方がいい。
4. What’s the default position adjustment for geom_boxplot()? Create a visualisation of the mpg dataset that demonstrates it.
p <- ggplot(mpg, aes(class, hwy, color = drv))
p1 <- p + geom_boxplot() + labs(title = "dodge2")
p2 <- p + geom_boxplot(position = "identity") + labs(title = "identity")
p1 + p2

3.9.1 Exercises
1. Turn a stacked bar chart into a pie chart using coord_polar()
.
p1 <- diamonds %>%
ggplot() +
geom_bar(mapping = aes(x = cut, fill = color), position = "fill")
p2 <- p1 + coord_polar(theta = "y")
p1 + p2

2. What does labs()
do? Read the documentation.
タイトルやキャプションをつける。
3. What’s the difference between coord_quickmap()
and coord_map()
?
緯度経度による歪みの補正があったりなかったり。
nz <- map_data("nz")
# Prepare a map of NZ
nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", colour = "black")
# Plot it in cartesian coordinates
(nzmap + labs(title = "normal")) +
(nzmap + coord_map() + labs(title = "map")) +
(nzmap + coord_quickmap() + labs(title = "quickmap"))

4. What does the plot below tell you about the relationship between city and highway mpg? Why is coord_fixed()
important? What does geom_abline()
do?
cty
とhwy
が傾き1の直線にのるような関係であることを示すために、 プロット画面の縦横比が変わっても描画領域の縦横比が変わらないようにしている。
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point() +
geom_abline() +
coord_fixed()

LS0tCnRpdGxlOiAiRGF0YSB2aXN1YWxpc2F0aW9uIgpkYXRlOiAiYHIgbHVicmlkYXRlOjp0b2RheSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICBwZGZfZG9jdW1lbnQ6CiAgICBsYXRleF9lbmdpbmU6IGx1YWxhdGV4CmRvY3VtZW50Y2xhc3M6IGx0anNhcnRpY2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHJsYW5nKQpsaWJyYXJ5KG1hcHMpCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUpCmBgYAoKIyMgMy4yLjQgRXhlcmNpc2VzCgojIyMgMS4gUnVuIGBnZ3Bsb3QoZGF0YSA9IG1wZylgLiBXaGF0IGRvIHlvdSBzZWU/CmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykKYGBgCgojIyMgMi4gSG93IG1hbnkgcm93cyBhcmUgaW4gYG1wZ2A/IEhvdyBtYW55IGNvbHVtbnM/CmByIG5yb3cobXBnKWDlgIvjga7jg4fjg7zjgr/jgYzjgYLjgorjgb7jgZnjgIIKCiMjIyAzLiBXaGF0IGRvZXMgdGhlIGBkcnZgIHZhcmlhYmxlIGRlc2NyaWJlPyBSZWFkIHRoZSBoZWxwIGZvciBgP21wZ2AgdG8gZmluZCBvdXQuCuODmOODq+ODl+OCkuiqreOBv+OBvuOBl+OBn+OAggoKIyMjIDQuIE1ha2UgYSBzY2F0dGVycGxvdCBvZiBgaHd5YCB2cyBgY3lsYC4KYGBge3J9Cm1wZyAlPiUKICBnZ3Bsb3QoYWVzKGh3eSwgY3lsKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCiMjIyA1LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1ha2UgYSBzY2F0dGVycGxvdCBvZiBgY2xhc3NgIHZzIGBkcnZgPyBXaHkgaXMgdGhlIHBsb3Qgbm90IHVzZWZ1bD8K6KSH5pWw44Gu44OH44O844K/44GM5LiA44Gk44Gu5qC85a2Q54K544Gr6YeN44Gq44KK44GZ44GO44Gm44GE44KL44Gf44KB44CB5YiG5biD44Gu5qeY5a2Q44GM44KP44GL44KJ44Gq44GE44CCCmBgYHtyfQptcGcgJT4lCiAgZ2dwbG90KGFlcyhjbGFzcywgZHJ2KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCiMjIyMg5pS56Imv54mIMQpgZ2VvbV9qaXR0ZXJg44KS5L2/44Gj44Gm44OQ44Op44Gk44GN44KS5oyB44Gf44Gb44KL44CCCmBgYHtyfQptcGcgJT4lCiAgZ2dwbG90KGFlcyhjbGFzcywgZHJ2KSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xNSwgaGVpZ2h0ID0gMC4xNSwgYWxwaGEgPSAwLjQpCmBgYAoKIyMjIyDmlLnoia/niYgyCumHjeOBquOBo+OBpuOCi+ODh+ODvOOCv+OBruaVsOOCkuOAgeeCueOBruOCteOCpOOCuuOBqOOBl+OBpuihqOePvuOBmeOCi+OAggpgYGB7cn0KbXBnICU+JQogIGNvdW50KGNsYXNzLCBkcnYpICU+JQogIGdncGxvdChhZXMoY2xhc3MsIGRydikpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gbikpCmBgYAoKIyMgMy4zLjEgRXhlcmNpc2VzCgojIyMgMS4gV2hhdOKAmXMgZ29uZSB3cm9uZyB3aXRoIHRoaXMgY29kZT8gV2h5IGFyZSB0aGUgcG9pbnRzIG5vdCBibHVlPwpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSAiYmx1ZSIpKQpgYGAKYGFlc2DplqLmlbDjga/lvJXmlbDjgpLjg4fjg7zjgr/jgajjgZfjgabop6Pph4jjgZnjgovjga7jgafjgIHkuIroqJjjga7jgrPjg7zjg4njga/ku6XkuIvjgajlkIzjgZjjgojjgYbjgarmhI/lkbPjgavjgarjgovjgIIKYGBge3J9Cm1wZyAlPiUgbXV0YXRlKGNvbG9yID0gImJsdWUiKSAlPiUKICBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBjb2xvcikpCmBgYAoKIyMjIyDkv67mraPniYgKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJibHVlIikKYGBgCgojIyMgMi4gV2hpY2ggdmFyaWFibGVzIGluIGBtcGdgIGFyZSBjYXRlZ29yaWNhbD8gV2hpY2ggdmFyaWFibGVzIGFyZSBjb250aW51b3VzPyAoSGludDogdHlwZSBgP21wZ2AgdG8gcmVhZCB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGRhdGFzZXQpLiBIb3cgY2FuIHlvdSBzZWUgdGhpcyBpbmZvcm1hdGlvbiB3aGVuIHlvdSBydW4gYG1wZ2A/CgpgaXMuY2hhcmFjdGVyYOOBp+OBguOCjOOBsOOCq+ODhuOCtOODquOCq+ODqz8KYGBge3IsIGV2YWwgPSBGQUxTRX0KbXBnICU+JSBzZWxlY3RfaWYoaXMuY2hhcmFjdGVyKSAlPiUgbmFtZXMKYGBgCgojIyMgMy4gTWFwIGEgY29udGludW91cyB2YXJpYWJsZSB0byBgY29sb3JgLCBgc2l6ZWAsIGFuZCBgc2hhcGVgLiBIb3cgZG8gdGhlc2UgYWVzdGhldGljcyBiZWhhdmUgZGlmZmVyZW50bHkgZm9yIGNhdGVnb3JpY2FsIHZzLiBjb250aW51b3VzIHZhcmlhYmxlcz8KCnNoYXBl44Gv6YCj57aa44Gg44Go44OA44Oh44CCCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIyBteXBsb3QgPC0gZnVuY3Rpb24oYWVzX25hbWUsIHZhcl9uYW1lKSB7CiMjICAgYWVzX25hbWUgPC0gc3ltKGFlc19uYW1lKQojIyAgIHZhcl9uYW1lIDwtIHN5bSh2YXJfbmFtZSkKIyMgICBwIDwtIGdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5KSkgKwojIyAgICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKCEhYWVzX25hbWUgOj0gISF2YXJfbmFtZSkpCiMjICAgcHJpbnQocCkKIyMgfQoKbXlwbG90IDwtIGZ1bmN0aW9uKGFlc19uYW1lLCB2YXJfbmFtZSkgewogIGFlc19uYW1lIDwtIHN5bShhZXNfbmFtZSkKICB2YXJfbmFtZSA8LSBzeW0odmFyX25hbWUpCiAgZ2dwbG90KG1wZykgKwogICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksICEhYWVzX25hbWUgOj0gISF2YXJfbmFtZSkpCn0KCnZhcl9uYW1lcyA8LSBtcGcgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUgbmFtZXMKYWVzX25hbWVzIDwtIGMoImNvbG9yIiwgInNpemUiLCAic2hhcGUiKQoKcGxvdHMgPC0gY3Jvc3NpbmcoYWVzX25hbWUgPSBhZXNfbmFtZXMsIHZhcl9uYW1lID0gdmFyX25hbWVzKSAgJT4lIHBtYXAobXlwbG90KQpwbG90cyAlPiUgd2FsayhzYWZlbHkocHJpbnQpKQpgYGAKCiMjIyA0LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1hcCB0aGUgc2FtZSB2YXJpYWJsZSB0byBtdWx0aXBsZSBhZXN0aGV0aWNzPwoKYGBge3J9CmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2xhc3MsIHNoYXBlID0gY2xhc3MsIHNpemUgPSBjbGFzcykpCmBgYAoKIyMjIDUuIFdoYXQgZG9lcyB0aGUgYHN0cm9rZWAgYWVzdGhldGljIGRvPyBXaGF0IHNoYXBlcyBkb2VzIGl0IHdvcmsgd2l0aD8gKEhpbnQ6IHVzZSBgP2dlb21fcG9pbnRgKQoKYGBge3J9CiMgRm9yIHNoYXBlcyB0aGF0IGhhdmUgYSBib3JkZXIgKGxpa2UgMjEpLCB5b3UgY2FuIGNvbG91ciB0aGUgaW5zaWRlIGFuZAojIG91dHNpZGUgc2VwYXJhdGVseS4gVXNlIHRoZSBzdHJva2UgYWVzdGhldGljIHRvIG1vZGlmeSB0aGUgd2lkdGggb2YgdGhlCiMgYm9yZGVyCmdncGxvdChtdGNhcnMsIGFlcyh3dCwgbXBnKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgY29sb3VyID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIsIHNpemUgPSA1LCBzdHJva2UgPSA1KQpgYGAKCiMjIyA2LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1hcCBhbiBhZXRoZXRpYyB0byBzb21ldGhpbmcgb3RoZXIgdGhhbiBhIHZhcmlhYmxlIG5hbWUsIGxpa2UgYGFlcyhjb2xvdXIgPSBkaXNwbCA8IDUpYD8gTm90ZSwgeW91J2xsIGFsc28gbmVlZCB0byBzcGVjaWZ5IHggYW5kIHkuCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGRpc3BsLCBod3kpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gZGlzcGwgPCA1KSkKYGBgCgoKIyMgMy41LjEgRXhlcmNpc2VzCgojIyMgMS4gV2hhdCBoYXBwZW5zIGlmIHlvdSBmYWNldCBvbiBhIGNvbnRpbnVvdXMgdmFyaWFibGU/CuOBn+OBj+OBleOCk+OBp+OBpuOBj+OCi+OAggpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGh3eSwgY3R5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+ZGlzcGwpICAKYGBgCgojIyMgMi4gV2hhdCBkbyB0aGUgZW1wdHkgY2VsbHMgaW4gcGxvdCB3aXRoIGBmYWNldF9ncmlkKGRydiB+IGN5bClgIG1lYW4/IEhvdyBkbyB0aGV5IHJlbGF0ZSB0byB0aGlzIHBsb3Q/CgrjgZ3jga7jgojjgYbjgapjeWzjgahkcnbjga7ntYTjgb/lkIjjgo/jgZvjgpLmjIHjgaTou4rjgYzlrZjlnKjjgZfjgarjgYTjgZPjgajjgpLmhI/lkbPjgZnjgovjgIIKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpleHBhbmQobXBnLCBjeWwsIGRydikgJT4lIGxlZnRfam9pbihjb3VudChtcGcsIGN5bCwgZHJ2KSkKYGBgCgojIyMgMy4gV2hhdCBwbG90cyBkb2VzIHRoZSBmb2xsb3dpbmcgY29kZSBtYWtlPyBXaGF0IGRvZXMgLiBkbz8KCj4gIEZvciBjb21wYXRpYmlsaXR5IHdpdGggdGhlIGNsYXNzaWMgaW50ZXJmYWNlLCDigJhyb3dz4oCZIGNhbgo+ICBhbHNvIGJlIGEgZm9ybXVsYSB3aXRoIHRoZSByb3dzIChvZiB0aGUgdGFidWxhciBkaXNwbGF5KSBvbgo+ICB0aGUgTEhTIGFuZCB0aGUgY29sdW1ucyAob2YgdGhlIHRhYnVsYXIgZGlzcGxheSkgb24gdGhlIFJIUzsKPiAgdGhlIGRvdCBpbiB0aGUgZm9ybXVsYSBpcyB1c2VkIHRvIGluZGljYXRlIHRoZXJlIHNob3VsZCBiZSBubwo+ICBmYWNldGluZyBvbiB0aGlzIGRpbWVuc2lvbiAoZWl0aGVyIHJvdyBvciBjb2x1bW4pLgoKYGZhY2V0X2dyaWRg44GvZm9ybXVsYeOBruW3pui+uuOCknJvd+OAgeWPs+i+uuOCkmNvbHVtbuOBqOOBl+OBpuino+mHiOOBmeOCi+OAgmAuYOOBr+epuuOCkuaEj+WRs+OBmeOCi+OAggoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF9ncmlkKGRydiB+IC4pCgojIyDkuIrjgajlkIzjgZgKZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGRydikpCgpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoLiB+IGN5bCkKCiMjIOS4iuOBqOWQjOOBmApnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY3lsKSkKYGBgCgojIyMgNC4gVGFrZSB0aGUgZmlyc3QgZmFjZXRlZCBwbG90IGluIHRoaXMgc2VjdGlvbjoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZmFjZXRfd3JhcCh+IGNsYXNzLCBucm93ID0gMikKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gY2xhc3MpKQpgYGAKV2hhdCBhcmUgdGhlIGFkdmFudGFnZXMgdG8gdXNpbmcgZmFjZXRpbmcgaW5zdGVhZCBvZiB0aGUgY29sb3VyIGFlc3RoZXRpYz8gV2hhdCBhcmUgdGhlIGRpc2FkdmFudGFnZXM/IEhvdyBtaWdodCB0aGUgYmFsYW5jZSBjaGFuZ2UgaWYgeW91IGhhZCBhIGxhcmdlciBkYXRhc2V0PwoKCmNsYXNz44GM44KC44Gj44Go5aSa44GP44Gq44KL44Go44CB6Imy44Gn44Gu6KaL5YiG44GR44Gv5Zuw6Zuj44Gr44Gq44KL44CC5bCR44Gq44GE44GG44Gh44Gv6Imy44Gu44G744GG44GM5LiA55uu44Gn55CG6Kej44GX44KE44GZ44GE44CCCgojIyMgNS4gUmVhZCA/ZmFjZXRfd3JhcC4gV2hhdCBkb2VzIG5yb3cgZG8/IFdoYXQgZG9lcyBuY29sIGRvPyBXaGF0IG90aGVyIG9wdGlvbnMgY29udHJvbCB0aGUgbGF5b3V0IG9mIHRoZSBpbmRpdmlkdWFsIHBhbmVscz8gV2h5IGRvZXNu4oCZdCBmYWNldF9ncmlkKCkgaGF2ZSBucm93IGFuZCBuY29sIGFyZ3VtZW50cz8KCm5yb3fjgahuY29s44Gn6KGo56S644GZ44KL6Zqb44Gu6KGM5pWw44CB5YiX5pWw44KS5oyH5a6a44GX44Gm44GE44KL44CCYGZhY2V0X2dyaWRg44Gu5aC05ZCI44CB44Gd44KM44KJ44Gv44OH44O844K/44Gr44KI44Gj44Gm5rG644G+44KL44Gu44Gn5oyH5a6a44GZ44KL5oSP5ZGz44GM44Gq44GE44CCCgojIyMgNi4gV2hlbiB1c2luZyBmYWNldF9ncmlkKCkgeW91IHNob3VsZCB1c3VhbGx5IHB1dCB0aGUgdmFyaWFibGUgd2l0aCBtb3JlIHVuaXF1ZSBsZXZlbHMgaW4gdGhlIGNvbHVtbnMuIFdoeT8KCuWVj+mhjOOBruaEj+WRs+OBjOOCiOOBj+OCj+OBi+OCieOBquOBi+OBo+OBn+OAggpjb2xz44Gu5YCk44GM5LiA44Gk44GX44GL44Gq44GL44Gj44Gf44KJ5oSP5ZGz44GM44Gq44GE44Go44GE44GG44GT44GoPwpgYGB7cn0KbXBnICU+JSBtdXRhdGUoeCA9IDEpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoeCkpCmBgYAoKCiMjIDMuNi4xIEV4ZXJjaXNlcwoKIyMjIDEuIFdoYXQgZ2VvbSB3b3VsZCB5b3UgdXNlIHRvIGRyYXcgYSBsaW5lIGNoYXJ0PyBBIGJveHBsb3Q/IEEgaGlzdG9ncmFtPyBBbiBhcmVhIGNoYXJ0PwoKYGdlb21fbGluZWAsYGdlb21fcGF0aGAsYGdlb21fYm94cGxvdGAsYGdlb21faGlzdG9ncmFtYCxgZ2VvbV9hcmVhYAoKIyMjIDIuIFJ1biB0aGlzIGNvZGUgaW4geW91ciBoZWFkIGFuZCBwcmVkaWN0IHdoYXQgdGhlIG91dHB1dCB3aWxsIGxvb2sgbGlrZS4gVGhlbiwgcnVuIHRoZSBjb2RlIGluIFIgYW5kIGNoZWNrIHlvdXIgcHJlZGljdGlvbnMuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKYGBgCgojIyMgMy4gV2hhdCBkb2VzIGBzaG93LmxlZ2VuZCA9IEZBTFNFYCBkbz8gV2hhdCBoYXBwZW5zIGlmIHlvdSByZW1vdmUgaXQ/IFdoeSBkbyB5b3UgdGhpbmsgSSB1c2VkIGl0IGVhcmxpZXIgaW4gdGhlIGNoYXB0ZXI/CuS7luOBruODl+ODreODg+ODiOOBqOihqOekuuOCkuaPg+OBiOOCi+OBn+OCgeOAggpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3Ntb290aCgKICAgIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydiksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKQpgYGAKCiMjIyA0LiBXaGF0IGRvZXMgdGhlIHNlIGFyZ3VtZW50IHRvIGdlb21fc21vb3RoKCkgZG8/Cgrkv6HpoLzljLrplpPjgpLooajnpLrjgZnjgovjgYvjganjgYbjgYvjgIIKCiMjIyA1LiBXaWxsIHRoZXNlIHR3byBncmFwaHMgbG9vayBkaWZmZXJlbnQ/IFdoeS93aHkgbm90PwoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aCgpCgpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGdlb21fc21vb3RoKGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkKYGBgCuWQjOOBmOOAgmdncGxvdOOBp+ODh+ODleOCqeODq+ODiOOBrm1hcHBpbmfjgpLmjIflrprjgZfjgabjgYTjgovjga7jgafjgIIKCiMjIyA2LiBSZWNyZWF0ZSB0aGUgUiBjb2RlIG5lY2Vzc2FyeSB0byBnZW5lcmF0ZSB0aGUgZm9sbG93aW5nIGdyYXBocy4KCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CnBfYmFzZSA8LSBnZ3Bsb3QobXBnLCBhZXMoZGlzcGwsIGh3eSkpCnBfcG9pbnQgPC0gcF9iYXNlICsgZ2VvbV9wb2ludCgpCgpwMSA8LSBwX3BvaW50ICsgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKcDIgPC0gcF9wb2ludCArIGdlb21fc21vb3RoKGFlcyhncm91cCA9IGRydiksIHNlID0gRkFMU0UpCgpwX2NvbG9yIDwtIHBfYmFzZSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZHJ2KSkKcDMgPC0gcF9jb2xvciArIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IGRydiksIHNlID0gRkFMU0UpCnA0IDwtIHBfY29sb3IgKyBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQpwNSA8LSBwX2NvbG9yICsgZ2VvbV9zbW9vdGgoYWVzKGxpbmV0eXBlID0gZHJ2KSwgc2UgPSBGQUxTRSkKcDYgPC0gcF9iYXNlICsgZ2VvbV9wb2ludChjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA0KSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZHJ2KSkKCnAxICsgcDIgKyBwMyArIHA0ICsgcDUgKyBwNiArIHBsb3RfbGF5b3V0KG5jb2wgPSAyKQpgYGAKCiMjIDMuNy4xIEV4ZXJjaXNlcwoKIyMjIDEuIFdoYXQgaXMgdGhlIGRlZmF1bHQgZ2VvbSBhc3NvY2lhdGVkIHdpdGggYHN0YXRfc3VtbWFyeSgpYD8gSG93IGNvdWxkIHlvdSByZXdyaXRlIHRoZSBwcmV2aW91cyBwbG90IHRvIHVzZSB0aGF0IGdlb20gZnVuY3Rpb24gaW5zdGVhZCBvZiB0aGUgc3RhdCBmdW5jdGlvbj8KCmBgYHtyfQpkaWFtb25kcyAlPiUgZ3JvdXBfYnkoY3V0KSAlPiUKICBzdW1tYXJpc2UoeW1pbiA9IG1pbihkZXB0aCksCiAgICAgICAgICAgIHltYXggPSBtYXgoZGVwdGgpLAogICAgICAgICAgICB5ID0gbWVkaWFuKGRlcHRoKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeCA9IGN1dCwgeSA9IHksIHltaW4gPSB5bWluLCB5bWF4ID0geW1heCkpCmBgYAoKIyMjIDIuIFdoYXQgZG9lcyBgZ2VvbV9jb2woKWAgZG8/IEhvdyBpcyBpdCBkaWZmZXJlbnQgdG8gYGdlb21fYmFyKClgPwoKYGdlb21fYmFyYOOBr2BzdGF0X2NvdW50YOOCkuS9v+OBhuOBjOOAgWBnZW9tX2NvbGDjga9gaWRlbnRpdHlg44KS5L2/44Gj44Gm44GE44KL44CCCuOCq+OCpuODs+ODiOmDqOWIhuOCkuiHquWJjeOBp+WHpueQhuOBl+OBn+ODh+ODvOOCv+OCkuihqOekuuOBl+OBn+OBhOOBqOOBjeOBq+S+v+WIqeOAggoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQpKQoKZGlhbW9uZHMgJT4lIGNvdW50KGN1dCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gY3V0LCB5ID0gbikpCgpkaWFtb25kcyAlPiUgY291bnQoY3V0KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoYWVzKHggPSBjdXQsIHkgPSBuKSwgc3RhdCA9ICJpZGVudGl0eSIpCmBgYAoKIyMjIDMuIE1vc3QgZ2VvbXMgYW5kIHN0YXRzIGNvbWUgaW4gcGFpcnMgdGhhdCBhcmUgYWxtb3N0IGFsd2F5cyB1c2VkIGluIGNvbmNlcnQuIFJlYWQgdGhyb3VnaCB0aGUgZG9jdW1lbnRhdGlvbiBhbmQgbWFrZSBhIGxpc3Qgb2YgYWxsIHRoZSBwYWlycy4gV2hhdCBkbyB0aGV5IGhhdmUgaW4gY29tbW9uPwoK6Z2i5YCS44Gq44Gu44Gn44OR44K5CgojIyMgNC4gV2hhdCB2YXJpYWJsZXMgZG9lcyBgc3RhdF9zbW9vdGgoKWAgY29tcHV0ZT8gV2hhdCBwYXJhbWV0ZXJzIGNvbnRyb2wgaXRzIGJlaGF2aW91cj8KCj4geSBwcmVkaWN0ZWQgdmFsdWUKPiB5bWluIGxvd2VyIHBvaW50d2lzZSBjb25maWRlbmNlIGludGVydmFsIGFyb3VuZCB0aGUgbWVhbgo+IHltYXggdXBwZXIgcG9pbnR3aXNlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYXJvdW5kIHRoZSBtZWFuCj4gc2Ugc3RhbmRhcmQgZXJyb3IKClNtb290aGluZyBtZXRob2TjgpLlpInmm7TjgZnjgovjgajlpInjgo/jgovjgIIKCiMjIyA1LiBJbiBvdXIgcHJvcG9ydGlvbiBiYXIgY2hhcnQsIHdlIG5lZWQgdG8gc2V0IGdyb3VwID0gMS4gV2h5PyBJbiBvdGhlciB3b3JkcyB3aGF0IGlzIHRoZSBwcm9ibGVtIHdpdGggdGhlc2UgdHdvIGdyYXBocz8KCiMjIyMgMQpgcHJvcGDjga9ncm91cOOBlOOBqOOBq+ioiOeul+OBleOCjOOCi+OAggrjg4fjg5Xjgqnjg6vjg4jjgaDjgah444GM44Kw44Or44O844OX44Gr44Gq44KL44Gu44GnKOOBk+OBruWgtOWQiGN1dCnjgIHlhajjgabjgpLlkIzjgZjjgrDjg6vjg7zjg5fjgavjgZnjgovjgZ/jgoHjgasx44KS5rih44GZ5b+F6KaB44GM44GC44KLCgpgYGB7cn0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSAuLnByb3AuLikpCmdncGxvdF9idWlsZChwMSkkZGF0YVtbMV1dICU+JSBzZWxlY3QoY291bnQsIHByb3AsIHgsIGdyb3VwKQoKcDIgPC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSAuLnByb3AuLiwgZ3JvdXAgPSAxKSkKZ2dwbG90X2J1aWxkKHAyKSRkYXRhW1sxXV0gJT4lIHNlbGVjdChjb3VudCwgcHJvcCwgeCwgZ3JvdXApCgpwMSArIHAyCmBgYAoKIyMjIyAyCgpncm91cOOCkmN1dOOBq+OBmeOCi+OBqOS4iuaJi+OBj+OBhOOBi+OBquOBhOOBruOBp2NvdW5044GX44Gf44CCCgpgYGB7cn0KZGlhbW9uZHMgJT4lIGNvdW50KGN1dCwgY29sb3IpICU+JSBtdXRhdGUocHJvcCA9IG4vc3VtKG4pKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gcHJvcCwgZmlsbCA9IGNvbG9yKSkKYGBgCgoKIyMgMy44LjEgRXhlcmNpc2VzCgojIyMgMS4gV2hhdCBpcyB0aGUgcHJvYmxlbSB3aXRoIHRoaXMgcGxvdD8gSG93IGNvdWxkIHlvdSBpbXByb3ZlIGl0PwoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQoKQpgYGAKCumHjeOBquOCiuOBjOWkmuOBhOOBruOBp2ppdHRlcuOBl+OBpuOBv+OCi+OAggpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGN0eSwgeSA9IGh3eSkpICsgCiAgZ2VvbV9qaXR0ZXIoKQpgYGAKCiMjIyAyLiBXaGF0IHBhcmFtZXRlcnMgdG8gZ2VvbV9qaXR0ZXIoKSBjb250cm9sIHRoZSBhbW91bnQgb2Ygaml0dGVyaW5nPwoKYHdpZHRoYOOBqGBoZWlnaHRgCgojIyMgMy4gQ29tcGFyZSBhbmQgY29udHJhc3QgYGdlb21faml0dGVyKClgIHdpdGggYGdlb21fY291bnQoKWAuCgrkuIrjgadqaXR0ZXLjgZfjgabjgb/jgZ/jgoLjga7jgpJjb3VudOOBl+OBpuOBv+OCi+OAggoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKSArIAogIGdlb21fY291bnQoKQpgYGAKCumHjeOBquOBo+OBpuOBhOOCi+eCueOBruaVsOOBq+OBsOOCieOBpOOBjeOBjOOBguOCi+OBquOCiWNvdW5044Gu5pa544GM44GE44GE44CCCumHjeOBquOBo+OBpuOBhOOCi+eCueOBruaVsOOBjOOBoOOBhOOBn+OBhOWQjOOBmOOCiOOBhuOBquOCiWppdHRlcuOBruaWueOBjOOBhOOBhOOAggoKIyMjIDQuIFdoYXTigJlzIHRoZSBkZWZhdWx0IHBvc2l0aW9uIGFkanVzdG1lbnQgZm9yIGdlb21fYm94cGxvdCgpPyBDcmVhdGUgYSB2aXN1YWxpc2F0aW9uIG9mIHRoZSBtcGcgZGF0YXNldCB0aGF0IGRlbW9uc3RyYXRlcyBpdC4KCmBgYHtyfQpwIDwtIGdncGxvdChtcGcsIGFlcyhjbGFzcywgaHd5LCBjb2xvciA9IGRydikpCnAxIDwtIHAgKyBnZW9tX2JveHBsb3QoKSArIGxhYnModGl0bGUgPSAiZG9kZ2UyIikKcDIgPC0gcCArIGdlb21fYm94cGxvdChwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgbGFicyh0aXRsZSA9ICJpZGVudGl0eSIpCnAxICsgcDIKYGBgCgojIyAzLjkuMSBFeGVyY2lzZXMKCgojIyMgMS4gVHVybiBhIHN0YWNrZWQgYmFyIGNoYXJ0IGludG8gYSBwaWUgY2hhcnQgdXNpbmcgYGNvb3JkX3BvbGFyKClgLgoKYGBge3J9CnAxIDwtIGRpYW1vbmRzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjb2xvciksIHBvc2l0aW9uID0gImZpbGwiKQoKcDIgPC0gcDEgKyBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikKCnAxICsgcDIKYGBgCgojIyMgMi4gV2hhdCBkb2VzIGBsYWJzKClgIGRvPyBSZWFkIHRoZSBkb2N1bWVudGF0aW9uLgoK44K/44Kk44OI44Or44KE44Kt44Oj44OX44K344On44Oz44KS44Gk44GR44KL44CCCgojIyMgMy4gV2hhdOKAmXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBgY29vcmRfcXVpY2ttYXAoKWAgYW5kIGBjb29yZF9tYXAoKWA/Cgrnt6/luqbntYzluqbjgavjgojjgovmrarjgb/jga7oo5zmraPjgYzjgYLjgaPjgZ/jgorjgarjgYvjgaPjgZ/jgorjgIIKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KbnogPC0gbWFwX2RhdGEoIm56IikKIyBQcmVwYXJlIGEgbWFwIG9mIE5aCm56bWFwIDwtIGdncGxvdChueiwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fcG9seWdvbihmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImJsYWNrIikKCiMgUGxvdCBpdCBpbiBjYXJ0ZXNpYW4gY29vcmRpbmF0ZXMKKG56bWFwICsgbGFicyh0aXRsZSA9ICJub3JtYWwiKSkgKwogIChuem1hcCArIGNvb3JkX21hcCgpICsgbGFicyh0aXRsZSA9ICJtYXAiKSkgKwogIChuem1hcCArIGNvb3JkX3F1aWNrbWFwKCkgKyBsYWJzKHRpdGxlID0gInF1aWNrbWFwIikpCmBgYAojIyMgNC4gV2hhdCBkb2VzIHRoZSBwbG90IGJlbG93IHRlbGwgeW91IGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjaXR5IGFuZCBoaWdod2F5IG1wZz8gV2h5IGlzIGBjb29yZF9maXhlZCgpYCBpbXBvcnRhbnQ/IFdoYXQgZG9lcyBgZ2VvbV9hYmxpbmUoKWAgZG8/CgpgY3R5YOOBqGBod3lg44GM5YK+44GNMeOBruebtOe3muOBq+OBruOCi+OCiOOBhuOBqumWouS/guOBp+OBguOCi+OBk+OBqOOCkuekuuOBmeOBn+OCgeOBq+OAgQrjg5fjg63jg4Pjg4jnlLvpnaLjga7nuKbmqKrmr5TjgYzlpInjgo/jgaPjgabjgoLmj4/nlLvpoJjln5/jga7nuKbmqKrmr5TjgYzlpInjgo/jgonjgarjgYTjgojjgYbjgavjgZfjgabjgYTjgovjgIIKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY3R5LCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fYWJsaW5lKCkgKwogIGNvb3JkX2ZpeGVkKCkKYGBgCg==