• Setup
    • The plot
    • Trace before & after after_stat()
    • Trace before & after after_scale()
  • Trigger traces and collect tracedump
  • Inspect tracedump
    • after_stat() before & after
    • after_scale() before & after
    • Compare to the final layer data
  • Where were the methods called from?
  • Contextualizing self
  • Session info

Setup

You can install {ggtrace} from Github. More on the package website.

# remotes::install_github("yjunechoe/ggtrace")
library(ggtrace) # v0.3.7
library(ggplot2)
library(rlang)
library(dplyr)

The plot

# Bar plot using computed/"mapped" aesthetics with `after_stat()` and `after_scale()`
barplot_plot <- ggplot(data = palmerpenguins::penguins) +
  geom_bar(
    mapping = aes(
      x = species,                           # Discrete x-axis representing species
      y = after_stat(count / sum(count)),    # Bars represent count of species as proportions
      color = species,                       # The outline of the bars are colored by species
      fill = after_scale(alpha(color, 0.5))  # The fill of the bars are lighter than the outline color
    ),
    size = 3
  )
barplot_plot

Trace before & after after_stat()

https://github.com/tidyverse/ggplot2/blob/de5d63f7eba06e507187f34780bea071cb31fee4/R/layer.r#L293-L341

ggtrace(
  method = ggplot2:::Layer$map_statistic, # Layer is not exported so need the `:::`
  trace_steps = c(1, 1, -1),
  trace_exprs = exprs(
    traceback = trace_back(), # Log the traceback when the method is called
    before = data,            # What does the data look like BEFORE resolving `after_stat()`?
    after = ~step             # What does the data look like AFTER resolving `after_stat()`?
                              # - The `~step` keyword runs the step and returns its output
  ),
  verbose = FALSE
)

Trace before & after after_scale()

https://github.com/tidyverse/ggplot2/blob/87e9b85dd9f2a294f339d88a353d0c11c851489d/R/geom-.r#L126-L150

ggtrace(
  method = Geom$use_defaults,
  trace_steps = c(1, 6, 7),
  trace_exprs = exprs(
    traceback = trace_back(), # Log the traceback when the method is called
    before = data,            # What does the data look like BEFORE resolving `after_scale()`
    after = data              # What does the data look like AFTER resolving `after_scale()`
  ),
  verbose = FALSE
)

Trigger traces and collect tracedump

# Print the plot and trigger the traces
# Note that with the default `once = TRUE`, the traces are removed on exit
barplot_plot

tracedump <- global_ggtrace()
names(tracedump)
## [1] "ggplot2:::Layer$map_statistic-000000001CE607B8"
## [2] "Geom$use_defaults-000000001FB67E60"
names(tracedump) <- c("after_stat", "after_scale")
lapply(tracedump, names)
## $after_stat
## [1] "traceback" "before"    "after"    
## 
## $after_scale
## [1] "traceback" "before"    "after"

Inspect tracedump

after_stat() before & after

tracedump$after_stat$before
ABCDEFGHIJ0123456789
count
<dbl>
prop
<dbl>
x
<int>
width
<dbl>
flipped_aes
<lgl>
colour
<fct>
PANEL
<fct>
group
<int>
152110.9FALSEAdelie11
68120.9FALSEChinstrap12
124130.9FALSEGentoo13
tracedump$after_stat$after
ABCDEFGHIJ0123456789
y
<dbl>
count
<dbl>
prop
<dbl>
x
<int>
width
<dbl>
flipped_aes
<lgl>
colour
<fct>
PANEL
<fct>
group
<int>
0.4418605152110.9FALSEAdelie11
0.197674468120.9FALSEChinstrap12
0.3604651124130.9FALSEGentoo13
identical(
  tracedump$after_stat$before %>% 
    mutate(y = count / sum(count)) %>% 
    relocate(y, .before = 1),
  tracedump$after_stat$after
)
## [1] TRUE

after_scale() before & after

