This is the supplementary material to an invited commentary for Basole et al. (2021). We provide all code that are used to generate the figures in the commentary in addition to other supplementary figures (and its code).
-
To see the code, click on the CODE button.
-
You can also download the whole R Markdown file from the drop down menu on the top right corner.
-
The GitHub repo for this material can be found at https://github.com/emitanaka/supp-visOM.
List of figures
- Figure S1: Recreating Figure 3 of Basole et al. (2021) using
ggplot2
.
- Figure S2: An alternative design to Figure 3 of Basole et al. (2021).
- Figure S3: Lineup for the tile grid plot used in Figure 3 of Basole et al. (2021).
- Figure S4: Lineup for the scatter plot.
- Figure S5: Lineup for the tile grid plot on data with purposely high association.
- Figure S6: Lineup for the scatter plot on data with purposely high association.
Code to load library and data
library(tidyverse)
library(ggtext)
library(patchwork)
library(readxl)
library(nullabor)
library(here)
library(janitor)
library(scales)
df_full <- read_xlsx(here("data/MaskedCoverage-Fig3.xlsx")) %>%
clean_names() %>%
add_row(state = c("OR", "WY", "SD", "WV", "DC", "AL")) %>%
mutate(row = case_when(
state %in% c("ME") ~ 1L,
state %in% c("VT", "NH") ~ 2L,
state %in% c("WA", "ID", "MT", "ND", "MN", "IL", "WI", "MI", "NY", "RI", "MA") ~ 3L,
state %in% c("OR", "NV", "WY", "SD", "IA", "IN", "OH", "PA", "NJ", "CT") ~ 4L,
state %in% c("CA", "UT", "CO", "NE", "MO", "KY", "WV", "VA", "MD", "DE") ~ 5L,
state %in% c("AZ", "NM", "KS", "AR", "TN", "NC", "SC", "DC") ~ 6L,
state %in% c("OK", "LA", "MS", "AL", "GA") ~ 7L,
state %in% c("TX", "FL") ~ 8L,
TRUE ~ 0L),
col = case_when(
state %in% c("WA", "OR", "CA") ~ 1L,
state %in% c("ID", "NV", "UT", "AZ") ~ 2L,
state %in% c("MT", "WY", "CO", "NM") ~ 3L,
state %in% c("ND", "SD", "NE", "KS", "OK", "TX") ~ 4L,
state %in% c("MN", "IA", "MO", "AR", "LA") ~ 5L,
state %in% c("IL", "IN", "KY", "TN", "MS") ~ 6L,
state %in% c("WI", "OH", "WV", "NC", "AL") ~ 7L,
state %in% c("MI", "PA", "VA", "SC", "GA") ~ 8L,
state %in% c("NY", "NJ", "MD", "DC", "FL") ~ 9L,
state %in% c("VT", "RI", "CT", "DE") ~ 10L,
state %in% c("ME", "NH", "MA") ~ 11L,
TRUE ~ 0L
))
df_miss <- df_full %>%
filter(!is.na(readmission_rate))
g1 <- df_miss %>%
mutate(y = readmission_rate * 100) %>%
ggplot(aes(col, row)) +
geom_point(aes(size = coverage_obscured, color = y), alpha = 0.8) +
geom_text(aes(label = percent(y/100, 0.01)), nudge_y = -0.1, size = 2.5) +
labs(color = "Readmission Rate", size = "Coverage") +
scale_color_gradient2(low = "#3F6E9A", high = "#AB4C30", midpoint = median(df_miss$readmission_rate * 100), mid = "#ffffe0") +
theme_void() +
geom_text(data = df_full, aes(label = state), color = "black", nudge_y = 0.05) +
scale_size(range = c(3, 30)) +
scale_y_reverse() +
theme(plot.margin = margin(r = 30))
g2 <- g1 %+% mutate(df_miss, y = colorectal_cancer_screenings) +
scale_color_gradient2(low = "#3F6E9A", high = "#AB4C30", midpoint = median(df_miss$colorectal_cancer_screenings), mid = "#ffffe0") +
labs(color = "Cancer Screening Rate")
g1 + g2 + plot_layout(guides = "collect")
theme_set(theme_classic())
g1 <- ggplot(df_miss, aes(coverage_obscured * 100, readmission_rate * 100)) +
geom_point() +
labs(x = "Coverage (%)", y = "Readmission (%)") +
geom_smooth(method = loess, formula = y ~ x) +
annotate("richtext", x = 80, y = 15.3, label.color = NA, fill = "transparent", label = glue::glue("R<sup>2</sup> = {scales::comma(cor(df_miss$coverage_obscured, df_miss$readmission_rate)^2, 0.001)}"))
g2 <- ggplot(df_miss, aes(coverage_obscured * 100, colorectal_cancer_screenings)) +
geom_point() +
labs(x = "Coverage (%)", y = "Cancer Screening (%)") +
geom_smooth(method = loess, formula = y ~ x) +
annotate("richtext", x = 80, y = 73, label.color = NA, fill = "transparent", label = glue::glue("R<sup>2</sup> = {scales::comma(cor(df_miss$coverage_obscured, df_miss$colorectal_cancer_screenings)^2, 0.001)}"))
g1 + g2
set.seed(2021)
lineup_data <- null_permute("colorectal_cancer_screenings") %>%
lineup(true = df_miss, n = 20, pos = 3)
plot_lineup_theirs <- ggplot(lineup_data, aes(col, row)) +
geom_point(aes(size = coverage_obscured, color = colorectal_cancer_screenings), alpha = 0.8) +
theme_void() +
scale_color_gradient2(low = "#3F6E9A", high = "#AB4C30", midpoint = median(df_miss$colorectal_cancer_screenings), mid = "#ffffe0") +
scale_size(range = c(1, 5)) +
scale_y_reverse(expand = c(0.1, 0.2)) +
guides(color = "none", size = "none") +
facet_wrap(~.sample, ncol = 5) +
scale_x_continuous(expand = c(0.1, 0.1)) +
theme(legend.position = "bottom",
strip.text = element_text(size = 18, margin = margin(t = 3, b = 3)),
strip.background = element_rect(color = "black", size = 1.5))
plot_lineup_theirs
plot_lineup_ours <- ggplot(lineup_data, aes(coverage_obscured * 100, colorectal_cancer_screenings)) +
geom_point() +
geom_smooth(method = loess, formula = y ~ x) +
facet_wrap(~.sample, ncol = 5) +
scale_x_continuous(expand = c(0.1, 0.1)) +
theme(legend.position = "bottom",
strip.text = element_text(size = 18, margin = margin(t = 3, b = 3)),
strip.background = element_rect(color = "black", size = 1.5),
axis.text = element_blank(),
axis.title = element_blank(),
axis.line = element_blank(),
axis.ticks.length = unit(0, "pt"))
plot_lineup_ours
Same plots with higher associations between variables
The following are plots based on data that purposely modifies cancer screening to induce a higher association with the coverage. This higher association is induced (as shown in the code below) by rearranging data by the coverage and modifying the cancer screening percentage so that it is ordered from low to high.
df_false <- df_miss %>%
arrange(coverage_obscured) %>%
mutate(colorectal_cancer_screenings = sort(colorectal_cancer_screenings))
lineup_false_data <- null_permute("colorectal_cancer_screenings") %>%
lineup(true = df_false, n = 20, pos = 5)
plot_lineup_theirs %+% lineup_false_data
plot_lineup_ours %+% lineup_false_data
Positions of the data plot
The positions of the data plot for the lineup are as follows:
We expect that you would have struggled to find the data plto in Figure S3 and Figure S4 as we do not observe strong association between the cancer screening rate and coverage. Additionally, we expect that most would spot the data plot in Figure S5 and all would spot the data plot in Figure S6. For those that spot the data plot in Figure S5, we suspect it took longer than spotting the data plot in Figure S6.
Acknowledgement
We thank Basole et al. (2021) for supplying us the synthetic data to draw the above plots.
Reference
Session Information
sessioninfo::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
## setting value
## version R version 4.0.1 (2020-06-06)
## os macOS 10.16
## system x86_64, darwin17.0
## ui X11
## language (EN)
## collate en_AU.UTF-8
## ctype en_AU.UTF-8
## tz Australia/Melbourne
## date 2021-10-19
##
## ─ Packages ───────────────────────────────────────────────────────────────────
## package * version date lib source
## assertthat 0.2.1 2019-03-21 [2] CRAN (R 4.0.0)
## backports 1.2.1 2020-12-09 [1] CRAN (R 4.0.2)
## bookdown 0.22.17 2021-08-07 [1] Github (rstudio/bookdown@9615b14)
## broom 0.7.9 2021-07-27 [1] CRAN (R 4.0.2)
## bslib 0.3.0 2021-09-02 [1] CRAN (R 4.0.2)
## cellranger 1.1.0 2016-07-27 [2] CRAN (R 4.0.0)
## class 7.3-19 2021-05-03 [2] CRAN (R 4.0.2)
## cli 3.0.1 2021-07-17 [1] CRAN (R 4.0.2)
## cluster 2.1.2 2021-04-17 [2] CRAN (R 4.0.2)
## colorspace 2.0-2 2021-06-24 [1] CRAN (R 4.0.2)
## crayon 1.4.1 2021-02-08 [1] CRAN (R 4.0.2)
## DBI 1.1.1 2021-01-15 [1] CRAN (R 4.0.2)
## dbplyr 2.1.1 2021-04-06 [1] CRAN (R 4.0.2)
## DEoptimR 1.0-8 2016-11-19 [2] CRAN (R 4.0.0)
## digest 0.6.28 2021-09-23 [1] CRAN (R 4.0.2)
## diptest 0.76-0 2021-05-04 [2] CRAN (R 4.0.2)
## dplyr * 1.0.7 2021-06-18 [1] CRAN (R 4.0.2)
## ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.0.2)
## evaluate 0.14 2019-05-28 [2] CRAN (R 4.0.0)
## fansi 0.5.0 2021-05-25 [1] CRAN (R 4.0.2)
## farver 2.1.0 2021-02-28 [1] CRAN (R 4.0.2)
## fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.0.2)
## flexmix 2.3-17 2020-10-12 [1] CRAN (R 4.0.2)
## forcats * 0.5.1 2021-01-27 [1] CRAN (R 4.0.2)
## fpc 2.2-9 2020-12-06 [2] CRAN (R 4.0.2)
## fs 1.5.0 2020-07-31 [1] CRAN (R 4.0.2)
## generics 0.1.0 2020-10-31 [2] CRAN (R 4.0.2)
## ggplot2 * 3.3.5 2021-06-25 [1] CRAN (R 4.0.2)
## ggtext * 0.1.1 2020-12-17 [1] CRAN (R 4.0.2)
## glue 1.4.2 2020-08-27 [1] CRAN (R 4.0.2)
## gridtext 0.1.4 2020-12-10 [1] CRAN (R 4.0.2)
## gtable 0.3.0 2019-03-25 [2] CRAN (R 4.0.0)
## haven 2.4.1 2021-04-23 [2] CRAN (R 4.0.2)
## here * 1.0.1 2020-12-13 [2] CRAN (R 4.0.2)
## highr 0.9 2021-04-16 [2] CRAN (R 4.0.2)
## hms 1.1.1 2021-09-26 [1] CRAN (R 4.0.2)
## htmltools 0.5.2 2021-08-25 [1] CRAN (R 4.0.2)
## httr 1.4.2 2020-07-20 [1] CRAN (R 4.0.2)
## janitor * 2.1.0 2021-01-05 [2] CRAN (R 4.0.2)
## jquerylib 0.1.4 2021-04-26 [1] CRAN (R 4.0.2)
## jsonlite 1.7.2 2020-12-09 [1] CRAN (R 4.0.2)
## kernlab 0.9-29 2019-11-12 [2] CRAN (R 4.0.0)
## knitr 1.34 2021-09-09 [1] CRAN (R 4.0.2)
## labeling 0.4.2 2020-10-20 [1] CRAN (R 4.0.2)
## lattice 0.20-44 2021-05-02 [2] CRAN (R 4.0.2)
## lifecycle 1.0.1 2021-09-24 [1] CRAN (R 4.0.2)
## lubridate 1.7.10 2021-02-26 [1] CRAN (R 4.0.2)
## magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.0.2)
## markdown 1.1 2019-08-07 [2] CRAN (R 4.0.0)
## MASS 7.3-54 2021-05-03 [1] CRAN (R 4.0.2)
## Matrix 1.3-3 2021-05-04 [2] CRAN (R 4.0.2)
## mclust 5.4.7 2020-11-20 [2] CRAN (R 4.0.2)
## mgcv 1.8-35 2021-04-18 [2] CRAN (R 4.0.2)
## modelr 0.1.8 2020-05-19 [2] CRAN (R 4.0.0)
## modeltools 0.2-23 2020-03-05 [2] CRAN (R 4.0.0)
## moments 0.14 2015-01-05 [2] CRAN (R 4.0.0)
## munsell 0.5.0 2018-06-12 [2] CRAN (R 4.0.0)
## nlme 3.1-152 2021-02-04 [2] CRAN (R 4.0.2)
## nnet 7.3-16 2021-05-03 [2] CRAN (R 4.0.2)
## nullabor * 0.3.9 2020-02-25 [1] CRAN (R 4.0.2)
## patchwork * 1.1.1 2020-12-17 [1] CRAN (R 4.0.2)
## pillar 1.6.3 2021-09-26 [1] CRAN (R 4.0.1)
## pkgconfig 2.0.3 2019-09-22 [2] CRAN (R 4.0.0)
## prabclus 2.3-2 2020-01-08 [2] CRAN (R 4.0.0)
## purrr * 0.3.4 2020-04-17 [2] CRAN (R 4.0.0)
## R6 2.5.1 2021-08-19 [1] CRAN (R 4.0.1)
## Rcpp 1.0.7 2021-07-07 [1] CRAN (R 4.0.2)
## readr * 2.0.1 2021-08-10 [1] CRAN (R 4.0.2)
## readxl * 1.3.1 2019-03-13 [2] CRAN (R 4.0.0)
## reprex 2.0.0 2021-04-02 [1] CRAN (R 4.0.2)
## rlang 0.4.11 2021-04-30 [1] CRAN (R 4.0.2)
## rmarkdown 2.11 2021-09-14 [1] CRAN (R 4.0.2)
## robustbase 0.93-7 2021-01-04 [2] CRAN (R 4.0.2)
## rprojroot 2.0.2 2020-11-15 [1] CRAN (R 4.0.2)
## rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.0.1)
## rvest 1.0.1 2021-07-26 [1] CRAN (R 4.0.2)
## sass 0.4.0 2021-05-12 [1] CRAN (R 4.0.2)
## scales * 1.1.1 2020-05-11 [2] CRAN (R 4.0.0)
## sessioninfo 1.1.1 2018-11-05 [2] CRAN (R 4.0.0)
## snakecase 0.11.0 2019-05-25 [2] CRAN (R 4.0.0)
## stringi 1.7.4 2021-08-25 [1] CRAN (R 4.0.2)
## stringr * 1.4.0 2019-02-10 [2] CRAN (R 4.0.0)
## tibble * 3.1.5 2021-09-30 [1] CRAN (R 4.0.2)
## tidyr * 1.1.3 2021-03-03 [1] CRAN (R 4.0.2)
## tidyselect 1.1.1 2021-04-30 [1] CRAN (R 4.0.2)
## tidyverse * 1.3.1 2021-04-15 [1] CRAN (R 4.0.2)
## tzdb 0.1.2 2021-07-20 [1] CRAN (R 4.0.2)
## utf8 1.2.2 2021-07-24 [1] CRAN (R 4.0.2)
## vctrs 0.3.8 2021-04-29 [1] CRAN (R 4.0.2)
## withr 2.4.2 2021-04-18 [1] CRAN (R 4.0.2)
## xfun 0.26 2021-09-14 [1] CRAN (R 4.0.2)
## xml2 1.3.2 2020-04-23 [2] CRAN (R 4.0.0)
## yaml 2.2.1 2020-02-01 [1] CRAN (R 4.0.2)
##
## [1] /Users/etan0038/Library/R/4.0/library
## [2] /Library/Frameworks/R.framework/Versions/4.0/Resources/library
Basole, Rahul C., Elliot Bendoly, Aravind Chandrasekaran, and Kevin Linderman. 2021. “Visualization in Operations Management Research.” INFORMS Journal on Data Science (to appear).
Wickham, Hadley. 2016.
Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York.
https://doi.org/10.1007/978-0-387-98141-3.
LS0tCnRpdGxlOiAiU3VwcGxlbWVudGFyeSBtYXRlcmlhbCBmb3IgXCJJbmNvcnBvcmF0aW5nIHN0YXRpc3RpY2FsIHRoaW5raW5nIGludG8gdmlzdWFsaXNhdGlvbiBwcmFjdGljZXMgZm9yIGRlY2lzaW9uLW1ha2luZyBpbiBvcGVyYXRpb25hbCBtYW5hZ2VtZW50XCIiCmF1dGhvcjoKICAtIG5hbWU6IEVtaSBUYW5ha2EKICAgIGFmZmlsaWF0aW9uOiBEZXBhcnRtZW50IG9mIEVjb25vbWV0cmljcyBhbmQgQnVzaW5lc3MgU3RhdGlzdGljcywgTW9uYXNoIFVuaXZlcnNpdHksIE1lbGJvdXJuZSwgVklDIDM4MDAKICAgIGVtYWlsOiBlbWkudGFuYWthQG1vbmFzaC5lZHUKICAtIG5hbWU6IEplc3NpY2EgV2FpIFlpbiBMZXVuZwogICAgYWZmaWxpYXRpb246IERlcGFydG1lbnQgb2YgRWNvbm9tZXRyaWNzIGFuZCBCdXNpbmVzcyBTdGF0aXN0aWNzLCBNb25hc2ggVW5pdmVyc2l0eSwgTWVsYm91cm5lLCBWSUMgMzgwMAogICAgZW1haWw6IGplc3NpY2EubGV1bmdAbW9uYXNoLmVkdQogIC0gbmFtZTogRGlhbm5lIENvb2sKICAgIGFmZmlsaWF0aW9uOiBEZXBhcnRtZW50IG9mIEVjb25vbWV0cmljcyBhbmQgQnVzaW5lc3MgU3RhdGlzdGljcywgTW9uYXNoIFVuaXZlcnNpdHksIE1lbGJvdXJuZSwgVklDIDM4MDAKICAgIGVtYWlsOiBkaWNvb2tAbW9uYXNoLmVkdQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliIApvdXRwdXQ6CiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgY29kZV9mb2xkaW5nOiAiaGlkZSIKICAgIHRoZW1lOiAicGFwZXIiCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCi0tLQoKClRoaXMgaXMgdGhlIHN1cHBsZW1lbnRhcnkgbWF0ZXJpYWwgdG8gYW4gaW52aXRlZCBjb21tZW50YXJ5IGZvciBAYmFzb2xlMjAyMS4gV2UgcHJvdmlkZSBhbGwgY29kZSB0aGF0IGFyZSB1c2VkIHRvIGdlbmVyYXRlIHRoZSBmaWd1cmVzIGluIHRoZSBjb21tZW50YXJ5IGluIGFkZGl0aW9uIHRvIG90aGVyIHN1cHBsZW1lbnRhcnkgZmlndXJlcyAoYW5kIGl0cyBjb2RlKS4gCgoKPHVsIGNsYXNzPSJmYS11bCI+CiAgPGxpPjxzcGFuIGNsYXNzPSJmYS1saSI+PGkgY2xhc3M9ImZhcyBmYS1jb2RlIj48L2k+PC9zcGFuPiBUbyBzZWUgdGhlIGNvZGUsIGNsaWNrIG9uIHRoZSBDT0RFIGJ1dHRvbi4gPC9saT4KICA8bGk+PHNwYW4gY2xhc3M9ImZhLWxpIj48aSBjbGFzcz0iZmFzIGZhLWRvd25sb2FkIj48L2k+PC9zcGFuPiBZb3UgY2FuIGFsc28gZG93bmxvYWQgdGhlIHdob2xlIFIgTWFya2Rvd24gZmlsZSBmcm9tIHRoZSBkcm9wIGRvd24gbWVudSBvbiB0aGUgdG9wIHJpZ2h0IGNvcm5lci48L2xpPgogIDxsaT48c3BhbiBjbGFzcz0iZmEtbGkiPjxpIGNsYXNzPSJmYWIgZmEtZ2l0aHViIj48L2k+PC9zcGFuPiBUaGUgR2l0SHViIHJlcG8gZm9yIHRoaXMgbWF0ZXJpYWwgY2FuIGJlIGZvdW5kIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9lbWl0YW5ha2Evc3VwcC12aXNPTS4gPC9saT4KPC91bD4KCioqTGlzdCBvZiBmaWd1cmVzKiogCgoqIFtGaWd1cmUgUzFdKCNmaWc6bWltaWMtb3JpZ2luYWwpOiBSZWNyZWF0aW5nIEZpZ3VyZSAzIG9mIEBiYXNvbGUyMDIxIHVzaW5nIGBnZ3Bsb3QyYC4gCiogW0ZpZ3VyZSBTMl0oI2ZpZzpmaWczLWFsdCk6IEFuIGFsdGVybmF0aXZlIGRlc2lnbiB0byBGaWd1cmUgMyBvZiBAYmFzb2xlMjAyMS4KKiBbRmlndXJlIFMzXSgjZmlnOmxpbmV1cC10aGVpcnMpOiBMaW5ldXAgZm9yIHRoZSB0aWxlIGdyaWQgcGxvdCB1c2VkIGluIEZpZ3VyZSAzIG9mIEBiYXNvbGUyMDIxLgoqIFtGaWd1cmUgUzRdKCNmaWc6bGluZXVwLW91cnMpOiBMaW5ldXAgZm9yIHRoZSBzY2F0dGVyIHBsb3QuIAoqIFtGaWd1cmUgUzVdKCNmaWc6bGluZXVwLXRoZWlycy1mYWxzZSk6IExpbmV1cCBmb3IgdGhlIHRpbGUgZ3JpZCBwbG90IG9uIGRhdGEgd2l0aCBwdXJwb3NlbHkgaGlnaCBhc3NvY2lhdGlvbi4KKiBbRmlndXJlIFM2XSgjZmlnOmxpbmV1cC1vdXJzLWZhbHNlKTogTGluZXVwIGZvciB0aGUgc2NhdHRlciBwbG90IG9uIGRhdGEgd2l0aCBwdXJwb3NlbHkgaGlnaCBhc3NvY2lhdGlvbi4KCjxkZXRhaWxzPgo8c3VtbWFyeT5Db2RlIHRvIGxvYWQgbGlicmFyeSBhbmQgZGF0YTwvc3VtbWFyeT4KYGBge3Igc2V0dXAsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2d0ZXh0KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobnVsbGFib3IpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHNjYWxlcykKYGBgCgpgYGB7ciBrbml0ci1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQpodG1sdG9vbHM6OnRhZ0xpc3Qocm1hcmtkb3duOjpodG1sX2RlcGVuZGVuY3lfZm9udF9hd2Vzb21lKCkpCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcucGF0aCA9ICJpbWFnZXMvIiwKICAgICAgICAgICAgICAgICAgICAgIGRldiA9IGMoInBuZyIsICJwZGYiLCAic3ZnIiksCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgY2FjaGUucGF0aCA9ICJjYWNoZS8iLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFKQpvcHRpb25zKGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmBgYAoKCgpgYGB7ciBkYXRhLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KZGZfZnVsbCA8LSByZWFkX3hsc3goaGVyZSgiZGF0YS9NYXNrZWRDb3ZlcmFnZS1GaWczLnhsc3giKSkgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIGFkZF9yb3coc3RhdGUgPSBjKCJPUiIsICJXWSIsICJTRCIsICJXViIsICJEQyIsICJBTCIpKSAlPiUgCiAgbXV0YXRlKHJvdyA9IGNhc2Vfd2hlbigKICAgIHN0YXRlICVpbiUgYygiTUUiKSB+IDFMLAogICAgc3RhdGUgJWluJSBjKCJWVCIsICJOSCIpIH4gMkwsCiAgICBzdGF0ZSAlaW4lIGMoIldBIiwgIklEIiwgIk1UIiwgIk5EIiwgIk1OIiwgIklMIiwgIldJIiwgIk1JIiwgIk5ZIiwgIlJJIiwgIk1BIikgfiAzTCwKICAgIHN0YXRlICVpbiUgYygiT1IiLCAiTlYiLCAiV1kiLCAiU0QiLCAiSUEiLCAiSU4iLCAiT0giLCAiUEEiLCAiTkoiLCAiQ1QiKSB+IDRMLAogICAgc3RhdGUgJWluJSBjKCJDQSIsICJVVCIsICJDTyIsICJORSIsICJNTyIsICJLWSIsICJXViIsICJWQSIsICJNRCIsICJERSIpIH4gNUwsCiAgICBzdGF0ZSAlaW4lIGMoIkFaIiwgIk5NIiwgIktTIiwgIkFSIiwgIlROIiwgIk5DIiwgIlNDIiwgIkRDIikgfiA2TCwKICAgIHN0YXRlICVpbiUgYygiT0siLCAiTEEiLCAiTVMiLCAiQUwiLCAiR0EiKSB+IDdMLAogICAgc3RhdGUgJWluJSBjKCJUWCIsICJGTCIpIH4gOEwsCiAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMEwpLAogICAgY29sID0gY2FzZV93aGVuKAogICAgICBzdGF0ZSAlaW4lIGMoIldBIiwgIk9SIiwgIkNBIikgfiAxTCwKICAgICAgc3RhdGUgJWluJSBjKCJJRCIsICJOViIsICJVVCIsICJBWiIpIH4gMkwsCiAgICAgIHN0YXRlICVpbiUgYygiTVQiLCAiV1kiLCAiQ08iLCAiTk0iKSB+IDNMLAogICAgICBzdGF0ZSAlaW4lIGMoIk5EIiwgIlNEIiwgIk5FIiwgIktTIiwgIk9LIiwgIlRYIikgfiA0TCwKICAgICAgc3RhdGUgJWluJSBjKCJNTiIsICJJQSIsICJNTyIsICJBUiIsICJMQSIpIH4gNUwsCiAgICAgIHN0YXRlICVpbiUgYygiSUwiLCAiSU4iLCAiS1kiLCAiVE4iLCAiTVMiKSB+IDZMLAogICAgICBzdGF0ZSAlaW4lIGMoIldJIiwgIk9IIiwgIldWIiwgIk5DIiwgIkFMIikgfiA3TCwKICAgICAgc3RhdGUgJWluJSBjKCJNSSIsICJQQSIsICJWQSIsICJTQyIsICJHQSIpIH4gOEwsCiAgICAgIHN0YXRlICVpbiUgYygiTlkiLCAiTkoiLCAiTUQiLCAiREMiLCAiRkwiKSB+IDlMLAogICAgICBzdGF0ZSAlaW4lIGMoIlZUIiwgIlJJIiwgIkNUIiwgIkRFIikgfiAxMEwsCiAgICAgIHN0YXRlICVpbiUgYygiTUUiLCAiTkgiLCAiTUEiKSB+IDExTCwKICAgICAgVFJVRSB+IDBMCiAgICApKQoKZGZfbWlzcyA8LSBkZl9mdWxsICU+JSAKICBmaWx0ZXIoIWlzLm5hKHJlYWRtaXNzaW9uX3JhdGUpKQpgYGAKPC9kZXRhaWxzPgoKKHJlZjptaW1pY2FyeSkgVGhpcyBmaWd1cmUgcmVjcmVhdGVzIEZpZ3VyZSAzIGluIEBiYXNvbGUyMDIxIHVzaW5nIHRoZSBgZ2dwbG90MmAgUi1wYWNrYWdlIFtAZ2dwbG90Ml0uIFRoZSBjb2RlIGlzIGRpc3BsYXllZCBhYm92ZSBieSBjbGlja2luZyBvbiB0aGUgQ09ERSBidXR0b24ganVzdCBhYm92ZSB0aGUgcmlnaHQgY29ybmVyIG9mIHRoaXMgcGxvdC4KCmBgYHtyIG1pbWljLW9yaWdpbmFsLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTgsIGZpZy5jYXAgPSAiKHJlZjptaW1pY2FyeSkifSAgICAgICAgICAgCmcxIDwtIGRmX21pc3MgJT4lIAogIG11dGF0ZSh5ID0gcmVhZG1pc3Npb25fcmF0ZSAqIDEwMCkgJT4lIAogIGdncGxvdChhZXMoY29sLCByb3cpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGNvdmVyYWdlX29ic2N1cmVkLCBjb2xvciA9IHkpLCBhbHBoYSA9IDAuOCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KHkvMTAwLCAwLjAxKSksIG51ZGdlX3kgPSAtMC4xLCBzaXplID0gMi41KSArCiAgbGFicyhjb2xvciA9ICJSZWFkbWlzc2lvbiBSYXRlIiwgc2l6ZSA9ICJDb3ZlcmFnZSIpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gIiMzRjZFOUEiLCBoaWdoID0gIiNBQjRDMzAiLCBtaWRwb2ludCA9IG1lZGlhbihkZl9taXNzJHJlYWRtaXNzaW9uX3JhdGUgKiAxMDApLCBtaWQgPSAiI2ZmZmZlMCIpICsKICB0aGVtZV92b2lkKCkgKwogIGdlb21fdGV4dChkYXRhID0gZGZfZnVsbCwgYWVzKGxhYmVsID0gc3RhdGUpLCBjb2xvciA9ICJibGFjayIsIG51ZGdlX3kgPSAwLjA1KSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMywgMzApKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKHIgPSAzMCkpCgpnMiA8LSBnMSAlKyUgbXV0YXRlKGRmX21pc3MsIHkgPSBjb2xvcmVjdGFsX2NhbmNlcl9zY3JlZW5pbmdzKSArIAogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAiIzNGNkU5QSIsIGhpZ2ggPSAiI0FCNEMzMCIsIG1pZHBvaW50ID0gbWVkaWFuKGRmX21pc3MkY29sb3JlY3RhbF9jYW5jZXJfc2NyZWVuaW5ncyksIG1pZCA9ICIjZmZmZmUwIikgKwogIGxhYnMoY29sb3IgPSAiQ2FuY2VyIFNjcmVlbmluZyBSYXRlIikKCmcxICsgZzIgKyBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpIApgYGAKCihyZWY6ZmlnMy1hbHQpIFRoZSBhYm92ZSBmaWd1cmUgc2hvdyBhbiBhbHRlcm5hdGl2ZSBwbG90IGRlc2lnbiB0byBkaXNwbGF5IHRoZSBpbmZvcm1hdGlvbiBpbiBbRmlndXJlIFMxXSgjZmlnOm1pbWljLW9yaWdpbmFsKSBhbmQgaXMgdGhlIHNhbWUgZmlndXJlIGFzIEZpZ3VyZSAxIGluIHRoZSBtYWluIHBhcGVyLiBUaGUgcGxvdCBzaG93cyBhIHNjYXR0ZXIgcGxvdCBvZiBwZXJjZW50YWdlIG9mIHJlYWRtaXNzaW9uIGFuZCBjb3ZlcmFnZSBvbiB0aGUgbGVmdCBhbmQgYSBzY2F0dGVyIHBsb3Qgb2YgcGVyY2VudGFnZSBvZiBjYW5jZXIgc2NyZWVuaW5nIGFuZCBjb3ZlcmFnZSBvbiB0aGUgcmlnaHQuIEJvdGggcGxvdHMgYXJlIHN1cGVyaW1wb3NlZCBieSBhIGxvY2FsIHBvbHlub21pYWwgcmVncmVzc2lvbiAoZGlzcGxheWVkIGFzIGEgYmx1ZSBsaW5lKSB3aXRoIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBsaW5lIChkaXNwbGF5ZWQgaW4gZ3JheSkuIFRoZSBjb2RlIGlzIGRpc3BsYXllZCBhYm92ZSBieSBjbGlja2luZyBvbiB0aGUgQ09ERSBidXR0b24ganVzdCBhYm92ZSB0aGUgcmlnaHQgY29ybmVyIG9mIHRoaXMgcGxvdC4KIApgYGB7ciBmaWczLWFsdCwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDgsIGZpZy5jYXAgPSAiKHJlZjpmaWczLWFsdCkifQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpnMSA8LSBnZ3Bsb3QoZGZfbWlzcywgYWVzKGNvdmVyYWdlX29ic2N1cmVkICogMTAwLCByZWFkbWlzc2lvbl9yYXRlICogMTAwKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4ID0gIkNvdmVyYWdlICglKSIsIHkgPSAiUmVhZG1pc3Npb24gKCUpIikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxvZXNzLCBmb3JtdWxhID0geSB+IHgpICsKICBhbm5vdGF0ZSgicmljaHRleHQiLCB4ID0gODAsIHkgPSAxNS4zLCBsYWJlbC5jb2xvciA9IE5BLCBmaWxsID0gInRyYW5zcGFyZW50IiwgbGFiZWwgPSBnbHVlOjpnbHVlKCJSPHN1cD4yPC9zdXA+ID0ge3NjYWxlczo6Y29tbWEoY29yKGRmX21pc3MkY292ZXJhZ2Vfb2JzY3VyZWQsIGRmX21pc3MkcmVhZG1pc3Npb25fcmF0ZSleMiwgMC4wMDEpfSIpKSAKCmcyIDwtIGdncGxvdChkZl9taXNzLCBhZXMoY292ZXJhZ2Vfb2JzY3VyZWQgKiAxMDAsIGNvbG9yZWN0YWxfY2FuY2VyX3NjcmVlbmluZ3MpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHggPSAiQ292ZXJhZ2UgKCUpIiwgeSA9ICJDYW5jZXIgU2NyZWVuaW5nICglKSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcywgZm9ybXVsYSA9IHkgfiB4KSArCiAgYW5ub3RhdGUoInJpY2h0ZXh0IiwgeCA9IDgwLCB5ID0gNzMsIGxhYmVsLmNvbG9yID0gTkEsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBsYWJlbCA9IGdsdWU6OmdsdWUoIlI8c3VwPjI8L3N1cD4gPSB7c2NhbGVzOjpjb21tYShjb3IoZGZfbWlzcyRjb3ZlcmFnZV9vYnNjdXJlZCwgZGZfbWlzcyRjb2xvcmVjdGFsX2NhbmNlcl9zY3JlZW5pbmdzKV4yLCAwLjAwMSl9IikpIAoKCmcxICsgZzIgCmBgYAoKYGBge3IgbGluZXVwLWRhdGF9CnNldC5zZWVkKDIwMjEpCmxpbmV1cF9kYXRhIDwtIG51bGxfcGVybXV0ZSgiY29sb3JlY3RhbF9jYW5jZXJfc2NyZWVuaW5ncyIpICU+JSAKICBsaW5ldXAodHJ1ZSA9IGRmX21pc3MsIG4gPSAyMCwgcG9zID0gMykKYGBgCgoocmVmOmxpbmV1cC10aGVpcnMpIFRoZSBhYm92ZSBmaWd1cmUgc2hvd3MgYSBsaW5ldXAgZm9yIHRoaXMgdGlsZSBncmlkIHBsb3Qgd2hlcmUgb25lIG9mIHRoZSBwbG90cyBpcyBtYWRlIHVzaW5nIHRoZSBkYXRhLCBhbmQgdGhlIG90aGVyIG5pbmV0ZWVuIHBsb3RzIGFyZSBjb25zdHJ1Y3RlZCBhZnRlciBmaXJzdCBwZXJtdXRpbmcgdGhlIHBlcmNlbnRhZ2Ugb2YgY2FuY2VyIHNjcmVlbmluZyBhY3Jvc3MgZGlmZmVyZW50IHN0YXRlcyB3aXRoIHRoZSBtaXNzaW5nIHZhbHVlIHN0cnVjdHVyZSBpcyBwcmVzZXJ2ZWQuIFRleHQgYW5kIGxlZ2VuZHMgaGF2ZSBiZWVuIHJlbW92ZWQgdG8gbWluaW1pc2UgdGhlIGJpYXMgaW4gcmVhZGluZyBwbG90cyBkdWUgdG8gdGhlIHJlYWRlciBiZWluZyBhd2FyZSBvZiB0aGUgY29udGV4dC4gKipXaGljaCBwbG90IHN0cmlrZXMgdGhlIG1vc3QgZGlmZmVyZW50IHRvIHlvdT8qKiAgVGhlIGNvZGUgaXMgZGlzcGxheWVkIGFib3ZlIGJ5IGNsaWNraW5nIG9uIHRoZSBDT0RFIGJ1dHRvbiBqdXN0IGFib3ZlIHRoZSByaWdodCBjb3JuZXIgb2YgdGhpcyBwbG90LiBUcnkgdGhlIG90aGVyIGxpbmV1cHMgYmVmb3JlIGZpbmRpbmcgdGhlIGRhdGEgcGxvdCBwb3NpdGlvbiBhdCB0aGUgYm90dG9tIG9mIHRoaXMgZG9jdW1lbnQuCgpgYGB7ciBsaW5ldXAtdGhlaXJzLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwLCBmaWcuY2FwID0gIihyZWY6bGluZXVwLXRoZWlycykifQpwbG90X2xpbmV1cF90aGVpcnMgPC0gZ2dwbG90KGxpbmV1cF9kYXRhLCBhZXMoY29sLCByb3cpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGNvdmVyYWdlX29ic2N1cmVkLCBjb2xvciA9IGNvbG9yZWN0YWxfY2FuY2VyX3NjcmVlbmluZ3MpLCBhbHBoYSA9IDAuOCkgKwogIHRoZW1lX3ZvaWQoKSArIAogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAiIzNGNkU5QSIsIGhpZ2ggPSAiI0FCNEMzMCIsIG1pZHBvaW50ID0gbWVkaWFuKGRmX21pc3MkY29sb3JlY3RhbF9jYW5jZXJfc2NyZWVuaW5ncyksIG1pZCA9ICIjZmZmZmUwIikgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDUpKSArCiAgc2NhbGVfeV9yZXZlcnNlKGV4cGFuZCA9IGMoMC4xLCAwLjIpKSAgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIiwgc2l6ZSA9ICJub25lIikgKyAKICBmYWNldF93cmFwKH4uc2FtcGxlLCBuY29sID0gNSkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMSwgMC4xKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgbWFyZ2luID0gbWFyZ2luKHQgPSAzLCBiID0gMykpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMS41KSkKCnBsb3RfbGluZXVwX3RoZWlycwpgYGAKCihyZWY6bGluZXVwLW91cnMpIFRoZSBhYm92ZSBmaWd1cmUgc2hvd3MgYSBsaW5ldXAgZm9yIHRoZSBzY2F0dGVyIHBsb3QgZGVzaWduIHVzZWQgaW4gW0ZpZ3VyZSBTMl0oI2ZpZzpmaWczLWFsdCkuIFRoZSBzYW1lIGRhdGEgdXNlZCB0byBjcmVhdGUgW0ZpZ3VyZSBTM10oI2ZpZzpsaW5ldXAtdGhlaXJzKSAoaW5jbHVkaW5nIHRoZSBudWxsIGRhdGEpIGlzIHVzZWQgdG8gY3JlYXRlIHRoaXMgbGluZXVwLiBUaGUgY29kZSBpcyBkaXNwbGF5ZWQgYWJvdmUgYnkgY2xpY2tpbmcgb24gdGhlIENPREUgYnV0dG9uIGp1c3QgYWJvdmUgdGhlIHJpZ2h0IGNvcm5lciBvZiB0aGlzIHBsb3QuIFdoZW4geW91IGFyZSByZWFkeSwgZmluZCB0aGUgcG9zaXRpb24gb2YgdGhlIGRhdGEgcGxvdCBpcyByZXZlYWxlZCBhdCB0aGUgW2JvdHRvbSBvZiB0aGlzIGRvY3VtZW50XSgjcG9zaXRpb24pLgoKYGBge3IgbGluZXVwLW91cnMsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTAsIGZpZy5jYXAgPSAiKHJlZjpsaW5ldXAtb3VycykifQpwbG90X2xpbmV1cF9vdXJzIDwtIGdncGxvdChsaW5ldXBfZGF0YSwgYWVzKGNvdmVyYWdlX29ic2N1cmVkICogMTAwLCBjb2xvcmVjdGFsX2NhbmNlcl9zY3JlZW5pbmdzKSkgKwogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcywgZm9ybXVsYSA9IHkgfiB4KSArCiAgZmFjZXRfd3JhcCh+LnNhbXBsZSwgbmNvbCA9IDUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjEsIDAuMSkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIG1hcmdpbiA9IG1hcmdpbih0ID0gMywgYiA9IDMpKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEuNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MubGVuZ3RoID0gdW5pdCgwLCAicHQiKSkKCnBsb3RfbGluZXVwX291cnMKYGBgCgoKCiMgU2FtZSBwbG90cyB3aXRoIGhpZ2hlciBhc3NvY2lhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMKClRoZSBmb2xsb3dpbmcgYXJlIHBsb3RzIGJhc2VkIG9uIGRhdGEgdGhhdCBwdXJwb3NlbHkgbW9kaWZpZXMgY2FuY2VyIHNjcmVlbmluZyB0byBpbmR1Y2UgYSBoaWdoZXIgYXNzb2NpYXRpb24gd2l0aCB0aGUgY292ZXJhZ2UuIFRoaXMgaGlnaGVyIGFzc29jaWF0aW9uIGlzIGluZHVjZWQgKGFzIHNob3duIGluIHRoZSBjb2RlIGJlbG93KSBieSByZWFycmFuZ2luZyBkYXRhIGJ5IHRoZSBjb3ZlcmFnZSBhbmQgbW9kaWZ5aW5nIHRoZSBjYW5jZXIgc2NyZWVuaW5nIHBlcmNlbnRhZ2Ugc28gdGhhdCBpdCBpcyBvcmRlcmVkIGZyb20gbG93IHRvIGhpZ2guIAoKYGBge3IgZGF0YS1mYWxzZSwgY2xhc3Muc291cmNlPSJmb2xkLXNob3cifQpkZl9mYWxzZSA8LSBkZl9taXNzICU+JSAKICBhcnJhbmdlKGNvdmVyYWdlX29ic2N1cmVkKSAlPiUgCiAgbXV0YXRlKGNvbG9yZWN0YWxfY2FuY2VyX3NjcmVlbmluZ3MgPSBzb3J0KGNvbG9yZWN0YWxfY2FuY2VyX3NjcmVlbmluZ3MpKQoKbGluZXVwX2ZhbHNlX2RhdGEgPC0gbnVsbF9wZXJtdXRlKCJjb2xvcmVjdGFsX2NhbmNlcl9zY3JlZW5pbmdzIikgJT4lIAogIGxpbmV1cCh0cnVlID0gZGZfZmFsc2UsIG4gPSAyMCwgcG9zID0gNSkKYGBgCgoocmVmOmxpbmV1cC10aGVpcnMtZmFsc2UpIFRoZSBhYm92ZSBzaG93cyBhIGxpbmV1cCBmb3IgdGhlIHRpbGUgZ3JpZCBwbG90IGRlc2lnbiB3aGVyZSB0aGUgZGF0YSB3YXMgcHVycG9zZWx5IG1hbmlwdWxhdGVkIHRvIGluZHVjZSBhIGhpZ2hlciBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgb2YgaW50ZXJlc3QuIFdoaWNoIHBsb3QgbG9va3MgdGhlIG1vc3Qgc3RyaWtpbmdseSBkaWZmZXJlbnQgdG8geW91PyBUcnkgdGhlIG5leHQgbGluZXVwIHRvIHNlZSBpZiB5b3UgY2FuIGZpbmQgdGhlIGRhdGEgcGxvdCBiZWZvcmUgZmluZGluZyB0aGUgcG9zaXRpb24gb2YgdGhlIGRhdGEgcGxvdCBbaGVyZV0oI3Bvc2l0aW9uKS4KCmBgYHtyIGxpbmV1cC10aGVpcnMtZmFsc2UsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTAsIGZpZy5jYXAgPSAiKHJlZjpsaW5ldXAtdGhlaXJzLWZhbHNlKSJ9CnBsb3RfbGluZXVwX3RoZWlycyAlKyUgbGluZXVwX2ZhbHNlX2RhdGEKYGBgCgoocmVmOmxpbmV1cC1vdXJzLWZhbHNlKSBUaGUgYWJvdmUgc2hvd3MgYSBsaW5ldXAgZm9yIHRoZSBzY2F0dGVyIHBsb3QgZGVzaWduIHdpdGggdGhlIGRhdGEgdGhhdCB3YXMgcHVycG9zZWx5IG1hbmlwdWxhdGVkIHNvIHRoYXQgdHdvIHZhcmlhYmxlcyBtYXBwZWQgdG8gdGhlICR4JC1heGlzIGFuZCAkeSQtYXhpcyBoYXZlIGEgaGlnaGVyIGFzc29jaWF0aW9uLiBIb3cgZWFzeSB3YXMgaXQgdG8gc3BvdCB0aGUgZGF0YSBwbG90IGNvbXBhcmVkIHRvIFtGaWd1cmUgUzVdKCNmaWc6bGluZXVwLXRoZWlycy1mYWxzZSk/IFlvdSBjYW4gZmluZCB0aGUgY29kZSB0byBnZW5lcmF0ZSB0aGUgYWJvdmUgbGluZXVwIHBsb3QgYnkgY29sbGFwc2luZyBhbGwgY29kZXMuIAoKYGBge3IgbGluZXVwLW91cnMtZmFsc2UsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTAsIGZpZy5jYXAgPSAiKHJlZjpsaW5ldXAtb3Vycy1mYWxzZSkifQpwbG90X2xpbmV1cF9vdXJzICUrJSBsaW5ldXBfZmFsc2VfZGF0YQpgYGAKCiMgUG9zaXRpb25zIG9mIHRoZSBkYXRhIHBsb3QgeyNwb3NpdGlvbn0KClRoZSBwb3NpdGlvbnMgb2YgdGhlIGRhdGEgcGxvdCBmb3IgdGhlIGxpbmV1cCBhcmUgYXMgZm9sbG93czoKCiogW0ZpZ3VyZSBTM10oI2ZpZzpsaW5ldXAtdGhlaXJzKTogcG9zaXRpb24gMy4gCiogW0ZpZ3VyZSBTNF0oI2ZpZzpsaW5ldXAtb3Vycyk6IHBvc2l0aW9uIDMuIAoqIFtGaWd1cmUgUzVdKCNmaWc6bGluZXVwLXRoZWlycy1mYWxzZSk6IHBvc2l0aW9uIDUuIAoqIFtGaWd1cmUgUzZdKCNmaWc6bGluZXVwLW91cnMtZmFsc2UpOiBwb3NpdGlvbiA1LiAKCldlIGV4cGVjdCB0aGF0IHlvdSB3b3VsZCBoYXZlIHN0cnVnZ2xlZCB0byBmaW5kIHRoZSBkYXRhIHBsdG8gaW4gW0ZpZ3VyZSBTM10oI2ZpZzpsaW5ldXAtdGhlaXJzKSBhbmQgW0ZpZ3VyZSBTNF0oI2ZpZzpsaW5ldXAtb3VycykgYXMgd2UgZG8gbm90IG9ic2VydmUgc3Ryb25nIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGNhbmNlciBzY3JlZW5pbmcgcmF0ZSBhbmQgY292ZXJhZ2UuIEFkZGl0aW9uYWxseSwgd2UgZXhwZWN0IHRoYXQgbW9zdCB3b3VsZCBzcG90IHRoZSBkYXRhIHBsb3QgaW4gW0ZpZ3VyZSBTNV0oI2ZpZzpsaW5ldXAtdGhlaXJzLWZhbHNlKSBhbmQgYWxsIHdvdWxkIHNwb3QgdGhlIGRhdGEgcGxvdCBpbiBbRmlndXJlIFM2XSgjZmlnOmxpbmV1cC1vdXJzLWZhbHNlKS4gRm9yIHRob3NlIHRoYXQgc3BvdCB0aGUgZGF0YSBwbG90IGluIFtGaWd1cmUgUzVdKCNmaWc6bGluZXVwLXRoZWlycy1mYWxzZSksIHdlIHN1c3BlY3QgaXQgdG9vayBsb25nZXIgdGhhbiBzcG90dGluZyB0aGUgZGF0YSBwbG90IGluIFtGaWd1cmUgUzZdKCNmaWc6bGluZXVwLW91cnMtZmFsc2UpLiAKCiMgQWNrbm93bGVkZ2VtZW50IAoKV2UgdGhhbmsgQGJhc29sZTIwMjEgZm9yIHN1cHBseWluZyB1cyB0aGUgc3ludGhldGljIGRhdGEgdG8gZHJhdyB0aGUgYWJvdmUgcGxvdHMuIAoKIyBSZWZlcmVuY2UKCjxkZXRhaWxzPgo8c3VtbWFyeT5TZXNzaW9uIEluZm9ybWF0aW9uPC9zdW1tYXJ5PgpgYGB7ciBzZXNzaW9uLWluZm99CnNlc3Npb25pbmZvOjpzZXNzaW9uX2luZm8oKQpgYGAKPC9kZXRhaWxzPgoKICAKPGJyPgoKCmBgYHtyIGNvcHktZm9yLXBhcGVyLCBpbmNsdWRlID0gRkFMU0V9CiMgdGhpcyBjaHVuayBtdXN0IGJlIHRoZSBsYXN0IG9uZQpmczo6ZmlsZV9jb3B5KCJpbWFnZXMvZmlnMy1hbHQtMS5wZGYiLCAicGFwZXIvIiwgb3ZlcndyaXRlID0gVFJVRSkKZnM6OmZpbGVfY29weSgiaW1hZ2VzL2xpbmV1cC10aGVpcnMtMS5wZGYiLCAicGFwZXIvIiwgb3ZlcndyaXRlID0gVFJVRSkKIyBleHRyYWN0IGFsbCB0aGUgUiBjb2RlIAprbml0cjo6cHVybCgiaW5kZXguUm1kIiwKICAgICAgICAgICAgZG9jdW1lbnRhdGlvbiA9IDEpCmZzOjpmaWxlX21vdmUoImluZGV4LlIiLCAiY29kZS9wbG90cy5SIikKIyByZW1vdmUgdGhpcyBjaHVuayBhbmQgdGhlIGtuaXRyIHNldHVwIGZyb20gdGhlIG91dHB1dCBSIGNvZGUKZiA8LSByZWFkTGluZXMoImNvZGUvcGxvdHMuUiIpCmkxIDwtIHdoaWNoKHN0cl9kZXRlY3QoZiwgIl4jIyAtLS0ta25pdHItc2V0dXAiKSkKY2h1bmtfaW5kZXhlcyA8LSB3aGljaChzdHJfZGV0ZWN0KGYsICJeIyMgLS0tLSIpKQpqMSA8LSBjaHVua19pbmRleGVzW2NodW5rX2luZGV4ZXMgPiBpMV1bMV0gLSAxCiAgCmkyIDwtIG1heCh3aGljaChzdHJfZGV0ZWN0KGYsICJeIyMgLS0tLWNvcHktZm9yLXBhcGVyIikpKQpqMiA8LSBsZW5ndGgoZikKb3V0IDwtIGZbLWMoaTE6ajEsIGkyOmoyKV0Kd3JpdGVMaW5lcyhvdXQsICJjb2RlL3Bsb3RzLlIiKQpgYGAKCg==