Smelly armpit dataset
Smelly armpits are not caused by sweat, itself. The smell is caused by specific micro-organisms belonging to the group of Corynebacterium spp. that metabolise sweat. Another group of abundant bacteria are the Staphylococcus spp., these bacteria do not metabolise sweat in smelly compounds.
The CMET-group at Ghent University does research to on transplanting the armpit microbiome to save people with smelly armpits.
Proposed Therapy:
- Remove armpit-microbiome with antibiotics
- Influence armpit microbiome with microbial transplant, see this 2 minute talk on youtube
Experiment:
- 20 students with smelly armpits are attributed to one of two treatment groups
- placebo (only antibiotics)
- transplant (antibiotica followed by microbial transplant).
- The microbiome is sampled 6 weeks upon the treatment
- The relative abundance of Staphylococcus spp. on Corynebacterium spp. + Staphylococcus spp. in the microbiome is measured via DGGE (Denaturing Gradient Gel Electrophoresis).
Goal
The overarching goal of this research was to assess if the relative abundance Staphylococcus spp. in the microbiome of the armpit is affected by transplanting the microbiome. To this end the researchers randomized patients to two treatment: A treatment with antibiotics only and a treatment with antibiotics and a microbial transplant.
In the tutorial on hypotheses testing we will use a formal statistical test to generalize the results from the sample to that of the population.
Import the dataset
#Load the libraries
library(tidyverse)
Import the data
ap <- read_csv("https://raw.githubusercontent.com/statOmics/PSLS21/data/armpit.csv")
## Rows: 20 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): trt
## dbl (1): rel
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 20
## Columns: 2
## $ trt <chr> "placebo", "placebo", "placebo", "placebo", "placebo", "placebo", …
## $ rel <dbl> 54.99208, 31.84466, 41.09948, 59.52064, 63.57341, 41.48649, 30.440…
Data Exploration
A crucial first step in a data analysis is to visualize and to explore the raw data.
ap %>% ggplot(aes(x=trt,y=rel,fill=trt)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter") +
ylab("relative abundance (%)") +
xlab("treatment group") +
stat_summary(fun.y=mean, geom="point", shape=5, size=3, color="black", fill="black")
## Warning: `fun.y` is deprecated. Use `fun` instead.
We clearly see that, on average, the subjects who had a microbial transplant have a higher relative abundance of Staphylococcus spp. But is this difference statistically
significant so that we can generalized what we observe in the sample to the population?
We can test this with an unpaired, two-sample t-test, which falsifies the null hypothesis that there is on average no difference in relative abundance of Staphylococcus in the armpit microbiome between the transplant and the placebo group against the alternative hypothesis that there is a difference in average abundance of Staphyloccocus in the armpit microbiome between the transplant and placebo treatment.
But, before we can start the analysis, we must check if all assumptions to perform a t-test are met.
Analysis
Check the assumptions
The observations are independent. This has to be guaranteed by the design.
The data (rel) are normally distributed in each of the groups
The variability within both groups is similar.
To check the normality assumption, we will use QQ plots.
ap %>%
ggplot(aes(sample=rel)) +
geom_qq() +
geom_qq_line() +
facet_grid(cols = vars(trt))
We can see that all of the data lies nicely around the quantile-quantile line (black line). As such, we may assume that our data are normally distributed.
For the third assumption, we must compare the within-group variability of both groups. We can do this visually:
ap %>% ggplot(aes(x=trt,y=rel)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter") +
ylab("relative abundance (%)") +
xlab("treatment group") +
stat_summary(fun.y=mean, geom="point", shape=5, size=3, color="black", fill="black")
## Warning: `fun.y` is deprecated. Use `fun` instead.
Here we can see that the interquartile range is approximately equal for groups.
As all three assumptions are met we may continue with performing the unpaired two-sample t-test.
Hypothesis test
placebo_rel <- ap %>%
filter(trt=="placebo") %>%
pull(rel)
transplant_rel <- ap %>%
filter(trt=="transplant") %>%
pull(rel)
output <- t.test(placebo_rel,
transplant_rel,
conf.level = 0.95,
var.equal = TRUE)
output
##
## Two Sample t-test
##
## data: placebo_rel and transplant_rel
## t = -5.0334, df = 18, p-value = 8.638e-05
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -31.53191 -12.96072
## sample estimates:
## mean of x mean of y
## 44.15496 66.40127
Conclusion
On average the relative abundance of Staphylococcus spp. in the microbiome of the armpit in the transplant group is extremely significantly different from that in the placebo group (\(p<<0.001\)). The relative abundance of Staphylococcus spp. is on average 22.2% larger in the transplant group than in the placebo group (95% CI [13.0,31.5]%).
ADDENDUM: Train yourself in checking the assumptions
In order for the learners to get more proficient in evaluating the assumptions we will simulate 9 dataset with sample sizes similar to our data for which the assumptions of normality and equal variance do hold. For the QQ-plots we will only plot the one from one of the groups.
Simulate data
We simulate 9 datasets with the same sample sizes, means and pooled variance as in the sample.
ap <- read_csv("https://raw.githubusercontent.com/statOmics/PSLS21/data/armpit.csv")
## Rows: 20 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): trt
## dbl (1): rel
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
nSamp <- 9
## descriptive statistics
apRelSum<-ap %>%
group_by(trt)%>%
summarize_at("rel",
list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
mutate(se=sd/sqrt(n))
sigma <- sqrt(sum(apRelSum$sd^2*(apRelSum$n-1))/(sum(apRelSum$n)-2))
normSim <- matrix(rnorm(sum(apRelSum$n)*nSamp,
mean=c(rep(apRelSum$mean[1],apRelSum$n[1]),
rep(apRelSum$mean[2],apRelSum$n[2])),
sd=sigma),nrow=sum(apRelSum$n)) %>%
as.data.frame %>%
mutate(trt=ap$trt)
Comparisons of variances
normSim %>% gather(samp,data,-trt) %>%
ggplot(aes(x=trt,y=data)) +
geom_boxplot() +
facet_wrap(~samp)
Evaluation of normality
Placebo group
normSim %>%
gather(samp,data,-trt) %>%
filter(trt=="placebo") %>%
ggplot(aes(sample=data)) +
geom_qq() +
geom_qq_line() +
facet_wrap(~samp)
Transplant group
normSim %>%
gather(samp,data,-trt) %>%
filter(trt=="transplant") %>%
ggplot(aes(sample=data)) +
geom_qq() +
geom_qq_line() +
facet_wrap(~samp)
LS0tCnRpdGxlOiAiRXhlcmNpc2UgNS4yOiBIeXBvdGhlc2lzIHRlc3Rpbmcgb24gdGhlIGFybXBpdCBkYXRhc2V0IC0gc29sdXRpb24iICAgCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IGFuZCBKZXJvZW4gR2lsaXMiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiICAKb3V0cHV0OgogICAgaHRtbF9kb2N1bWVudDoKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICAKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgojIFNtZWxseSBhcm1waXQgZGF0YXNldAoKU21lbGx5IGFybXBpdHMgYXJlIG5vdCBjYXVzZWQgYnkgc3dlYXQsIGl0c2VsZi4gVGhlIHNtZWxsIGlzIGNhdXNlZApieSBzcGVjaWZpYyBtaWNyby1vcmdhbmlzbXMgYmVsb25naW5nIHRvIHRoZSBncm91cCBvZgoqQ29yeW5lYmFjdGVyaXVtIHNwcC4qIHRoYXQgbWV0YWJvbGlzZSBzd2VhdC4gQW5vdGhlciBncm91cCBvZiBhYnVuZGFudCBiYWN0ZXJpYQphcmUgdGhlICpTdGFwaHlsb2NvY2N1cyBzcHAuKiwgdGhlc2UgYmFjdGVyaWEgZG8gbm90IG1ldGFib2xpc2Ugc3dlYXQgaW4gc21lbGx5IApjb21wb3VuZHMuCgpUaGUgQ01FVC1ncm91cCBhdCBHaGVudCBVbml2ZXJzaXR5IGRvZXMgcmVzZWFyY2ggdG8gb24gdHJhbnNwbGFudGluZyB0aGUgYXJtcGl0IAptaWNyb2Jpb21lIHRvIHNhdmUgcGVvcGxlIHdpdGggc21lbGx5IGFybXBpdHMuCgotIFByb3Bvc2VkIFRoZXJhcHk6CiAgCTEuIFJlbW92ZSBhcm1waXQtbWljcm9iaW9tZSB3aXRoIGFudGliaW90aWNzCiAgICAyLiBJbmZsdWVuY2UgYXJtcGl0IG1pY3JvYmlvbWUgd2l0aCBtaWNyb2JpYWwgdHJhbnNwbGFudCwgc2VlIHRoaXMgMiBtaW51dGUKICAgICAgIHRhbGsgb24gW3lvdXR1YmVdKGh0dHBzOi8veW91dHUuYmUvOVJJRnlxTFhkVncpCgotIEV4cGVyaW1lbnQ6CgogICAgLSAyMCBzdHVkZW50cyB3aXRoIHNtZWxseSBhcm1waXRzIGFyZSBhdHRyaWJ1dGVkIHRvIG9uZSBvZiAKICAgICAgdHdvIHRyZWF0bWVudCBncm91cHMKICAgIC0gcGxhY2VibyAob25seSBhbnRpYmlvdGljcykKICAgIC0gdHJhbnNwbGFudCAoYW50aWJpb3RpY2EgZm9sbG93ZWQgYnkgbWljcm9iaWFsIHRyYW5zcGxhbnQpLgogICAgLSBUaGUgbWljcm9iaW9tZSBpcyBzYW1wbGVkIDYgd2Vla3MgdXBvbiB0aGUgdHJlYXRtZW50CiAgICAtIFRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgKlN0YXBoeWxvY29jY3VzIHNwcC4qIG9uCiAgICAgICpDb3J5bmViYWN0ZXJpdW0gc3BwLiogKyAqU3RhcGh5bG9jb2NjdXMgc3BwLiogaW4gdGhlCiAgICAgIG1pY3JvYmlvbWUgaXMgbWVhc3VyZWQgdmlhIERHR0UgKCpEZW5hdHVyaW5nIEdyYWRpZW50IEdlbAogICAgICBFbGVjdHJvcGhvcmVzaXMqKS4KICAgIAojIEdvYWwKClRoZSBvdmVyYXJjaGluZyBnb2FsIG9mIHRoaXMgcmVzZWFyY2ggd2FzIHRvIGFzc2VzcyBpZiB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlIAoqU3RhcGh5bG9jb2NjdXMgc3BwLioKaW4gdGhlIG1pY3JvYmlvbWUgb2YgdGhlIGFybXBpdCBpcyBhZmZlY3RlZCBieSB0cmFuc3BsYW50aW5nIHRoZSBtaWNyb2Jpb21lLiAKVG8gdGhpcyBlbmQgdGhlIHJlc2VhcmNoZXJzIHJhbmRvbWl6ZWQgcGF0aWVudHMgdG8gdHdvIHRyZWF0bWVudDoKQSB0cmVhdG1lbnQgd2l0aCBhbnRpYmlvdGljcyBvbmx5IGFuZCBhIHRyZWF0bWVudCB3aXRoCmFudGliaW90aWNzIGFuZCBhIG1pY3JvYmlhbCB0cmFuc3BsYW50LgoKSW4gdGhlIHR1dG9yaWFsIG9uIGh5cG90aGVzZXMgdGVzdGluZyB3ZSB3aWxsIHVzZSBhIGZvcm1hbCBzdGF0aXN0aWNhbCB0ZXN0IHRvIApnZW5lcmFsaXplIHRoZSByZXN1bHRzIGZyb20gdGhlIHNhbXBsZSB0byB0aGF0IG9mIHRoZSBwb3B1bGF0aW9uLgoKIyBJbXBvcnQgdGhlIGRhdGFzZXQKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQojTG9hZCB0aGUgbGlicmFyaWVzCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCkltcG9ydCB0aGUgZGF0YQoKYGBge3J9CmFwIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL1BTTFMyMS9kYXRhL2FybXBpdC5jc3YiKQpgYGAKCmBgYHtyfQpnbGltcHNlKGFwKQpgYGAKCiMgRGF0YSBFeHBsb3JhdGlvbgoKQSBjcnVjaWFsIGZpcnN0IHN0ZXAgaW4gYSBkYXRhIGFuYWx5c2lzIGlzIHRvIHZpc3VhbGl6ZSBhbmQgdG8gZXhwbG9yZSB0aGUgcmF3IApkYXRhLgoKYGBge3J9CmFwICU+JSBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsLGZpbGw9dHJ0KSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKyAKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArCiAgeWxhYigicmVsYXRpdmUgYWJ1bmRhbmNlICglKSIpICsKICB4bGFiKCJ0cmVhdG1lbnQgZ3JvdXAiKSArIAogIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTUsIHNpemU9MywgY29sb3I9ImJsYWNrIiwgZmlsbD0iYmxhY2siKQpgYGAKCldlIGNsZWFybHkgc2VlIHRoYXQsIG9uIGF2ZXJhZ2UsIHRoZSBzdWJqZWN0cyB3aG8gaGFkIGEKbWljcm9iaWFsIHRyYW5zcGxhbnQgaGF2ZSBhIGhpZ2hlciByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YKU3RhcGh5bG9jb2NjdXMgc3BwLiBCdXQgaXMgdGhpcyBkaWZmZXJlbmNlIHN0YXRpc3RpY2FsbHkgIAoqc2lnbmlmaWNhbnQqIHNvIHRoYXQgd2UgY2FuIGdlbmVyYWxpemVkIHdoYXQgd2Ugb2JzZXJ2ZSAKaW4gdGhlIHNhbXBsZSB0byB0aGUgcG9wdWxhdGlvbj8KCldlIGNhbiB0ZXN0IHRoaXMgd2l0aCBhbiB1bnBhaXJlZCwgdHdvLXNhbXBsZSB0LXRlc3QsIHdoaWNoIGZhbHNpZmllcyB0aGUgbnVsbCAKaHlwb3RoZXNpcyB0aGF0IHRoZXJlIGlzIG9uIGF2ZXJhZ2Ugbm8gZGlmZmVyZW5jZSBpbiByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgCipTdGFwaHlsb2NvY2N1cyogaW4gdGhlIGFybXBpdCBtaWNyb2Jpb21lIGJldHdlZW4gdGhlIHRyYW5zcGxhbnQgYW5kIHRoZSAKcGxhY2VibyBncm91cCBhZ2FpbnN0IHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIAppbiBhdmVyYWdlIGFidW5kYW5jZSBvZiAqU3RhcGh5bG9jY29jdXMqIGluIHRoZSBhcm1waXQgbWljcm9iaW9tZSBiZXR3ZWVuIAp0aGUgdHJhbnNwbGFudCBhbmQgcGxhY2VibyB0cmVhdG1lbnQuIAoKQnV0LCBiZWZvcmUgd2UgY2FuIHN0YXJ0IHRoZSBhbmFseXNpcywgd2UgbXVzdCBjaGVjayBpZiBhbGwgYXNzdW1wdGlvbnMgdG8gCnBlcmZvcm0gYSB0LXRlc3QgYXJlIG1ldC4KCiMgQW5hbHlzaXMKCiMjIENoZWNrIHRoZSBhc3N1bXB0aW9ucwoKMS4gVGhlIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQuIFRoaXMgaGFzIHRvIGJlIApndWFyYW50ZWVkIGJ5IHRoZSBkZXNpZ24uCgoyLiBUaGUgZGF0YSAocmVsKSBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgaW4gZWFjaCBvZiB0aGUgZ3JvdXBzCgozLiBUaGUgdmFyaWFiaWxpdHkgd2l0aGluIGJvdGggZ3JvdXBzIGlzIHNpbWlsYXIuCgpUbyBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24sIHdlIHdpbGwgdXNlIFFRIHBsb3RzLgoKYGBge3J9CmFwICU+JQogIGdncGxvdChhZXMoc2FtcGxlPXJlbCkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpICsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKHRydCkpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IGFsbCBvZiB0aGUgZGF0YSBsaWVzIG5pY2VseSBhcm91bmQgdGhlIHF1YW50aWxlLXF1YW50aWxlCmxpbmUgKGJsYWNrIGxpbmUpLiBBcyBzdWNoLCB3ZSBtYXkgYXNzdW1lIHRoYXQgb3VyIGRhdGEgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKRm9yIHRoZSB0aGlyZCBhc3N1bXB0aW9uLCB3ZSBtdXN0IGNvbXBhcmUgdGhlIHdpdGhpbi1ncm91cAp2YXJpYWJpbGl0eSBvZiBib3RoIGdyb3Vwcy4gV2UgY2FuIGRvIHRoaXMgdmlzdWFsbHk6CgpgYGB7cn0KYXAgJT4lICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKyAKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArCiAgeWxhYigicmVsYXRpdmUgYWJ1bmRhbmNlICglKSIpICsKICB4bGFiKCJ0cmVhdG1lbnQgZ3JvdXAiKSArIAogIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTUsIHNpemU9MywgY29sb3I9ImJsYWNrIiwgZmlsbD0iYmxhY2siKQpgYGAKCkhlcmUgd2UgY2FuIHNlZSB0aGF0IHRoZSBpbnRlcnF1YXJ0aWxlIHJhbmdlIGlzIGFwcHJveGltYXRlbHkgZXF1YWwgZm9yIGdyb3Vwcy4KCkFzIGFsbCB0aHJlZSBhc3N1bXB0aW9ucyBhcmUgbWV0IHdlIG1heSBjb250aW51ZSB3aXRoCnBlcmZvcm1pbmcgdGhlIHVucGFpcmVkIHR3by1zYW1wbGUgdC10ZXN0LgoKIyMgSHlwb3RoZXNpcyB0ZXN0CgpgYGB7cn0KcGxhY2Vib19yZWwgPC0gYXAgJT4lCiAgZmlsdGVyKHRydD09InBsYWNlYm8iKSAlPiUKICBwdWxsKHJlbCkKCnRyYW5zcGxhbnRfcmVsIDwtIGFwICU+JQogIGZpbHRlcih0cnQ9PSJ0cmFuc3BsYW50IikgJT4lCiAgcHVsbChyZWwpCgpvdXRwdXQgPC0gdC50ZXN0KHBsYWNlYm9fcmVsLAogICAgICAgICAgICAgICAgIHRyYW5zcGxhbnRfcmVsLAogICAgICAgICAgICAgICAgIGNvbmYubGV2ZWwgPSAwLjk1LAogICAgICAgICAgICAgICAgIHZhci5lcXVhbCA9IFRSVUUpCm91dHB1dApgYGAKCiMjIENvbmNsdXNpb24KCk9uIGF2ZXJhZ2UgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiAqU3RhcGh5bG9jb2NjdXMgc3BwLiogaW4gdGhlIG1pY3JvYmlvbWUgb2YgdGhlIGFybXBpdCBpbiB0aGUgdHJhbnNwbGFudCBncm91cCBpcyBleHRyZW1lbHkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB0aGF0IGluIHRoZSBwbGFjZWJvIGdyb3VwICgkcDw8MC4wMDEkKS4gVGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiAqU3RhcGh5bG9jb2NjdXMgc3BwLiogaXMgb24gYXZlcmFnZSBgciByb3VuZChkaWZmKHQudGVzdChyZWx+dHJ0LGRhdGE9YXAsdmFyLmVxdWFsPVRSVUUpJGVzdGltYXRlKSwxKWAlIGxhcmdlciBpbiB0aGUgdHJhbnNwbGFudCBncm91cCB0aGFuIGluIHRoZSBwbGFjZWJvIGdyb3VwICg5NVwlIENJIFtgciBwYXN0ZShmb3JtYXQoLXQudGVzdChyZWx+dHJ0LGRhdGE9YXAsdmFyLmVxdWFsPVRSVUUpJGNvbmYuaW50WzI6MV0sZGlnaXRzPTIsbnNtYWxsPTEpLGNvbGxhcHNlPSIsIilgXSUpLgoKIyBBRERFTkRVTTogVHJhaW4geW91cnNlbGYgaW4gY2hlY2tpbmcgdGhlIGFzc3VtcHRpb25zCgpJbiBvcmRlciBmb3IgdGhlIGxlYXJuZXJzIHRvIGdldCBtb3JlIHByb2ZpY2llbnQgaW4gZXZhbHVhdGluZyB0aGUgYXNzdW1wdGlvbnMgd2Ugd2lsbCBzaW11bGF0ZSA5IGRhdGFzZXQgd2l0aCBzYW1wbGUgc2l6ZXMgc2ltaWxhciB0byBvdXIgZGF0YSBmb3Igd2hpY2ggdGhlIGFzc3VtcHRpb25zIG9mIG5vcm1hbGl0eSBhbmQgZXF1YWwgdmFyaWFuY2UgZG8gaG9sZC4gRm9yIHRoZSBRUS1wbG90cyB3ZSB3aWxsIG9ubHkgcGxvdCB0aGUgb25lIGZyb20gb25lIG9mIHRoZSBncm91cHMuIAoKIyMgU2ltdWxhdGUgZGF0YSAKCldlIHNpbXVsYXRlIDkgZGF0YXNldHMgd2l0aCB0aGUgc2FtZSBzYW1wbGUgc2l6ZXMsIG1lYW5zIGFuZCBwb29sZWQgdmFyaWFuY2UgYXMgaW4gdGhlIHNhbXBsZS4gCgpgYGB7cn0KYXAgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3MvUFNMUzIxL2RhdGEvYXJtcGl0LmNzdiIpCgpuU2FtcCA8LSA5CiMjIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MKYXBSZWxTdW08LWFwICU+JQogIGdyb3VwX2J5KHRydCklPiUKICBzdW1tYXJpemVfYXQoInJlbCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpCgpzaWdtYSA8LSBzcXJ0KHN1bShhcFJlbFN1bSRzZF4yKihhcFJlbFN1bSRuLTEpKS8oc3VtKGFwUmVsU3VtJG4pLTIpKSAKCm5vcm1TaW0gPC0gbWF0cml4KHJub3JtKHN1bShhcFJlbFN1bSRuKSpuU2FtcCwKICAgICAgICAgICAgICBtZWFuPWMocmVwKGFwUmVsU3VtJG1lYW5bMV0sYXBSZWxTdW0kblsxXSksCiAgICAgICAgICAgICAgICAgICAgIHJlcChhcFJlbFN1bSRtZWFuWzJdLGFwUmVsU3VtJG5bMl0pKSwKICAgICAgICAgICAgICAgICAgICAgc2Q9c2lnbWEpLG5yb3c9c3VtKGFwUmVsU3VtJG4pKSAlPiUKICBhcy5kYXRhLmZyYW1lICU+JSAKICBtdXRhdGUodHJ0PWFwJHRydCkKYGBgCgojIyBDb21wYXJpc29ucyBvZiB2YXJpYW5jZXMKCmBgYHtyfQpub3JtU2ltICU+JSBnYXRoZXIoc2FtcCxkYXRhLC10cnQpICU+JQogIGdncGxvdChhZXMoeD10cnQseT1kYXRhKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5zYW1wKQpgYGAKCiMjIEV2YWx1YXRpb24gb2Ygbm9ybWFsaXR5CgojIyMgUGxhY2VibyBncm91cAoKYGBge3J9Cm5vcm1TaW0gJT4lIAogIGdhdGhlcihzYW1wLGRhdGEsLXRydCkgJT4lCiAgZmlsdGVyKHRydD09InBsYWNlYm8iKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZT1kYXRhKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X3dyYXAofnNhbXApCmBgYAoKIyMjIFRyYW5zcGxhbnQgZ3JvdXAKCmBgYHtyfQpub3JtU2ltICU+JSAKICBnYXRoZXIoc2FtcCxkYXRhLC10cnQpICU+JQogIGZpbHRlcih0cnQ9PSJ0cmFuc3BsYW50IikgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGU9ZGF0YSkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpICsKICBmYWNldF93cmFwKH5zYW1wKQpgYGAKCg==