Combine two plots by row

sapply(c("pipeR", "ggplot2", "readr", "lubridate"), require, character.only = TRUE)
 要求されたパッケージ pipeR をロード中です 
 要求されたパッケージ ggplot2 をロード中です 
 要求されたパッケージ readr をロード中です 
 要求されたパッケージ lubridate をロード中です 

 次のパッケージを付け加えます: ‘lubridate’ 

 以下のオブジェクトは ‘package:base’ からマスクされています: 

     date 
    pipeR   ggplot2     readr lubridate 
     TRUE      TRUE      TRUE      TRUE 

Naha

d1 <- read_csv("data/ggplot2-two-axis/naha.csv", skip = 5, col_names = c("Date", "Temperature", "Precipitation"), col_types = cols(col_date(format = "%Y/%m"), "d", "_", "_", "d", "_", "_", "_"), locale = locale(encoding = "SJIS"))
head(d1)

Use geom_segment() to match x axis

gp1 <- d1 %>>% ggplot() + 
  geom_segment(mapping = aes(x = Date, y = Precipitation * 30 / 400, xend = Date, yend = 0), size = 11, lineend = "butt", colour = gray(0.5)) + 
  geom_line(mapping = aes(x = Date, y = Temperature)) + 
  geom_point(mapping = aes(x = Date, y = Temperature), size = 3, shape = 21, fill = "white") + 
  scale_x_date(name = "Month", breaks = seq.Date(as.Date("2015-01-01"), as.Date("2015-12-31"), by = "1 month"), labels = function(date){return(month(date, label = TRUE))}) + 
  scale_y_continuous(
    name = expression("Temperature ("~degree~"C)"), 
    sec.axis = sec_axis(~ . * 400 / 30 , name = "Precipitation (mm)"), 
    limits = c(0, 30)) + 
  theme_bw() + 
  theme(
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank()
  )
gp1

Kushiro

d2 <- read_csv("data/ggplot2-two-axis/kushiro.csv", skip = 5, col_names = c("Date", "Temperature", "Precipitation"), col_types = cols(col_date(format = "%Y/%m"), "d", "_", "_", "d", "_", "_", "_"), locale = locale(encoding = "SJIS"))
head(d2)
gp2 <- d2 %>>% ggplot() + 
  geom_segment(mapping = aes(x = Date, y = Precipitation / 10 - 5, xend = Date, yend = -5), size = 11, lineend = "butt", colour = gray(0.5)) +
  geom_line(mapping = aes(x = Date, y = Temperature)) +
  geom_point(mapping = aes(x = Date, y = Temperature), size = 3, shape = 21, fill = "white") +
  scale_x_date(name = "Month", breaks = seq.Date(as.Date("2015-01-01"), as.Date("2015-12-31"), by = "1 month"), labels = function(date){return(month(date, label = TRUE))}) +
  scale_y_continuous(
    name = expression("Temperature ("~degree~"C)"),
    sec.axis = sec_axis(~ (. + 5) * 10 , name = "Precipitation (mm)"),
    limits = c(-5, 20)) +
  theme_bw() +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
  )
gp2

Combine by gridExtra::grid.arrange()

library("gridExtra")
grid.arrange(gp1, gp2, nrow = 2, heights = c(1, 1))

Share X axis

gp1$theme$axis.title.x <- element_blank()
gp1$theme$axis.text.x <- element_blank()
grid.arrange(gp1, gp2, nrow = 2, heights = c(1, 1))

Fix the height of above plot

grid.arrange(rbind(ggplotGrob(gp1), ggplotGrob(gp2), size = "last"))

Share Y axis title