tracedump$after_scale$before
ABCDEFGHIJ0123456789
colour
<chr>
y
<dbl>
count
<dbl>
prop
<dbl>
x
<mppd_dsc>
flipped_aes
<lgl>
PANEL
<fct>
group
<int>
ymin
<dbl>
ymax
<dbl>
#F8766D0.441860515211FALSE1100.4418605
#00BA380.19767446812FALSE1200.1976744
#619CFF0.360465112413FALSE1300.3604651
tracedump$after_scale$after
ABCDEFGHIJ0123456789
fill
<chr>
colour
<chr>
y
<dbl>
count
<dbl>
prop
<dbl>
x
<mppd_dsc>
flipped_aes
<lgl>
PANEL
<fct>
group
<int>
ymin
<dbl>
#F8766D80#F8766D0.441860515211FALSE110
#00BA3880#00BA380.19767446812FALSE120
#619CFF80#619CFF0.360465112413FALSE130
identical(
  tracedump$after_scale$before %>% 
    mutate(fill = alpha(colour, 0.5)) %>% 
    relocate(fill, .before = 1),
  tracedump$after_scale$after
)
## [1] TRUE

Compare to the final layer data

layer_data(barplot_plot, 1)
ABCDEFGHIJ0123456789
fill
<chr>
colour
<chr>
y
<dbl>
count
<dbl>
prop
<dbl>
x
<mppd_dsc>
flipped_aes
<lgl>
PANEL
<fct>
group
<int>
ymin
<dbl>
#F8766D80#F8766D0.441860515211FALSE110
#00BA3880#00BA380.19767446812FALSE120
#619CFF80#619CFF0.360465112413FALSE130

Where were the methods called from?

# What about the tracebacks?
# - traceback contains information about the "call stack" (what called the method?)
# We see that they're called from different places in `ggplot_build.ggplot(x)`
# - Layer$map_statistic in Line 73, Layer$compute_geom_2 (which calls Geom$use_defaults) in Line 100
#     - https://github.com/tidyverse/ggplot2/blob/de5d63f7eba06e507187f34780bea071cb31fee4/R/plot-build.r
lapply(tracedump, `[[`, "traceback") 
## $after_stat
##     x
##  1. \-ggplot2:::print.ggplot(x)
##  2.   +-ggplot2::ggplot_build(x)
##  3.   \-ggplot2:::ggplot_build.ggplot(x)
##  4.     \-ggplot2:::by_layer(function(l, d) l$map_statistic(d, plot))
##  5.       \-ggplot2:::f(l = layers[[i]], d = data[[i]])
##  6.         \-l$map_statistic(d, plot)
##  7.           \-ggplot2:::f(..., self = self)
## 
## $after_scale
##     x
##  1. \-ggplot2:::print.ggplot(x)
##  2.   +-ggplot2::ggplot_build(x)
##  3.   \-ggplot2:::ggplot_build.ggplot(x)
##  4.     \-ggplot2:::by_layer(function(l, d) l$compute_geom_2(d))
##  5.       \-ggplot2:::f(l = layers[[i]], d = data[[i]])
##  6.         \-l$compute_geom_2(d)
##  7.           \-ggplot2:::f(..., self = self)
##  8.             \-self$geom$use_defaults(data, self$aes_params, modifiers)
##  9.               \-ggplot2:::f(..., self = self)

Contextualizing self

# We can also get the context for self

# First, clear the global tracedump
clear_global_ggtrace()
## NULL
# Return `self` inside the method
# `self` should be contextualized to the Layer and the Geom
ggtrace(ggplot2:::Layer$compute_geom_2, 1, quote(self), verbose = FALSE)
ggtrace(Geom$use_defaults, 1, quote(self), verbose = FALSE)

# Force evaluation of plot code without printing it
invisible(ggplot_build(barplot_plot))

traced_self <- unlist(global_ggtrace(), recursive = FALSE)
names(traced_self) <- c("layer", "geom")

traced_self
## $layer
## mapping: x = ~species, y = ~after_stat(count/sum(count)), colour = ~species, fill = ~after_scale(alpha(color, 0.5)) 
## geom_bar: width = NULL, na.rm = FALSE, orientation = NA
## stat_count: width = NULL, na.rm = FALSE, orientation = NA
## position_stack 
## 
## $geom
## <ggproto object: Class GeomBar, GeomRect, Geom, gg>
##     aesthetics: function
##     default_aes: uneval
##     draw_group: function
##     draw_key: function
##     draw_layer: function
##     draw_panel: function
##     extra_params: na.rm orientation
##     handle_na: function
##     non_missing_aes: xmin xmax ymin ymax
##     optional_aes: 
##     parameters: function
##     required_aes: x y
##     setup_data: function
##     setup_params: function
##     use_defaults: function
##     super:  <ggproto object: Class GeomRect, Geom, gg>
# The geom is GeomBar
identical(traced_self$geom, GeomBar)
## [1] TRUE
# This is also the default geom for the layer returned by `geom_bar()`
identical(traced_self$geom, geom_bar()$geom)
## [1] TRUE
# Which is also the geom of the actual Layer that we traced
identical(traced_self$geom, traced_self$layer$geom)
## [1] TRUE
# The stat of the traced layer is StatCount
identical(traced_self$layer$stat, StatCount)
## [1] TRUE
# This is the default for `geom_bar()` (default is `geom_bar(stat = "count")`)
identical(traced_self$layer$stat, geom_bar()$stat)
## [1] TRUE

