Creative Commons License

1 Puromycin dataset

Data on the velocity of an enzymatic reaction were obtained by Treloar (1974). The number of counts per minute of radioactive product from the reaction was measured as a function of substrate concentration in parts per million (ppm) and from these counts the initial rate (or velocity) of the reaction was calculated (counts/min/min). The experiment was conducted once with the enzyme treated with Puromycin, and once with the enzyme untreated.

Import libraries

2 Import data

In contrast to the other datasets we have worked with so far, this dataset is not available through a URL link. In stead, the data is directly available from an R package that was pre-installed in your R working environment. As such, we can simple do

data(Puromycin)

and an object called Puromycin is immediately available in your working environment.

3 Data wrangling

Filter the data so that we are left with only the “treated” enzymes.

4 Data exploration

In the original publication the authors observed a linear relationship between the log10 substrate concentration and the reaction rate. Make a visualization that allows for reproducing this finding.

Puromycin %>%
  ggplot(...) + # select which elements of the dataset we need to visualize
  ... # use a relevant plotting geometry
stat_smooth(...) + # draw a smooth line through the data cloud
  stat_smooth(...) # draw a straight (linear regression) line through the data cloud
... # you can add some extra elements like axis labels, title, ...

Note, that the researchers have chosen 6 different substrate concentrations and conducted an experiment where they assessed the initial reaction rate twice for every concentration.

5 Question 1

Use the data to calculate the power to pick up an association that is as least as strong as the association you observed in the dataset when using an experiment with the same design.

5.1 Simulation function

For this first question, we will need a function that allows us to simulate data similar to that of our experiment under our model assumptions. We provide this function for you:

simFast <- function(form, data, betas, sd, contrasts, alpha = .05, nSim = 10000) {
  ySim <- rnorm(nrow(data) * nSim, sd = sd)
  dim(ySim) <- c(nrow(data), nSim)
  design <- model.matrix(form, data)
  ySim <- ySim + c(design %*% betas)
  ySim <- t(ySim)

  ### Fitting
  fitAll <- limma::lmFit(ySim, design)

  ### Inference
  varUnscaled <- c(t(contrasts) %*% fitAll$cov.coefficients %*% contrasts)
  contrasts <- fitAll$coefficients %*% contrasts
  seContrasts <- varUnscaled^.5 * fitAll$sigma
  tstats <- contrasts / seContrasts
  pvals <- pt(abs(tstats), fitAll$df.residual, lower.tail = FALSE) * 2
  return(mean(pvals < alpha))
}

Without going into the full code details, this function allows us to simulate data similar to that of our experiment under our model assumptions, given the following inputs:

  • form: model formula for the experiment we want to simulate
  • data: the target dataset on which we want to base our simulations on
  • betas: the linear regression coefficients for the target dataset
  • sd: the residual standard errors from the linear regression model fit on the target dataset
  • contrasts: comparison of interest, i.e. which (combination of) model parameters we would like to assess
  • alpha: alpha-level at which to conduct the hypothesis testing
  • nSim: number of datasets we would like to simulate

To simulate new data based on our target dataset Puromycin, we will need to fill in all the arguments to the simFast function.

Hint: for the betas and sd, we will need to fit a linear model first!

power1 <- simFast(
  form = ...,
  data = ...,
  betas = ...,
  sd = ...,
  contrasts = ...,
  alpha = ...,
  nSim = ...
)
power1

6 Question 2

Use the data to calculate the power to pick up an association where the reaction rate increases on average with 10 counts/min when the substrate concentration is 10 times higher (\(\beta_1=10\)).

Again, we will need to fill in all the arguments to the simFast function. This time, however, the question is slightly different from question 1. Adjust the inputs accordingly!

power2 <- simFast(
  form = ...,
  data = ...,
  betas = ...,
  sd = ...,
  contrasts = ...,
  alpha = ...,
  nSim = ...
)
power2

Compare your result with the one from question 1!

7 Question 3

Use the data to calculate the number of repeats you need for each concentration to pick up an association where the reaction rate increases on average with 10 counts/min when the substrate concentration is 10 times higher (\(\beta_1=10\)) with a power of at least 90%.

Hint: this will require us to repeat the simulation process as many times as we have concentration values.

concentrations <- Puromycin %>%
  pull(conc) %>%
  unique()

