In this second tutorial, we will see some basics in hypothesis testing and more specifically on t-tests. As an example, we will work with the captopril dataset that we explored yesterday.
We will work around these three research questions;
Is the average systolic blood pressure before captopril treatment (SBPb) higher than 149 mmHg?
Is the average SBP before captopril treatment significantly different from the average SBP after captopril treatment?
First, we will load the required R libraries:
Import the data
captopril <- read.table("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/captopril.txt", header = TRUE, sep = ",")
Data exploration
Before we start delving into the data in order to solve our research hypothese, it is always a good idea to first have a look at the data. Our dataset looks like this;
## id SBPb DBPb SBPa DBPa
## 1 1 210 130 201 125
## 2 2 169 122 165 121
## 3 3 187 124 166 121
## 4 4 160 104 157 106
## 5 5 167 112 147 101
## 6 6 176 101 145 85
We have 15 patients, for which we have measure the systolic blood pressure and diastolyic blood pressure, before and after treatment with the captopril drug.
We can visualize the entire dataframe in an informative way with boxplots;
captopril %>%
gather(type,bp,-id) %>%
ggplot(aes(x=type,y=bp,fill=type)) +
scale_fill_brewer(palette="RdGy") +
theme_bw() +
geom_boxplot(outlier.shape=NA) +
geom_jitter(width = 0.2) +
ggtitle("Boxplot of different blood pressure measures") +
ylab("blood pressure (mmHg)") + stat_summary(fun.y=mean, geom="point", shape=5, size=3, color="black", fill="black")
Clearly, it seems that on average the measurements after treatment are lower than those before treatment. But is this difference significant? To answer this question, we will need to perform hypothesis tests. Let’s start of with question 1.
Question 1
Is the average systolic blood pressure (SBP) before captopril treatment higher tahn 149 mmHg?
Yesterday, we used the NHANES dataset to set up a reference interval, i.e. an interval that is expected to hold 95% of the SBP values of healthy individuals. We found the interval of [93;149] mmHg.
To test the effect of the captopril on diseased individuals (patients), we need to find a group of patients that have elevated SBP levels, higher than 149 mmHg.Therefore, we want to test whether or not the provided patients have an SBP level that is greater than 149 mmHg. To test this, we will perform a one-sample t-test, which will tell us if the average SBPb of our patients is significantly greater thatn 149 mmHg on the 5% significance level.
** important **
Before we can perform a t-test, we must check that the required assumptions are met!
- The observations are independent of each other
- The data (SBPb) must be normally distributed
For the first assumption requires us to think about the data. Are there any underlying correlation structures (that we know of) in the data? For instance, if all the 15 subjects are members of the same family, we expect that the data will give us a good representation of the underlying population of interest, i.e., all past, present and future patients with elevated SBP levels.
In this dataset, we have no reason to believe that this assumption was violated; we may we have assume 15 unrelated, “random” patients with elevated SBP levels.
We can assess the second assumption with a quantile-quantile plot.
captopril %>%
ggplot(aes(sample=SBPb)) +
geom_qq() +
geom_qq_line()
We can see that all of the data lies nicely around the quantile-quantile line (black line). As such, we may conclude that our data is normally distributed.
As such, we may proceed with our analysis. Here, we will test if mean SBPb is significantly higher than 149 mmHg.
More specifically, we will test the null hypothesis;
\(H0:\) the mean SBPb is equal to 149 mmHg
versus the alternative hypothesis;
\(HA:\) the mean SBPb is greater than 149 mmHg
output1 <- t.test(captopril$SBPb,mu=149,alternative = "greater",conf.level = 0.95)
output1
##
## One Sample t-test
##
## data: captopril$SBPb
## t = 5.2606, df = 14, p-value = 6.025e-05
## alternative hypothesis: true mean is greater than 149
## 95 percent confidence interval:
## 167.581 Inf
## sample estimates:
## mean of x
## 176.9333
When writing a conclusion on your research hypothesis, it is very important to be precise and concise, yet complete.
An example of such a conclusion for our research question is given below:
The mean SBP of patients before treatment with captopril is significantly higher (p=610^{-5}) than the upper bound of the reference interval (147 mmHg) on the 5% signifcance level. The mean SBPb equals 176.93 mmHg with a 95% confidence interval of [167.58, ]).
As we have seen in the theory class, the 95% confidence interval can be interpreted as;
With 95% confidence we can state that the interval [167.58, ] contains the true average of SBP of diseased patient before treatment with captopril.
Question 2
Is the average SBP before captopril treatment different from the average SBP after captopril treatment?
As the data is paired, there will be a strong correlation between the BP values before and after treatment of each individual patient. We can show this with a scatterplot.
captopril %>%
ggplot(aes(x=SBPb,y=SBPa)) +
geom_point() +
ggtitle("correlation between SBPb and SBPa") +
ylab("SBPa (mmHg)") +
xlab("SBPb (mmHg)")
We clearly see that if a patient’s SBPb value is high, its SBPa value will be comparatively high as well.
Check the assumptions
The paired t-test has 2 assumptions:
- The observations are independent of each other (in both groups)
- The data (SBPb and SBPa) must be normally distributed (in both groups)
Additionally, we must check if the variances are similar for both groups. If so, we can use a t-test with a pooled variance (see theory). If not, we must rely on the Welch t-test, which can deal with unequal variances.
The first assumption is met (same concept as for question 1). We must first check if the SBPa
values are also normally distributed.
captopril %>%
ggplot(aes(sample=SBPa)) +
geom_qq() +
geom_qq_line()
Again, we can see that all of the data lies nicely around the quantile-quantile line. As such, we may conclude that our data is normally distributed.
For the third assumption, we must compare the within-group variability of both groups. We can do this visually with the boxplots.
captopril %>%
select(SBPb,SBPa) %>%
gather(type,bp) %>%
ggplot(aes(x=type,y=bp,fill=type)) +
scale_fill_brewer(palette="RdGy") +
theme_bw() +
geom_boxplot(outlier.shape=NA) +
geom_jitter(width = 0.2) +
ggtitle("Boxplot of different blood pressure measures") +
ylab("blood pressure (mmHg)") + stat_summary(fun.y=mean, geom="point", shape=5, size=3, color="black", fill="black")
As a measure of variability, we may take the height of each boxplot’s box. This is the interval between the 25% and 75% quantile. Here we can see that this interval, as well as the length of the whiskers, is approximately equal for both groups. When the sample sizes are small (as is the case here, we speak about deviation from equality if one height is more than 2 or 3 times larger/smaller than that of the other group.
As all three assumptions are met we may continue with performing the unpaired two-sample t-test.
As such, we will now perform a paired
t-test.
output2 <- t.test(captopril$SBPb,captopril$SBPa, paired = TRUE)
output2
##
## Paired t-test
##
## data: captopril$SBPb and captopril$SBPa
## t = 8.1228, df = 14, p-value = 1.146e-06
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 13.93409 23.93258
## sample estimates:
## mean of the differences
## 18.93333
Clearly, by correctly stating that the data is paired, we have gained a lot of statistical power for rejecting the null hypothesis that the true mdifferenc in means is equal to 0. The p-value (p = 0) has now become extremely significant. Note that the 95% CI has become narrower!
** Conclusion **
We may conclude that, on the 5% significance level, the mean SBP levels of patients before captopril treatment is extremely significantly (p = 0) higher than the mean SBP levels of patients after captopril treatment. The SBP levels are on average 18.93 mmHg higher before treatment than after treatment (95% CI [13.93, 23.93]).
One-sample t-test on the difference
On final thing; performing a paired two-sample t-test is analogous to performing a one-sample t-test on the difference between both groups.
This can be easily seen from the output of the paired two-sample t-test. The alternative hypothesis \(HA\) there states that the “true difference in means is not equal to 0”. So internally, R will actually perform a one-sample t-test on the difference, and check whether or not the true mean difference is equal to 0. We can also set this up manually.
bp_diff <- captopril %>%
mutate(bp_diff = SBPb-SBPa) %>%
select(bp_diff)
t.test(bp_diff,mu=0)
##
## One Sample t-test
##
## data: bp_diff
## t = 8.1228, df = 14, p-value = 1.146e-06
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 13.93409 23.93258
## sample estimates:
## mean of x
## 18.93333
Indeed, the output is completely analogous to that of the paired two-sample t-test.
LS0tCnRpdGxlOiAiVHV0b3JpYWwgNS4xOiBIeXBvdGhlc2lzIHRlc3Rpbmcgb24gdGhlIGNhcHRvcHJpbCBkYXRhc2V0IiAgIApvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCkluIHRoaXMgc2Vjb25kIHR1dG9yaWFsLCB3ZSB3aWxsIHNlZSBzb21lIGJhc2ljcwppbiBoeXBvdGhlc2lzIHRlc3RpbmcgYW5kIG1vcmUgc3BlY2lmaWNhbGx5IG9uCnQtdGVzdHMuIEFzIGFuIGV4YW1wbGUsIHdlIHdpbGwgd29yayB3aXRoIHRoZQpjYXB0b3ByaWwgZGF0YXNldCB0aGF0IHdlIGV4cGxvcmVkIHllc3RlcmRheS4KCldlIHdpbGwgd29yayBhcm91bmQgdGhlc2UgdGhyZWUgcmVzZWFyY2ggcXVlc3Rpb25zOwoKMSkgSXMgdGhlIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUKYmVmb3JlIGNhcHRvcHJpbCB0cmVhdG1lbnQgKFNCUGIpIGhpZ2hlciB0aGFuIDE0OSBtbUhnPwoKMikgSXMgdGhlIGF2ZXJhZ2UgU0JQIGJlZm9yZSBjYXB0b3ByaWwgdHJlYXRtZW50IApzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHRoZSBhdmVyYWdlIFNCUCBhZnRlcgpjYXB0b3ByaWwgdHJlYXRtZW50PwoKRmlyc3QsIHdlIHdpbGwgbG9hZCB0aGUgcmVxdWlyZWQgUiBsaWJyYXJpZXM6CgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyBJbXBvcnQgdGhlIGRhdGEKCmBgYHtyfQpjYXB0b3ByaWwgPC0gcmVhZC50YWJsZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2NhcHRvcHJpbC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIpCmBgYAoKIyBEYXRhIGV4cGxvcmF0aW9uCgpCZWZvcmUgd2Ugc3RhcnQgZGVsdmluZyBpbnRvIHRoZSBkYXRhIGluIG9yZGVyIHRvIHNvbHZlIApvdXIgcmVzZWFyY2ggaHlwb3RoZXNlLCBpdCBpcyBhbHdheXMgYSBnb29kIGlkZWEgdG8gZmlyc3QKaGF2ZSBhIGxvb2sgYXQgdGhlIGRhdGEuIE91ciBkYXRhc2V0IGxvb2tzIGxpa2UgdGhpczsKCmBgYHtyfQpoZWFkKGNhcHRvcHJpbCkKYGBgCgpXZSBoYXZlIDE1IHBhdGllbnRzLCBmb3Igd2hpY2ggd2UgaGF2ZSBtZWFzdXJlIHRoZSBzeXN0b2xpYyAKYmxvb2QgcHJlc3N1cmUgYW5kIGRpYXN0b2x5aWMgYmxvb2QgcHJlc3N1cmUsIGJlZm9yZSBhbmQgYWZ0ZXIKdHJlYXRtZW50IHdpdGggdGhlIGNhcHRvcHJpbCBkcnVnLgoKV2UgY2FuIHZpc3VhbGl6ZSB0aGUgZW50aXJlIGRhdGFmcmFtZSBpbiBhbiBpbmZvcm1hdGl2ZSB3YXkgCndpdGggYm94cGxvdHM7CgpgYGB7cn0KY2FwdG9wcmlsICU+JSAKICBnYXRoZXIodHlwZSxicCwtaWQpICU+JSAKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwLGZpbGw9dHlwZSkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iUmRHeSIpICsKICB0aGVtZV9idygpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKyAKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMikgKwogIGdndGl0bGUoIkJveHBsb3Qgb2YgZGlmZmVyZW50IGJsb29kIHByZXNzdXJlIG1lYXN1cmVzIikgKwogIHlsYWIoImJsb29kIHByZXNzdXJlIChtbUhnKSIpICsgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9NSwgc2l6ZT0zLCBjb2xvcj0iYmxhY2siLCBmaWxsPSJibGFjayIpCmBgYAoKQ2xlYXJseSwgaXQgc2VlbXMgdGhhdCBvbiBhdmVyYWdlIHRoZSBtZWFzdXJlbWVudHMKYWZ0ZXIgdHJlYXRtZW50IGFyZSBsb3dlciB0aGFuIHRob3NlIGJlZm9yZSB0cmVhdG1lbnQuCkJ1dCBpcyB0aGlzIGRpZmZlcmVuY2UgKipzaWduaWZpY2FudCoqPyBUbyBhbnN3ZXIgdGhpcwpxdWVzdGlvbiwgd2Ugd2lsbCBuZWVkIHRvIHBlcmZvcm0gaHlwb3RoZXNpcyB0ZXN0cy4KTGV0J3Mgc3RhcnQgb2Ygd2l0aCBxdWVzdGlvbiAxLgoKIyBRdWVzdGlvbiAxCgpJcyB0aGUgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSAoU0JQKQpiZWZvcmUgY2FwdG9wcmlsIHRyZWF0bWVudCBoaWdoZXIgdGFobiAxNDkgbW1IZz8KClllc3RlcmRheSwgd2UgdXNlZCB0aGUgTkhBTkVTIGRhdGFzZXQgdG8gc2V0IHVwIGEgcmVmZXJlbmNlCmludGVydmFsLCBpLmUuIGFuIGludGVydmFsIHRoYXQgaXMgZXhwZWN0ZWQgdG8gaG9sZCA5NSUgb2YKdGhlIFNCUCB2YWx1ZXMgb2YgaGVhbHRoeSBpbmRpdmlkdWFscy4gV2UgZm91bmQgdGhlIGludGVydmFsCm9mIFs5MzsxNDldIG1tSGcuCgpUbyB0ZXN0IHRoZSBlZmZlY3Qgb2YgdGhlIGNhcHRvcHJpbCBvbiBkaXNlYXNlZCBpbmRpdmlkdWFscwoocGF0aWVudHMpLCB3ZSBuZWVkIHRvIGZpbmQgYSBncm91cCBvZiBwYXRpZW50cyB0aGF0IGhhdmUKZWxldmF0ZWQgU0JQIGxldmVscywgaGlnaGVyIHRoYW4gMTQ5IG1tSGcuVGhlcmVmb3JlLCB3ZSB3YW50CnRvIHRlc3Qgd2hldGhlciBvciBub3QgdGhlIHByb3ZpZGVkIHBhdGllbnRzIGhhdmUgYW4gU0JQIGxldmVsCnRoYXQgaXMgZ3JlYXRlciB0aGFuIDE0OSBtbUhnLiBUbyB0ZXN0IHRoaXMsIHdlIHdpbGwgcGVyZm9ybSBhCm9uZS1zYW1wbGUgdC10ZXN0LCB3aGljaCB3aWxsIHRlbGwgdXMgaWYgdGhlIGF2ZXJhZ2UgU0JQYiBvZgpvdXIgcGF0aWVudHMgaXMgc2lnbmlmaWNhbnRseSBncmVhdGVyIHRoYXRuIDE0OSBtbUhnIG9uIHRoZSA1JQpzaWduaWZpY2FuY2UgbGV2ZWwuCgoqKiBpbXBvcnRhbnQgKioKCkJlZm9yZSB3ZSBjYW4gcGVyZm9ybSBhIHQtdGVzdCwgd2UgbXVzdCBjaGVjayB0aGF0IHRoZSByZXF1aXJlZAphc3N1bXB0aW9ucyBhcmUgbWV0IQoKCjEuIFRoZSBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIKMi4gVGhlIGRhdGEgKFNCUGIpIG11c3QgYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKCkZvciB0aGUgZmlyc3QgYXNzdW1wdGlvbiByZXF1aXJlcyB1cyB0byB0aGluayBhYm91dCB0aGUgZGF0YS4gCkFyZSB0aGVyZSBhbnkgdW5kZXJseWluZyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmVzICh0aGF0IHdlIGtub3cgb2YpCmluIHRoZSBkYXRhPyBGb3IgaW5zdGFuY2UsIGlmIGFsbCB0aGUgMTUgc3ViamVjdHMgYXJlIG1lbWJlcnMgb2YKdGhlIHNhbWUgZmFtaWx5LCB3ZSBleHBlY3QgdGhhdCB0aGUgZGF0YSB3aWxsIGdpdmUgdXMgYSBnb29kIApyZXByZXNlbnRhdGlvbiBvZiB0aGUgdW5kZXJseWluZyBwb3B1bGF0aW9uIG9mIGludGVyZXN0LCBpLmUuLCAKYWxsIHBhc3QsIHByZXNlbnQgYW5kIGZ1dHVyZSBwYXRpZW50cyB3aXRoIGVsZXZhdGVkIFNCUCBsZXZlbHMuCgpJbiB0aGlzIGRhdGFzZXQsIHdlIGhhdmUgbm8gcmVhc29uIHRvIGJlbGlldmUgdGhhdCB0aGlzIAphc3N1bXB0aW9uIHdhcyB2aW9sYXRlZDsgd2UgbWF5IHdlIGhhdmUgYXNzdW1lIDE1IHVucmVsYXRlZCwgCiJyYW5kb20iICBwYXRpZW50cyB3aXRoIGVsZXZhdGVkIFNCUCBsZXZlbHMuCgpXZSBjYW4gYXNzZXNzIHRoZSBzZWNvbmQgYXNzdW1wdGlvbiB3aXRoIGEgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdC4KCmBgYHtyfQpjYXB0b3ByaWwgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGU9U0JQYikpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IGFsbCBvZiB0aGUgZGF0YSBsaWVzIG5pY2VseSBhcm91bmQgdGhlIHF1YW50aWxlLXF1YW50aWxlCmxpbmUgKGJsYWNrIGxpbmUpLiBBcyBzdWNoLCB3ZSBtYXkgY29uY2x1ZGUgdGhhdCBvdXIgZGF0YSBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4KCkFzIHN1Y2gsIHdlIG1heSBwcm9jZWVkIHdpdGggb3VyIGFuYWx5c2lzLiBIZXJlLCB3ZSB3aWxsIAp0ZXN0IGlmIG1lYW4gU0JQYiBpcyBzaWduaWZpY2FudGx5IGhpZ2hlciB0aGFuIDE0OSBtbUhnLgoKTW9yZSBzcGVjaWZpY2FsbHksIHdlIHdpbGwgdGVzdCB0aGUgbnVsbCBoeXBvdGhlc2lzOwoKJEgwOiQgdGhlIG1lYW4gU0JQYiBpcyBlcXVhbCB0byAxNDkgbW1IZwoKdmVyc3VzIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzOwoKJEhBOiQgdGhlIG1lYW4gU0JQYiBpcyBncmVhdGVyIHRoYW4gMTQ5IG1tSGcKCmBgYHtyfQpvdXRwdXQxIDwtIHQudGVzdChjYXB0b3ByaWwkU0JQYixtdT0xNDksYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsY29uZi5sZXZlbCA9IDAuOTUpCm91dHB1dDEKYGBgCgpXaGVuIHdyaXRpbmcgYSBjb25jbHVzaW9uIG9uIHlvdXIgcmVzZWFyY2ggaHlwb3RoZXNpcywKaXQgaXMgdmVyeSBpbXBvcnRhbnQgdG8gYmUgcHJlY2lzZSBhbmQgY29uY2lzZSwgeWV0IGNvbXBsZXRlLgoKQW4gZXhhbXBsZSBvZiBzdWNoIGEgY29uY2x1c2lvbiBmb3Igb3VyIHJlc2VhcmNoIHF1ZXN0aW9uCmlzIGdpdmVuIGJlbG93OgoKVGhlIG1lYW4gU0JQIG9mIHBhdGllbnRzIGJlZm9yZSB0cmVhdG1lbnQgd2l0aCBjYXB0b3ByaWwKaXMgc2lnbmlmaWNhbnRseSBoaWdoZXIgKHA9YHIgcm91bmQodW5uYW1lKG91dHB1dDEkcC52YWx1ZSksNSlgKSB0aGFuIHRoZSAKdXBwZXIgYm91bmQgb2YgdGhlIHJlZmVyZW5jZSBpbnRlcnZhbCAoMTQ3IG1tSGcpIG9uIHRoZSA1JSBzaWduaWZjYW5jZSBsZXZlbC4gClRoZSBtZWFuIFNCUGIgZXF1YWxzIGByIHJvdW5kKHVubmFtZShvdXRwdXQxJGVzdGltYXRlKSwyKWAgbW1IZyB3aXRoIAphIDk1JSBjb25maWRlbmNlIGludGVydmFsIG9mIFtgciByb3VuZChvdXRwdXQxJGNvbmYuaW50W2MoMSwyKV0sMilgXSkuCgpBcyB3ZSBoYXZlIHNlZW4gaW4gdGhlIHRoZW9yeSBjbGFzcywgdGhlIDk1JSBjb25maWRlbmNlIAppbnRlcnZhbCBjYW4gYmUgaW50ZXJwcmV0ZWQgYXM7CgpXaXRoIDk1JSBjb25maWRlbmNlIHdlIGNhbiBzdGF0ZSB0aGF0IHRoZSBpbnRlcnZhbCAKW2ByIHJvdW5kKG91dHB1dDEkY29uZi5pbnRbYygxLDIpXSwyKWBdCmNvbnRhaW5zIHRoZSB0cnVlIGF2ZXJhZ2Ugb2YgU0JQIG9mIGRpc2Vhc2VkIHBhdGllbnQgYmVmb3JlCnRyZWF0bWVudCB3aXRoIGNhcHRvcHJpbC4KCgojIFF1ZXN0aW9uIDIKCklzIHRoZSBhdmVyYWdlIFNCUCBiZWZvcmUgY2FwdG9wcmlsIHRyZWF0bWVudCAKZGlmZmVyZW50IGZyb20gdGhlIGF2ZXJhZ2UgU0JQIGFmdGVyIGNhcHRvcHJpbCB0cmVhdG1lbnQ/CgpBcyB0aGUgZGF0YSBpcyBwYWlyZWQsIHRoZXJlIHdpbGwgYmUgYSBzdHJvbmcgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgQlAgdmFsdWVzIApiZWZvcmUgYW5kIGFmdGVyIHRyZWF0bWVudCBvZiBlYWNoIGluZGl2aWR1YWwgcGF0aWVudC4gV2UgY2FuIHNob3cgdGhpcwp3aXRoIGEgc2NhdHRlcnBsb3QuCgpgYGB7cn0KY2FwdG9wcmlsICU+JSAKICBnZ3Bsb3QoYWVzKHg9U0JQYix5PVNCUGEpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJjb3JyZWxhdGlvbiBiZXR3ZWVuIFNCUGIgYW5kIFNCUGEiKSArCiAgeWxhYigiU0JQYSAobW1IZykiKSArCiAgeGxhYigiU0JQYiAobW1IZykiKQpgYGAKCldlIGNsZWFybHkgc2VlIHRoYXQgaWYgYSBwYXRpZW50J3MgU0JQYiB2YWx1ZSBpcyBoaWdoLCBpdHMKU0JQYSB2YWx1ZSB3aWxsIGJlIGNvbXBhcmF0aXZlbHkgaGlnaCBhcyB3ZWxsLgoKIyBDaGVjayB0aGUgYXNzdW1wdGlvbnMKClRoZSBwYWlyZWQgdC10ZXN0IGhhcyAyIGFzc3VtcHRpb25zOgoKMS4gVGhlIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlciAoaW4gYm90aCBncm91cHMpCjIuIFRoZSBkYXRhIChTQlBiIGFuZCBTQlBhKSBtdXN0IGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpbiBib3RoIGdyb3VwcykKCkFkZGl0aW9uYWxseSwgd2UgbXVzdCBjaGVjayBpZiB0aGUgdmFyaWFuY2VzIGFyZSBzaW1pbGFyIGZvciBib3RoIGdyb3Vwcy4KSWYgc28sIHdlIGNhbiB1c2UgYSB0LXRlc3Qgd2l0aCBhIHBvb2xlZCB2YXJpYW5jZSAoc2VlIHRoZW9yeSkuCklmIG5vdCwgd2UgbXVzdCByZWx5IG9uIHRoZSBXZWxjaCB0LXRlc3QsIHdoaWNoIGNhbiBkZWFsIHdpdGgKdW5lcXVhbCB2YXJpYW5jZXMuCgpUaGUgZmlyc3QgYXNzdW1wdGlvbiBpcyBtZXQgKHNhbWUgY29uY2VwdCBhcyBmb3IgcXVlc3Rpb24gMSkuCldlIG11c3QgZmlyc3QgY2hlY2sgaWYgdGhlIGBTQlBhYCB2YWx1ZXMgYXJlIGFsc28gbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgpgYGB7cn0KY2FwdG9wcmlsICU+JQogIGdncGxvdChhZXMoc2FtcGxlPVNCUGEpKSArCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQpgYGAKCkFnYWluLCB3ZSBjYW4gc2VlIHRoYXQgYWxsIG9mIHRoZSBkYXRhIGxpZXMgbmljZWx5IGFyb3VuZCB0aGUgcXVhbnRpbGUtcXVhbnRpbGUKbGluZS4gQXMgc3VjaCwgd2UgbWF5IGNvbmNsdWRlIHRoYXQgb3VyIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgpGb3IgdGhlIHRoaXJkIGFzc3VtcHRpb24sIHdlIG11c3QgY29tcGFyZSB0aGUgd2l0aGluLWdyb3VwCnZhcmlhYmlsaXR5IG9mIGJvdGggZ3JvdXBzLiBXZSBjYW4gZG8gdGhpcyB2aXN1YWxseSB3aXRoIHRoZSBib3hwbG90cy4KCmBgYHtyfQpjYXB0b3ByaWwgJT4lIAogIHNlbGVjdChTQlBiLFNCUGEpICU+JQogIGdhdGhlcih0eXBlLGJwKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1icCxmaWxsPXR5cGUpKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlJkR3kiKSArCiAgdGhlbWVfYncoKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsgCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIpICsKICBnZ3RpdGxlKCJCb3hwbG90IG9mIGRpZmZlcmVudCBibG9vZCBwcmVzc3VyZSBtZWFzdXJlcyIpICsKICB5bGFiKCJibG9vZCBwcmVzc3VyZSAobW1IZykiKSArIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTUsIHNpemU9MywgY29sb3I9ImJsYWNrIiwgZmlsbD0iYmxhY2siKQpgYGAKCkFzIGEgbWVhc3VyZSBvZiB2YXJpYWJpbGl0eSwgd2UgbWF5IHRha2UgdGhlIGhlaWdodApvZiBlYWNoIGJveHBsb3QncyBib3guIFRoaXMgaXMgdGhlIGludGVydmFsIGJldHdlZW4KdGhlIDI1JSBhbmQgNzUlIHF1YW50aWxlLiBIZXJlIHdlIGNhbiBzZWUgdGhhdCB0aGlzCmludGVydmFsLCBhcyB3ZWxsIGFzIHRoZSBsZW5ndGggb2YgdGhlIHdoaXNrZXJzLCBpcwphcHByb3hpbWF0ZWx5IGVxdWFsIGZvciBib3RoIGdyb3Vwcy4gV2hlbiB0aGUgc2FtcGxlCnNpemVzIGFyZSBzbWFsbCAoYXMgaXMgdGhlIGNhc2UgaGVyZSwgd2Ugc3BlYWsgYWJvdXQgZGV2aWF0aW9uCmZyb20gZXF1YWxpdHkgaWYgb25lIGhlaWdodCBpcyBtb3JlIHRoYW4gMiBvciAzIHRpbWVzCmxhcmdlci9zbWFsbGVyIHRoYW4gdGhhdCBvZiB0aGUgb3RoZXIgZ3JvdXAuIAoKQXMgYWxsIHRocmVlIGFzc3VtcHRpb25zIGFyZSBtZXQgd2UgbWF5IGNvbnRpbnVlIHdpdGgKcGVyZm9ybWluZyB0aGUgdW5wYWlyZWQgdHdvLXNhbXBsZSB0LXRlc3QuCgpBcyBzdWNoLCB3ZSB3aWxsIG5vdyBwZXJmb3JtIGEgYHBhaXJlZGAgdC10ZXN0LgoKYGBge3J9Cm91dHB1dDIgPC0gdC50ZXN0KGNhcHRvcHJpbCRTQlBiLGNhcHRvcHJpbCRTQlBhLCBwYWlyZWQgPSBUUlVFKQpvdXRwdXQyCmBgYAoKQ2xlYXJseSwgYnkgY29ycmVjdGx5IHN0YXRpbmcgdGhhdCB0aGUgZGF0YSBpcyBwYWlyZWQsCndlIGhhdmUgZ2FpbmVkIGEgbG90IG9mIHN0YXRpc3RpY2FsIHBvd2VyIGZvciByZWplY3RpbmcKdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSB0cnVlIG1kaWZmZXJlbmMgaW4gbWVhbnMgaXMKZXF1YWwgdG8gMC4gVGhlIHAtdmFsdWUgKHAgPSBgciByb3VuZCh1bm5hbWUob3V0cHV0MiRwLnZhbHVlKSw1KWApIGhhcyBub3cgYmVjb21lCmV4dHJlbWVseSBzaWduaWZpY2FudC4gTm90ZSB0aGF0IHRoZSA5NSUgQ0kgaGFzIGJlY29tZSAKbmFycm93ZXIhCgoqKiBDb25jbHVzaW9uICoqCgpXZSBtYXkgY29uY2x1ZGUgdGhhdCwgb24gdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbCwgdGhlIG1lYW4gClNCUCBsZXZlbHMgb2YgcGF0aWVudHMgYmVmb3JlIGNhcHRvcHJpbCB0cmVhdG1lbnQgaXMgCmV4dHJlbWVseSBzaWduaWZpY2FudGx5IChwID0gYHIgcm91bmQodW5uYW1lKG91dHB1dDIkcC52YWx1ZSksNSlgKSBoaWdoZXIgdGhhbiB0aGUgbWVhbiAKU0JQIGxldmVscyBvZiBwYXRpZW50cyBhZnRlciBjYXB0b3ByaWwgdHJlYXRtZW50LiBUaGUgU0JQIGxldmVscyAKYXJlIG9uIGF2ZXJhZ2UgYHIgcm91bmQodW5uYW1lKG91dHB1dDIkZXN0aW1hdGUpLDIpYCBtbUhnCmhpZ2hlciBiZWZvcmUgdHJlYXRtZW50IHRoYW4gYWZ0ZXIgdHJlYXRtZW50ICg5NSUgQ0kgW2ByIHJvdW5kKG91dHB1dDIkY29uZi5pbnRbYygxLDIpXSwyKWBdKS4KCiMjIyBPbmUtc2FtcGxlIHQtdGVzdCBvbiB0aGUgZGlmZmVyZW5jZQoKT24gZmluYWwgdGhpbmc7IHBlcmZvcm1pbmcgYSBwYWlyZWQgdHdvLXNhbXBsZSB0LXRlc3QgaXMKYW5hbG9nb3VzIHRvIHBlcmZvcm1pbmcgYSBvbmUtc2FtcGxlIHQtdGVzdCBvbiB0aGUgZGlmZmVyZW5jZQpiZXR3ZWVuIGJvdGggZ3JvdXBzLgoKVGhpcyBjYW4gYmUgZWFzaWx5IHNlZW4gZnJvbSB0aGUgb3V0cHV0IG9mIHRoZSBwYWlyZWQgdHdvLXNhbXBsZQp0LXRlc3QuIFRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICRIQSQgdGhlcmUgc3RhdGVzIHRoYXQgCnRoZSAidHJ1ZSBkaWZmZXJlbmNlIGluIG1lYW5zIGlzIG5vdCBlcXVhbCB0byAwIi4gU28gaW50ZXJuYWxseSwKUiB3aWxsIGFjdHVhbGx5IHBlcmZvcm0gYSBvbmUtc2FtcGxlIHQtdGVzdCBvbiB0aGUgZGlmZmVyZW5jZSwgYW5kCmNoZWNrIHdoZXRoZXIgb3Igbm90IHRoZSB0cnVlIG1lYW4gZGlmZmVyZW5jZSBpcyBlcXVhbCB0byAwLgpXZSBjYW4gYWxzbyBzZXQgdGhpcyB1cCBtYW51YWxseS4KCmBgYHtyfQpicF9kaWZmIDwtIGNhcHRvcHJpbCAlPiUKICBtdXRhdGUoYnBfZGlmZiA9IFNCUGItU0JQYSkgJT4lCiAgc2VsZWN0KGJwX2RpZmYpCgp0LnRlc3QoYnBfZGlmZixtdT0wKQpgYGAKCkluZGVlZCwgdGhlIG91dHB1dCBpcyBjb21wbGV0ZWx5IGFuYWxvZ291cyB0byB0aGF0Cm9mIHRoZSBwYWlyZWQgdHdvLXNhbXBsZSB0LXRlc3QuCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo=