ALL IMPORTED FILES MUST BE IN THE SAME DIRECTORY AS THIS SCRIPT
High-performance computing cluster (e.g. using RStudio Server) strongly recommended, due to large memory requirements
Load required packages
library("tidyverse")
library("readbulk")
library("glmmTMB")
library("betareg")
library("DHARMa")
Import data; each file comprises 1000 SIGNAL bootstrap solutions (generated using https://signal.mutationalsignatures.com/analyse2) using the OvCa-specific signature set (OVARY_A/B/C/D/E/F/G- see https://signal.mutationalsignatures.com/explore/studyTissueType/1-15) for the 12 samples comprising the pooled reference group (‘HGSrefMutSig’), imported twice as separate data sets 1 and 2; refer to Chapters 4.2.2.3-4 for further details
mut_sig_SIGNAL_exposures_HGSrefMutSig1 <- read.delim("masterfile_tumour_samples_SIGNAL_HGSrefMutSig.tsv") %>%
mutate(Group = "HGSrefMutSig1")
mut_sig_SIGNAL_exposures_HGSrefMutSig2 <- read.delim("masterfile_tumour_samples_SIGNAL_HGSrefMutSig.tsv") %>%
mutate(Group = "HGSrefMutSig2")
Import number of somatic mutations used for signature fitting for the 12 HGSrefMutSig samples
HGSrefMutSig_samples <- read.delim("HGSrefMutSig_samples.tsv")
Perform random sampling of two samples with combined total of >= 60 mutations from the HGSrefMutSig group 100 times, comparing these each time against the complete HGSrefMutSig group using the GLMM, and output results with exact p-values (NB may need to be run multiple times to generate n = 100 results)
for (i in c(1:100)) {
HGSrefMutSigTest <- sample_n(HGSrefMutSig_samples, 2, replace=FALSE)
if(sum(HGSrefMutSigTest$No_Mutations)>=60){
mut_sig_SIGNAL_exposures_HGSrefMutSig_subset <- filter(mut_sig_SIGNAL_exposures_HGSrefMutSig2, Tumour_Sample%in%HGSrefMutSigTest$Tumour_Sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2 <- bind_rows(mut_sig_SIGNAL_exposures_HGSrefMutSig1,mut_sig_SIGNAL_exposures_HGSrefMutSig_subset)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures <- replace(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures, mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures==1, 0.9999999)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Group <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Group)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solu_Sample <- paste(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution,
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample,
sep=":") %>%
as.factor()
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Signature <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Signature)
mut_sig_mixed_lmer_bin_HGSrefMutSig <- glmmTMB(Exposures ~ Age + Group +
(1|Solu_Sample) + (1|Signature),
data = mut_sig_SIGNAL_exposures_HGSrefMutSig1_2,
family=beta_family(),
ziformula = ~1,
control = glmmTMBControl(parallel = 48)
)
sink(file=(paste(`i`,"testSamples_vs_HGSrefMutSig_SIGNAL_lmer_bin_2&60_results.txt",sep="")),append = FALSE)
print(HGSrefMutSigTest)
summary(mut_sig_mixed_lmer_bin_HGSrefMutSig) %>% print()
sink()
sink(file="testSamples_vs_HGSrefMutSig_SIGNAL_lmer_bin_2&60_all_p_values.txt",append = TRUE)
print(i)
print(HGSrefMutSigTest)
print(coef(summary(mut_sig_mixed_lmer_bin_HGSrefMutSig))$cond)
sink()
}else{
rm(HGSrefMutSigTest)
}
closeAllConnections()
}
Perform random sampling of three samples with combined total of >= 150 mutations from the HGSrefMutSig group 100 times, comparing these each time against the complete HGSrefMutSig group using the GLMM, and output results with exact p-values (NB may need to be run multiple times to generate n = 100 results)
for (i in c(1:100)) {
HGSrefMutSigTest <- sample_n(HGSrefMutSig_samples, 3, replace=FALSE)
if(sum(HGSrefMutSigTest$No_Mutations)>=150){
mut_sig_SIGNAL_exposures_HGSrefMutSig_subset <- filter(mut_sig_SIGNAL_exposures_HGSrefMutSig2, Tumour_Sample%in%HGSrefMutSigTest$Tumour_Sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2 <- bind_rows(mut_sig_SIGNAL_exposures_HGSrefMutSig1,mut_sig_SIGNAL_exposures_HGSrefMutSig_subset)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures <- replace(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures, mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Exposures==1, 0.9999999)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Group <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Group)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solu_Sample <- paste(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution,
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample,
sep=":") %>%
as.factor()
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Tumour_Sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Solution)
mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Signature <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig1_2$Signature)
mut_sig_mixed_lmer_bin_HGSrefMutSig <- glmmTMB(Exposures ~ Age + Group +
(1|Solu_Sample) + (1|Signature),
data = mut_sig_SIGNAL_exposures_HGSrefMutSig1_2,
family=beta_family(),
ziformula = ~1,
control = glmmTMBControl(parallel = 48)
)
sink(file=(paste(`i`,"testSamples_vs_HGSrefMutSig_SIGNAL_lmer_bin_3&150_results.txt",sep="")),append = FALSE)
print(HGSrefMutSigTest)
summary(mut_sig_mixed_lmer_bin_HGSrefMutSig) %>% print()
sink()
sink(file="testSamples_vs_HGSrefMutSig_SIGNAL_lmer_bin_3&150_all_p_values.txt",append = TRUE)
print(i)
print(HGSrefMutSigTest)
print(coef(summary(mut_sig_mixed_lmer_bin_HGSrefMutSig))$cond)
sink()
}else{
rm(HGSrefMutSigTest)
}
closeAllConnections()
}
Compare HGSrefMutSig individual samples against the complete HGSrefMutSig group using the GLMM, perform DHARMa residual diagnostics tests for each comparison, and output results
HGSrefMutSig_samples_list <- HGSrefMutSig_samples$Tumour_Sample
for (HGSrefMutSig in HGSrefMutSig_samples_list){
mut_sig_SIGNAL_exposures_sample <- filter(mut_sig_SIGNAL_exposures_HGSrefMutSig2, Tumour_Sample%in%HGSrefMutSig) %>%
mutate(Group = HGSrefMutSig)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample <- bind_rows(mut_sig_SIGNAL_exposures_HGSrefMutSig1,mut_sig_SIGNAL_exposures_sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Exposures <- replace(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Exposures, mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Exposures==1, 0.9999999)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Group <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Group)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Solu_Sample <- paste(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Solution,
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Tumour_Sample,
sep=":") %>%
as.factor()
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Tumour_Sample <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Tumour_Sample)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Solution <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Solution)
mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Signature <- as.factor(mut_sig_SIGNAL_exposures_HGSrefMutSig_sample$Signature)
mut_sig_mixed_lmer_bin_HGSrefMutSig_sample <- glmmTMB(Exposures ~ Age + Group +
(1|Solu_Sample) + (1|Signature),
data = mut_sig_SIGNAL_exposures_HGSrefMutSig1_2,
family=beta_family(),
ziformula = ~1,
control = glmmTMBControl(parallel = 48)
)
simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample <- simulateResiduals(mut_sig_mixed_lmer_bin_HGSrefMutSig_sample)
sink(file=(paste(`HGSrefMutSig`,"_vs_HGSrefMutSig_SIGNAL_lmer_bin_simRes_results.txt",sep="")),append = FALSE)
pdf(paste(`HGSrefMutSig`,"_vs_HGSrefMutSig_SIGNAL_lmer_bin_simRes_results.pdf",sep=""))
print(HGSrefMutSigTest)
summary(mut_sig_mixed_lmer_bin_HGSrefMutSig_sample) %>% print()
plot(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample)
testDispersion(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample) %>% print()
testUniformity(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample) %>% print()
testOutliers(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample,type="bootstrap") %>% print()
testZeroInflation(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample) %>% print()
plotResiduals(simres_mut_sig_mixed_lmer_bin_HGSrefMutSig_sample, mut_sig_mixed_lmer_bin_HGSrefMutSig_sample$Group)
sink()
sink(file="testSamples_vs_HGSrefMutSig_SIGNAL_lmer_bin_all_p_values.txt",append = TRUE)
print(HGSrefMutSig)
print(HGSrefMutSigTest)
print(coef(summary(mut_sig_mixed_lmer_bin_HGSrefMutSig_sample))$cond)
sink()
}
closeAllConnections()
LS0tCnRpdGxlOiAiVGhlc2lzIFNJR05BTCBNdXRhdGlvbmFsIFNpZ25hdHVyZSBHTE1NIFRlc3RpbmcgU2NyaXB0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpBTEwgSU1QT1JURUQgRklMRVMgTVVTVCBCRSBJTiBUSEUgU0FNRSBESVJFQ1RPUlkgQVMgVEhJUyBTQ1JJUFQKCkhpZ2gtcGVyZm9ybWFuY2UgY29tcHV0aW5nIGNsdXN0ZXIgKGUuZy4gdXNpbmcgUlN0dWRpbyBTZXJ2ZXIpIHN0cm9uZ2x5IHJlY29tbWVuZGVkLCBkdWUgdG8gbGFyZ2UgbWVtb3J5IHJlcXVpcmVtZW50cyAKCkxvYWQgcmVxdWlyZWQgcGFja2FnZXMKYGBge3J9CmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoInJlYWRidWxrIikKbGlicmFyeSgiZ2xtbVRNQiIpCmxpYnJhcnkoImJldGFyZWciKQpsaWJyYXJ5KCJESEFSTWEiKQpgYGAKCkltcG9ydCBkYXRhOyBlYWNoIGZpbGUgY29tcHJpc2VzIDEwMDAgU0lHTkFMIGJvb3RzdHJhcCBzb2x1dGlvbnMgKGdlbmVyYXRlZCB1c2luZyBodHRwczovL3NpZ25hbC5tdXRhdGlvbmFsc2lnbmF0dXJlcy5jb20vYW5hbHlzZTIpIHVzaW5nIHRoZSBPdkNhLXNwZWNpZmljIHNpZ25hdHVyZSBzZXQgKE9WQVJZX0EvQi9DL0QvRS9GL0ctIHNlZSBodHRwczovL3NpZ25hbC5tdXRhdGlvbmFsc2lnbmF0dXJlcy5jb20vZXhwbG9yZS9zdHVkeVRpc3N1ZVR5cGUvMS0xNSkgZm9yIHRoZSAxMiBzYW1wbGVzIGNvbXByaXNpbmcgdGhlIHBvb2xlZCByZWZlcmVuY2UgZ3JvdXAgKCdIR1NyZWZNdXRTaWcnKSwgaW1wb3J0ZWQgdHdpY2UgYXMgc2VwYXJhdGUgZGF0YSBzZXRzIDEgYW5kIDI7IHJlZmVyIHRvIENoYXB0ZXJzIDQuMi4yLjMtNCBmb3IgZnVydGhlciBkZXRhaWxzCmBgYHtyfQptdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMSA8LSByZWFkLmRlbGltKCJtYXN0ZXJmaWxlX3R1bW91cl9zYW1wbGVzX1NJR05BTF9IR1NyZWZNdXRTaWcudHN2IikgJT4lIAogIG11dGF0ZShHcm91cCA9ICJIR1NyZWZNdXRTaWcxIikKbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzIgPC0gcmVhZC5kZWxpbSgibWFzdGVyZmlsZV90dW1vdXJfc2FtcGxlc19TSUdOQUxfSEdTcmVmTXV0U2lnLnRzdiIpICU+JSAKICBtdXRhdGUoR3JvdXAgPSAiSEdTcmVmTXV0U2lnMiIpCmBgYAoKSW1wb3J0IG51bWJlciBvZiBzb21hdGljIG11dGF0aW9ucyB1c2VkIGZvciBzaWduYXR1cmUgZml0dGluZyBmb3IgdGhlIDEyIEhHU3JlZk11dFNpZyBzYW1wbGVzCmBgYHtyfQpIR1NyZWZNdXRTaWdfc2FtcGxlcyA8LSByZWFkLmRlbGltKCJIR1NyZWZNdXRTaWdfc2FtcGxlcy50c3YiKQpgYGAKClBlcmZvcm0gcmFuZG9tIHNhbXBsaW5nIG9mIHR3byBzYW1wbGVzIHdpdGggY29tYmluZWQgdG90YWwgb2YgPj0gNjAgbXV0YXRpb25zIGZyb20gdGhlIEhHU3JlZk11dFNpZyBncm91cCAxMDAgdGltZXMsIGNvbXBhcmluZyB0aGVzZSBlYWNoIHRpbWUgYWdhaW5zdCB0aGUgY29tcGxldGUgSEdTcmVmTXV0U2lnIGdyb3VwIHVzaW5nIHRoZSBHTE1NLCBhbmQgb3V0cHV0IHJlc3VsdHMgd2l0aCBleGFjdCBwLXZhbHVlcyAoTkIgbWF5IG5lZWQgdG8gYmUgcnVuIG11bHRpcGxlIHRpbWVzIHRvIGdlbmVyYXRlIG4gPSAxMDAgcmVzdWx0cykKYGBge3J9CmZvciAoaSBpbiBjKDE6MTAwKSkgewogIEhHU3JlZk11dFNpZ1Rlc3QgPC0gc2FtcGxlX24oSEdTcmVmTXV0U2lnX3NhbXBsZXMsIDIsIHJlcGxhY2U9RkFMU0UpCiAgaWYoc3VtKEhHU3JlZk11dFNpZ1Rlc3QkTm9fTXV0YXRpb25zKT49NjApewogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zdWJzZXQgPC0gZmlsdGVyKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcyLCBUdW1vdXJfU2FtcGxlJWluJUhHU3JlZk11dFNpZ1Rlc3QkVHVtb3VyX1NhbXBsZSkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIgPC0gYmluZF9yb3dzKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxLG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc3Vic2V0KQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRFeHBvc3VyZXMgPC0gcmVwbGFjZShtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJEV4cG9zdXJlcywgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRFeHBvc3VyZXM9PTEsIDAuOTk5OTk5OSkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkR3JvdXAgPC0gYXMuZmFjdG9yKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkR3JvdXApCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJFNvbHVfU2FtcGxlIDwtIHBhc3RlKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkU29sdXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJFR1bW91cl9TYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IjoiKSAlPiUgCiAgICAgIGFzLmZhY3RvcigpCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJFR1bW91cl9TYW1wbGUgPC0gYXMuZmFjdG9yKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkVHVtb3VyX1NhbXBsZSkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkU29sdXRpb24gPC0gYXMuZmFjdG9yKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkU29sdXRpb24pCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJFNpZ25hdHVyZSA8LSBhcy5mYWN0b3IobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRTaWduYXR1cmUpCiAgICAKICAgIG11dF9zaWdfbWl4ZWRfbG1lcl9iaW5fSEdTcmVmTXV0U2lnIDwtIGdsbW1UTUIoRXhwb3N1cmVzIH4gQWdlICsgR3JvdXAgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDF8U29sdV9TYW1wbGUpICsgKDF8U2lnbmF0dXJlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1iZXRhX2ZhbWlseSgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHppZm9ybXVsYSA9IH4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGdsbW1UTUJDb250cm9sKHBhcmFsbGVsID0gNDgpICNwYXJhbGxlbCA9IG5vLiBvZiBhdmFpbGFibGUgcHJvY2Vzc29yIGNvcmVzL3RocmVhZHMKICAgICkKICAgIHNpbmsoZmlsZT0ocGFzdGUoYGlgLCJ0ZXN0U2FtcGxlc192c19IR1NyZWZNdXRTaWdfU0lHTkFMX2xtZXJfYmluXzImNjBfcmVzdWx0cy50eHQiLHNlcD0iIikpLGFwcGVuZCA9IEZBTFNFKQogICAgcHJpbnQoSEdTcmVmTXV0U2lnVGVzdCkKICAgIHN1bW1hcnkobXV0X3NpZ19taXhlZF9sbWVyX2Jpbl9IR1NyZWZNdXRTaWcpICU+JSBwcmludCgpCiAgICBzaW5rKCkKICAgIHNpbmsoZmlsZT0idGVzdFNhbXBsZXNfdnNfSEdTcmVmTXV0U2lnX1NJR05BTF9sbWVyX2Jpbl8yJjYwX2FsbF9wX3ZhbHVlcy50eHQiLGFwcGVuZCA9IFRSVUUpCiAgICBwcmludChpKQogICAgcHJpbnQoSEdTcmVmTXV0U2lnVGVzdCkKICAgIHByaW50KGNvZWYoc3VtbWFyeShtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZykpJGNvbmQpCiAgICBzaW5rKCkKICB9ZWxzZXsKICAgIHJtKEhHU3JlZk11dFNpZ1Rlc3QpCiAgfQogIGNsb3NlQWxsQ29ubmVjdGlvbnMoKQp9CmBgYAoKUGVyZm9ybSByYW5kb20gc2FtcGxpbmcgb2YgdGhyZWUgc2FtcGxlcyB3aXRoIGNvbWJpbmVkIHRvdGFsIG9mID49IDE1MCBtdXRhdGlvbnMgZnJvbSB0aGUgSEdTcmVmTXV0U2lnIGdyb3VwIDEwMCB0aW1lcywgY29tcGFyaW5nIHRoZXNlIGVhY2ggdGltZSBhZ2FpbnN0IHRoZSBjb21wbGV0ZSBIR1NyZWZNdXRTaWcgZ3JvdXAgdXNpbmcgdGhlIEdMTU0sIGFuZCBvdXRwdXQgcmVzdWx0cyB3aXRoIGV4YWN0IHAtdmFsdWVzIChOQiBtYXkgbmVlZCB0byBiZSBydW4gbXVsdGlwbGUgdGltZXMgdG8gZ2VuZXJhdGUgbiA9IDEwMCByZXN1bHRzKQpgYGB7cn0KZm9yIChpIGluIGMoMToxMDApKSB7CiAgSEdTcmVmTXV0U2lnVGVzdCA8LSBzYW1wbGVfbihIR1NyZWZNdXRTaWdfc2FtcGxlcywgMywgcmVwbGFjZT1GQUxTRSkKICBpZihzdW0oSEdTcmVmTXV0U2lnVGVzdCROb19NdXRhdGlvbnMpPj0xNTApewogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zdWJzZXQgPC0gZmlsdGVyKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcyLCBUdW1vdXJfU2FtcGxlJWluJUhHU3JlZk11dFNpZ1Rlc3QkVHVtb3VyX1NhbXBsZSkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIgPC0gYmluZF9yb3dzKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxLG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc3Vic2V0KQogICAgCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJEV4cG9zdXJlcyA8LSByZXBsYWNlKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkRXhwb3N1cmVzLCBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJEV4cG9zdXJlcz09MSwgMC45OTk5OTk5KQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRHcm91cCA8LSBhcy5mYWN0b3IobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRHcm91cCkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkU29sdV9TYW1wbGUgPC0gcGFzdGUobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRTb2x1dGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkVHVtb3VyX1NhbXBsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcD0iOiIpICU+JSAKICAgICAgYXMuZmFjdG9yKCkKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkVHVtb3VyX1NhbXBsZSA8LSBhcy5mYWN0b3IobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRUdW1vdXJfU2FtcGxlKQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRTb2x1dGlvbiA8LSBhcy5mYWN0b3IobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiRTb2x1dGlvbikKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxXzIkU2lnbmF0dXJlIDwtIGFzLmZhY3RvcihtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yJFNpZ25hdHVyZSkKICAgIG11dF9zaWdfbWl4ZWRfbG1lcl9iaW5fSEdTcmVmTXV0U2lnIDwtIGdsbW1UTUIoRXhwb3N1cmVzIH4gQWdlICsgR3JvdXAgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDF8U29sdV9TYW1wbGUpICsgKDF8U2lnbmF0dXJlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMV8yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1iZXRhX2ZhbWlseSgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHppZm9ybXVsYSA9IH4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGdsbW1UTUJDb250cm9sKHBhcmFsbGVsID0gNDgpCiAgICApCiAgICBzaW5rKGZpbGU9KHBhc3RlKGBpYCwidGVzdFNhbXBsZXNfdnNfSEdTcmVmTXV0U2lnX1NJR05BTF9sbWVyX2Jpbl8zJjE1MF9yZXN1bHRzLnR4dCIsc2VwPSIiKSksYXBwZW5kID0gRkFMU0UpCiAgICBwcmludChIR1NyZWZNdXRTaWdUZXN0KQogICAgc3VtbWFyeShtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZykgJT4lIHByaW50KCkKICAgIHNpbmsoKQogICAgc2luayhmaWxlPSJ0ZXN0U2FtcGxlc192c19IR1NyZWZNdXRTaWdfU0lHTkFMX2xtZXJfYmluXzMmMTUwX2FsbF9wX3ZhbHVlcy50eHQiLGFwcGVuZCA9IFRSVUUpCiAgICBwcmludChpKQogICAgcHJpbnQoSEdTcmVmTXV0U2lnVGVzdCkKICAgIHByaW50KGNvZWYoc3VtbWFyeShtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZykpJGNvbmQpCiAgICBzaW5rKCkKICB9ZWxzZXsKICAgIHJtKEhHU3JlZk11dFNpZ1Rlc3QpCiAgfQogIGNsb3NlQWxsQ29ubmVjdGlvbnMoKQp9CmBgYAoKQ29tcGFyZSBIR1NyZWZNdXRTaWcgaW5kaXZpZHVhbCBzYW1wbGVzIGFnYWluc3QgdGhlIGNvbXBsZXRlIEhHU3JlZk11dFNpZyBncm91cCB1c2luZyB0aGUgR0xNTSwgcGVyZm9ybSBESEFSTWEgcmVzaWR1YWwgZGlhZ25vc3RpY3MgdGVzdHMgZm9yIGVhY2ggY29tcGFyaXNvbiwgYW5kIG91dHB1dCByZXN1bHRzCmBgYHtyfQpIR1NyZWZNdXRTaWdfc2FtcGxlc19saXN0IDwtIEhHU3JlZk11dFNpZ19zYW1wbGVzJFR1bW91cl9TYW1wbGUKZm9yIChIR1NyZWZNdXRTaWcgaW4gSEdTcmVmTXV0U2lnX3NhbXBsZXNfbGlzdCl7CiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfc2FtcGxlIDwtIGZpbHRlcihtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnMiwgVHVtb3VyX1NhbXBsZSVpbiVIR1NyZWZNdXRTaWcpICU+JSAKICAgICAgbXV0YXRlKEdyb3VwID0gSEdTcmVmTXV0U2lnKQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zYW1wbGUgPC0gYmluZF9yb3dzKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWcxLG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19zYW1wbGUpCiAgICAKICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc2FtcGxlJEV4cG9zdXJlcyA8LSByZXBsYWNlKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc2FtcGxlJEV4cG9zdXJlcywgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zYW1wbGUkRXhwb3N1cmVzPT0xLCAwLjk5OTk5OTkpCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRHcm91cCA8LSBhcy5mYWN0b3IobXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zYW1wbGUkR3JvdXApCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRTb2x1X1NhbXBsZSA8LSBwYXN0ZShtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRTb2x1dGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc2FtcGxlJFR1bW91cl9TYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IjoiKSAlPiUgCiAgICAgIGFzLmZhY3RvcigpCiAgICBtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRUdW1vdXJfU2FtcGxlIDwtIGFzLmZhY3RvcihtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRUdW1vdXJfU2FtcGxlKQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zYW1wbGUkU29sdXRpb24gPC0gYXMuZmFjdG9yKG11dF9zaWdfU0lHTkFMX2V4cG9zdXJlc19IR1NyZWZNdXRTaWdfc2FtcGxlJFNvbHV0aW9uKQogICAgbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZ19zYW1wbGUkU2lnbmF0dXJlIDwtIGFzLmZhY3RvcihtdXRfc2lnX1NJR05BTF9leHBvc3VyZXNfSEdTcmVmTXV0U2lnX3NhbXBsZSRTaWduYXR1cmUpCiAgICAKICAgIG11dF9zaWdfbWl4ZWRfbG1lcl9iaW5fSEdTcmVmTXV0U2lnX3NhbXBsZSA8LSBnbG1tVE1CKEV4cG9zdXJlcyB+IEFnZSArIEdyb3VwICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxfFNvbHVfU2FtcGxlKSArICgxfFNpZ25hdHVyZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXV0X3NpZ19TSUdOQUxfZXhwb3N1cmVzX0hHU3JlZk11dFNpZzFfMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9YmV0YV9mYW1pbHkoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6aWZvcm11bGEgPSB+MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1tVE1CQ29udHJvbChwYXJhbGxlbCA9IDQ4KQogICAgKQogICAgc2ltcmVzX211dF9zaWdfbWl4ZWRfbG1lcl9iaW5fSEdTcmVmTXV0U2lnX3NhbXBsZSA8LSBzaW11bGF0ZVJlc2lkdWFscyhtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZ19zYW1wbGUpCiAgICBzaW5rKGZpbGU9KHBhc3RlKGBIR1NyZWZNdXRTaWdgLCJfdnNfSEdTcmVmTXV0U2lnX1NJR05BTF9sbWVyX2Jpbl9zaW1SZXNfcmVzdWx0cy50eHQiLHNlcD0iIikpLGFwcGVuZCA9IEZBTFNFKQogICAgcGRmKHBhc3RlKGBIR1NyZWZNdXRTaWdgLCJfdnNfSEdTcmVmTXV0U2lnX1NJR05BTF9sbWVyX2Jpbl9zaW1SZXNfcmVzdWx0cy5wZGYiLHNlcD0iIikpCiAgICBwcmludChIR1NyZWZNdXRTaWdUZXN0KQogICAgc3VtbWFyeShtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZ19zYW1wbGUpICU+JSBwcmludCgpCiAgICBwbG90KHNpbXJlc19tdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZ19zYW1wbGUpCiAgICB0ZXN0RGlzcGVyc2lvbihzaW1yZXNfbXV0X3NpZ19taXhlZF9sbWVyX2Jpbl9IR1NyZWZNdXRTaWdfc2FtcGxlKSAlPiUgcHJpbnQoKQogICAgdGVzdFVuaWZvcm1pdHkoc2ltcmVzX211dF9zaWdfbWl4ZWRfbG1lcl9iaW5fSEdTcmVmTXV0U2lnX3NhbXBsZSkgJT4lIHByaW50KCkKICAgIHRlc3RPdXRsaWVycyhzaW1yZXNfbXV0X3NpZ19taXhlZF9sbWVyX2Jpbl9IR1NyZWZNdXRTaWdfc2FtcGxlLHR5cGU9ImJvb3RzdHJhcCIpICU+JSBwcmludCgpCiAgICB0ZXN0WmVyb0luZmxhdGlvbihzaW1yZXNfbXV0X3NpZ19taXhlZF9sbWVyX2Jpbl9IR1NyZWZNdXRTaWdfc2FtcGxlKSAlPiUgcHJpbnQoKQogICAgcGxvdFJlc2lkdWFscyhzaW1yZXNfbXV0X3NpZ19taXhlZF9sbWVyX2Jpbl9IR1NyZWZNdXRTaWdfc2FtcGxlLCBtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZ19zYW1wbGUkR3JvdXApCiAgICBzaW5rKCkKICAgIHNpbmsoZmlsZT0idGVzdFNhbXBsZXNfdnNfSEdTcmVmTXV0U2lnX1NJR05BTF9sbWVyX2Jpbl9hbGxfcF92YWx1ZXMudHh0IixhcHBlbmQgPSBUUlVFKQogICAgcHJpbnQoSEdTcmVmTXV0U2lnKQogICAgcHJpbnQoSEdTcmVmTXV0U2lnVGVzdCkKICAgIHByaW50KGNvZWYoc3VtbWFyeShtdXRfc2lnX21peGVkX2xtZXJfYmluX0hHU3JlZk11dFNpZ19zYW1wbGUpKSRjb25kKQogICAgc2luaygpCn0KY2xvc2VBbGxDb25uZWN0aW9ucygpCmBgYAo=