powers <- data.frame(n = 1:10, power = NA) # to later store our results

for (i in 1:10)
{
  simData <- data.frame(conc = rep(concentrations, each = i))
  powers[i, 2] <- simFast(
    form = ...,
    data = ...,
    betas = ...,
    sd = ...,
    contrasts = ...,
    alpha = ...,
    nSim = ...
  )
}

Make a visualization that displays the power in function of the number of repeats in the data.

powers %>%
  ggplot(...) +
  geom_line() +
  geom_hline(yintercept = 0.9, lty = 2)

8 Question 4

Suppose that you would set up an experiment with a design similar with the same concentrations as in the puromycin dataset and you have the following restriction: you need to use each concentration at least once and can setup at most 12 reactions, how would you choose your design points? Calculate the power for this design when the effect size is 10 counts/min per 10 times increase in the substrate concentration (\(\beta_1=10\)).

concentrations <- ...


simData <- data.frame(conc = c(
  concentrations, rep(min(concentrations), 3),
  rep(max(concentrations), 3)
))

powerOpt <- simFast(
  form = ...,
  data = ...,
  betas = ...,
  sd = ...,
  contrasts = ...,
  alpha = ...,
  nSim = ...
)

simData
powerOpt

Make a visualization that displays the power in function of the number of repeats in the data.

Inspect and interpret the results.