Session info

sessioninfo::session_info()
## - Session info ---------------------------------------------------------------
##  setting  value                       
##  version  R version 4.1.1 (2021-08-10)
##  os       Windows 10 x64              
##  system   x86_64, mingw32             
##  ui       RTerm                       
##  language (EN)                        
##  collate  English_United States.1252  
##  ctype    English_United States.1252  
##  tz       America/New_York            
##  date     2021-10-25                  
## 
## - Packages -------------------------------------------------------------------
##  package        * version date       lib source        
##  assertthat       0.2.1   2019-03-21 [1] CRAN (R 4.0.0)
##  bslib            0.3.1   2021-10-06 [1] CRAN (R 4.1.1)
##  cli              3.0.1   2021-07-17 [1] CRAN (R 4.1.0)
##  colorspace       2.0-2   2021-06-24 [1] CRAN (R 4.1.0)
##  crayon           1.4.1   2021-02-08 [1] CRAN (R 4.0.3)
##  DBI              1.1.1   2021-01-15 [1] CRAN (R 4.0.3)
##  digest           0.6.28  2021-09-23 [1] CRAN (R 4.1.1)
##  dplyr          * 1.0.7   2021-06-18 [1] CRAN (R 4.1.0)
##  ellipsis         0.3.2   2021-04-29 [1] CRAN (R 4.1.0)
##  evaluate         0.14    2019-05-28 [1] CRAN (R 4.0.0)
##  fansi            0.5.0   2021-05-25 [1] CRAN (R 4.1.1)
##  farver           2.1.0   2021-02-28 [1] CRAN (R 4.1.0)
##  fastmap          1.1.0   2021-01-25 [1] CRAN (R 4.1.1)
##  generics         0.1.0   2020-10-31 [1] CRAN (R 4.0.3)
##  ggplot2        * 3.3.5   2021-06-25 [1] CRAN (R 4.1.0)
##  ggtrace        * 0.3.7   2021-10-23 [1] local         
##  glue             1.4.2   2020-08-27 [1] CRAN (R 4.0.3)
##  gtable           0.3.0   2019-03-25 [1] CRAN (R 4.0.0)
##  highr            0.8     2019-03-20 [1] CRAN (R 4.0.0)
##  htmltools        0.5.2   2021-08-25 [1] CRAN (R 4.1.1)
##  jquerylib        0.1.4   2021-04-26 [1] CRAN (R 4.1.1)
##  jsonlite         1.7.2   2020-12-09 [1] CRAN (R 4.0.3)
##  knitr            1.36    2021-09-29 [1] CRAN (R 4.1.1)
##  labeling         0.4.2   2020-10-20 [1] CRAN (R 4.0.3)
##  lifecycle        1.0.1   2021-09-24 [1] CRAN (R 4.1.1)
##  magrittr         2.0.1   2020-11-17 [1] CRAN (R 4.0.3)
##  munsell          0.5.0   2018-06-12 [1] CRAN (R 4.0.0)
##  palmerpenguins   0.1.0   2020-07-23 [1] CRAN (R 4.0.2)
##  pillar           1.6.4   2021-10-18 [1] CRAN (R 4.1.1)
##  pkgconfig        2.0.3   2019-09-22 [1] CRAN (R 4.0.0)
##  purrr            0.3.4   2020-04-17 [1] CRAN (R 4.0.2)
##  R6               2.5.1   2021-08-19 [1] CRAN (R 4.1.1)
##  rlang          * 0.4.11  2021-04-30 [1] CRAN (R 4.1.1)
##  rmarkdown        2.11    2021-09-14 [1] CRAN (R 4.1.1)
##  rstudioapi       0.13    2020-11-12 [1] CRAN (R 4.0.3)
##  sass             0.4.0   2021-05-12 [1] CRAN (R 4.1.0)
##  scales           1.1.1   2020-05-11 [1] CRAN (R 4.0.2)
##  sessioninfo      1.1.1   2018-11-05 [1] CRAN (R 4.0.4)
##  stringi          1.7.5   2021-10-04 [1] CRAN (R 4.1.0)
##  stringr          1.4.0   2019-02-10 [1] CRAN (R 4.0.0)
##  tibble           3.1.5   2021-09-30 [1] CRAN (R 4.1.0)
##  tidyselect       1.1.1   2021-04-30 [1] CRAN (R 4.1.0)
##  utf8             1.2.2   2021-07-24 [1] CRAN (R 4.1.1)
##  vctrs            0.3.8   2021-04-29 [1] CRAN (R 4.1.0)
##  withr            2.4.2   2021-04-18 [1] CRAN (R 4.1.0)
##  xfun             0.27    2021-10-18 [1] CRAN (R 4.1.1)
##  yaml             2.2.1   2020-02-01 [1] CRAN (R 4.0.0)
## 
## [1] C:/Users/jchoe/R/win-library/packages
## [2] C:/Program Files/R/R-4.1.1/library
LS0tDQp0aXRsZTogIntnZ3RyYWNlfSBhZXNfZXZhbCB2aWduZXR0ZSBkcmFmdCINCmF1dGhvcjogIkp1bmUgQ2hvZSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQojIFNldHVwDQoNCllvdSBjYW4gaW5zdGFsbCB7Z2d0cmFjZX0gZnJvbSBbR2l0aHViXShodHRwczovL2dpdGh1Yi5jb20veWp1bmVjaG9lL2dndHJhY2UpLiBNb3JlIG9uIHRoZSBbcGFja2FnZSB3ZWJzaXRlXShodHRwczovL3lqdW5lY2hvZS5naXRodWIuaW8vZ2d0cmFjZS8pLg0KDQpgYGB7cn0NCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInlqdW5lY2hvZS9nZ3RyYWNlIikNCmxpYnJhcnkoZ2d0cmFjZSkgIyB2MC4zLjcNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmxhbmcpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiMjIFRoZSBwbG90DQoNCmBgYHtyfQ0KIyBCYXIgcGxvdCB1c2luZyBjb21wdXRlZC8ibWFwcGVkIiBhZXN0aGV0aWNzIHdpdGggYGFmdGVyX3N0YXQoKWAgYW5kIGBhZnRlcl9zY2FsZSgpYA0KYmFycGxvdF9wbG90IDwtIGdncGxvdChkYXRhID0gcGFsbWVycGVuZ3VpbnM6OnBlbmd1aW5zKSArDQogIGdlb21fYmFyKA0KICAgIG1hcHBpbmcgPSBhZXMoDQogICAgICB4ID0gc3BlY2llcywgICAgICAgICAgICAgICAgICAgICAgICAgICAjIERpc2NyZXRlIHgtYXhpcyByZXByZXNlbnRpbmcgc3BlY2llcw0KICAgICAgeSA9IGFmdGVyX3N0YXQoY291bnQgLyBzdW0oY291bnQpKSwgICAgIyBCYXJzIHJlcHJlc2VudCBjb3VudCBvZiBzcGVjaWVzIGFzIHByb3BvcnRpb25zDQogICAgICBjb2xvciA9IHNwZWNpZXMsICAgICAgICAgICAgICAgICAgICAgICAjIFRoZSBvdXRsaW5lIG9mIHRoZSBiYXJzIGFyZSBjb2xvcmVkIGJ5IHNwZWNpZXMNCiAgICAgIGZpbGwgPSBhZnRlcl9zY2FsZShhbHBoYShjb2xvciwgMC41KSkgICMgVGhlIGZpbGwgb2YgdGhlIGJhcnMgYXJlIGxpZ2h0ZXIgdGhhbiB0aGUgb3V0bGluZSBjb2xvcg0KICAgICksDQogICAgc2l6ZSA9IDMNCiAgKQ0KYmFycGxvdF9wbG90DQpgYGANCg0KIyMgVHJhY2UgYmVmb3JlICYgYWZ0ZXIgYGFmdGVyX3N0YXQoKWANCg0KW2h0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvZ2dwbG90Mi9ibG9iL2RlNWQ2M2Y3ZWJhMDZlNTA3MTg3ZjM0NzgwYmVhMDcxY2IzMWZlZTQvUi9sYXllci5yI0wyOTMtTDM0MV0oaHR0cHM6Ly9naXRodWIuY29tL3RpZHl2ZXJzZS9nZ3Bsb3QyL2Jsb2IvZGU1ZDYzZjdlYmEwNmU1MDcxODdmMzQ3ODBiZWEwNzFjYjMxZmVlNC9SL2xheWVyLnIjTDI5My1MMzQxKQ0KDQpgYGB7cn0NCmdndHJhY2UoDQogIG1ldGhvZCA9IGdncGxvdDI6OjpMYXllciRtYXBfc3RhdGlzdGljLCAjIExheWVyIGlzIG5vdCBleHBvcnRlZCBzbyBuZWVkIHRoZSBgOjo6YA0KICB0cmFjZV9zdGVwcyA9IGMoMSwgMSwgLTEpLA0KICB0cmFjZV9leHBycyA9IGV4cHJzKA0KICAgIHRyYWNlYmFjayA9IHRyYWNlX2JhY2soKSwgIyBMb2cgdGhlIHRyYWNlYmFjayB3aGVuIHRoZSBtZXRob2QgaXMgY2FsbGVkDQogICAgYmVmb3JlID0gZGF0YSwgICAgICAgICAgICAjIFdoYXQgZG9lcyB0aGUgZGF0YSBsb29rIGxpa2UgQkVGT1JFIHJlc29sdmluZyBgYWZ0ZXJfc3RhdCgpYD8NCiAgICBhZnRlciA9IH5zdGVwICAgICAgICAgICAgICMgV2hhdCBkb2VzIHRoZSBkYXRhIGxvb2sgbGlrZSBBRlRFUiByZXNvbHZpbmcgYGFmdGVyX3N0YXQoKWA/DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIC0gVGhlIGB+c3RlcGAga2V5d29yZCBydW5zIHRoZSBzdGVwIGFuZCByZXR1cm5zIGl0cyBvdXRwdXQNCiAgKSwNCiAgdmVyYm9zZSA9IEZBTFNFDQopDQpgYGANCg0KIyMgVHJhY2UgYmVmb3JlICYgYWZ0ZXIgYGFmdGVyX3NjYWxlKClgDQoNCltodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL2dncGxvdDIvYmxvYi84N2U5Yjg1ZGQ5ZjJhMjk0ZjMzOWQ4OGEzNTNkMGMxMWM4NTE0ODlkL1IvZ2VvbS0uciNMMTI2LUwxNTBdKGh0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvZ2dwbG90Mi9ibG9iLzg3ZTliODVkZDlmMmEyOTRmMzM5ZDg4YTM1M2QwYzExYzg1MTQ4OWQvUi9nZW9tLS5yI0wxMjYtTDE1MCkNCg0KYGBge3J9DQpnZ3RyYWNlKA0KICBtZXRob2QgPSBHZW9tJHVzZV9kZWZhdWx0cywNCiAgdHJhY2Vfc3RlcHMgPSBjKDEsIDYsIDcpLA0KICB0cmFjZV9leHBycyA9IGV4cHJzKA0KICAgIHRyYWNlYmFjayA9IHRyYWNlX2JhY2soKSwgIyBMb2cgdGhlIHRyYWNlYmFjayB3aGVuIHRoZSBtZXRob2QgaXMgY2FsbGVkDQogICAgYmVmb3JlID0gZGF0YSwgICAgICAgICAgICAjIFdoYXQgZG9lcyB0aGUgZGF0YSBsb29rIGxpa2UgQkVGT1JFIHJlc29sdmluZyBgYWZ0ZXJfc2NhbGUoKWANCiAgICBhZnRlciA9IGRhdGEgICAgICAgICAgICAgICMgV2hhdCBkb2VzIHRoZSBkYXRhIGxvb2sgbGlrZSBBRlRFUiByZXNvbHZpbmcgYGFmdGVyX3NjYWxlKClgDQogICksDQogIHZlcmJvc2UgPSBGQUxTRQ0KKQ0KYGBgDQoNCiMgVHJpZ2dlciB0cmFjZXMgYW5kIGNvbGxlY3QgdHJhY2VkdW1wDQoNCmBgYHtyfQ0KIyBQcmludCB0aGUgcGxvdCBhbmQgdHJpZ2dlciB0aGUgdHJhY2VzDQojIE5vdGUgdGhhdCB3aXRoIHRoZSBkZWZhdWx0IGBvbmNlID0gVFJVRWAsIHRoZSB0cmFjZXMgYXJlIHJlbW92ZWQgb24gZXhpdA0KYmFycGxvdF9wbG90DQoNCnRyYWNlZHVtcCA8LSBnbG9iYWxfZ2d0cmFjZSgpDQpuYW1lcyh0cmFjZWR1bXApDQpuYW1lcyh0cmFjZWR1bXApIDwtIGMoImFmdGVyX3N0YXQiLCAiYWZ0ZXJfc2NhbGUiKQ0KbGFwcGx5KHRyYWNlZHVtcCwgbmFtZXMpDQpgYGANCg0KIyBJbnNwZWN0IHRyYWNlZHVtcA0KDQojIyBgYWZ0ZXJfc3RhdCgpYCBiZWZvcmUgJiBhZnRlcg0KDQpgYGB7cn0NCnRyYWNlZHVtcCRhZnRlcl9zdGF0JGJlZm9yZQ0KdHJhY2VkdW1wJGFmdGVyX3N0YXQkYWZ0ZXINCmlkZW50aWNhbCgNCiAgdHJhY2VkdW1wJGFmdGVyX3N0YXQkYmVmb3JlICU+JSANCiAgICBtdXRhdGUoeSA9IGNvdW50IC8gc3VtKGNvdW50KSkgJT4lIA0KICAgIHJlbG9jYXRlKHksIC5iZWZvcmUgPSAxKSwNCiAgdHJhY2VkdW1wJGFmdGVyX3N0YXQkYWZ0ZXINCikNCmBgYA0KDQojIyBgYWZ0ZXJfc2NhbGUoKWAgYmVmb3JlICYgYWZ0ZXINCg0KYGBge3J9DQp0cmFjZWR1bXAkYWZ0ZXJfc2NhbGUkYmVmb3JlDQp0cmFjZWR1bXAkYWZ0ZXJfc2NhbGUkYWZ0ZXINCmlkZW50aWNhbCgNCiAgdHJhY2VkdW1wJGFmdGVyX3NjYWxlJGJlZm9yZSAlPiUgDQogICAgbXV0YXRlKGZpbGwgPSBhbHBoYShjb2xvdXIsIDAuNSkpICU+JSANCiAgICByZWxvY2F0ZShmaWxsLCAuYmVmb3JlID0gMSksDQogIHRyYWNlZHVtcCRhZnRlcl9zY2FsZSRhZnRlcg0KKQ0KYGBgDQoNCiMjIENvbXBhcmUgdG8gdGhlIGZpbmFsIGxheWVyIGRhdGENCg0KYGBge3J9DQpsYXllcl9kYXRhKGJhcnBsb3RfcGxvdCwgMSkNCmBgYA0KDQojIFdoZXJlIHdlcmUgdGhlIG1ldGhvZHMgY2FsbGVkIGZyb20/DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQojIFdoYXQgYWJvdXQgdGhlIHRyYWNlYmFja3M/DQojIC0gdHJhY2ViYWNrIGNvbnRhaW5zIGluZm9ybWF0aW9uIGFib3V0IHRoZSAiY2FsbCBzdGFjayIgKHdoYXQgY2FsbGVkIHRoZSBtZXRob2Q/KQ0KIyBXZSBzZWUgdGhhdCB0aGV5J3JlIGNhbGxlZCBmcm9tIGRpZmZlcmVudCBwbGFjZXMgaW4gYGdncGxvdF9idWlsZC5nZ3Bsb3QoeClgDQojIC0gTGF5ZXIkbWFwX3N0YXRpc3RpYyBpbiBMaW5lIDczLCBMYXllciRjb21wdXRlX2dlb21fMiAod2hpY2ggY2FsbHMgR2VvbSR1c2VfZGVmYXVsdHMpIGluIExpbmUgMTAwDQojICAgICAtIGh0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvZ2dwbG90Mi9ibG9iL2RlNWQ2M2Y3ZWJhMDZlNTA3MTg3ZjM0NzgwYmVhMDcxY2IzMWZlZTQvUi9wbG90LWJ1aWxkLnINCmxhcHBseSh0cmFjZWR1bXAsIGBbW2AsICJ0cmFjZWJhY2siKSANCmBgYA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0KbGFwcGx5KHRyYWNlZHVtcCwgYFtbYCwgInRyYWNlYmFjayIpICU+JSANCiAgbGFwcGx5KGZ1bmN0aW9uKHgpIHJsYW5nOjo6dHJhY2Vfc3Vic2V0KHgsIDI0OnRyYWNlX2xlbmd0aCh4KSkpICMgSWdub3JlIHRoaXMgLSB0cmltcyBybWFya2Rvd24gcmVuZGVyaW5nIGNhbGxzDQpgYGANCg0KDQojIENvbnRleHR1YWxpemluZyBgc2VsZmANCg0KYGBge3J9DQojIFdlIGNhbiBhbHNvIGdldCB0aGUgY29udGV4dCBmb3Igc2VsZg0KDQojIEZpcnN0LCBjbGVhciB0aGUgZ2xvYmFsIHRyYWNlZHVtcA0KY2xlYXJfZ2xvYmFsX2dndHJhY2UoKQ0KDQojIFJldHVybiBgc2VsZmAgaW5zaWRlIHRoZSBtZXRob2QNCiMgYHNlbGZgIHNob3VsZCBiZSBjb250ZXh0dWFsaXplZCB0byB0aGUgTGF5ZXIgYW5kIHRoZSBHZW9tDQpnZ3RyYWNlKGdncGxvdDI6OjpMYXllciRjb21wdXRlX2dlb21fMiwgMSwgcXVvdGUoc2VsZiksIHZlcmJvc2UgPSBGQUxTRSkNCmdndHJhY2UoR2VvbSR1c2VfZGVmYXVsdHMsIDEsIHF1b3RlKHNlbGYpLCB2ZXJib3NlID0gRkFMU0UpDQoNCiMgRm9yY2UgZXZhbHVhdGlvbiBvZiBwbG90IGNvZGUgd2l0aG91dCBwcmludGluZyBpdA0KaW52aXNpYmxlKGdncGxvdF9idWlsZChiYXJwbG90X3Bsb3QpKQ0KDQp0cmFjZWRfc2VsZiA8LSB1bmxpc3QoZ2xvYmFsX2dndHJhY2UoKSwgcmVjdXJzaXZlID0gRkFMU0UpDQpuYW1lcyh0cmFjZWRfc2VsZikgPC0gYygibGF5ZXIiLCAiZ2VvbSIpDQoNCnRyYWNlZF9zZWxmDQojIFRoZSBnZW9tIGlzIEdlb21CYXINCmlkZW50aWNhbCh0cmFjZWRfc2VsZiRnZW9tLCBHZW9tQmFyKQ0KIyBUaGlzIGlzIGFsc28gdGhlIGRlZmF1bHQgZ2VvbSBmb3IgdGhlIGxheWVyIHJldHVybmVkIGJ5IGBnZW9tX2JhcigpYA0KaWRlbnRpY2FsKHRyYWNlZF9zZWxmJGdlb20sIGdlb21fYmFyKCkkZ2VvbSkNCiMgV2hpY2ggaXMgYWxzbyB0aGUgZ2VvbSBvZiB0aGUgYWN0dWFsIExheWVyIHRoYXQgd2UgdHJhY2VkDQppZGVudGljYWwodHJhY2VkX3NlbGYkZ2VvbSwgdHJhY2VkX3NlbGYkbGF5ZXIkZ2VvbSkNCiMgVGhlIHN0YXQgb2YgdGhlIHRyYWNlZCBsYXllciBpcyBTdGF0Q291bnQNCmlkZW50aWNhbCh0cmFjZWRfc2VsZiRsYXllciRzdGF0LCBTdGF0Q291bnQpDQojIFRoaXMgaXMgdGhlIGRlZmF1bHQgZm9yIGBnZW9tX2JhcigpYCAoZGVmYXVsdCBpcyBgZ2VvbV9iYXIoc3RhdCA9ICJjb3VudCIpYCkNCmlkZW50aWNhbCh0cmFjZWRfc2VsZiRsYXllciRzdGF0LCBnZW9tX2JhcigpJHN0YXQpDQpgYGANCiANCiMgU2Vzc2lvbiBpbmZvDQogDQpgYGB7cn0NCnNlc3Npb25pbmZvOjpzZXNzaW9uX2luZm8oKQ0KYGBgDQogDQog