library(devtools)
library(usethis)
library(tidyverse)

Imported functions

Build doc and install

Run this to update documentation and install locally.

Examples

library(adas.utils)
fp_design_matrix(5) %>% 
  fp_fraction(~A*B*C*D) %>% 
  fp_fraction(~B*C*D*E) %>% 
  dplyr::mutate(Y=rnorm(dplyr::n()))
fp_alias(~A*B*C*D)
fp_alias(~B*C*D*E)
dm <- fp_design_matrix(3)

fp_augment_center <- function(dm, rep=5) {
  stopifnot("factorial.plan" %in% class(dm))
  r <- nrow(dm)
  fct <- attr(dm, "factors")
  
  dm %>% 
    add_row(
      StdOrder = (r+1):(r+rep),
      RunOrder = sample((r+1):(r+rep)),
      .treat = "0",
      .rep = 1:rep,
    ) %>% 
    mutate(
      across({fct}, ~ 0)
    )
}

dm %>% 
  fp_augment_center(5)

Making data

\(2^2\) CCD

set.seed(0)

f <- function(a, b) {
  1 + 2*a + 3*a^2+ 3*b + 0.05*b^2 + 4*a*b + rnorm(length(a))
}

dm <- fp_design_matrix(2, rep=3) %>% 
  fp_augment_center(rep=4) %>%
  fp_augment_axial(rep=2) %>%
  mutate(
    Y = f(A, B)
  )

dm
dm %>% 
  filter(.treat != "center" & .treat != "axial") %>% 
  lm(Y ~ A*B, data=.) %>%
  anova()
dm %>% 
  filter(.treat != "axial") %>% 
  lm(Y ~ A*I(A^2)*B, data=.) %>%
  anova()
dm %>% 
  lm(Y ~ A*I(A^2)*B*I(B^2)+A:B, data=.) %>%
  anova()
dm %>% 
  lm(Y ~  A * B * I(A^2) * I(B^2), data=.) %>%
  anova()
ccd_experiment_yield <- list(
  base = dm %>% 
    filter(.treat != "center" & .treat != "axial") %>% 
    pull(Y),
  center = dm %>% 
    filter(.treat == "center") %>% 
    pull(Y),
  axial = dm %>%
    filter(.treat == "axial") %>% 
    pull(Y)
)
dm <- fp_design_matrix(3, rep=2)

# fp_add_scale <- function(dm, ..., suffix="_s") {
#   attr(dm, "scales") <- list()
#   for (i in 1:...length()) {
#     name <- ...names()[i]
#     rng <- ...elt(i)
#     if (!(is.numeric(rng) & length(rng) == 2 & is.numeric(dm[[name]]))) {
#       warning("Skipping factor ", name, " (it is not a number, or wrong scale range/type provided)\n")
#       next
#     }
#     dm <- dm %>% 
#       mutate(
#         !!paste0(name, suffix) := scales::rescale(!!sym(name), to=rng)
#       )
#     attr(dm, "scales") <- append(attr(dm, "scales"), setNames(list(rng), name))
#   }
#   return(dm)
# }

dms <-  dm %>% 
  fp_add_scale(A=c(2, 12), B=c(40, 60), suffix="")

dms
fp_design_matrix(2) %>% 
  fp_add_names(A="Temperature", B="Pressure") 
dm <- fp_design_matrix(2) %>% 
  fp_add_names(A="Temperature", B="Pressure") %>% 
  fp_add_scale(A=c(2, 12), B=c(40, 60), suffix="_s") %>%
  fp_write_csv("design_matrix.csv")
dm %>%
  fp_read_csv("design_matrix.csv")

For Tukey

battery <- examples_url("battery.dat") %>% read.table(header=TRUE) %>% 
  mutate(across(Temperature:Material, factor)) %>% glimpse()
Rows: 36
Columns: 6
$ RunOrder      <int> 34, 25, 16, 7, 8, 1, 26, 36, 6, 13, 3, 31, 27, 29, 12, 14, 30, 24, 5, 21, 1…
$ StandardOrder <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, …
$ Temperature   <fct> 15, 70, 125, 15, 70, 125, 15, 70, 125, 15, 70, 125, 15, 70, 125, 15, 70, 12…
$ Material      <fct> 1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, …
$ Repeat        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, …
$ Response      <int> 130, 34, 20, 150, 136, 25, 138, 174, 96, 155, 40, 70, 188, 122, 70, 110, 12…
cotton <- examples_url("cotton.dat") %>% read.table(header=TRUE) %>% 
  mutate(Cotton = factor(Cotton)) %>% 
  glimpse()