library(grid)
gp1$theme$axis.title.y <- element_blank()
gp1 <- gp1 + annotate("text", x = as.Date("2015-01-01"), y = 28, label = "Naha", hjust = 0)
gp2$theme$axis.title.y <- element_blank()
gp2 <- gp2 + annotate("text", x = as.Date("2015-01-01"), y = 18, label = "Kushiro", hjust = 0)
grid.arrange(rbind(ggplotGrob(gp1), ggplotGrob(gp2), size = "last"), left = textGrob(label = expression("Temperature ("~degree~"C)"), rot = 90), right = "Precipitation (mm)")

Draw line from top of above plot to bottom of below plot

library("gtable")

20 \(\times\) 7 gtable

gp12 <- rbind(ggplotGrob(gp1), ggplotGrob(gp2), size = "last")
gp12
TableGrob (20 x 7) "layout": 34 grobs
    z         cells       name                                       grob
1   0 ( 1-10, 1- 7) background            rect[plot.background..rect.538]
2   5 ( 5- 5, 3- 3)     spacer                             zeroGrob[NULL]
3   7 ( 6- 6, 3- 3)     axis-l        absoluteGrob[GRID.absoluteGrob.526]
4   3 ( 7- 7, 3- 3)     spacer                             zeroGrob[NULL]
5   6 ( 5- 5, 4- 4)     axis-t                             zeroGrob[NULL]
6   1 ( 6- 6, 4- 4)      panel                   gTree[panel-1.gTree.511]
7   9 ( 7- 7, 4- 4)     axis-b        absoluteGrob[GRID.absoluteGrob.519]
8   4 ( 5- 5, 5- 5)     spacer                             zeroGrob[NULL]
9   8 ( 6- 6, 5- 5)     axis-r        absoluteGrob[GRID.absoluteGrob.533]
10  2 ( 7- 7, 5- 5)     spacer                             zeroGrob[NULL]
11 10 ( 4- 4, 4- 4)     xlab-t                             zeroGrob[NULL]
12 11 ( 8- 8, 4- 4)     xlab-b       zeroGrob[axis.title.x..zeroGrob.512]
13 12 ( 6- 6, 2- 2)     ylab-l       zeroGrob[axis.title.y..zeroGrob.513]
14 13 ( 6- 6, 6- 6)     ylab-r zeroGrob[axis.title.y.right..zeroGrob.514]
15 14 ( 3- 3, 4- 4)   subtitle      zeroGrob[plot.subtitle..zeroGrob.535]
16 15 ( 2- 2, 4- 4)      title         zeroGrob[plot.title..zeroGrob.534]
17 16 ( 9- 9, 4- 4)    caption       zeroGrob[plot.caption..zeroGrob.536]
18  0 (11-20, 1- 7) background            rect[plot.background..rect.586]
19  5 (15-15, 3- 3)     spacer                             zeroGrob[NULL]
20  7 (16-16, 3- 3)     axis-l        absoluteGrob[GRID.absoluteGrob.574]
21  3 (17-17, 3- 3)     spacer                             zeroGrob[NULL]
22  6 (15-15, 4- 4)     axis-t                             zeroGrob[NULL]
23  1 (16-16, 4- 4)      panel                   gTree[panel-1.gTree.555]
24  9 (17-17, 4- 4)     axis-b        absoluteGrob[GRID.absoluteGrob.567]
25  4 (15-15, 5- 5)     spacer                             zeroGrob[NULL]
26  8 (16-16, 5- 5)     axis-r        absoluteGrob[GRID.absoluteGrob.581]
27  2 (17-17, 5- 5)     spacer                             zeroGrob[NULL]
28 10 (14-14, 4- 4)     xlab-t                             zeroGrob[NULL]
29 11 (18-18, 4- 4)     xlab-b     titleGrob[axis.title.x..titleGrob.558]
30 12 (16-16, 2- 2)     ylab-l       zeroGrob[axis.title.y..zeroGrob.559]
31 13 (16-16, 6- 6)     ylab-r zeroGrob[axis.title.y.right..zeroGrob.560]
32 14 (13-13, 4- 4)   subtitle      zeroGrob[plot.subtitle..zeroGrob.583]
33 15 (12-12, 4- 4)      title         zeroGrob[plot.title..zeroGrob.582]
34 16 (19-19, 4- 4)    caption       zeroGrob[plot.caption..zeroGrob.584]
gt <- gtable_add_grob(gp12, segmentsGrob(x0 = 0.455, x1 = 0.455, y0 = 0.1, y1 = 0.98, gp=gpar(lty="dashed")), t = 1, l = 1, b = 20, r = 7, z = 1)
gt
TableGrob (20 x 7) "layout": 35 grobs
    z         cells       name                                       grob
