The poison dataset
In this experiment, 96 fish (dojofish, goldfish and zebrafish) were placed separately in a tank with two liters of water and a certain dose (in mg) of the poison EI-43,064. The resistance of the fish against the poison was measured as the amount of minutes the fish survived after being exposed to the poison (Surv_time
, in minutes). Additionally, the weight of each fish was measured.
Goal
In this tutorial session we will focus on Dojofish, and we will model the survival time in function of the poison dose while correcting for the weight of the fish.
We will first analyse the survival data by only considering the dose as an explanatory variable for survival time
Next we will model the survival data with and additive model for dose and weight
Load libraries
# install.packages("GGally")
library(GGally)
library(car)
library(multcomp)
library(tidyverse)
theme_set(theme_bw())
Import the data
poison <- read_csv("https://raw.githubusercontent.com/statOmics/PSLSData/main/poison.csv")
Data tidying
We can see a couple of things in the data that can be improved:
Capitalise the fist column name
Set the Species column as a factor
Change the species factor levels from “0” to Dojofish. Hint: use the fct_recode
function.
In the previous analysis on this dataset (Simple linear regression session
), we performed a log-transformation on the response variable Surv_time
to meet the normality and homoscedasticity assumptions of the linear model. Here, we will immediately work with log-transformed survival times; store these in the new variable log2Surv_time
and remove the non-transformed values.
Subset the data to only retain Dojofish.
poison <- poison %>%
rename("Species" = "species") %>%
mutate(Species = as.factor(Species)) %>%
mutate(Species = fct_recode(Species,
Dojofish = "0", Goldfish = "1", Zebrafish = "2"
)) %>%
mutate(log2Surv_time = log2(Surv_time)) %>%
select(-Surv_time) %>%
filter(Species == "Dojofish")
poison
Data exploration
Prior to the analysis, we should explore our data. To start our data exploration, we will make use of the ggpairs
function of the GGally
R package. This function will generate a visualization containing multiple panels, which display (1) univariate plots of the different variables in our dataset, (2) bivariate plots and (3) correlation coefficients between the different variables.
ggpairs(poison, columns = 2:4)
Based on these plots, we observe that:
- The survival time seems to be associated with dose and fish weight.
From the tutorial of H6 we have seen that the fish weights were not nicely uniform across the different poison dosages due to the randomisation.
poison %>%
ggplot(aes(x = Dose, y = Weight)) +
geom_point() +
ggtitle("Association between dose and weight") +
theme_bw() +
stat_summary(
fun = mean, geom = "point",
col = "black", size = 4,
shape = 24, fill = "red"
)
Simple linear regression
This is the same regression model that we have already fit in the exercise session on simple linear regression, with Dose
as the only explanatory variable for log2Surv_time
.
# fit a linear regression model with 'Surv_time' as response variable and
# 'Dose' as predictor variabele
lm_simple <- lm(log2Surv_time ~ Dose, data = poison)
## display the diagnostic plots of the model
par(mfrow = c(2, 2))
plot(lm_simple)
- The independence assumption was met because the fish were randomized to the dose.
- The linearity assumption is met.
- The normality assumption is met.
- The homoscedasticity assumption is met.
Finally, we look at the output of the model.
##
## Call:
## lm(formula = log2Surv_time ~ Dose, data = poison)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.6891 -0.3804 -0.1076 0.3452 1.0856
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.0469 0.3462 8.800 1.33e-10 ***
## Dose -0.9063 0.2208 -4.104 0.000215 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4828 on 37 degrees of freedom
## Multiple R-squared: 0.3128, Adjusted R-squared: 0.2942
## F-statistic: 16.84 on 1 and 37 DF, p-value: 0.0002146
Or for an interpretation at the original scale (minutes in stead of log2 minutes):
2^(coef(lm_simple))["Dose"]
## Dose
## 0.5335551
2^(confint(lm_simple))[2, ]
## 2.5 % 97.5 %
## 0.3912681 0.7275855
There is a very significant effect of the poison on survival of Dojofish (p< 0.001). Dojofish that are exposed to a higher dose of the poison will have a survival time that decrease on average with a factor 0.53 per gram of poison that is added (95% CI [0.39, 0.73]).
Analysis with additive effect for weight
Model specification
Here, we will estimate the effect of the poison while correcting for weight
and we will add it as an additional covariate to our linear regression model, such that
\[
y_i=\beta_0+\beta_d x_d + \beta_g x_g + \epsilon_i,
\]
with \(\epsilon_i \text{ i.i.d. } N(0,\sigma^2)\).
Assumptions
The model will again be fit to allow for assessing the model assumptions
lm_additive <- lm(log2Surv_time ~ Dose + Weight, data = poison)
par(mfrow = c(2, 2))
plot(lm_additive)
The assumption of independence, linearity and homoscedasticity are met.
The QQ-plot suggest that there might be some deviation from normality in the left tail of the,distribution. However, when we would simulate data under the normality assumption, it seems that deviations of this size may be expected when normality is met. We will use simulation to assess if we can observe similar residual plots if all assumptions for the linear model hold.
set.seed(1031)
sigma <- sigma(lm_additive)
dataHlp <- poison
par(mfrow = c(3, 3))
for (i in 1:9) {
nobs <- nrow(poison)
dataHlp$ySim <- fitted.values(lm_additive) + rnorm(nobs, sd = sigma)
simModel <- lm(ySim ~ Dose + Weight, dataHlp)
plot(simModel, which = 2)
}
It seems that deviations of the size that we see in our real data may be expected even when normality is met. As such, all assumptions for linear regression seem to be valid.
Inference
We then inspect the results.
##
## Call:
## lm(formula = log2Surv_time ~ Dose + Weight, data = poison)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.59629 -0.33110 -0.06836 0.32507 0.83315
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.8294 0.6457 1.285 0.207119
## Dose -0.9590 0.1888 -5.081 1.17e-05 ***
## Weight 1.0783 0.2792 3.862 0.000451 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4116 on 36 degrees of freedom
## Multiple R-squared: 0.5141, Adjusted R-squared: 0.4871
## F-statistic: 19.04 on 2 and 36 DF, p-value: 2.282e-06
Interpretation of model parameters
We see that the effect of dose on survival time remains similar, however, it has become more significant after we have incorporated weight in our model. Indeed, from the data exploration, we learned that weight is associated with survival.
As such, by incorporating weight in our model, we are able to explain a larger part of the variability in the response variable survival time. As a consequence, the variability in the residuals of the model will decrease, which in turn will lead to smaller standard error estimates for the different parameter estimates in the model.
From the data exploration, we additionally found that the dojo-fish weights were not uniform across the different poison dosages due to the randomisation. Therefore, we can estimate the effect between dose and survival time better while accounting for the weight.
In this model, the effect of Dose
can be interpreted as the average change in the log2 survival time between two groups of dojofish with the same weight that are exposed to a poison dosage that differs 1 mg/L. In symbols:
\[\begin{eqnarray}
\hat{\mu_1}&=& \beta_0 + \beta_d x_{1d} + \beta_g x_g \text{ (average log2-survival time for dose 1 for a certain weight)}\\
\hat{\mu_2}&=& \beta_0 + \beta_d x_{2d} + \beta_g x_g \text{ (average log2-survival time for dose 2 for that same weight)}\\
\hat \mu_2- \hat \mu_1&=&\beta_0 + \beta_d x_{2d} + \beta_g x_g - (\beta_0 + \beta_d x_{1d} + \beta_g x_g) \text{ (difference in average log2-survival time between dose 2 en dose 1)}\\
\hat \mu_2-\hat \mu_1&=&\beta_d (x_{2d}-x_{1d})
\end{eqnarray}\]
Conclusion
## (Intercept) Dose Weight
## 1.777004 0.514402 2.111484
## 2.5 % 97.5 %
## (Intercept) 0.7169728 4.4042734
## Dose 0.3945101 0.6707292
## Weight 1.4259918 3.1265018
The dose of the poison has an extremely significant effect on the log2 transformed survival time of dojofish (p-value = 1e-05). The geometric average of the survival time for dojofish that are exposed to a poison dose that is 1mg/L larger is approximately halved (factor = \(2^{\beta_d}=\) 0.51) .
The effect of weight on the survival time of dojofish is also extremely significant (p-value = 5e-04). The geometric average of the survival time of a dojofish that weighs 1 gram more than another dojofish is approximately twice as long (factor = \(2^{ \beta_g}\)= 2.1, 95% BI [1.4,3.1]).
LS0tCnRpdGxlOiAiRXhlcmNpc2UgOC4xOiBBZGRpdGl2ZSBsaW5lYXIgbW9kZWwgb24gdGhlIHBvaXNvbiBkYXRhc2V0IC0gc29sdXRpb24iCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50LCBKZXJvZW4gR2lsaXMgYW5kIE1pbGFuIE1hbGZhaXQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCi0tLQoKIyBUaGUgcG9pc29uIGRhdGFzZXQKCkluIHRoaXMgZXhwZXJpbWVudCwgOTYgZmlzaCAoZG9qb2Zpc2gsIGdvbGRmaXNoIGFuZCB6ZWJyYWZpc2gpCndlcmUgcGxhY2VkIHNlcGFyYXRlbHkgaW4gYSB0YW5rIHdpdGggdHdvIGxpdGVycyBvZiB3YXRlciBhbmQKYSBjZXJ0YWluIGRvc2UgKGluIG1nKSBvZiB0aGUgcG9pc29uIEVJLTQzLDA2NC4gVGhlIHJlc2lzdGFuY2UKb2YgdGhlIGZpc2ggYWdhaW5zdCB0aGUgcG9pc29uIHdhcyBtZWFzdXJlZCBhcyB0aGUgYW1vdW50IG9mCm1pbnV0ZXMgdGhlIGZpc2ggc3Vydml2ZWQgYWZ0ZXIgYmVpbmcgZXhwb3NlZCB0byB0aGUgcG9pc29uIChgU3Vydl90aW1lYCwgaW4KbWludXRlcykuIEFkZGl0aW9uYWxseSwgdGhlIHdlaWdodCBvZiBlYWNoIGZpc2ggd2FzIG1lYXN1cmVkLgoKIyBHb2FsCgpJbiB0aGlzIHR1dG9yaWFsIHNlc3Npb24gd2Ugd2lsbCBmb2N1cyBvbiAqKkRvam9maXNoKiosIGFuZCB3ZSB3aWxsIG1vZGVsIHRoZQpzdXJ2aXZhbCB0aW1lIGluIGZ1bmN0aW9uIG9mIHRoZSBwb2lzb24gZG9zZSB3aGlsZSBjb3JyZWN0aW5nIGZvciB0aGUgd2VpZ2h0IG9mCnRoZSBmaXNoLgoKMS4gV2Ugd2lsbCBmaXJzdCBhbmFseXNlIHRoZSBzdXJ2aXZhbCBkYXRhIGJ5IG9ubHkgY29uc2lkZXJpbmcgdGhlIGRvc2UgYXMgYW4KZXhwbGFuYXRvcnkgdmFyaWFibGUgZm9yIHN1cnZpdmFsIHRpbWUKCjIuIE5leHQgd2Ugd2lsbCBtb2RlbCB0aGUgc3Vydml2YWwgZGF0YSB3aXRoIGFuZCBhZGRpdGl2ZSBtb2RlbCBmb3IgZG9zZSBhbmQKd2VpZ2h0CgpMb2FkIGxpYnJhcmllcwoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KG11bHRjb21wKQoKbGlicmFyeSh0aWR5dmVyc2UpCnRoZW1lX3NldCh0aGVtZV9idygpKQpgYGAKCiMgSW1wb3J0IHRoZSBkYXRhCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KcG9pc29uIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1BTTFNEYXRhL21haW4vcG9pc29uLmNzdiIpCmBgYAoKIyBEYXRhIHRpZHlpbmcKCldlIGNhbiBzZWUgYSBjb3VwbGUgb2YgdGhpbmdzIGluIHRoZSBkYXRhIHRoYXQgY2FuIGJlIGltcHJvdmVkOgoKMS4gQ2FwaXRhbGlzZSB0aGUgZmlzdCBjb2x1bW4gbmFtZQoKMy4gU2V0IHRoZSBTcGVjaWVzIGNvbHVtbiBhcyBhIGZhY3RvcgoKNC4gQ2hhbmdlIHRoZSBzcGVjaWVzIGZhY3RvciBsZXZlbHMgZnJvbSAiMCIgdG8gRG9qb2Zpc2guCipIaW50KjogdXNlIHRoZSBgZmN0X3JlY29kZWAgZnVuY3Rpb24uCgo0LiBJbiB0aGUgcHJldmlvdXMgYW5hbHlzaXMgb24gdGhpcyBkYXRhc2V0CihgU2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIHNlc3Npb25gKSwgd2UgcGVyZm9ybWVkIGEgbG9nLXRyYW5zZm9ybWF0aW9uIG9uIHRoZQpyZXNwb25zZSB2YXJpYWJsZSBgU3Vydl90aW1lYCB0byBtZWV0IHRoZSBub3JtYWxpdHkgYW5kIGhvbW9zY2VkYXN0aWNpdHkKYXNzdW1wdGlvbnMgb2YgdGhlIGxpbmVhciBtb2RlbC4gSGVyZSwgd2Ugd2lsbCBpbW1lZGlhdGVseSB3b3JrIHdpdGgKbG9nLXRyYW5zZm9ybWVkIHN1cnZpdmFsIHRpbWVzOyBzdG9yZSB0aGVzZSBpbiB0aGUgbmV3ICB2YXJpYWJsZSBgbG9nMlN1cnZfdGltZWAKYW5kIHJlbW92ZSB0aGUgbm9uLXRyYW5zZm9ybWVkIHZhbHVlcy4KCjUuIFN1YnNldCB0aGUgZGF0YSB0byBvbmx5IHJldGFpbiAqKkRvam9maXNoKiouCgpgYGB7cn0KcG9pc29uIDwtIHBvaXNvbiAlPiUKICByZW5hbWUoIlNwZWNpZXMiID0gInNwZWNpZXMiKSAlPiUKICBtdXRhdGUoU3BlY2llcyA9IGFzLmZhY3RvcihTcGVjaWVzKSkgJT4lCiAgbXV0YXRlKFNwZWNpZXMgPSBmY3RfcmVjb2RlKFNwZWNpZXMsCiAgICBEb2pvZmlzaCA9ICIwIiwgR29sZGZpc2ggPSAiMSIsIFplYnJhZmlzaCA9ICIyIgogICkpICU+JQogIG11dGF0ZShsb2cyU3Vydl90aW1lID0gbG9nMihTdXJ2X3RpbWUpKSAlPiUKICBzZWxlY3QoLVN1cnZfdGltZSkgJT4lCiAgZmlsdGVyKFNwZWNpZXMgPT0gIkRvam9maXNoIikKCnBvaXNvbgpgYGAKCiMgRGF0YSBleHBsb3JhdGlvbgoKUHJpb3IgdG8gdGhlIGFuYWx5c2lzLCB3ZSBzaG91bGQgZXhwbG9yZSBvdXIgZGF0YS4gVG8gc3RhcnQgb3VyIGRhdGEKZXhwbG9yYXRpb24sIHdlIHdpbGwgbWFrZSB1c2Ugb2YgdGhlIGBnZ3BhaXJzYCBmdW5jdGlvbiBvZiB0aGUKYEdHYWxseWAgUiBwYWNrYWdlLiBUaGlzIGZ1bmN0aW9uIHdpbGwgZ2VuZXJhdGUgYSB2aXN1YWxpemF0aW9uIGNvbnRhaW5pbmcKbXVsdGlwbGUgcGFuZWxzLCB3aGljaCBkaXNwbGF5ICgxKSB1bml2YXJpYXRlIHBsb3RzIG9mIHRoZSBkaWZmZXJlbnQgdmFyaWFibGVzCmluIG91ciBkYXRhc2V0LCAoMikgYml2YXJpYXRlIHBsb3RzIGFuZCAoMykgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4KdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZmlnLndpZHRoPTEyfQpnZ3BhaXJzKHBvaXNvbiwgY29sdW1ucyA9IDI6NCkKYGBgCgpCYXNlZCBvbiB0aGVzZSBwbG90cywgd2Ugb2JzZXJ2ZSB0aGF0OgoKLSBUaGUgc3Vydml2YWwgdGltZSBzZWVtcyB0byBiZSBhc3NvY2lhdGVkIHdpdGggZG9zZSBhbmQgZmlzaCB3ZWlnaHQuCgpGcm9tIHRoZSB0dXRvcmlhbCBvZiBINiB3ZSBoYXZlIHNlZW4gdGhhdCB0aGUgZmlzaCB3ZWlnaHRzIHdlcmUgbm90IG5pY2VseQp1bmlmb3JtIGFjcm9zcyB0aGUgZGlmZmVyZW50IHBvaXNvbiBkb3NhZ2VzIGR1ZSB0byB0aGUgcmFuZG9taXNhdGlvbi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpwb2lzb24gJT4lCiAgZ2dwbG90KGFlcyh4ID0gRG9zZSwgeSA9IFdlaWdodCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIkFzc29jaWF0aW9uIGJldHdlZW4gZG9zZSBhbmQgd2VpZ2h0IikgKwogIHRoZW1lX2J3KCkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLAogICAgY29sID0gImJsYWNrIiwgc2l6ZSA9IDQsCiAgICBzaGFwZSA9IDI0LCBmaWxsID0gInJlZCIKICApCmBgYAoKIyBTaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24KClRoaXMgaXMgdGhlIHNhbWUgcmVncmVzc2lvbiBtb2RlbCB0aGF0IHdlIGhhdmUgYWxyZWFkeSBmaXQgaW4gdGhlIGV4ZXJjaXNlCnNlc3Npb24gb24gc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uLCB3aXRoIGBEb3NlYCBhcyB0aGUgb25seSBleHBsYW5hdG9yeQp2YXJpYWJsZSBmb3IgYGxvZzJTdXJ2X3RpbWVgLgoKYGBge3J9CiMgZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCAnU3Vydl90aW1lJyBhcyByZXNwb25zZSB2YXJpYWJsZSBhbmQKIyAnRG9zZScgYXMgcHJlZGljdG9yIHZhcmlhYmVsZQpsbV9zaW1wbGUgPC0gbG0obG9nMlN1cnZfdGltZSB+IERvc2UsIGRhdGEgPSBwb2lzb24pCgojIyBkaXNwbGF5IHRoZSBkaWFnbm9zdGljIHBsb3RzIG9mIHRoZSBtb2RlbApwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KGxtX3NpbXBsZSkKYGBgCgoxLiBUaGUgaW5kZXBlbmRlbmNlIGFzc3VtcHRpb24gd2FzICoqbWV0KiogYmVjYXVzZSB0aGUgZmlzaCB3ZXJlIHJhbmRvbWl6ZWQgdG8KdGhlIGRvc2UuCjIuIFRoZSBsaW5lYXJpdHkgYXNzdW1wdGlvbiBpcyAqKm1ldCoqLgozLiBUaGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gaXMgKiptZXQqKi4KNC4gVGhlIGhvbW9zY2VkYXN0aWNpdHkgYXNzdW1wdGlvbiBpcyAqKm1ldCoqLgoKRmluYWxseSwgd2UgbG9vayBhdCB0aGUgb3V0cHV0IG9mIHRoZSBtb2RlbC4KCmBgYHtyfQpzdW1tYXJ5KGxtX3NpbXBsZSkKYGBgCgpPciBmb3IgYW4gaW50ZXJwcmV0YXRpb24gYXQgdGhlIG9yaWdpbmFsIHNjYWxlIChtaW51dGVzIGluIHN0ZWFkIG9mIGxvZzIKbWludXRlcyk6CgpgYGB7cn0KMl4oY29lZihsbV9zaW1wbGUpKVsiRG9zZSJdCjJeKGNvbmZpbnQobG1fc2ltcGxlKSlbMiwgXQpgYGAKClRoZXJlIGlzIGEgdmVyeSBzaWduaWZpY2FudCBlZmZlY3Qgb2YgdGhlIHBvaXNvbiBvbiBzdXJ2aXZhbCBvZiBEb2pvZmlzaAoocDwgMC4wMDEpLiBEb2pvZmlzaCB0aGF0IGFyZSBleHBvc2VkIHRvIGEgaGlnaGVyIGRvc2Ugb2YgdGhlIHBvaXNvbiB3aWxsCmhhdmUgYSBzdXJ2aXZhbCB0aW1lIHRoYXQgZGVjcmVhc2Ugb24gYXZlcmFnZSB3aXRoIGEgZmFjdG9yCmByIGxtX3NpbXBsZSRjb2VmWzJdICU+JSAyXi4gJT4lIHJvdW5kKC4sMilgIHBlciBncmFtIG9mIHBvaXNvbiB0aGF0CmlzIGFkZGVkICg5NSUgQ0kgW2ByIGNvbmZpbnQobG1fc2ltcGxlKVsyLF0gJT4lIDJeLiAlPiUgcm91bmQoLiwyKWBdKS4KCiMgQW5hbHlzaXMgd2l0aCBhZGRpdGl2ZSBlZmZlY3QgZm9yIHdlaWdodAoKIyMgTW9kZWwgc3BlY2lmaWNhdGlvbgoKSGVyZSwgd2Ugd2lsbCBlc3RpbWF0ZSB0aGUgZWZmZWN0IG9mIHRoZSBwb2lzb24gd2hpbGUgY29ycmVjdGluZyBmb3IgYHdlaWdodGAKYW5kIHdlIHdpbGwgYWRkIGl0IGFzIGFuIGFkZGl0aW9uYWwgY292YXJpYXRlIHRvIG91ciBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCwKc3VjaCB0aGF0CgokJAp5X2k9XGJldGFfMCtcYmV0YV9kIHhfZCArIFxiZXRhX2cgeF9nICsgXGVwc2lsb25faSwKJCQKCndpdGggJFxlcHNpbG9uX2kgXHRleHR7IGkuaS5kLiB9IE4oMCxcc2lnbWFeMikkLgoKIyMgQXNzdW1wdGlvbnMKClRoZSBtb2RlbCB3aWxsIGFnYWluIGJlIGZpdCB0byBhbGxvdyBmb3IgYXNzZXNzaW5nIHRoZSBtb2RlbCBhc3N1bXB0aW9ucwoKYGBge3J9CmxtX2FkZGl0aXZlIDwtIGxtKGxvZzJTdXJ2X3RpbWUgfiBEb3NlICsgV2VpZ2h0LCBkYXRhID0gcG9pc29uKQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KGxtX2FkZGl0aXZlKQpgYGAKClRoZSBhc3N1bXB0aW9uIG9mIGluZGVwZW5kZW5jZSwgbGluZWFyaXR5IGFuZCBob21vc2NlZGFzdGljaXR5IGFyZSBtZXQuCgpUaGUgUVEtcGxvdCBzdWdnZXN0IHRoYXQgdGhlcmUgbWlnaHQgYmUgc29tZSBkZXZpYXRpb24gZnJvbSBub3JtYWxpdHkgaW4gdGhlCmxlZnQgdGFpbCBvZiB0aGUsZGlzdHJpYnV0aW9uLiBIb3dldmVyLCB3aGVuIHdlIHdvdWxkIHNpbXVsYXRlIGRhdGEgdW5kZXIgdGhlCm5vcm1hbGl0eSBhc3N1bXB0aW9uLCBpdCBzZWVtcyB0aGF0IGRldmlhdGlvbnMgb2YgdGhpcyBzaXplIG1heSBiZSBleHBlY3RlZCB3aGVuCm5vcm1hbGl0eSBpcyBtZXQuIFdlIHdpbGwgdXNlIHNpbXVsYXRpb24gdG8gYXNzZXNzIGlmIHdlIGNhbiBvYnNlcnZlIHNpbWlsYXIKcmVzaWR1YWwgcGxvdHMgaWYgYWxsIGFzc3VtcHRpb25zIGZvciB0aGUgbGluZWFyIG1vZGVsIGhvbGQuCgpgYGB7cn0Kc2V0LnNlZWQoMTAzMSkKc2lnbWEgPC0gc2lnbWEobG1fYWRkaXRpdmUpCgpkYXRhSGxwIDwtIHBvaXNvbgoKcGFyKG1mcm93ID0gYygzLCAzKSkKZm9yIChpIGluIDE6OSkgewogIG5vYnMgPC0gbnJvdyhwb2lzb24pCiAgZGF0YUhscCR5U2ltIDwtIGZpdHRlZC52YWx1ZXMobG1fYWRkaXRpdmUpICsgcm5vcm0obm9icywgc2QgPSBzaWdtYSkKICBzaW1Nb2RlbCA8LSBsbSh5U2ltIH4gRG9zZSArIFdlaWdodCwgZGF0YUhscCkKICBwbG90KHNpbU1vZGVsLCB3aGljaCA9IDIpCn0KYGBgCgpJdCBzZWVtcyB0aGF0IGRldmlhdGlvbnMgb2YgdGhlIHNpemUgdGhhdCB3ZSBzZWUgaW4gb3VyIHJlYWwgZGF0YSBtYXkgYmUKZXhwZWN0ZWQgZXZlbiB3aGVuIG5vcm1hbGl0eSBpcyBtZXQuIEFzIHN1Y2gsIGFsbCBhc3N1bXB0aW9ucyBmb3IgbGluZWFyCnJlZ3Jlc3Npb24gc2VlbSB0byBiZSB2YWxpZC4KCiMjIEluZmVyZW5jZQoKV2UgdGhlbiBpbnNwZWN0IHRoZSByZXN1bHRzLgoKYGBge3J9CnN1bW1hcnkobG1fYWRkaXRpdmUpCmBgYAoKIyMgSW50ZXJwcmV0YXRpb24gb2YgbW9kZWwgcGFyYW1ldGVycwoKV2Ugc2VlIHRoYXQgdGhlIGVmZmVjdCBvZiBkb3NlIG9uIHN1cnZpdmFsIHRpbWUgcmVtYWlucyBzaW1pbGFyLCBob3dldmVyLCBpdApoYXMgYmVjb21lIG1vcmUgc2lnbmlmaWNhbnQgYWZ0ZXIgd2UgaGF2ZSBpbmNvcnBvcmF0ZWQgd2VpZ2h0IGluIG91ciBtb2RlbC4KSW5kZWVkLCBmcm9tIHRoZSBkYXRhIGV4cGxvcmF0aW9uLCB3ZSBsZWFybmVkIHRoYXQgd2VpZ2h0IGlzIGFzc29jaWF0ZWQgd2l0aApzdXJ2aXZhbC4KCjEuIEFzIHN1Y2gsIGJ5IGluY29ycG9yYXRpbmcgd2VpZ2h0IGluIG91ciBtb2RlbCwgd2UgYXJlIGFibGUgdG8KZXhwbGFpbiBhIGxhcmdlciBwYXJ0IG9mIHRoZSB2YXJpYWJpbGl0eSBpbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUgc3Vydml2YWwgdGltZS4KQXMgYSBjb25zZXF1ZW5jZSwgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSByZXNpZHVhbHMgb2YgdGhlIG1vZGVsIHdpbGwgZGVjcmVhc2UsCndoaWNoIGluIHR1cm4gd2lsbCBsZWFkIHRvIHNtYWxsZXIgc3RhbmRhcmQgZXJyb3IgZXN0aW1hdGVzIGZvciB0aGUgZGlmZmVyZW50CnBhcmFtZXRlciBlc3RpbWF0ZXMgaW4gdGhlIG1vZGVsLgoKMi4gRnJvbSB0aGUgZGF0YSBleHBsb3JhdGlvbiwgd2UgYWRkaXRpb25hbGx5IGZvdW5kIHRoYXQgdGhlIGRvam8tZmlzaCB3ZWlnaHRzCndlcmUgbm90IHVuaWZvcm0gYWNyb3NzIHRoZSBkaWZmZXJlbnQgcG9pc29uIGRvc2FnZXMgZHVlIHRvIHRoZSByYW5kb21pc2F0aW9uLgpUaGVyZWZvcmUsIHdlIGNhbiBlc3RpbWF0ZSB0aGUgZWZmZWN0IGJldHdlZW4gZG9zZSBhbmQgc3Vydml2YWwgdGltZSBiZXR0ZXIKd2hpbGUgYWNjb3VudGluZyBmb3IgdGhlIHdlaWdodC4KCkluIHRoaXMgbW9kZWwsIHRoZSBlZmZlY3Qgb2YgYERvc2VgIGNhbiBiZSBpbnRlcnByZXRlZCBhcyB0aGUgYXZlcmFnZSBjaGFuZ2UgaW4KdGhlIGxvZzIgc3Vydml2YWwgdGltZSBiZXR3ZWVuIHR3byBncm91cHMgb2YgZG9qb2Zpc2ggKip3aXRoIHRoZSBzYW1lIHdlaWdodCoqCnRoYXQgYXJlIGV4cG9zZWQgdG8gYSBwb2lzb24gZG9zYWdlIHRoYXQgZGlmZmVycyAxIG1nL0wuIEluIHN5bWJvbHM6CgpcYmVnaW57ZXFuYXJyYXl9ClxoYXR7XG11XzF9Jj0mIFxiZXRhXzAgKyBcYmV0YV9kIHhfezFkfSArIFxiZXRhX2cgeF9nIFx0ZXh0eyAoYXZlcmFnZSBsb2cyLXN1cnZpdmFsIHRpbWUgZm9yIGRvc2UgMSBmb3IgYSBjZXJ0YWluIHdlaWdodCl9XFwKXGhhdHtcbXVfMn0mPSYgXGJldGFfMCArIFxiZXRhX2QgeF97MmR9ICsgXGJldGFfZyB4X2cgXHRleHR7IChhdmVyYWdlIGxvZzItc3Vydml2YWwgdGltZSBmb3IgZG9zZSAyIGZvciB0aGF0IHNhbWUgd2VpZ2h0KX1cXApcaGF0IFxtdV8yLSBcaGF0IFxtdV8xJj0mXGJldGFfMCArIFxiZXRhX2QgeF97MmR9ICsgXGJldGFfZyB4X2cgLSAoXGJldGFfMCArIFxiZXRhX2QgeF97MWR9ICsgXGJldGFfZyB4X2cpIFx0ZXh0eyAoZGlmZmVyZW5jZSBpbiBhdmVyYWdlIGxvZzItc3Vydml2YWwgdGltZSBiZXR3ZWVuIGRvc2UgMiBlbiBkb3NlIDEpfVxcClxoYXQgXG11XzItXGhhdCBcbXVfMSY9JlxiZXRhX2QgKHhfezJkfS14X3sxZH0pClxlbmR7ZXFuYXJyYXl9CgojIyBDb25jbHVzaW9uCgpgYGB7cn0KMl4oY29lZihsbV9hZGRpdGl2ZSkpCjJeKGNvbmZpbnQobG1fYWRkaXRpdmUpKQpgYGAKClRoZSBkb3NlIG9mIHRoZSBwb2lzb24gaGFzIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGxvZzIKdHJhbnNmb3JtZWQgc3Vydml2YWwgdGltZSBvZiBkb2pvZmlzaAoocC12YWx1ZSA9IGByIGZvcm1hdChzdW1tYXJ5KGxtX2FkZGl0aXZlKSRjb2VmZmljaWVudHNbMiw0XSxkaWdpdHM9MSlgKS4gVGhlCmdlb21ldHJpYyBhdmVyYWdlIG9mIHRoZSBzdXJ2aXZhbCB0aW1lIGZvciBkb2pvZmlzaCB0aGF0IGFyZSBleHBvc2VkIHRvIGEKcG9pc29uIGRvc2UgdGhhdCBpcyAxbWcvTCBsYXJnZXIgaXMgYXBwcm94aW1hdGVseSBoYWx2ZWQgKGZhY3RvciA9ICQyXntcYmV0YV9kfT0kIGByIGZvcm1hdCgyXihsbV9hZGRpdGl2ZSRjb2VmWyJEb3NlIl0pLGRpZ2l0cz0yKWApIC4KClRoZSBlZmZlY3Qgb2Ygd2VpZ2h0IG9uIHRoZSBzdXJ2aXZhbCB0aW1lIG9mIGRvam9maXNoIGlzIGFsc28gZXh0cmVtZWx5CnNpZ25pZmljYW50CihwLXZhbHVlID0gYHIgZm9ybWF0KHN1bW1hcnkobG1fYWRkaXRpdmUpJGNvZWZmaWNpZW50c1szLDRdLGRpZ2l0cz0xKWApLiBUaGUKZ2VvbWV0cmljIGF2ZXJhZ2Ugb2YgdGhlIHN1cnZpdmFsIHRpbWUgb2YgYSBkb2pvZmlzaCB0aGF0IHdlaWdocyAxIGdyYW0gbW9yZQp0aGFuIGFub3RoZXIgZG9qb2Zpc2ggaXMgYXBwcm94aW1hdGVseSB0d2ljZSBhcyBsb25nCihmYWN0b3IgPSAkMl57IFxiZXRhX2d9JD0gYHIgZm9ybWF0KDJeKGxtX2FkZGl0aXZlJGNvZWZbIldlaWdodCJdKSxkaWdpdHM9MilgLAo5NSUgQkkgW2ByIHBhc3RlKGZvcm1hdCgyXihjb25maW50KGxtX2FkZGl0aXZlKVsiV2VpZ2h0IixdKSxkaWdpdHM9MiksY29sbGFwc2U9IiwiKWBdKS4KCiMjIFJlbWFya3MKCkluIHRoZSBgbG1fYWRkaXRpdmVgIG1vZGVsLCB3ZSBpbmNsdWRlZCBvbmx5IGEgKm1haW4gZWZmZWN0KiBmb3Igd2VpZ2h0LgpIb3dldmVyLCB0aGVyZSBjb3VsZCBhbHNvIGJlIGFuICppbnRlcmFjdGlvbiBlZmZlY3QqIGJldHdlZW4gd2VpZ2h0IGFuZApkb3NlLiBBbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIHdlaWdodCBhbmQgZG9zZSBpbXBsaWVzIHRoYXQgdGhlIGRvc2UgZWZmZWN0IG9uCnRoZSBzdXJ2aXZhbCB0aW1lIGNoYW5nZXMgYWNjb3JkaW5nIHRvIHRoZSB3ZWlnaHQgb2YgdGhlIGZpc2guCg==