Rows: 25
Columns: 3
$ Run      <int> 14, 23, 20, 16, 21, 24, 7, 11, 8, 9, 17, 18, 25, 4, 22, 15, 3, 6, 1, 2, 13, 12, …
$ Cotton   <fct> 15, 15, 15, 15, 15, 20, 20, 20, 20, 20, 25, 25, 25, 25, 25, 30, 30, 30, 30, 30, …
$ Strength <int> 7, 7, 15, 11, 9, 12, 17, 12, 18, 18, 14, 18, 18, 19, 19, 19, 25, 22, 19, 23, 7, …
usethis::use_data(battery, overwrite=TRUE)
✔ Saving "battery" to "data/battery.rda".
☐ Document your data (see <]8;;https://r-pkgs.org/data.htmlhttps://r-pkgs.org/data.html]8;;>).
usethis::use_data(cotton, overwrite=TRUE)
✔ Saving "cotton" to "data/cotton.rda".
☐ Document your data (see <]8;;https://r-pkgs.org/data.htmlhttps://r-pkgs.org/data.html]8;;>).

Centered design

set.seed(0)
fp <- fp_design_matrix(2, rep=3) %>% 
  mutate(Y=f(A, B))
fp
fp %>% 
  lm(Y ~ A*B, data=.) %>% 
  anova()

All factors and their interactions are significant. But is the two-level model enough? Let’s check for the quadratic terms, by augmenting the plan with a central point repeated 4 times. We also load the center field from the ccd_experiment_yield dataset:

set.seed(0)
f <- function(a, b) {
  1 + 2*a + 3*b + (3*a^2 + 0.05*b^2)*0.5 + 4*a*b + rnorm(length(a))
}

fpc <- fp %>% 
  fp_augment_center(rep=4) %>% 
  mutate(Y=f(A,B))

fp <- fpc %>% 
  filter(.treat != "center")

fpc

fpc %>% 
  lm(Y ~ A*B+I(A^2), data=.) %>% 
  anova()

fp %>% 
  lm(Y~A*B, data=.) %>% 
  predict(newdata=fpc, interval="confidence") %>% 
  bind_cols(fpc) %>% 
  filter(.treat == "center") %>% 
  summarise(lwr=min(lwr), upr=max(upr)) %>% 
  mutate(what="base") %>% 
  bind_rows(
    fpc %>% 
      filter(.treat == "center") %>% 
      pull(Y) %>% 
      t.test() %>% 
      broom::tidy() %>% 
      select(lwr=conf.low, upr=conf.high) %>% 
      mutate("what"="center")
  ) %>% 
  ggplot(aes(x=what, ymin=lwr, ymax=upr)) +
  geom_errorbar()