1   0 ( 1-10, 1- 7) background            rect[plot.background..rect.538]
2   5 ( 5- 5, 3- 3)     spacer                             zeroGrob[NULL]
3   7 ( 6- 6, 3- 3)     axis-l        absoluteGrob[GRID.absoluteGrob.526]
4   3 ( 7- 7, 3- 3)     spacer                             zeroGrob[NULL]
5   6 ( 5- 5, 4- 4)     axis-t                             zeroGrob[NULL]
6   1 ( 6- 6, 4- 4)      panel                   gTree[panel-1.gTree.511]
7   9 ( 7- 7, 4- 4)     axis-b        absoluteGrob[GRID.absoluteGrob.519]
8   4 ( 5- 5, 5- 5)     spacer                             zeroGrob[NULL]
9   8 ( 6- 6, 5- 5)     axis-r        absoluteGrob[GRID.absoluteGrob.533]
10  2 ( 7- 7, 5- 5)     spacer                             zeroGrob[NULL]
11 10 ( 4- 4, 4- 4)     xlab-t                             zeroGrob[NULL]
12 11 ( 8- 8, 4- 4)     xlab-b       zeroGrob[axis.title.x..zeroGrob.512]
13 12 ( 6- 6, 2- 2)     ylab-l       zeroGrob[axis.title.y..zeroGrob.513]
14 13 ( 6- 6, 6- 6)     ylab-r zeroGrob[axis.title.y.right..zeroGrob.514]
15 14 ( 3- 3, 4- 4)   subtitle      zeroGrob[plot.subtitle..zeroGrob.535]
16 15 ( 2- 2, 4- 4)      title         zeroGrob[plot.title..zeroGrob.534]
17 16 ( 9- 9, 4- 4)    caption       zeroGrob[plot.caption..zeroGrob.536]
18  0 (11-20, 1- 7) background            rect[plot.background..rect.586]
19  5 (15-15, 3- 3)     spacer                             zeroGrob[NULL]
20  7 (16-16, 3- 3)     axis-l        absoluteGrob[GRID.absoluteGrob.574]
21  3 (17-17, 3- 3)     spacer                             zeroGrob[NULL]
22  6 (15-15, 4- 4)     axis-t                             zeroGrob[NULL]
23  1 (16-16, 4- 4)      panel                   gTree[panel-1.gTree.555]
24  9 (17-17, 4- 4)     axis-b        absoluteGrob[GRID.absoluteGrob.567]
25  4 (15-15, 5- 5)     spacer                             zeroGrob[NULL]
26  8 (16-16, 5- 5)     axis-r        absoluteGrob[GRID.absoluteGrob.581]
27  2 (17-17, 5- 5)     spacer                             zeroGrob[NULL]
28 10 (14-14, 4- 4)     xlab-t                             zeroGrob[NULL]
29 11 (18-18, 4- 4)     xlab-b     titleGrob[axis.title.x..titleGrob.558]
30 12 (16-16, 2- 2)     ylab-l       zeroGrob[axis.title.y..zeroGrob.559]
31 13 (16-16, 6- 6)     ylab-r zeroGrob[axis.title.y.right..zeroGrob.560]
32 14 (13-13, 4- 4)   subtitle      zeroGrob[plot.subtitle..zeroGrob.583]
33 15 (12-12, 4- 4)      title         zeroGrob[plot.title..zeroGrob.582]
34 16 (19-19, 4- 4)    caption       zeroGrob[plot.caption..zeroGrob.584]
35  1 ( 1-20, 1- 7)     layout                segments[GRID.segments.587]