LS0tCnRpdGxlOiAiRXhwZXJpbWVudGFsIERlc2lnbiBJSTogcmVwbGljYXRpb24gYW5kIHBvd2VyIGV4ZXJjaXNlIDIiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50ICYgQWxleGFuZHJlIFNlZ2VycyIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKLS0tCgo8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1zYS80LjAiPjxpbWcgYWx0PSJDcmVhdGl2ZSBDb21tb25zIExpY2Vuc2UiIHN0eWxlPSJib3JkZXItd2lkdGg6MCIgc3JjPSJodHRwczovL2kuY3JlYXRpdmVjb21tb25zLm9yZy9sL2J5LW5jLXNhLzQuMC84OHgzMS5wbmciIC8+PC9hPgoKIyBQdXJvbXljaW4gZGF0YXNldAoKRGF0YSBvbiB0aGUgdmVsb2NpdHkgb2YgYW4gZW56eW1hdGljIHJlYWN0aW9uIHdlcmUgb2J0YWluZWQgYnkgVHJlbG9hciAoMTk3NCkuClRoZSBudW1iZXIgb2YgY291bnRzIHBlciBtaW51dGUgb2YgcmFkaW9hY3RpdmUgcHJvZHVjdCBmcm9tIHRoZSByZWFjdGlvbiB3YXMKbWVhc3VyZWQgYXMgYSBmdW5jdGlvbiBvZiBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBpbiBwYXJ0cyBwZXIgbWlsbGlvbiAocHBtKSBhbmQKZnJvbSB0aGVzZSBjb3VudHMgdGhlIGluaXRpYWwgcmF0ZSAob3IgdmVsb2NpdHkpIG9mIHRoZSByZWFjdGlvbiB3YXMgY2FsY3VsYXRlZCAoY291bnRzL21pbi9taW4pLiBUaGUgZXhwZXJpbWVudCB3YXMgY29uZHVjdGVkIG9uY2Ugd2l0aCB0aGUgZW56eW1lIHRyZWF0ZWQKd2l0aCBQdXJvbXljaW4sIGFuZCBvbmNlIHdpdGggdGhlIGVuenltZSB1bnRyZWF0ZWQuCgpJbXBvcnQgbGlicmFyaWVzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmBgYAoKIyBJbXBvcnQgZGF0YQoKSW4gY29udHJhc3QgdG8gdGhlIG90aGVyIGRhdGFzZXRzIHdlIGhhdmUgd29ya2VkIHdpdGggc28gZmFyLCB0aGlzIGRhdGFzZXQgaXMKbm90IGF2YWlsYWJsZSB0aHJvdWdoIGEgVVJMIGxpbmsuIEluIHN0ZWFkLCB0aGUgZGF0YSBpcyBkaXJlY3RseSBhdmFpbGFibGUgZnJvbQphbiBSIHBhY2thZ2UgdGhhdCB3YXMgcHJlLWluc3RhbGxlZCBpbiB5b3VyIFIgd29ya2luZyBlbnZpcm9ubWVudC4gQXMgc3VjaCwgd2UKY2FuIHNpbXBsZSBkbwoKYGBge3J9CmRhdGEoUHVyb215Y2luKQpgYGAKCmFuZCBhbiBvYmplY3QgY2FsbGVkIGBQdXJvbXljaW5gIGlzIGltbWVkaWF0ZWx5IGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtpbmcKZW52aXJvbm1lbnQuCgojIERhdGEgd3JhbmdsaW5nCgpGaWx0ZXIgdGhlIGRhdGEgc28gdGhhdCB3ZSBhcmUgbGVmdCB3aXRoIG9ubHkgdGhlICJ0cmVhdGVkIiBlbnp5bWVzLgoKYGBge3J9CgpgYGAKCiMgRGF0YSBleHBsb3JhdGlvbgoKSW4gdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uIHRoZSBhdXRob3JzIG9ic2VydmVkIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuCnRoZSBsb2cxMCBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBhbmQgdGhlIHJlYWN0aW9uIHJhdGUuIE1ha2UgYSB2aXN1YWxpemF0aW9uCnRoYXQgYWxsb3dzIGZvciByZXByb2R1Y2luZyB0aGlzIGZpbmRpbmcuCgpgYGB7ciwgZXZhbD1GQUxTRX0KUHVyb215Y2luICU+JQogIGdncGxvdCguLi4pICsgIyBzZWxlY3Qgd2hpY2ggZWxlbWVudHMgb2YgdGhlIGRhdGFzZXQgd2UgbmVlZCB0byB2aXN1YWxpemUKICAuLi4gIyB1c2UgYSByZWxldmFudCBwbG90dGluZyBnZW9tZXRyeQpzdGF0X3Ntb290aCguLi4pICsgIyBkcmF3IGEgc21vb3RoIGxpbmUgdGhyb3VnaCB0aGUgZGF0YSBjbG91ZAogIHN0YXRfc21vb3RoKC4uLikgIyBkcmF3IGEgc3RyYWlnaHQgKGxpbmVhciByZWdyZXNzaW9uKSBsaW5lIHRocm91Z2ggdGhlIGRhdGEgY2xvdWQKLi4uICMgeW91IGNhbiBhZGQgc29tZSBleHRyYSBlbGVtZW50cyBsaWtlIGF4aXMgbGFiZWxzLCB0aXRsZSwgLi4uCmBgYAoKTm90ZSwgdGhhdCB0aGUgcmVzZWFyY2hlcnMgaGF2ZSBjaG9zZW4gNiBkaWZmZXJlbnQgc3Vic3RyYXRlIGNvbmNlbnRyYXRpb25zIGFuZApjb25kdWN0ZWQgYW4gZXhwZXJpbWVudCB3aGVyZSB0aGV5IGFzc2Vzc2VkIHRoZSBpbml0aWFsIHJlYWN0aW9uIHJhdGUgdHdpY2UgZm9yCmV2ZXJ5IGNvbmNlbnRyYXRpb24uCgojIFF1ZXN0aW9uIDEKClVzZSB0aGUgZGF0YSB0byBjYWxjdWxhdGUgdGhlIHBvd2VyIHRvIHBpY2sgdXAgYW4gYXNzb2NpYXRpb24gdGhhdCBpcyBhcwpsZWFzdCBhcyBzdHJvbmcgYXMgdGhlIGFzc29jaWF0aW9uIHlvdSBvYnNlcnZlZCBpbiB0aGUgZGF0YXNldCB3aGVuIHVzaW5nIGFuCmV4cGVyaW1lbnQgd2l0aCB0aGUgc2FtZSBkZXNpZ24uCgojIyBTaW11bGF0aW9uIGZ1bmN0aW9uCgpGb3IgdGhpcyBmaXJzdCBxdWVzdGlvbiwgd2Ugd2lsbCBuZWVkIGEgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdXMgdG8gc2ltdWxhdGUgZGF0YQpzaW1pbGFyIHRvIHRoYXQgb2Ygb3VyIGV4cGVyaW1lbnQgdW5kZXIgb3VyIG1vZGVsIGFzc3VtcHRpb25zLiBXZSBwcm92aWRlIHRoaXMKZnVuY3Rpb24gZm9yIHlvdToKCmBgYHtyfQpzaW1GYXN0IDwtIGZ1bmN0aW9uKGZvcm0sIGRhdGEsIGJldGFzLCBzZCwgY29udHJhc3RzLCBhbHBoYSA9IC4wNSwgblNpbSA9IDEwMDAwKSB7CiAgeVNpbSA8LSBybm9ybShucm93KGRhdGEpICogblNpbSwgc2QgPSBzZCkKICBkaW0oeVNpbSkgPC0gYyhucm93KGRhdGEpLCBuU2ltKQogIGRlc2lnbiA8LSBtb2RlbC5tYXRyaXgoZm9ybSwgZGF0YSkKICB5U2ltIDwtIHlTaW0gKyBjKGRlc2lnbiAlKiUgYmV0YXMpCiAgeVNpbSA8LSB0KHlTaW0pCgogICMjIyBGaXR0aW5nCiAgZml0QWxsIDwtIGxpbW1hOjpsbUZpdCh5U2ltLCBkZXNpZ24pCgogICMjIyBJbmZlcmVuY2UKICB2YXJVbnNjYWxlZCA8LSBjKHQoY29udHJhc3RzKSAlKiUgZml0QWxsJGNvdi5jb2VmZmljaWVudHMgJSolIGNvbnRyYXN0cykKICBjb250cmFzdHMgPC0gZml0QWxsJGNvZWZmaWNpZW50cyAlKiUgY29udHJhc3RzCiAgc2VDb250cmFzdHMgPC0gdmFyVW5zY2FsZWReLjUgKiBmaXRBbGwkc2lnbWEKICB0c3RhdHMgPC0gY29udHJhc3RzIC8gc2VDb250cmFzdHMKICBwdmFscyA8LSBwdChhYnModHN0YXRzKSwgZml0QWxsJGRmLnJlc2lkdWFsLCBsb3dlci50YWlsID0gRkFMU0UpICogMgogIHJldHVybihtZWFuKHB2YWxzIDwgYWxwaGEpKQp9CmBgYAoKV2l0aG91dCBnb2luZyBpbnRvIHRoZSBmdWxsIGNvZGUgZGV0YWlscywgdGhpcyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gc2ltdWxhdGUKZGF0YSBzaW1pbGFyIHRvIHRoYXQgb2Ygb3VyIGV4cGVyaW1lbnQgdW5kZXIgb3VyIG1vZGVsIGFzc3VtcHRpb25zLCBnaXZlbiB0aGUKZm9sbG93aW5nIGlucHV0czoKCi0gYGZvcm1gOiBtb2RlbCBmb3JtdWxhIGZvciB0aGUgZXhwZXJpbWVudCB3ZSB3YW50IHRvIHNpbXVsYXRlCi0gYGRhdGFgOiB0aGUgdGFyZ2V0IGRhdGFzZXQgb24gd2hpY2ggd2Ugd2FudCB0byBiYXNlIG91ciBzaW11bGF0aW9ucyBvbgotIGBiZXRhc2A6IHRoZSBsaW5lYXIgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgZm9yIHRoZSB0YXJnZXQgZGF0YXNldAotIGBzZGA6IHRoZSByZXNpZHVhbCBzdGFuZGFyZCBlcnJvcnMgZnJvbSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgZml0IG9uCnRoZSB0YXJnZXQgZGF0YXNldAotIGBjb250cmFzdHNgOiBjb21wYXJpc29uIG9mIGludGVyZXN0LCBpLmUuIHdoaWNoIChjb21iaW5hdGlvbiBvZikgbW9kZWwKcGFyYW1ldGVycyB3ZSB3b3VsZCBsaWtlIHRvIGFzc2VzcwotIGBhbHBoYWA6IGFscGhhLWxldmVsIGF0IHdoaWNoIHRvIGNvbmR1Y3QgdGhlIGh5cG90aGVzaXMgdGVzdGluZwotIGBuU2ltYDogbnVtYmVyIG9mIGRhdGFzZXRzIHdlIHdvdWxkIGxpa2UgdG8gc2ltdWxhdGUKClRvIHNpbXVsYXRlIG5ldyBkYXRhIGJhc2VkIG9uIG91ciB0YXJnZXQgZGF0YXNldCBgUHVyb215Y2luYCwgd2Ugd2lsbCBuZWVkIHRvCmZpbGwgaW4gYWxsIHRoZSBhcmd1bWVudHMgdG8gdGhlIGBzaW1GYXN0YCBmdW5jdGlvbi4KCioqSGludDogZm9yIHRoZSBiZXRhcyBhbmQgc2QsIHdlIHdpbGwgbmVlZCB0byBmaXQgYSBsaW5lYXIgbW9kZWwgZmlyc3QhKioKCmBgYHtyLCBldmFsPUZBTFNFfQpwb3dlcjEgPC0gc2ltRmFzdCgKICBmb3JtID0gLi4uLAogIGRhdGEgPSAuLi4sCiAgYmV0YXMgPSAuLi4sCiAgc2QgPSAuLi4sCiAgY29udHJhc3RzID0gLi4uLAogIGFscGhhID0gLi4uLAogIG5TaW0gPSAuLi4KKQpwb3dlcjEKYGBgCgojIFF1ZXN0aW9uIDIKClVzZSB0aGUgZGF0YSB0byBjYWxjdWxhdGUgdGhlIHBvd2VyIHRvIHBpY2sgdXAgYW4gYXNzb2NpYXRpb24gd2hlcmUgdGhlCnJlYWN0aW9uIHJhdGUgaW5jcmVhc2VzIG9uIGF2ZXJhZ2Ugd2l0aCAxMCBjb3VudHMvbWluIHdoZW4gdGhlIHN1YnN0cmF0ZQpjb25jZW50cmF0aW9uIGlzIDEwIHRpbWVzIGhpZ2hlciAoJFxiZXRhXzE9MTAkKS4KCkFnYWluLCB3ZSB3aWxsIG5lZWQgdG8gZmlsbCBpbiBhbGwgdGhlIGFyZ3VtZW50cyB0byB0aGUgYHNpbUZhc3RgIGZ1bmN0aW9uLgpUaGlzIHRpbWUsIGhvd2V2ZXIsIHRoZSBxdWVzdGlvbiBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSBxdWVzdGlvbiAxLgpBZGp1c3QgdGhlIGlucHV0cyBhY2NvcmRpbmdseSEKCmBgYHtyLCBldmFsPUZBTFNFfQpwb3dlcjIgPC0gc2ltRmFzdCgKICBmb3JtID0gLi4uLAogIGRhdGEgPSAuLi4sCiAgYmV0YXMgPSAuLi4sCiAgc2QgPSAuLi4sCiAgY29udHJhc3RzID0gLi4uLAogIGFscGhhID0gLi4uLAogIG5TaW0gPSAuLi4KKQpwb3dlcjIKYGBgCgoqKkNvbXBhcmUgeW91ciByZXN1bHQgd2l0aCB0aGUgb25lIGZyb20gcXVlc3Rpb24gMSEqKgoKIyBRdWVzdGlvbiAzCgpVc2UgdGhlIGRhdGEgdG8gY2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgcmVwZWF0cyB5b3UgbmVlZCBmb3IgZWFjaApjb25jZW50cmF0aW9uIHRvIHBpY2sgdXAgYW4gYXNzb2NpYXRpb24gd2hlcmUgdGhlIHJlYWN0aW9uIHJhdGUgaW5jcmVhc2VzIG9uCmF2ZXJhZ2Ugd2l0aCAxMCBjb3VudHMvbWluIHdoZW4gdGhlIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIGlzIDEwIHRpbWVzIGhpZ2hlcgooJFxiZXRhXzE9MTAkKSB3aXRoIGEgcG93ZXIgb2YgYXQgbGVhc3QgOTAlLgoKKipIaW50OiB0aGlzIHdpbGwgcmVxdWlyZSB1cyB0byByZXBlYXQgdGhlIHNpbXVsYXRpb24gcHJvY2VzcyBhcyBtYW55IHRpbWVzKioKKiphcyB3ZSBoYXZlIGNvbmNlbnRyYXRpb24gdmFsdWVzLioqCgpgYGB7ciwgZXZhbD1GQUxTRX0KY29uY2VudHJhdGlvbnMgPC0gUHVyb215Y2luICU+JQogIHB1bGwoY29uYykgJT4lCiAgdW5pcXVlKCkKCnBvd2VycyA8LSBkYXRhLmZyYW1lKG4gPSAxOjEwLCBwb3dlciA9IE5BKSAjIHRvIGxhdGVyIHN0b3JlIG91ciByZXN1bHRzCgpmb3IgKGkgaW4gMToxMCkKewogIHNpbURhdGEgPC0gZGF0YS5mcmFtZShjb25jID0gcmVwKGNvbmNlbnRyYXRpb25zLCBlYWNoID0gaSkpCiAgcG93ZXJzW2ksIDJdIDwtIHNpbUZhc3QoCiAgICBmb3JtID0gLi4uLAogICAgZGF0YSA9IC4uLiwKICAgIGJldGFzID0gLi4uLAogICAgc2QgPSAuLi4sCiAgICBjb250cmFzdHMgPSAuLi4sCiAgICBhbHBoYSA9IC4uLiwKICAgIG5TaW0gPSAuLi4KICApCn0KYGBgCgpNYWtlIGEgdmlzdWFsaXphdGlvbiB0aGF0IGRpc3BsYXlzIHRoZSBwb3dlciBpbiBmdW5jdGlvbiBvZiB0aGUgbnVtYmVyIG9mCnJlcGVhdHMgaW4gdGhlIGRhdGEuCgpgYGB7ciwgZXZhbD1GQUxTRX0KcG93ZXJzICU+JQogIGdncGxvdCguLi4pICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC45LCBsdHkgPSAyKQpgYGAKCiMgUXVlc3Rpb24gNAoKU3VwcG9zZSB0aGF0IHlvdSB3b3VsZCBzZXQgdXAgYW4gZXhwZXJpbWVudCB3aXRoIGEgZGVzaWduIHNpbWlsYXIgd2l0aCB0aGUKc2FtZSBjb25jZW50cmF0aW9ucyBhcyBpbiB0aGUgcHVyb215Y2luIGRhdGFzZXQgYW5kIHlvdSBoYXZlIHRoZSBmb2xsb3dpbmcKcmVzdHJpY3Rpb246IHlvdSBuZWVkIHRvIHVzZSBlYWNoIGNvbmNlbnRyYXRpb24gYXQgbGVhc3Qgb25jZSBhbmQgY2FuIHNldHVwIGF0Cm1vc3QgMTIgcmVhY3Rpb25zLCBob3cgd291bGQgeW91IGNob29zZSB5b3VyIGRlc2lnbiBwb2ludHM/IENhbGN1bGF0ZSB0aGUgcG93ZXIKZm9yIHRoaXMgZGVzaWduIHdoZW4gdGhlIGVmZmVjdCBzaXplIGlzIDEwIGNvdW50cy9taW4gcGVyIDEwIHRpbWVzIGluY3JlYXNlIGluCnRoZSBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiAoJFxiZXRhXzE9MTAkKS4KCmBgYHtyLCBldmFsPUZBTFNFfQpjb25jZW50cmF0aW9ucyA8LSAuLi4KCgpzaW1EYXRhIDwtIGRhdGEuZnJhbWUoY29uYyA9IGMoCiAgY29uY2VudHJhdGlvbnMsIHJlcChtaW4oY29uY2VudHJhdGlvbnMpLCAzKSwKICByZXAobWF4KGNvbmNlbnRyYXRpb25zKSwgMykKKSkKCnBvd2VyT3B0IDwtIHNpbUZhc3QoCiAgZm9ybSA9IC4uLiwKICBkYXRhID0gLi4uLAogIGJldGFzID0gLi4uLAogIHNkID0gLi4uLAogIGNvbnRyYXN0cyA9IC4uLiwKICBhbHBoYSA9IC4uLiwKICBuU2ltID0gLi4uCikKCnNpbURhdGEKcG93ZXJPcHQKYGBgCgpNYWtlIGEgdmlzdWFsaXphdGlvbiB0aGF0IGRpc3BsYXlzIHRoZSBwb3dlciBpbiBmdW5jdGlvbiBvZiB0aGUgbnVtYmVyIG9mCnJlcGVhdHMgaW4gdGhlIGRhdGEuCgpgYGB7ciwgZXZhbD1GQUxTRX0KCmBgYAoKSW5zcGVjdCBhbmQgaW50ZXJwcmV0IHRoZSByZXN1bHRzLgo=