LS0tCnRpdGxlOiAiRGV2ZWxvcG1lbnQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwfQpsaWJyYXJ5KGRldnRvb2xzKQpsaWJyYXJ5KHVzZXRoaXMpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMgSW1wb3J0ZWQgZnVuY3Rpb25zCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQp1c2VfaW1wb3J0X2Zyb20oCiAgImdsdWUiLCAKICAiZ2x1ZSIKKQoKdXNlX2ltcG9ydF9mcm9tKAogICJzY2FsZXMiLCAKICBjKCJyZXNjYWxlIikKKQoKdXNlX2ltcG9ydF9mcm9tKAogICJyZWFkciIsIGMoInJlYWRfY3N2IiwgInJlYWRfY3N2MiIsICJ3cml0ZV9jc3YiLCAid3JpdGVfY3N2MiIpCikKCnVzZV9pbXBvcnRfZnJvbSgKICAidGliYmxlIiwgCiAgYygidGliYmxlIiwgImFzX3RpYmJsZSIsICJyb3duYW1lc190b19jb2x1bW4iKQopCgp1c2VfaW1wb3J0X2Zyb20oImdnaGFsZm5vcm0iLCAiZ2doYWxmbm9ybSIpCgp1c2VfaW1wb3J0X2Zyb20oImx1YnJpZGF0ZSIsICJzdGFtcCIpCgp1c2VfaW1wb3J0X2Zyb20oCiAgInRpZHlyIiwKICAicGl2b3RfbG9uZ2VyIgopCgp1c2VfaW1wb3J0X2Zyb20oCiAgImdyRGV2aWNlcyIsIGMoImdyZXkiKQopCgp1c2VfaW1wb3J0X2Zyb20oCiAgInN0YXRzIiwgCiAgYygKICAgICJhcy5mb3JtdWxhIiwgImNvZWYiLCAiZWNkZiIsICJlZmZlY3RzIiwgIm5hLm9taXQiLAogICAgInBub3JtIiwgInNkIiwgInNldE5hbWVzIiwgInRlcm1zIiwgImFvdiIsICJUdWtleUhTRCIsIAogICAgIm1lZGlhbiIsICJyZWZvcm11bGF0ZSIpCikKCnVzZV9pbXBvcnRfZnJvbSgKICAidXRpbHMiLCBjKCJ0YWlsIikKKQoKdXNlX2ltcG9ydF9mcm9tKAogICJkcGx5ciIsIAogICBjKAogICAgICJhY3Jvc3MiLAogICAgICJhZGRfcm93IiwKICAgICAiYXJyYW5nZSIsIAogICAgICJiaW5kX3Jvd3MiLAogICAgICJjX2Fjcm9zcyIsCiAgICAgImRlc2MiLAogICAgICJmaWx0ZXIiLAogICAgICJpZl9lbHNlIiwKICAgICAibXV0YXRlIiwgCiAgICAgIm4iLCAKICAgICAicHVsbCIsCiAgICAgInJlbG9jYXRlIiwKICAgICAicmVuYW1lIiwKICAgICAicmVuYW1lX3dpdGgiLAogICAgICJyb3d3aXNlIiwKICAgICAic2VsZWN0IiwKICAgICAic2xpY2VfdGFpbCIsCiAgICAgInN1bW1hcml6ZV9hbGwiLAogICAgICJ1bmdyb3VwIgogICApCikKCnVzZV9pbXBvcnRfZnJvbSgKICAicHVycnIiLCAKICAgYygKICAgICAiYWNjdW11bGF0ZSIsCiAgICAgImRpc2NhcmQiLAogICAgICJrZWVwIiwKICAgICAibGlzdF9tZXJnZSIsCiAgICAgIm1hcCIsIAogICAgICJzZXRfbmFtZXMiLAogICAgICJ3YWxrIiwKICAgICAiaXdhbGsiCiAgICkgICAKKQoKdXNlX2ltcG9ydF9mcm9tKAogICJnZ3Bsb3QyIiwgCiAgYygKICAgICJhZXMiLCAKICAgICJjb29yZF9jYXJ0ZXNpYW4iLAogICAgImNvb3JkX2ZsaXAiLAogICAgImVsZW1lbnRfdGV4dCIsCiAgICAiZm9ydGlmeSIsCiAgICAiZ2dwbG90IiwKICAgICJnZW9tX2NvbCIsCiAgICAiZ2VvbV9mdW5jdGlvbiIsCiAgICAiZ2VvbV9obGluZSIsCiAgICAiZ2VvbV9sYWJlbCIsCiAgICAiZ2VvbV9saW5lIiwKICAgICJnZW9tX3BvaW50IiwKICAgICJnZW9tX3FxIiwKICAgICJnZW9tX3FxX2xpbmUiLAogICAgImdlb21fdGlsZSIsCiAgICAiZ2VvbV9lcnJvcmJhciIsCiAgICAibGFicyIsCiAgICAicG9zaXRpb25fZG9kZ2UiLAogICAgInNjYWxlX2ZpbGxfdmlyaWRpc19kIiwKICAgICJzY2FsZV95X2NvbnRpbnVvdXMiLAogICAgInNlY19heGlzIiwKICAgICJzdGF0X3FxIiwKICAgICJ0aGVtZSIKICAgIAogICkKKQoKdXNlX2ltcG9ydF9mcm9tKAogICJybGFuZyIsIAogIGMoImlzX2Zvcm11bGEiLCJzeW0iLCAiOj0iKQopCgp1c2VfaW1wb3J0X2Zyb20oCiAgInN0cmluZ3IiLAogICJzdHJfcmVtb3ZlX2FsbCIKKQpgYGAKIyBCdWlsZCBkb2MgYW5kIGluc3RhbGwKClJ1biB0aGlzIHRvIHVwZGF0ZSBkb2N1bWVudGF0aW9uIGFuZCBpbnN0YWxsIGxvY2FsbHkuCgoKYGBge3IgaW5jbHVkZT1GQUxTRSwgZXZhbD1GQUxTRX0KZGV2dG9vbHM6OmRvY3VtZW50KCkKZGV2dG9vbHM6OmJ1aWxkX3ZpZ25ldHRlcygpCmRldnRvb2xzOjppbnN0YWxsKCkKYGBgCgojIEV4YW1wbGVzCgpgYGB7cn0KbGlicmFyeShhZGFzLnV0aWxzKQpgYGAKCgpgYGB7cn0KZnBfZGVzaWduX21hdHJpeCg1KSAlPiUgCiAgZnBfZnJhY3Rpb24ofkEqQipDKkQpICU+JSAKICBmcF9mcmFjdGlvbih+QipDKkQqRSkgJT4lIAogIGRwbHlyOjptdXRhdGUoWT1ybm9ybShkcGx5cjo6bigpKSkKYGBgCgpgYGB7cn0KZnBfYWxpYXMofkEqQipDKkQpCmZwX2FsaWFzKH5CKkMqRCpFKQpgYGAKCmBgYHtyfQpkbSA8LSBmcF9kZXNpZ25fbWF0cml4KDMpCgpmcF9hdWdtZW50X2NlbnRlciA8LSBmdW5jdGlvbihkbSwgcmVwPTUpIHsKICBzdG9waWZub3QoImZhY3RvcmlhbC5wbGFuIiAlaW4lIGNsYXNzKGRtKSkKICByIDwtIG5yb3coZG0pCiAgZmN0IDwtIGF0dHIoZG0sICJmYWN0b3JzIikKICAKICBkbSAlPiUgCiAgICBhZGRfcm93KAogICAgICBTdGRPcmRlciA9IChyKzEpOihyK3JlcCksCiAgICAgIFJ1bk9yZGVyID0gc2FtcGxlKChyKzEpOihyK3JlcCkpLAogICAgICAudHJlYXQgPSAiMCIsCiAgICAgIC5yZXAgPSAxOnJlcCwKICAgICkgJT4lIAogICAgbXV0YXRlKAogICAgICBhY3Jvc3Moe2ZjdH0sIH4gMCkKICAgICkKfQoKZG0gJT4lIAogIGZwX2F1Z21lbnRfY2VudGVyKDUpCmBgYAoKCiMgTWFraW5nIGRhdGEKCiMjICQyXjIkIENDRAoKYGBge3J9CnNldC5zZWVkKDApCgpmIDwtIGZ1bmN0aW9uKGEsIGIpIHsKICAxICsgMiphICsgMyphXjIrIDMqYiArIDAuMDUqYl4yICsgNCphKmIgKyBybm9ybShsZW5ndGgoYSkpCn0KCmRtIDwtIGZwX2Rlc2lnbl9tYXRyaXgoMiwgcmVwPTMpICU+JSAKICBmcF9hdWdtZW50X2NlbnRlcihyZXA9NCkgJT4lCiAgZnBfYXVnbWVudF9heGlhbChyZXA9MikgJT4lCiAgbXV0YXRlKAogICAgWSA9IGYoQSwgQikKICApCgpkbQpgYGAKCgpgYGB7cn0KZG0gJT4lIAogIGZpbHRlcigudHJlYXQgIT0gImNlbnRlciIgJiAudHJlYXQgIT0gImF4aWFsIikgJT4lIAogIGxtKFkgfiBBKkIsIGRhdGE9LikgJT4lCiAgYW5vdmEoKQpgYGAKCmBgYHtyfQpkbSAlPiUgCiAgZmlsdGVyKC50cmVhdCAhPSAiYXhpYWwiKSAlPiUgCiAgbG0oWSB+IEEqSShBXjIpKkIsIGRhdGE9LikgJT4lCiAgYW5vdmEoKQpgYGAKCgoKYGBge3J9CmRtICU+JSAKICBsbShZIH4gQSpJKEFeMikqQipJKEJeMikrQTpCLCBkYXRhPS4pICU+JQogIGFub3ZhKCkKYGBgCgpgYGB7cn0KZG0gJT4lIAogIGxtKFkgfiAgQSAqIEIgKiBJKEFeMikgKiBJKEJeMiksIGRhdGE9LikgJT4lCiAgYW5vdmEoKQpgYGAKCgpgYGB7cn0KY2NkX2V4cGVyaW1lbnRfeWllbGQgPC0gbGlzdCgKICBiYXNlID0gZG0gJT4lIAogICAgZmlsdGVyKC50cmVhdCAhPSAiY2VudGVyIiAmIC50cmVhdCAhPSAiYXhpYWwiKSAlPiUgCiAgICBwdWxsKFkpLAogIGNlbnRlciA9IGRtICU+JSAKICAgIGZpbHRlcigudHJlYXQgPT0gImNlbnRlciIpICU+JSAKICAgIHB1bGwoWSksCiAgYXhpYWwgPSBkbSAlPiUKICAgIGZpbHRlcigudHJlYXQgPT0gImF4aWFsIikgJT4lIAogICAgcHVsbChZKQopCmBgYAoKCgoKYGBge3J9CmRtIDwtIGZwX2Rlc2lnbl9tYXRyaXgoMywgcmVwPTIpCgojIGZwX2FkZF9zY2FsZSA8LSBmdW5jdGlvbihkbSwgLi4uLCBzdWZmaXg9Il9zIikgewojICAgYXR0cihkbSwgInNjYWxlcyIpIDwtIGxpc3QoKQojICAgZm9yIChpIGluIDE6Li4ubGVuZ3RoKCkpIHsKIyAgICAgbmFtZSA8LSAuLi5uYW1lcygpW2ldCiMgICAgIHJuZyA8LSAuLi5lbHQoaSkKIyAgICAgaWYgKCEoaXMubnVtZXJpYyhybmcpICYgbGVuZ3RoKHJuZykgPT0gMiAmIGlzLm51bWVyaWMoZG1bW25hbWVdXSkpKSB7CiMgICAgICAgd2FybmluZygiU2tpcHBpbmcgZmFjdG9yICIsIG5hbWUsICIgKGl0IGlzIG5vdCBhIG51bWJlciwgb3Igd3Jvbmcgc2NhbGUgcmFuZ2UvdHlwZSBwcm92aWRlZClcbiIpCiMgICAgICAgbmV4dAojICAgICB9CiMgICAgIGRtIDwtIGRtICU+JSAKIyAgICAgICBtdXRhdGUoCiMgICAgICAgICAhIXBhc3RlMChuYW1lLCBzdWZmaXgpIDo9IHNjYWxlczo6cmVzY2FsZSghIXN5bShuYW1lKSwgdG89cm5nKQojICAgICAgICkKIyAgICAgYXR0cihkbSwgInNjYWxlcyIpIDwtIGFwcGVuZChhdHRyKGRtLCAic2NhbGVzIiksIHNldE5hbWVzKGxpc3Qocm5nKSwgbmFtZSkpCiMgICB9CiMgICByZXR1cm4oZG0pCiMgfQoKZG1zIDwtICBkbSAlPiUgCiAgZnBfYWRkX3NjYWxlKEE9YygyLCAxMiksIEI9Yyg0MCwgNjApLCBzdWZmaXg9IiIpCgpkbXMKYGBgCgpgYGB7cn0KZnBfZGVzaWduX21hdHJpeCgyKSAlPiUgCiAgZnBfYWRkX25hbWVzKEE9IlRlbXBlcmF0dXJlIiwgQj0iUHJlc3N1cmUiKSAKYGBgCgpgYGB7cn0KZG0gPC0gZnBfZGVzaWduX21hdHJpeCgyKSAlPiUgCiAgZnBfYWRkX25hbWVzKEE9IlRlbXBlcmF0dXJlIiwgQj0iUHJlc3N1cmUiKSAlPiUgCiAgZnBfYWRkX3NjYWxlKEE9YygyLCAxMiksIEI9Yyg0MCwgNjApLCBzdWZmaXg9Il9zIikgJT4lCiAgZnBfd3JpdGVfY3N2KCJkZXNpZ25fbWF0cml4LmNzdiIpCmBgYAoKCmBgYHtyfQpkbSAlPiUKICBmcF9yZWFkX2NzdigiZGVzaWduX21hdHJpeC5jc3YiKQpgYGAKCgojIyBGb3IgVHVrZXkKCmBgYHtyfQpiYXR0ZXJ5IDwtIGV4YW1wbGVzX3VybCgiYmF0dGVyeS5kYXQiKSAlPiUgcmVhZC50YWJsZShoZWFkZXI9VFJVRSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoVGVtcGVyYXR1cmU6TWF0ZXJpYWwsIGZhY3RvcikpICU+JSBnbGltcHNlKCkKCmNvdHRvbiA8LSBleGFtcGxlc191cmwoImNvdHRvbi5kYXQiKSAlPiUgcmVhZC50YWJsZShoZWFkZXI9VFJVRSkgJT4lIAogIG11dGF0ZShDb3R0b24gPSBmYWN0b3IoQ290dG9uKSkgJT4lIAogIGdsaW1wc2UoKQoKCnVzZXRoaXM6OnVzZV9kYXRhKGJhdHRlcnksIG92ZXJ3cml0ZT1UUlVFKQp1c2V0aGlzOjp1c2VfZGF0YShjb3R0b24sIG92ZXJ3cml0ZT1UUlVFKQpgYGAKCgoKIyBDZW50ZXJlZCBkZXNpZ24KCmBgYHtyfQpzZXQuc2VlZCgwKQpmcCA8LSBmcF9kZXNpZ25fbWF0cml4KDIsIHJlcD0zKSAlPiUgCiAgbXV0YXRlKFk9ZihBLCBCKSkKZnAKYGBgCgoKYGBge3J9CmZwICU+JSAKICBsbShZIH4gQSpCLCBkYXRhPS4pICU+JSAKICBhbm92YSgpCmBgYApBbGwgZmFjdG9ycyBhbmQgdGhlaXIgaW50ZXJhY3Rpb25zIGFyZSBzaWduaWZpY2FudC4gQnV0IGlzIHRoZSB0d28tbGV2ZWwgbW9kZWwgZW5vdWdoPyBMZXQncyBjaGVjayBmb3IgdGhlIHF1YWRyYXRpYyB0ZXJtcywgYnkgYXVnbWVudGluZyB0aGUgcGxhbiB3aXRoIGEgY2VudHJhbCBwb2ludCByZXBlYXRlZCA0IHRpbWVzLiBXZSBhbHNvIGxvYWQgdGhlIGBjZW50ZXJgIGZpZWxkIGZyb20gdGhlIGBjY2RfZXhwZXJpbWVudF95aWVsZGAgZGF0YXNldDoKCmBgYHtyfQpzZXQuc2VlZCgwKQpmIDwtIGZ1bmN0aW9uKGEsIGIpIHsKICAxICsgMiphICsgMypiICsgKDMqYV4yICsgMC4wNSpiXjIpKjAuNSArIDQqYSpiICsgcm5vcm0obGVuZ3RoKGEpKQp9CgpmcGMgPC0gZnAgJT4lIAogIGZwX2F1Z21lbnRfY2VudGVyKHJlcD00KSAlPiUgCiAgbXV0YXRlKFk9ZihBLEIpKQoKZnAgPC0gZnBjICU+JSAKICBmaWx0ZXIoLnRyZWF0ICE9ICJjZW50ZXIiKQoKZnBjCgpmcGMgJT4lIAogIGxtKFkgfiBBKkIrSShBXjIpLCBkYXRhPS4pICU+JSAKICBhbm92YSgpCgpmcCAlPiUgCiAgbG0oWX5BKkIsIGRhdGE9LikgJT4lIAogIHByZWRpY3QobmV3ZGF0YT1mcGMsIGludGVydmFsPSJjb25maWRlbmNlIikgJT4lIAogIGJpbmRfY29scyhmcGMpICU+JSAKICBmaWx0ZXIoLnRyZWF0ID09ICJjZW50ZXIiKSAlPiUgCiAgc3VtbWFyaXNlKGx3cj1taW4obHdyKSwgdXByPW1heCh1cHIpKSAlPiUgCiAgbXV0YXRlKHdoYXQ9ImJhc2UiKSAlPiUgCiAgYmluZF9yb3dzKAogICAgZnBjICU+JSAKICAgICAgZmlsdGVyKC50cmVhdCA9PSAiY2VudGVyIikgJT4lIAogICAgICBwdWxsKFkpICU+JSAKICAgICAgdC50ZXN0KCkgJT4lIAogICAgICBicm9vbTo6dGlkeSgpICU+JSAKICAgICAgc2VsZWN0KGx3cj1jb25mLmxvdywgdXByPWNvbmYuaGlnaCkgJT4lIAogICAgICBtdXRhdGUoIndoYXQiPSJjZW50ZXIiKQogICkgJT4lIAogIGdncGxvdChhZXMoeD13aGF0LCB5bWluPWx3ciwgeW1heD11cHIpKSArCiAgZ2VvbV9lcnJvcmJhcigpCmBgYAoKCg==