Draw it

grid.arrange(gt, left = textGrob(label = expression("Temperature ("~degree~"C)"), rot = 90), right = "Precipitation (mm)")

devtools::session_info()
Session info ----------------------------------------------------------------------------------------------------------
 setting  value                       
 version  R version 3.3.2 (2016-10-31)
 system   x86_64, mingw32             
 ui       RStudio (1.0.44)            
 language (EN)                        
 collate  Japanese_Japan.932          
 tz       Asia/Tokyo                  
 date     2016-11-29                  
Packages --------------------------------------------------------------------------------------------------------------
 package    * version date       source        
 assertthat   0.1     2013-12-06 CRAN (R 3.2.1)
 colorspace   1.2-7   2016-10-11 CRAN (R 3.3.2)
 devtools     1.12.0  2016-06-24 CRAN (R 3.3.1)
 digest       0.6.10  2016-08-02 CRAN (R 3.3.1)
 ggplot2    * 2.2.0   2016-11-11 CRAN (R 3.3.2)
 gridExtra  * 2.2.1   2016-02-29 CRAN (R 3.2.5)
 gtable     * 0.2.0   2016-02-26 CRAN (R 3.2.5)
 knitr        1.15    2016-11-09 CRAN (R 3.3.2)
 labeling     0.3     2014-08-23 CRAN (R 3.2.1)
 lazyeval     0.2.0   2016-06-12 CRAN (R 3.2.5)
 lubridate  * 1.6.0   2016-09-13 CRAN (R 3.2.5)
 magrittr     1.5     2014-11-22 CRAN (R 3.2.1)
 memoise      1.0.0   2016-01-29 CRAN (R 3.2.3)
 munsell      0.4.3   2016-02-13 CRAN (R 3.2.5)
 pipeR      * 0.6.1.3 2016-04-04 CRAN (R 3.3.1)
 plyr         1.8.4   2016-06-08 CRAN (R 3.2.5)
 Rcpp         0.12.7  2016-09-05 CRAN (R 3.2.5)
 readr      * 1.0.0   2016-08-03 CRAN (R 3.2.5)
 scales       0.4.1   2016-11-09 CRAN (R 3.3.2)
 stringi      1.1.2   2016-10-01 CRAN (R 3.3.2)
 stringr      1.1.0   2016-08-19 CRAN (R 3.2.5)
 tibble       1.2     2016-08-26 CRAN (R 3.2.5)
 withr        1.0.2   2016-06-20 CRAN (R 3.2.5)
