## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.3.5 ✔ purrr 0.3.4
## ✔ tibble 3.1.4 ✔ dplyr 1.0.7
## ✔ tidyr 1.1.4 ✔ stringr 1.4.0
## ✔ readr 2.0.2 ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
Puromycin data
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.
Here, we will focus again on the enzyme treated data.
data(Puromycin)
Puromycin <- Puromycin %>%
filter(state=="treated")
There was a linear association between the log10 substrate concentration and the reaction rate
Puromycin %>%
ggplot(aes(x=conc %>% log10,y=rate)) +
geom_point() +
stat_smooth(method = "loess",col="red") +
stat_smooth(method='lm',col="black") +
ylab("Reaction Rate (counts/min)") +
xlab("log10(Substrate concentration) (log10 ppm)")
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
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.
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.
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\)).
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 with a power of at least 90%. (\(\beta_1=10\))
Suppose that you would setup 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\)).
Simulation function
Function to simulate data similar to that of our experiment under our model assumptions.
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))
}
Power to pick up the same effect size as we observed in the data set with the same design
mod1 <- lm(rate ~ conc %>% log10, Puromycin)
betas <- mod1$coefficients
nSim <- 10000
form <- ~ conc %>% log10
sd <- sigma(mod1)
contrast <- matrix(c(0,1),ncol=1)
rownames(contrast) <- names(mod1$coefficients)
alpha <- 0.05
power <- simFast(form, Puromycin, betas, sd, contrasts = contrast, alpha = alpha, nSim = nSim)
power
## [1] 1
Power for \(\beta_1=10\)
mod1 <- lm(rate ~ conc %>% log10, Puromycin)
betas <- mod1$coefficients
betas[2] <- 10
nSim <- 10000
form <- ~ conc %>% log10
sd <- sigma(mod1)
contrast <- matrix(c(0,1),ncol=1)
rownames(contrast) <- names(mod1$coefficients)
alpha <- 0.05
power <- simFast(form, Puromycin, betas, sd, contrasts = contrast, alpha = alpha, nSim = nSim)
power
## [1] 0.4181
The power to pick up a slope of \(\beta_1=10\) for this experiment is only round(power*100,1)
%.
Calculate the number of repeats needed per concentration to obtain a power of 90% to pick up an effect of \(\beta=10\).
mod1 <- lm(rate ~ conc %>% log10, Puromycin)
concentrations <- Puromycin %>%
pull(conc) %>%
unique
betas <- mod1$coefficients
betas[2] <- 10
nSim <- 10000
form <- ~ conc %>% log10
sd <- sigma(mod1)
contrast <- matrix(c(0,1),ncol=1)
rownames(contrast) <- names(mod1$coefficients)
alpha <- 0.05
powers <- data.frame(n = 1:10, power=NA)
for (i in 1:10)
{
simData <- data.frame(conc = rep(concentrations,each=i))
powers[i,2] <- simFast(form, simData, betas, sd, contrasts = contrast, alpha = alpha, nSim = nSim)
}
powers %>%
ggplot(aes(n,power)) +
geom_line() +
geom_hline(yintercept = .9, lty = 2)
We need which(powers$power>0.9) %>%min
repeats for each concentration to obtain a power above 90%.
Optimal design with 12 reactions
concentrations <- Puromycin %>%
pull(conc) %>%
unique
betas <- mod1$coefficients
betas[2] <- 10
nSim <- 10000
form <- ~ conc %>% log10
sd <- sigma(mod1)
contrast <- matrix(c(0,1),ncol=1)
rownames(contrast) <- names(mod1$coefficients)
alpha <- 0.05
simData <- data.frame(conc = c(concentrations,rep(min(concentrations),3),rep(max(concentrations),3)))
powerOpt <- simFast(form, simData, betas, sd, contrasts = contrast, alpha = alpha, nSim = nSim)
simData
## [1] 0.6065
Note that the power for a design where we repeat each concentration 1 time and the minimum and maximum concentration 4 times is considerably higher than that for the designs where we repeat all data points.
powers %>%
ggplot(aes(n,power)) +
geom_line() +
geom_hline(yintercept = powerOpt, lty = 2)
Indeed, the power for our optimal design with 12 reactions is as high as the power for an experiment where you would repeat every concentration 3 times for which we need to conduct 18 reactions!
LS0tCnRpdGxlOiAiRXhwZXJpbWVudGFsIERlc2lnbiBJSTogcmVwbGljYXRpb24gYW5kIHBvd2VyIGV4ZXJjaXNlIDIiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50ICYgQWxleGFuZHJlIFNlZ2VycyIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwotLS0KCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyBQdXJvbXljaW4gZGF0YQoKRGF0YSBvbiB0aGUgdmVsb2NpdHkgb2YgYW4gZW56eW1hdGljIHJlYWN0aW9uIHdlcmUgb2J0YWluZWQgYnkgVHJlbG9hciAoMTk3NCkuICAKVGhlIG51bWJlciBvZiBjb3VudHMgcGVyIG1pbnV0ZSBvZiByYWRpb2FjdGl2ZSBwcm9kdWN0IGZyb20gdGhlIHJlYWN0aW9uIHdhcyBtZWFzdXJlZCBhcyBhIGZ1bmN0aW9uIG9mIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIGluIHBhcnRzIHBlciBtaWxsaW9uIChwcG0pIGFuZCBmcm9tIHRoZXNlIGNvdW50cyB0aGUgaW5pdGlhbCByYXRlIChvciB2ZWxvY2l0eSkgb2YgdGhlIHJlYWN0aW9uIHdhcyBjYWxjdWxhdGVkIChjb3VudHMvbWluL21pbikuICBUaGUgZXhwZXJpbWVudCB3YXMgY29uZHVjdGVkIG9uY2Ugd2l0aCB0aGUgZW56eW1lIHRyZWF0ZWQgd2l0aCBQdXJvbXljaW4sIGFuZCBvbmNlIHdpdGggdGhlIGVuenltZSB1bnRyZWF0ZWQuCgpIZXJlLCB3ZSB3aWxsIGZvY3VzIGFnYWluIG9uIHRoZSBlbnp5bWUgdHJlYXRlZCBkYXRhLiAKCmBgYHtyfQpkYXRhKFB1cm9teWNpbikKUHVyb215Y2luIDwtIFB1cm9teWNpbiAlPiUgCiAgZmlsdGVyKHN0YXRlPT0idHJlYXRlZCIpCmBgYAoKVGhlcmUgd2FzIGEgbGluZWFyIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGxvZzEwIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIGFuZCB0aGUgcmVhY3Rpb24gcmF0ZSAKCgpgYGB7cn0KUHVyb215Y2luICAlPiUKICBnZ3Bsb3QoYWVzKHg9Y29uYyAlPiUgbG9nMTAseT1yYXRlKSkgKwogIGdlb21fcG9pbnQoKSArIAogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsY29sPSJyZWQiKSArIAogIHN0YXRfc21vb3RoKG1ldGhvZD0nbG0nLGNvbD0iYmxhY2siKSArCiAgeWxhYigiUmVhY3Rpb24gUmF0ZSAoY291bnRzL21pbikiKSArCiAgeGxhYigibG9nMTAoU3Vic3RyYXRlIGNvbmNlbnRyYXRpb24pIChsb2cxMCBwcG0pIikKYGBgCgpOb3RlLCB0aGF0IHRoZSByZXNlYXJjaGVycyBoYXZlIGNob3NlbiA2IGRpZmZlcmVudCBzdWJzdHJhdGUgY29uY2VudHJhdGlvbnMgYW5kIGNvbmR1Y3RlZCBhbiBleHBlcmltZW50IHdoZXJlIHRoZXkgYXNzZXNzZWQgdGhlIGluaXRpYWwgcmVhY3Rpb24gcmF0ZSB0d2ljZSBmb3IgZXZlcnkgY29uY2VudHJhdGlvbi4gCgoxLiBVc2UgdGhlIGRhdGEgdG8gY2FsY3VsYXRlIHRoZSBwb3dlciB0byBwaWNrIHVwIGFuIGFzc29jaWF0aW9uIHRoYXQgaXMgYXMgbGVhc3QgYXMgc3Ryb25nIGFzIHRoZSBhc3NvY2lhdGlvbiB5b3Ugb2JzZXJ2ZWQgaW4gdGhlIGRhdGFzZXQgd2hlbiB1c2luZyBhbiBleHBlcmltZW50IHdpdGggdGhlIHNhbWUgZGVzaWduLiAKCjIuIFVzZSB0aGUgZGF0YSB0byBjYWxjdWxhdGUgdGhlIHBvd2VyIHRvIHBpY2sgdXAgYW4gYXNzb2NpYXRpb24gd2hlcmUgdGhlIHJlYWN0aW9uIHJhdGUgaW5jcmVhc2VzIG9uIGF2ZXJhZ2Ugd2l0aCAxMCBjb3VudHMvbWluIHdoZW4gdGhlIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIGlzIDEwIHRpbWVzIGhpZ2hlciAoJFxiZXRhXzE9MTAkKS4KCjMuIFVzZSB0aGUgZGF0YSB0byBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiByZXBlYXRzIHlvdSBuZWVkIGZvciBlYWNoIGNvbmNlbnRyYXRpb24gdG8gcGljayB1cCBhbiBhc3NvY2lhdGlvbiB3aGVyZSB0aGUgcmVhY3Rpb24gcmF0ZSBpbmNyZWFzZXMgb24gYXZlcmFnZSB3aXRoIDEwIGNvdW50cy9taW4gd2hlbiB0aGUgc3Vic3RyYXRlIGNvbmNlbnRyYXRpb24gaXMgMTAgdGltZXMgaGlnaGVyIHdpdGggYSBwb3dlciBvZiBhdCBsZWFzdCA5MCUuICgkXGJldGFfMT0xMCQpCgo0LiBTdXBwb3NlIHRoYXQgeW91IHdvdWxkIHNldHVwIGFuIGV4cGVyaW1lbnQgd2l0aCBhIGRlc2lnbiBzaW1pbGFyIHdpdGggdGhlIHNhbWUgY29uY2VudHJhdGlvbnMgYXMgaW4gdGhlIHB1cm9teWNpbiBkYXRhc2V0IGFuZCB5b3UgaGF2ZSB0aGUgZm9sbG93aW5nIHJlc3RyaWN0aW9uOiB5b3UgbmVlZCB0byB1c2UgZWFjaCBjb25jZW50cmF0aW9uIGF0IGxlYXN0IG9uY2UgYW5kIGNhbiBzZXR1cCBhdCBtb3N0IDEyIHJlYWN0aW9ucywgaG93IHdvdWxkIHlvdSBjaG9vc2UgeW91ciBkZXNpZ24gcG9pbnRzPyBDYWxjdWxhdGUgdGhlIHBvd2VyIGZvciB0aGlzIGRlc2lnbiB3aGVuIHRoZSBlZmZlY3Qgc2l6ZSBpcyAxMCBjb3VudHMvbWluIHBlciAxMCB0aW1lcyBpbmNyZWFzZSBpbiB0aGUgc3Vic3RyYXRlIGNvbmNlbnRyYXRpb24gKCRcYmV0YV8xPTEwJCkuCgojIyBTaW11bGF0aW9uIGZ1bmN0aW9uCgpGdW5jdGlvbiB0byBzaW11bGF0ZSBkYXRhIHNpbWlsYXIgdG8gdGhhdCBvZiBvdXIgZXhwZXJpbWVudCB1bmRlciBvdXIgbW9kZWwgYXNzdW1wdGlvbnMuIAoKYGBge3J9CnNpbUZhc3QgPC0gZnVuY3Rpb24oZm9ybSwgZGF0YSwgYmV0YXMsIHNkLCBjb250cmFzdHMsIGFscGhhID0gLjA1LCBuU2ltID0gMTAwMDApCnsKICAgIHlTaW0gPC0gcm5vcm0obnJvdyhkYXRhKSpuU2ltLHNkPXNkKQogICAgZGltKHlTaW0pIDwtYyhucm93KGRhdGEpLG5TaW0pCiAgICBkZXNpZ24gPC0gbW9kZWwubWF0cml4KGZvcm0sIGRhdGEpCiAgICB5U2ltIDwtIHlTaW0gKyBjKGRlc2lnbiAlKiViZXRhcykKICAgIHlTaW0gPC0gdCh5U2ltKQogIAogICAgIyMjIEZpdHRpbmcKICAgIGZpdEFsbCA8LSBsaW1tYTo6bG1GaXQoeVNpbSxkZXNpZ24pCiAgCiAgICAjIyMgSW5mZXJlbmNlCiAgICB2YXJVbnNjYWxlZCA8LSBjKHQoY29udHJhc3RzKSUqJWZpdEFsbCRjb3YuY29lZmZpY2llbnRzJSolY29udHJhc3RzKQogICAgY29udHJhc3RzIDwtIGZpdEFsbCRjb2VmZmljaWVudHMgJSolY29udHJhc3RzCiAgICBzZUNvbnRyYXN0cyA8LSB2YXJVbnNjYWxlZF4uNSpmaXRBbGwkc2lnbWEKICAgIHRzdGF0cyA8LSBjb250cmFzdHMvc2VDb250cmFzdHMKICAgIHB2YWxzIDwtIHB0KGFicyh0c3RhdHMpLGZpdEFsbCRkZi5yZXNpZHVhbCxsb3dlci50YWlsID0gRkFMU0UpKjIKICAgIHJldHVybihtZWFuKHB2YWxzIDwgYWxwaGEpKQp9CmBgYAoKIyMgUG93ZXIgdG8gcGljayB1cCB0aGUgc2FtZSBlZmZlY3Qgc2l6ZSBhcyB3ZSBvYnNlcnZlZCBpbiB0aGUgZGF0YSBzZXQgd2l0aCB0aGUgc2FtZSBkZXNpZ24gCgpgYGB7cn0KbW9kMSA8LSBsbShyYXRlIH4gY29uYyAlPiUgbG9nMTAsIFB1cm9teWNpbikKYmV0YXMgPC0gbW9kMSRjb2VmZmljaWVudHMKCm5TaW0gPC0gMTAwMDAKZm9ybSA8LSB+IGNvbmMgJT4lIGxvZzEwIApzZCA8LSBzaWdtYShtb2QxKQpjb250cmFzdCA8LSBtYXRyaXgoYygwLDEpLG5jb2w9MSkKcm93bmFtZXMoY29udHJhc3QpIDwtIG5hbWVzKG1vZDEkY29lZmZpY2llbnRzKQphbHBoYSA8LSAwLjA1IAoKcG93ZXIgPC0gc2ltRmFzdChmb3JtLCBQdXJvbXljaW4sIGJldGFzLCBzZCwgY29udHJhc3RzID0gY29udHJhc3QsIGFscGhhID0gYWxwaGEsIG5TaW0gPSBuU2ltKQpwb3dlcgpgYGAKCiMjIFBvd2VyIGZvciAkXGJldGFfMT0xMCQKCmBgYHtyfQptb2QxIDwtIGxtKHJhdGUgfiBjb25jICU+JSBsb2cxMCwgUHVyb215Y2luKQpiZXRhcyA8LSBtb2QxJGNvZWZmaWNpZW50cwpiZXRhc1syXSA8LSAxMAoKblNpbSA8LSAxMDAwMApmb3JtIDwtIH4gY29uYyAlPiUgbG9nMTAgCnNkIDwtIHNpZ21hKG1vZDEpCmNvbnRyYXN0IDwtIG1hdHJpeChjKDAsMSksbmNvbD0xKQpyb3duYW1lcyhjb250cmFzdCkgPC0gbmFtZXMobW9kMSRjb2VmZmljaWVudHMpCmFscGhhIDwtIDAuMDUgCgpwb3dlciA8LSBzaW1GYXN0KGZvcm0sIFB1cm9teWNpbiwgYmV0YXMsIHNkLCBjb250cmFzdHMgPSBjb250cmFzdCwgYWxwaGEgPSBhbHBoYSwgblNpbSA9IG5TaW0pCnBvd2VyCmBgYAoKVGhlIHBvd2VyIHRvIHBpY2sgdXAgYSBzbG9wZSBvZiAkXGJldGFfMT0xMCQgZm9yIHRoaXMgZXhwZXJpbWVudCBpcyBvbmx5IApgcm91bmQocG93ZXIqMTAwLDEpYCUuIAoKIyMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgcmVwZWF0cyBuZWVkZWQgcGVyIGNvbmNlbnRyYXRpb24gdG8gb2J0YWluIGEgcG93ZXIgb2YgOTAlIHRvIHBpY2sgdXAgYW4gZWZmZWN0IG9mICRcYmV0YT0xMCQuCgoKYGBge3J9Cm1vZDEgPC0gbG0ocmF0ZSB+IGNvbmMgJT4lIGxvZzEwLCBQdXJvbXljaW4pCmNvbmNlbnRyYXRpb25zIDwtIFB1cm9teWNpbiAlPiUgCiAgcHVsbChjb25jKSAlPiUgCiAgdW5pcXVlCiAgCiAgCmJldGFzIDwtIG1vZDEkY29lZmZpY2llbnRzCmJldGFzWzJdIDwtIDEwCgpuU2ltIDwtIDEwMDAwCmZvcm0gPC0gfiBjb25jICU+JSBsb2cxMCAKc2QgPC0gc2lnbWEobW9kMSkKY29udHJhc3QgPC0gbWF0cml4KGMoMCwxKSxuY29sPTEpCnJvd25hbWVzKGNvbnRyYXN0KSA8LSBuYW1lcyhtb2QxJGNvZWZmaWNpZW50cykKYWxwaGEgPC0gMC4wNSAKCnBvd2VycyA8LSBkYXRhLmZyYW1lKG4gPSAxOjEwLCBwb3dlcj1OQSkKCmZvciAoaSBpbiAxOjEwKQp7CiAgc2ltRGF0YSA8LSBkYXRhLmZyYW1lKGNvbmMgPSByZXAoY29uY2VudHJhdGlvbnMsZWFjaD1pKSkKICBwb3dlcnNbaSwyXSA8LSBzaW1GYXN0KGZvcm0sIHNpbURhdGEsIGJldGFzLCBzZCwgY29udHJhc3RzID0gY29udHJhc3QsIGFscGhhID0gYWxwaGEsIG5TaW0gPSBuU2ltKQp9Cgpwb3dlcnMgJT4lIAogIGdncGxvdChhZXMobixwb3dlcikpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLjksIGx0eSA9IDIpCmBgYApXZSBuZWVkIGB3aGljaChwb3dlcnMkcG93ZXI+MC45KSAlPiVtaW5gIHJlcGVhdHMgZm9yIGVhY2ggY29uY2VudHJhdGlvbiB0byAKb2J0YWluIGEgcG93ZXIgYWJvdmUgOTAlLiAKCiMgT3B0aW1hbCBkZXNpZ24gd2l0aCAxMiByZWFjdGlvbnMgCgpgYGB7cn0KY29uY2VudHJhdGlvbnMgPC0gUHVyb215Y2luICU+JSAKICBwdWxsKGNvbmMpICU+JSAKICB1bmlxdWUKICAKICAKYmV0YXMgPC0gbW9kMSRjb2VmZmljaWVudHMKYmV0YXNbMl0gPC0gMTAKCm5TaW0gPC0gMTAwMDAKZm9ybSA8LSB+IGNvbmMgJT4lIGxvZzEwIApzZCA8LSBzaWdtYShtb2QxKQpjb250cmFzdCA8LSBtYXRyaXgoYygwLDEpLG5jb2w9MSkKcm93bmFtZXMoY29udHJhc3QpIDwtIG5hbWVzKG1vZDEkY29lZmZpY2llbnRzKQphbHBoYSA8LSAwLjA1IAoKc2ltRGF0YSA8LSBkYXRhLmZyYW1lKGNvbmMgPSBjKGNvbmNlbnRyYXRpb25zLHJlcChtaW4oY29uY2VudHJhdGlvbnMpLDMpLHJlcChtYXgoY29uY2VudHJhdGlvbnMpLDMpKSkKcG93ZXJPcHQgPC0gc2ltRmFzdChmb3JtLCBzaW1EYXRhLCBiZXRhcywgc2QsIGNvbnRyYXN0cyA9IGNvbnRyYXN0LCBhbHBoYSA9IGFscGhhLCBuU2ltID0gblNpbSkKCnNpbURhdGEKcG93ZXJPcHQKYGBgCgpOb3RlIHRoYXQgdGhlIHBvd2VyIGZvciBhIGRlc2lnbiB3aGVyZSB3ZSByZXBlYXQgZWFjaCBjb25jZW50cmF0aW9uIDEgdGltZSBhbmQgCnRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGNvbmNlbnRyYXRpb24gNCB0aW1lcyBpcyBjb25zaWRlcmFibHkgaGlnaGVyIHRoYW4gdGhhdCAKZm9yIHRoZSBkZXNpZ25zIHdoZXJlIHdlIHJlcGVhdCBhbGwgZGF0YSBwb2ludHMuIAoKYGBge3J9CnBvd2VycyAlPiUgCiAgZ2dwbG90KGFlcyhuLHBvd2VyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBwb3dlck9wdCwgbHR5ID0gMikKYGBgCkluZGVlZCwgdGhlIHBvd2VyIGZvciBvdXIgb3B0aW1hbCBkZXNpZ24gd2l0aCAxMiByZWFjdGlvbnMgaXMgYXMgaGlnaCBhcyB0aGUgCnBvd2VyIGZvciBhbiBleHBlcmltZW50IHdoZXJlIHlvdSB3b3VsZCByZXBlYXQgZXZlcnkgY29uY2VudHJhdGlvbiAzIHRpbWVzIGZvciAKd2hpY2ggd2UgbmVlZCB0byBjb25kdWN0IDE4IHJlYWN0aW9ucyEgCg==