LS0tDQp0aXRsZTogImdncGxvdDI6IENvbWJpbmUgdHdvIHBsb3RzIGJ5IFJvdyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCi0tLQ0KDQoqIEVkaXQ6IEluY3JlbWVudGFsbHkgY2hhbmdlIGV4aXN0aW5nIHBsb3QgKDIwMTYtMTEtMjgpDQoNCi0tLQ0KDQpDb21iaW5lIFt0d28gcGxvdHNdKGh0dHBzOi8vd2hhdGFsbmsuZ2l0aHViLmlvL3ItdGlwcy9nZ3Bsb3QyLXNlY29uZGFyeS15LWF4aXMubmIuaHRtbCkgYnkgcm93DQoNCmBgYHtyfQ0Kc2FwcGx5KGMoInBpcGVSIiwgImdncGxvdDIiLCAicmVhZHIiLCAibHVicmlkYXRlIiksIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KTmFoYQ0KYGBge3J9DQpkMSA8LSByZWFkX2NzdigiZGF0YS9nZ3Bsb3QyLXR3by1heGlzL25haGEuY3N2Iiwgc2tpcCA9IDUsIGNvbF9uYW1lcyA9IGMoIkRhdGUiLCAiVGVtcGVyYXR1cmUiLCAiUHJlY2lwaXRhdGlvbiIpLCBjb2xfdHlwZXMgPSBjb2xzKGNvbF9kYXRlKGZvcm1hdCA9ICIlWS8lbSIpLCAiZCIsICJfIiwgIl8iLCAiZCIsICJfIiwgIl8iLCAiXyIpLCBsb2NhbGUgPSBsb2NhbGUoZW5jb2RpbmcgPSAiU0pJUyIpKQ0KaGVhZChkMSkNCmBgYA0KDQpVc2UgYGdlb21fc2VnbWVudCgpYCB0byBtYXRjaCB4IGF4aXMNCg0KYGBge3J9DQpncDEgPC0gZDEgJT4+JSBnZ3Bsb3QoKSArIA0KICBnZW9tX3NlZ21lbnQobWFwcGluZyA9IGFlcyh4ID0gRGF0ZSwgeSA9IFByZWNpcGl0YXRpb24gKiAzMCAvIDQwMCwgeGVuZCA9IERhdGUsIHllbmQgPSAwKSwgc2l6ZSA9IDExLCBsaW5lZW5kID0gImJ1dHQiLCBjb2xvdXIgPSBncmF5KDAuNSkpICsgDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBEYXRlLCB5ID0gVGVtcGVyYXR1cmUpKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IERhdGUsIHkgPSBUZW1wZXJhdHVyZSksIHNpemUgPSAzLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIikgKyANCiAgc2NhbGVfeF9kYXRlKG5hbWUgPSAiTW9udGgiLCBicmVha3MgPSBzZXEuRGF0ZShhcy5EYXRlKCIyMDE1LTAxLTAxIiksIGFzLkRhdGUoIjIwMTUtMTItMzEiKSwgYnkgPSAiMSBtb250aCIpLCBsYWJlbHMgPSBmdW5jdGlvbihkYXRlKXtyZXR1cm4obW9udGgoZGF0ZSwgbGFiZWwgPSBUUlVFKSl9KSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbmFtZSA9IGV4cHJlc3Npb24oIlRlbXBlcmF0dXJlICgifmRlZ3JlZX4iQykiKSwgDQogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gKiA0MDAgLyAzMCAsIG5hbWUgPSAiUHJlY2lwaXRhdGlvbiAobW0pIiksIA0KICAgIGxpbWl0cyA9IGMoMCwgMzApKSArIA0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkNCiAgKQ0KZ3AxDQpgYGANCg0KS3VzaGlybw0KYGBge3J9DQpkMiA8LSByZWFkX2NzdigiZGF0YS9nZ3Bsb3QyLXR3by1heGlzL2t1c2hpcm8uY3N2Iiwgc2tpcCA9IDUsIGNvbF9uYW1lcyA9IGMoIkRhdGUiLCAiVGVtcGVyYXR1cmUiLCAiUHJlY2lwaXRhdGlvbiIpLCBjb2xfdHlwZXMgPSBjb2xzKGNvbF9kYXRlKGZvcm1hdCA9ICIlWS8lbSIpLCAiZCIsICJfIiwgIl8iLCAiZCIsICJfIiwgIl8iLCAiXyIpLCBsb2NhbGUgPSBsb2NhbGUoZW5jb2RpbmcgPSAiU0pJUyIpKQ0KaGVhZChkMikNCmBgYA0KDQpgYGB7cn0NCmdwMiA8LSBkMiAlPj4lIGdncGxvdCgpICsgDQogIGdlb21fc2VnbWVudChtYXBwaW5nID0gYWVzKHggPSBEYXRlLCB5ID0gUHJlY2lwaXRhdGlvbiAvIDEwIC0gNSwgeGVuZCA9IERhdGUsIHllbmQgPSAtNSksIHNpemUgPSAxMSwgbGluZWVuZCA9ICJidXR0IiwgY29sb3VyID0gZ3JheSgwLjUpKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBEYXRlLCB5ID0gVGVtcGVyYXR1cmUpKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gRGF0ZSwgeSA9IFRlbXBlcmF0dXJlKSwgc2l6ZSA9IDMsIHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiKSArDQogIHNjYWxlX3hfZGF0ZShuYW1lID0gIk1vbnRoIiwgYnJlYWtzID0gc2VxLkRhdGUoYXMuRGF0ZSgiMjAxNS0wMS0wMSIpLCBhcy5EYXRlKCIyMDE1LTEyLTMxIiksIGJ5ID0gIjEgbW9udGgiKSwgbGFiZWxzID0gZnVuY3Rpb24oZGF0ZSl7cmV0dXJuKG1vbnRoKGRhdGUsIGxhYmVsID0gVFJVRSkpfSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbmFtZSA9IGV4cHJlc3Npb24oIlRlbXBlcmF0dXJlICgifmRlZ3JlZX4iQykiKSwNCiAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gKC4gKyA1KSAqIDEwICwgbmFtZSA9ICJQcmVjaXBpdGF0aW9uIChtbSkiKSwNCiAgICBsaW1pdHMgPSBjKC01LCAyMCkpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQpncDINCmBgYA0KDQpDb21iaW5lIGJ5IGBncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgpYA0KDQpgYGB7cn0NCmxpYnJhcnkoImdyaWRFeHRyYSIpDQpgYGANCmBgYHtyfQ0KZ3JpZC5hcnJhbmdlKGdwMSwgZ3AyLCBucm93ID0gMiwgaGVpZ2h0cyA9IGMoMSwgMSkpDQpgYGANCg0KU2hhcmUgWCBheGlzDQpgYGB7cn0NCmdwMSR0aGVtZSRheGlzLnRpdGxlLnggPC0gZWxlbWVudF9ibGFuaygpDQpncDEkdGhlbWUkYXhpcy50ZXh0LnggPC0gZWxlbWVudF9ibGFuaygpDQpncmlkLmFycmFuZ2UoZ3AxLCBncDIsIG5yb3cgPSAyLCBoZWlnaHRzID0gYygxLCAxKSkNCmBgYA0KDQpGaXggdGhlIGhlaWdodCBvZiBhYm92ZSBwbG90DQoNCiogQ3JlYXRlIGdyb2IgYnkgYGdncGxvdDI6OmdncGxvdEdyb2IoKWAgDQoqIENvbWJpbmUgZ3JvYiBhbmQgZml4IHRoZSBoZWlnaHQgYnkgYGdyaWRFeHRyYTo6cmJpbmQoZ3JvYjEsIGdyb2IyLCBzaXplID0gImxhc3QiKWANCiogRHJhdyBieSBgZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoKWANCg0KYGBge3J9DQpncmlkLmFycmFuZ2UocmJpbmQoZ2dwbG90R3JvYihncDEpLCBnZ3Bsb3RHcm9iKGdwMiksIHNpemUgPSAibGFzdCIpKQ0KYGBgDQoNClNoYXJlIFkgYXhpcyB0aXRsZQ0KDQoqIERyYXcgZmlyc3QgWSBheGlzIGJ5IHBhcmFtZXRlciBgbGVmdGAgb2YgYGdyaWQuYXJyYW5nZSgpYCwgc2Vjb25kIFkgYXhpcyBieSBgcmlnaHRgDQoqIEFzIGZvciBgZXhwcmVzc2lvbigpYCwgdXNlIGBncmlkOjp0ZXh0R3JvYigpYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ3JpZCkNCmBgYA0KYGBge3J9DQpncDEkdGhlbWUkYXhpcy50aXRsZS55IDwtIGVsZW1lbnRfYmxhbmsoKQ0KZ3AxIDwtIGdwMSArIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGFzLkRhdGUoIjIwMTUtMDEtMDEiKSwgeSA9IDI4LCBsYWJlbCA9ICJOYWhhIiwgaGp1c3QgPSAwKQ0KDQpncDIkdGhlbWUkYXhpcy50aXRsZS55IDwtIGVsZW1lbnRfYmxhbmsoKQ0KZ3AyIDwtIGdwMiArIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGFzLkRhdGUoIjIwMTUtMDEtMDEiKSwgeSA9IDE4LCBsYWJlbCA9ICJLdXNoaXJvIiwgaGp1c3QgPSAwKQ0KDQpncmlkLmFycmFuZ2UocmJpbmQoZ2dwbG90R3JvYihncDEpLCBnZ3Bsb3RHcm9iKGdwMiksIHNpemUgPSAibGFzdCIpLCBsZWZ0ID0gdGV4dEdyb2IobGFiZWwgPSBleHByZXNzaW9uKCJUZW1wZXJhdHVyZSAoIn5kZWdyZWV+IkMpIiksIHJvdCA9IDkwKSwgcmlnaHQgPSAiUHJlY2lwaXRhdGlvbiAobW0pIikNCmBgYA0KDQojIERyYXcgbGluZSBmcm9tIHRvcCBvZiBhYm92ZSBwbG90IHRvIGJvdHRvbSBvZiBiZWxvdyBwbG90DQpgYGB7cn0NCmxpYnJhcnkoImd0YWJsZSIpDQpgYGANCg0KMjAgJFx0aW1lcyQgNyBgZ3RhYmxlYA0KDQpgYGB7cn0NCmdwMTIgPC0gcmJpbmQoZ2dwbG90R3JvYihncDEpLCBnZ3Bsb3RHcm9iKGdwMiksIHNpemUgPSAibGFzdCIpDQpncDEyDQpgYGANCg0KKiBEcmF3IGxpbmUgYnkgYGdyaWQ6OnNlZ21lbnRzR3JvYigpYCBvbiAgKGFwcHJveGltYXRlbHkpIGAyMDE2LTAxLTAxYA0KKiBBZGQgYHNlZ21lbnRzR3JvYigpYCB0byBleGlzdGluZyBwbG90IGJ5IGBndGFibGU6Omd0YWJsZV9hZGRfZ3JvYigpYA0KICAgICogVG8gb3ZlcmxheSBvbiB0aGUgZW50aXJlIHBsb3QgKDIwICRcdGltZXMkIDcpLCBzcGVjaWZ5IGB0ID0gMSwgbCA9IDEsIGIgPSAyMCwgciA9IDdgDQoNCmBgYHtyfQ0KZ3QgPC0gZ3RhYmxlX2FkZF9ncm9iKGdwMTIsIHNlZ21lbnRzR3JvYih4MCA9IDAuNDU1LCB4MSA9IDAuNDU1LCB5MCA9IDAuMSwgeTEgPSAwLjk4LCBncD1ncGFyKGx0eT0iZGFzaGVkIikpLCB0ID0gMSwgbCA9IDEsIGIgPSAyMCwgciA9IDcsIHogPSAxKQ0KZ3QNCmBgYA0KDQpEcmF3IGl0DQpgYGB7cn0NCmdyaWQuYXJyYW5nZShndCwgbGVmdCA9IHRleHRHcm9iKGxhYmVsID0gZXhwcmVzc2lvbigiVGVtcGVyYXR1cmUgKCJ+ZGVncmVlfiJDKSIpLCByb3QgPSA5MCksIHJpZ2h0ID0gIlByZWNpcGl0YXRpb24gKG1tKSIpDQpgYGANCg0KYGBge3J9DQpkZXZ0b29sczo6c2Vzc2lvbl9pbmZvKCkNCmBgYA==