DMC analysis

We will perform for the TCGA-BRCA data set DMC analysis using a two-tailed t-test and one-tailed t-test to compare the results.

library(ELMER)

# Reload TCGA BRCA dataset
load("~/paper_elmer/mae_BRCA_hg38_450K_no_ffpe.rda")

# one tailed test: probes hypo methylated in group1 vs group2
Hypo.probe <- get.diff.meth(mae, 
                            diff.dir="hypo",
                            minSubgroupFrac = 1,
                            group.col = "definition", 
                            group1 = "Primary solid Tumor", 
                            group2 = "Solid Tissue Normal",
                            sig.dif = 0.3) # get hypomethylated probes

# one tailed test: probes hyper methylated in group1 vs group2
Hyper.probe <- get.diff.meth(mae, 
                             diff.dir="hyper",
                             minSubgroupFrac = 1,
                             group.col = "definition", 
                             group1 = "Primary solid Tumor", 
                             group2 = "Solid Tissue Normal",
                             sig.dif = 0.3) # get hypermethylated probes

# two tailed test: probes differently methylated in group1 vs group2
diff.probe <- get.diff.meth(mae, 
                            diff.dir= "both",
                            minSubgroupFrac = 1,
                            group.col = "definition", 
                            group1 = "Primary solid Tumor", 
                            group2 = "Solid Tissue Normal",
                            sig.dif = 0.3) # get differentlly methylated probes

Results

Hypo.probe
Hyper.probe
diff.probe

Volcano plots

One tailed test

One tailed test - Hypermethylated probes

One tailed test - Hypermethylated probes

One tailed test - Hypomethylated probes

One tailed test - Hypomethylated probes

Two tailed test

Two tailed test - Differently methylated probes

Two tailed test - Differently methylated probes

Number of probes identified

df <- t(data.frame("Hypomethylated probes [one-tailed]" = length(Hypo.probe$probe),
           "Hypermethylated probes  [one-tailed]" = length(Hyper.probe$probe),
           "Differently methylated probes  [two-tailed]" = length(diff.probe$probe)))
colnames(df) <- "# probes"
as.data.frame(df)

Intersection of probes identified

Here we check that all our probes identified by two-tailed t-test the same of the two one-tailed t-test.

# Are all hypo methylated probes identified using a one-tailed test also found using the two-tailed test? 
table(Hypo.probe$probe %in% diff.probe$probe)

TRUE 
1446 
# Are all hypermethylated probes identified using a one-tailed test also found using the two-tailed test? 
table(Hyper.probe$probe %in% diff.probe$probe) 

TRUE 
1077 
# Are all differently methylated probes identified using two-tailed test also found using two one-tailed test? 
all(diff.probe$probe %in% c(Hyper.probe$probe,Hypo.probe$probe)) 
[1] TRUE

Check p-values dissimilarity of significant probes (Euclidian distnace - 0 means equal)

df <- t(data.frame(
        as.numeric(dist(rbind(diff.probe[Hypo.probe$probe,]$pvalue, Hypo.probe$pvalue))),
        as.numeric(dist(rbind(diff.probe[Hypo.probe$probe,]$adjust.p, Hypo.probe$adjust.p))),
        as.numeric(dist(rbind(diff.probe[Hyper.probe$probe,]$pvalue, Hyper.probe$pvalue))), 
        as.numeric(dist(rbind(diff.probe[Hyper.probe$probe,]$adjust.p, Hyper.probe$adjust.p)))
))
colnames(df) <- "distance"
rownames(df) <- c("eucledian distance pvalue hypomethylated probes [two-tailed vs one tailed test]",
                  "eucledian distance pvalue adjusted hypomethylated probes [two-tailed vs one tailed test]",
                  "eucledian distance pvalues hypermethylated probes [two-tailed vs one tailed test]",
                  "eucledian distance pvalues adjusted hypermethylated probes [two-tailed vs one tailed test]")
as.data.frame(df)

Check difference of all probes p-values

The plot below shows that the difference of the raw pvalues for the significant probes is really low and would not affect which were selected the significant probes.

Raw p-values

data <- data.frame(probe = one_tailed_hypo$probe,
                  x = one_tailed_hypo$pvalue,
                  significant = as.factor(ifelse(one_tailed_hypo$probe %in% Hypo.probe$probe, "Significant","Insignificant")) ,
                  y = abs(two_tailed[match(one_tailed_hypo$probe,two_tailed$probe),]$pvalue-one_tailed_hypo$pvalue))
data <- subset(data, x < 0.5)
data$y <- -log10(data$y)
data$x <- -log10(data$x)
ggplot(data,aes(x=x,
                y=y,
                shape = significant,
                color = significant)) + 
  geom_point() + 
  geom_point(data = subset(data, significant == 'Significant'),   
             aes(x = x, 
                 y = y, 
                 color = significant)
             ) +
  theme_bw() + 
  scale_color_manual(values = c("Significant" = '#ff0000',
                                'Insignificant' = '#000000'),
                     name = "Probe identified as:") + 
  scale_shape_manual(values = c('Significant' = 17, 
                                'Insignificant' = 16),
                     name="Probe identified as:") +
  labs(title = "Comparing one-tailed  (hypo direction) and two-tailed raw-pvalues",
       subtitle = "Showing only probes raw p-value < 0.5.",
       y = "-log10(Difference of raw p-values Two-tailed t-test - One tailed t-test)", 
       x = "-log10(Raw P-value - One tailed t-test)") 

data <- data.frame(probe = one_tailed_hyper$probe,
                  x = one_tailed_hyper$pvalue,
                  significant = as.factor(ifelse(one_tailed_hyper$probe %in% Hyper.probe$probe, "Significant","Insignificant")) ,
                  y = abs(two_tailed[match(one_tailed_hyper$probe,two_tailed$probe),]$pvalue-one_tailed_hyper$pvalue))
data <- subset(data, x < 0.5)
data$y <- -log10(data$y)
data$x <- -log10(data$x)
ggplot(data,aes(x=x,
                y=y,
                shape = significant,
                color = significant)) + 
  geom_point() + 
  geom_point(data = subset(data, significant == 'Significant'),   
             aes(x = x, 
                 y = y, 
                 color = significant)
             ) +
  theme_bw() + 
  scale_color_manual(values = c("Significant" = '#ff0000',
                                'Insignificant' = '#000000'),
                     name = "Probe identified as:") + 
  scale_shape_manual(values = c('Significant' = 17, 
                                'Insignificant' = 16),
                     name="Probe identified as:") +
  labs(title = "Comparing one-tailed  (hyper direction) and two-tailed raw-pvalues",
       subtitle = "Showing only probes raw p-value < 0.5.",
       y = "-log10(Difference of raw p-values Two-tailed t-test - One tailed t-test)", 
       x = "-log10(Raw P-value - One tailed t-test)") 

Adjusted p-values

data <- data.frame(probe = one_tailed_hypo$probe,
                  x = one_tailed_hypo$adjust.p,
                  significant = as.factor(ifelse(one_tailed_hypo$probe %in% Hypo.probe$probe, "Significant","Insignificant")) ,
                  y = abs(two_tailed[match(one_tailed_hypo$probe,two_tailed$probe),]$adjust.p-one_tailed_hypo$adjust.p))
data <- subset(data, x < 0.5)
data$y <- -log10(data$y)
data$x <- -log10(data$x)
ggplot(data,aes(x=x,
                y=y,
                shape = significant,
                color = significant)) + 
  geom_point() + 
  geom_point(data = subset(data, significant == 'Significant'),   
             aes(x = x, 
                 y = y, 
                 color = significant)
             ) +
  theme_bw() + 
  scale_color_manual(values = c("Significant" = '#ff0000',
                                'Insignificant' = '#000000'),
                     name = "Probe identified as:") + 
  scale_shape_manual(values = c('Significant' = 17, 
                                'Insignificant' = 16),
                     name="Probe identified as:") +
  geom_vline(xintercept=-log10(0.01), linetype="dashed", color = "blue") +
  labs(title = "Comparing one-tailed  (hypo direction) and two-tailed adjusted-pvalues",
       subtitle = "Showing only probes adjusted p-value < 0.5. Dashed blue line: 0.01 cut-off",
       y = "-log10(|Difference of raw p-values Two-tailed t-test - One tailed t-test|)", 
       x = "-log10(Adjusted P-value - One tailed t-test)") 

data <- data.frame(probe = one_tailed_hyper$probe,
                  x = one_tailed_hyper$adjust.p,
                  significant = as.factor(ifelse(one_tailed_hyper$probe %in% Hyper.probe$probe, "Significant","Insignificant")) ,
                  y = abs(two_tailed[match(one_tailed_hyper$probe,two_tailed$probe),]$adjust.p-one_tailed_hyper$adjust.p))
data <- subset(data, x < 0.5)
data$y <- -log10(data$y)
data$x <- -log10(data$x)
ggplot(data,aes(x=x,
                y=y,
                shape = significant,
                color = significant)) + 
  geom_point() + 
  geom_point(data = subset(data, significant == 'Significant'),   
             aes(x = x, 
                 y = y, 
                 color = significant)
             ) +
  theme_bw() + 
  scale_color_manual(values = c("Significant" = '#ff0000',
                                'Insignificant' = '#000000'),
                     name = "Probe identified as:") + 
  scale_shape_manual(values = c('Significant' = 17, 
                                'Insignificant' = 16),
                     name="Probe identified as:") +
  geom_vline(xintercept=-log10(0.01), linetype="dashed", color = "blue") +
  labs(title = "Comparing one-tailed  (hyper direction) and two-tailed adjusted-pvalues",
       subtitle = "Showing only probes adjusted p-value < 0.5. Dashed blue line: 0.01 cut-off",
       y = "-log10(|Difference of raw p-values Two-tailed t-test - One tailed t-test|)", 
       x = "-log10(Adjusted P-value - One tailed t-test)") 

Check difference of mean DNA methylation

range(diff.probe$Primary.solid.Tumor_Minus_Solid.Tissue.Normal)
[1] -0.4839175  0.5459320
range(Hyper.probe$Primary.solid.Tumor_Minus_Solid.Tissue.Normal)
[1] 0.3000309 0.5459320
range(Hypo.probe$Primary.solid.Tumor_Minus_Solid.Tissue.Normal)
[1] -0.4839175 -0.3000173
LS0tCnRpdGxlOiAiRUxNRVIgLSB0d28tdGFpbGVkIHZzIG9uZS10YWlsZWQgdGVzdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBETUMgYW5hbHlzaXMKCldlIHdpbGwgcGVyZm9ybSBmb3IgdGhlIFRDR0EtQlJDQSBkYXRhIHNldCBETUMgYW5hbHlzaXMgdXNpbmcgYSB0d28tdGFpbGVkIHQtdGVzdCBhbmQgb25lLXRhaWxlZCB0LXRlc3QgdG8gY29tcGFyZSB0aGUgcmVzdWx0cy4KCmBgYHtyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KEVMTUVSKQoKIyBSZWxvYWQgVENHQSBCUkNBIGRhdGFzZXQKbG9hZCgifi9wYXBlcl9lbG1lci9tYWVfQlJDQV9oZzM4XzQ1MEtfbm9fZmZwZS5yZGEiKQoKIyBvbmUgdGFpbGVkIHRlc3Q6IHByb2JlcyBoeXBvIG1ldGh5bGF0ZWQgaW4gZ3JvdXAxIHZzIGdyb3VwMgpIeXBvLnByb2JlIDwtIGdldC5kaWZmLm1ldGgobWFlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYuZGlyPSJoeXBvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblN1Ymdyb3VwRnJhYyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5jb2wgPSAiZGVmaW5pdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAxID0gIlByaW1hcnkgc29saWQgVHVtb3IiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMiA9ICJTb2xpZCBUaXNzdWUgTm9ybWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZy5kaWYgPSAwLjMpICMgZ2V0IGh5cG9tZXRoeWxhdGVkIHByb2JlcwoKIyBvbmUgdGFpbGVkIHRlc3Q6IHByb2JlcyBoeXBlciBtZXRoeWxhdGVkIGluIGdyb3VwMSB2cyBncm91cDIKSHlwZXIucHJvYmUgPC0gZ2V0LmRpZmYubWV0aChtYWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYuZGlyPSJoeXBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluU3ViZ3JvdXBGcmFjID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5jb2wgPSAiZGVmaW5pdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMSA9ICJQcmltYXJ5IHNvbGlkIFR1bW9yIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAyID0gIlNvbGlkIFRpc3N1ZSBOb3JtYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZy5kaWYgPSAwLjMpICMgZ2V0IGh5cGVybWV0aHlsYXRlZCBwcm9iZXMKCiMgdHdvIHRhaWxlZCB0ZXN0OiBwcm9iZXMgZGlmZmVyZW50bHkgbWV0aHlsYXRlZCBpbiBncm91cDEgdnMgZ3JvdXAyCmRpZmYucHJvYmUgPC0gZ2V0LmRpZmYubWV0aChtYWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZi5kaXI9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblN1Ymdyb3VwRnJhYyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5jb2wgPSAiZGVmaW5pdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAxID0gIlByaW1hcnkgc29saWQgVHVtb3IiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMiA9ICJTb2xpZCBUaXNzdWUgTm9ybWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZy5kaWYgPSAwLjMpICMgZ2V0IGRpZmZlcmVudGxseSBtZXRoeWxhdGVkIHByb2JlcwpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpsb2FkKGZpbGUgPSAidGVzdC5yZGEiKQpsaWJyYXJ5KHJlYWRyKQp0d29fdGFpbGVkIDwtIHJlYWRfY3N2KCJnZXRNZXRoZGlmZi5ib3RoLnByb2Jlcy5jc3YiKQpvbmVfdGFpbGVkX2h5cGVyIDwtIHJlYWRfY3N2KCJnZXRNZXRoZGlmZi5oeXBlci5wcm9iZXMuY3N2IikKb25lX3RhaWxlZF9oeXBvIDwtIHJlYWRfY3N2KCJnZXRNZXRoZGlmZi5oeXBvLnByb2Jlcy5jc3YiKQpgYGAKCiMjIFJlc3VsdHMKYGBge3J9Ckh5cG8ucHJvYmUKSHlwZXIucHJvYmUKZGlmZi5wcm9iZQpgYGAKCiMjIFZvbGNhbm8gcGxvdHMKIyMjIE9uZSB0YWlsZWQgdGVzdAohW09uZSB0YWlsZWQgdGVzdCAtIEh5cGVybWV0aHlsYXRlZCBwcm9iZXNdKHZvbGNhbm9QbG90LnByb2Jlcy5oeXBlci5wbmcpCgohW09uZSB0YWlsZWQgdGVzdCAtIEh5cG9tZXRoeWxhdGVkIHByb2Jlc10odm9sY2Fub1Bsb3QucHJvYmVzLmh5cG8ucG5nKQoKIyMjIFR3byB0YWlsZWQgdGVzdCAKCiFbVHdvIHRhaWxlZCB0ZXN0IC0gRGlmZmVyZW50bHkgbWV0aHlsYXRlZCBwcm9iZXNdKHZvbGNhbm9QbG90LnByb2Jlcy50d29fdGFpbGVkLnBuZykKCgojIyBOdW1iZXIgb2YgcHJvYmVzIGlkZW50aWZpZWQKYGBge3IsIGNvbHMucHJpbnQ9MjB9CmRmIDwtIHQoZGF0YS5mcmFtZSgiSHlwb21ldGh5bGF0ZWQgcHJvYmVzIFtvbmUtdGFpbGVkXSIgPSBsZW5ndGgoSHlwby5wcm9iZSRwcm9iZSksCiAgICAgICAgICAgIkh5cGVybWV0aHlsYXRlZCBwcm9iZXMgIFtvbmUtdGFpbGVkXSIgPSBsZW5ndGgoSHlwZXIucHJvYmUkcHJvYmUpLAogICAgICAgICAgICJEaWZmZXJlbnRseSBtZXRoeWxhdGVkIHByb2JlcyAgW3R3by10YWlsZWRdIiA9IGxlbmd0aChkaWZmLnByb2JlJHByb2JlKSkpCmNvbG5hbWVzKGRmKSA8LSAiIyBwcm9iZXMiCmFzLmRhdGEuZnJhbWUoZGYpCmBgYAoKIyMgSW50ZXJzZWN0aW9uIG9mIHByb2JlcyBpZGVudGlmaWVkCgpIZXJlIHdlIGNoZWNrIHRoYXQgYWxsIG91ciBwcm9iZXMgaWRlbnRpZmllZCBieSB0d28tdGFpbGVkIHQtdGVzdCB0aGUgc2FtZSBvZiB0aGUgdHdvIG9uZS10YWlsZWQgdC10ZXN0LiAKCmBgYHtyLCBjb2xzLnByaW50PTIwfQojIEFyZSBhbGwgaHlwbyBtZXRoeWxhdGVkIHByb2JlcyBpZGVudGlmaWVkIHVzaW5nIGEgb25lLXRhaWxlZCB0ZXN0IGFsc28gZm91bmQgdXNpbmcgdGhlIHR3by10YWlsZWQgdGVzdD8gCnRhYmxlKEh5cG8ucHJvYmUkcHJvYmUgJWluJSBkaWZmLnByb2JlJHByb2JlKQojIEFyZSBhbGwgaHlwZXJtZXRoeWxhdGVkIHByb2JlcyBpZGVudGlmaWVkIHVzaW5nIGEgb25lLXRhaWxlZCB0ZXN0IGFsc28gZm91bmQgdXNpbmcgdGhlIHR3by10YWlsZWQgdGVzdD8gCnRhYmxlKEh5cGVyLnByb2JlJHByb2JlICVpbiUgZGlmZi5wcm9iZSRwcm9iZSkgCiMgQXJlIGFsbCBkaWZmZXJlbnRseSBtZXRoeWxhdGVkIHByb2JlcyBpZGVudGlmaWVkIHVzaW5nIHR3by10YWlsZWQgdGVzdCBhbHNvIGZvdW5kIHVzaW5nIHR3byBvbmUtdGFpbGVkIHRlc3Q/IAphbGwoZGlmZi5wcm9iZSRwcm9iZSAlaW4lIGMoSHlwZXIucHJvYmUkcHJvYmUsSHlwby5wcm9iZSRwcm9iZSkpIApgYGAKCiMjIENoZWNrIHAtdmFsdWVzICBkaXNzaW1pbGFyaXR5IG9mIHNpZ25pZmljYW50IHByb2JlcyAoRXVjbGlkaWFuIGRpc3RuYWNlIC0gMCBtZWFucyBlcXVhbCkKYGBge3IsIGNvbHMucHJpbnQ9MjB9CmRmIDwtIHQoZGF0YS5mcmFtZSgKICAgICAgICBhcy5udW1lcmljKGRpc3QocmJpbmQoZGlmZi5wcm9iZVtIeXBvLnByb2JlJHByb2JlLF0kcHZhbHVlLCBIeXBvLnByb2JlJHB2YWx1ZSkpKSwKICAgICAgICBhcy5udW1lcmljKGRpc3QocmJpbmQoZGlmZi5wcm9iZVtIeXBvLnByb2JlJHByb2JlLF0kYWRqdXN0LnAsIEh5cG8ucHJvYmUkYWRqdXN0LnApKSksCiAgICAgICAgYXMubnVtZXJpYyhkaXN0KHJiaW5kKGRpZmYucHJvYmVbSHlwZXIucHJvYmUkcHJvYmUsXSRwdmFsdWUsIEh5cGVyLnByb2JlJHB2YWx1ZSkpKSwgCiAgICAgICAgYXMubnVtZXJpYyhkaXN0KHJiaW5kKGRpZmYucHJvYmVbSHlwZXIucHJvYmUkcHJvYmUsXSRhZGp1c3QucCwgSHlwZXIucHJvYmUkYWRqdXN0LnApKSkKKSkKY29sbmFtZXMoZGYpIDwtICJkaXN0YW5jZSIKcm93bmFtZXMoZGYpIDwtIGMoImV1Y2xlZGlhbiBkaXN0YW5jZSBwdmFsdWUgaHlwb21ldGh5bGF0ZWQgcHJvYmVzIFt0d28tdGFpbGVkIHZzIG9uZSB0YWlsZWQgdGVzdF0iLAogICAgICAgICAgICAgICAgICAiZXVjbGVkaWFuIGRpc3RhbmNlIHB2YWx1ZSBhZGp1c3RlZCBoeXBvbWV0aHlsYXRlZCBwcm9iZXMgW3R3by10YWlsZWQgdnMgb25lIHRhaWxlZCB0ZXN0XSIsCiAgICAgICAgICAgICAgICAgICJldWNsZWRpYW4gZGlzdGFuY2UgcHZhbHVlcyBoeXBlcm1ldGh5bGF0ZWQgcHJvYmVzIFt0d28tdGFpbGVkIHZzIG9uZSB0YWlsZWQgdGVzdF0iLAogICAgICAgICAgICAgICAgICAiZXVjbGVkaWFuIGRpc3RhbmNlIHB2YWx1ZXMgYWRqdXN0ZWQgaHlwZXJtZXRoeWxhdGVkIHByb2JlcyBbdHdvLXRhaWxlZCB2cyBvbmUgdGFpbGVkIHRlc3RdIikKYXMuZGF0YS5mcmFtZShkZikKYGBgCgojIyAgQ2hlY2sgZGlmZmVyZW5jZSBvZiBhbGwgcHJvYmVzIHAtdmFsdWVzCgpUaGUgcGxvdCBiZWxvdyBzaG93cyB0aGF0IHRoZSBkaWZmZXJlbmNlIG9mIHRoZSByYXcgcHZhbHVlcyBmb3IgdGhlIHNpZ25pZmljYW50IHByb2JlcyBpcyByZWFsbHkgbG93IGFuZCB3b3VsZCBub3QgYWZmZWN0IHdoaWNoIHdlcmUgc2VsZWN0ZWQgdGhlIHNpZ25pZmljYW50IHByb2Jlcy4KCiMjIyBSYXcgcC12YWx1ZXMKYGBge3IsZmlnLmhlaWdodD03fQpkYXRhIDwtIGRhdGEuZnJhbWUocHJvYmUgPSBvbmVfdGFpbGVkX2h5cG8kcHJvYmUsCiAgICAgICAgICAgICAgICAgIHggPSBvbmVfdGFpbGVkX2h5cG8kcHZhbHVlLAogICAgICAgICAgICAgICAgICBzaWduaWZpY2FudCA9IGFzLmZhY3RvcihpZmVsc2Uob25lX3RhaWxlZF9oeXBvJHByb2JlICVpbiUgSHlwby5wcm9iZSRwcm9iZSwgIlNpZ25pZmljYW50IiwiSW5zaWduaWZpY2FudCIpKSAsCiAgICAgICAgICAgICAgICAgIHkgPSBhYnModHdvX3RhaWxlZFttYXRjaChvbmVfdGFpbGVkX2h5cG8kcHJvYmUsdHdvX3RhaWxlZCRwcm9iZSksXSRwdmFsdWUtb25lX3RhaWxlZF9oeXBvJHB2YWx1ZSkpCgpkYXRhIDwtIHN1YnNldChkYXRhLCB4IDwgMC41KQpkYXRhJHkgPC0gLWxvZzEwKGRhdGEkeSkKZGF0YSR4IDwtIC1sb2cxMChkYXRhJHgpCgpnZ3Bsb3QoZGF0YSxhZXMoeD14LAogICAgICAgICAgICAgICAgeT15LAogICAgICAgICAgICAgICAgc2hhcGUgPSBzaWduaWZpY2FudCwKICAgICAgICAgICAgICAgIGNvbG9yID0gc2lnbmlmaWNhbnQpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChkYXRhLCBzaWduaWZpY2FudCA9PSAnU2lnbmlmaWNhbnQnKSwgICAKICAgICAgICAgICAgIGFlcyh4ID0geCwgCiAgICAgICAgICAgICAgICAgeSA9IHksIAogICAgICAgICAgICAgICAgIGNvbG9yID0gc2lnbmlmaWNhbnQpCiAgICAgICAgICAgICApICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlNpZ25pZmljYW50IiA9ICcjZmYwMDAwJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSW5zaWduaWZpY2FudCcgPSAnIzAwMDAwMCcpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlByb2JlIGlkZW50aWZpZWQgYXM6IikgKyAKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygnU2lnbmlmaWNhbnQnID0gMTcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJbnNpZ25pZmljYW50JyA9IDE2KSwKICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUHJvYmUgaWRlbnRpZmllZCBhczoiKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJpbmcgb25lLXRhaWxlZCAgKGh5cG8gZGlyZWN0aW9uKSBhbmQgdHdvLXRhaWxlZCByYXctcHZhbHVlcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJTaG93aW5nIG9ubHkgcHJvYmVzIHJhdyBwLXZhbHVlIDwgMC41LiIsCiAgICAgICB5ID0gIi1sb2cxMChEaWZmZXJlbmNlIG9mIHJhdyBwLXZhbHVlcyBUd28tdGFpbGVkIHQtdGVzdCAtIE9uZSB0YWlsZWQgdC10ZXN0KSIsIAogICAgICAgeCA9ICItbG9nMTAoUmF3IFAtdmFsdWUgLSBPbmUgdGFpbGVkIHQtdGVzdCkiKSAKCmRhdGEgPC0gZGF0YS5mcmFtZShwcm9iZSA9IG9uZV90YWlsZWRfaHlwZXIkcHJvYmUsCiAgICAgICAgICAgICAgICAgIHggPSBvbmVfdGFpbGVkX2h5cGVyJHB2YWx1ZSwKICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBhcy5mYWN0b3IoaWZlbHNlKG9uZV90YWlsZWRfaHlwZXIkcHJvYmUgJWluJSBIeXBlci5wcm9iZSRwcm9iZSwgIlNpZ25pZmljYW50IiwiSW5zaWduaWZpY2FudCIpKSAsCiAgICAgICAgICAgICAgICAgIHkgPSBhYnModHdvX3RhaWxlZFttYXRjaChvbmVfdGFpbGVkX2h5cGVyJHByb2JlLHR3b190YWlsZWQkcHJvYmUpLF0kcHZhbHVlLW9uZV90YWlsZWRfaHlwZXIkcHZhbHVlKSkKCmRhdGEgPC0gc3Vic2V0KGRhdGEsIHggPCAwLjUpCmRhdGEkeSA8LSAtbG9nMTAoZGF0YSR5KQpkYXRhJHggPC0gLWxvZzEwKGRhdGEkeCkKCmdncGxvdChkYXRhLGFlcyh4PXgsCiAgICAgICAgICAgICAgICB5PXksCiAgICAgICAgICAgICAgICBzaGFwZSA9IHNpZ25pZmljYW50LAogICAgICAgICAgICAgICAgY29sb3IgPSBzaWduaWZpY2FudCkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KGRhdGEsIHNpZ25pZmljYW50ID09ICdTaWduaWZpY2FudCcpLCAgIAogICAgICAgICAgICAgYWVzKHggPSB4LCAKICAgICAgICAgICAgICAgICB5ID0geSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzaWduaWZpY2FudCkKICAgICAgICAgICAgICkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiU2lnbmlmaWNhbnQiID0gJyNmZjAwMDAnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJbnNpZ25pZmljYW50JyA9ICcjMDAwMDAwJyksCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUHJvYmUgaWRlbnRpZmllZCBhczoiKSArIAogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCdTaWduaWZpY2FudCcgPSAxNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0luc2lnbmlmaWNhbnQnID0gMTYpLAogICAgICAgICAgICAgICAgICAgICBuYW1lPSJQcm9iZSBpZGVudGlmaWVkIGFzOiIpICsKICBsYWJzKHRpdGxlID0gIkNvbXBhcmluZyBvbmUtdGFpbGVkICAoaHlwZXIgZGlyZWN0aW9uKSBhbmQgdHdvLXRhaWxlZCByYXctcHZhbHVlcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJTaG93aW5nIG9ubHkgcHJvYmVzIHJhdyBwLXZhbHVlIDwgMC41LiIsCiAgICAgICB5ID0gIi1sb2cxMChEaWZmZXJlbmNlIG9mIHJhdyBwLXZhbHVlcyBUd28tdGFpbGVkIHQtdGVzdCAtIE9uZSB0YWlsZWQgdC10ZXN0KSIsIAogICAgICAgeCA9ICItbG9nMTAoUmF3IFAtdmFsdWUgLSBPbmUgdGFpbGVkIHQtdGVzdCkiKSAKCmBgYAoKIyMjIEFkanVzdGVkIHAtdmFsdWVzCmBgYHtyLGZpZy5oZWlnaHQ9N30KZGF0YSA8LSBkYXRhLmZyYW1lKHByb2JlID0gb25lX3RhaWxlZF9oeXBvJHByb2JlLAogICAgICAgICAgICAgICAgICB4ID0gb25lX3RhaWxlZF9oeXBvJGFkanVzdC5wLAogICAgICAgICAgICAgICAgICBzaWduaWZpY2FudCA9IGFzLmZhY3RvcihpZmVsc2Uob25lX3RhaWxlZF9oeXBvJHByb2JlICVpbiUgSHlwby5wcm9iZSRwcm9iZSwgIlNpZ25pZmljYW50IiwiSW5zaWduaWZpY2FudCIpKSAsCiAgICAgICAgICAgICAgICAgIHkgPSBhYnModHdvX3RhaWxlZFttYXRjaChvbmVfdGFpbGVkX2h5cG8kcHJvYmUsdHdvX3RhaWxlZCRwcm9iZSksXSRhZGp1c3QucC1vbmVfdGFpbGVkX2h5cG8kYWRqdXN0LnApKQoKZGF0YSA8LSBzdWJzZXQoZGF0YSwgeCA8IDAuNSkKZGF0YSR5IDwtIC1sb2cxMChkYXRhJHkpCmRhdGEkeCA8LSAtbG9nMTAoZGF0YSR4KQoKZ2dwbG90KGRhdGEsYWVzKHg9eCwKICAgICAgICAgICAgICAgIHk9eSwKICAgICAgICAgICAgICAgIHNoYXBlID0gc2lnbmlmaWNhbnQsCiAgICAgICAgICAgICAgICBjb2xvciA9IHNpZ25pZmljYW50KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzdWJzZXQoZGF0YSwgc2lnbmlmaWNhbnQgPT0gJ1NpZ25pZmljYW50JyksICAgCiAgICAgICAgICAgICBhZXMoeCA9IHgsIAogICAgICAgICAgICAgICAgIHkgPSB5LCAKICAgICAgICAgICAgICAgICBjb2xvciA9IHNpZ25pZmljYW50KQogICAgICAgICAgICAgKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJTaWduaWZpY2FudCIgPSAnI2ZmMDAwMCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0luc2lnbmlmaWNhbnQnID0gJyMwMDAwMDAnKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJQcm9iZSBpZGVudGlmaWVkIGFzOiIpICsgCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoJ1NpZ25pZmljYW50JyA9IDE3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSW5zaWduaWZpY2FudCcgPSAxNiksCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlByb2JlIGlkZW50aWZpZWQgYXM6IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0tbG9nMTAoMC4wMSksIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJibHVlIikgKwogIGxhYnModGl0bGUgPSAiQ29tcGFyaW5nIG9uZS10YWlsZWQgIChoeXBvIGRpcmVjdGlvbikgYW5kIHR3by10YWlsZWQgYWRqdXN0ZWQtcHZhbHVlcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJTaG93aW5nIG9ubHkgcHJvYmVzIGFkanVzdGVkIHAtdmFsdWUgPCAwLjUuIERhc2hlZCBibHVlIGxpbmU6IDAuMDEgY3V0LW9mZiIsCiAgICAgICB5ID0gIi1sb2cxMCh8RGlmZmVyZW5jZSBvZiByYXcgcC12YWx1ZXMgVHdvLXRhaWxlZCB0LXRlc3QgLSBPbmUgdGFpbGVkIHQtdGVzdHwpIiwgCiAgICAgICB4ID0gIi1sb2cxMChBZGp1c3RlZCBQLXZhbHVlIC0gT25lIHRhaWxlZCB0LXRlc3QpIikgCgpkYXRhIDwtIGRhdGEuZnJhbWUocHJvYmUgPSBvbmVfdGFpbGVkX2h5cGVyJHByb2JlLAogICAgICAgICAgICAgICAgICB4ID0gb25lX3RhaWxlZF9oeXBlciRhZGp1c3QucCwKICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBhcy5mYWN0b3IoaWZlbHNlKG9uZV90YWlsZWRfaHlwZXIkcHJvYmUgJWluJSBIeXBlci5wcm9iZSRwcm9iZSwgIlNpZ25pZmljYW50IiwiSW5zaWduaWZpY2FudCIpKSAsCiAgICAgICAgICAgICAgICAgIHkgPSBhYnModHdvX3RhaWxlZFttYXRjaChvbmVfdGFpbGVkX2h5cGVyJHByb2JlLHR3b190YWlsZWQkcHJvYmUpLF0kYWRqdXN0LnAtb25lX3RhaWxlZF9oeXBlciRhZGp1c3QucCkpCgpkYXRhIDwtIHN1YnNldChkYXRhLCB4IDwgMC41KQpkYXRhJHkgPC0gLWxvZzEwKGRhdGEkeSkKZGF0YSR4IDwtIC1sb2cxMChkYXRhJHgpCgpnZ3Bsb3QoZGF0YSxhZXMoeD14LAogICAgICAgICAgICAgICAgeT15LAogICAgICAgICAgICAgICAgc2hhcGUgPSBzaWduaWZpY2FudCwKICAgICAgICAgICAgICAgIGNvbG9yID0gc2lnbmlmaWNhbnQpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChkYXRhLCBzaWduaWZpY2FudCA9PSAnU2lnbmlmaWNhbnQnKSwgICAKICAgICAgICAgICAgIGFlcyh4ID0geCwgCiAgICAgICAgICAgICAgICAgeSA9IHksIAogICAgICAgICAgICAgICAgIGNvbG9yID0gc2lnbmlmaWNhbnQpCiAgICAgICAgICAgICApICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlNpZ25pZmljYW50IiA9ICcjZmYwMDAwJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSW5zaWduaWZpY2FudCcgPSAnIzAwMDAwMCcpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlByb2JlIGlkZW50aWZpZWQgYXM6IikgKyAKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygnU2lnbmlmaWNhbnQnID0gMTcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJbnNpZ25pZmljYW50JyA9IDE2KSwKICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUHJvYmUgaWRlbnRpZmllZCBhczoiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PS1sb2cxMCgwLjAxKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yID0gImJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJpbmcgb25lLXRhaWxlZCAgKGh5cGVyIGRpcmVjdGlvbikgYW5kIHR3by10YWlsZWQgYWRqdXN0ZWQtcHZhbHVlcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJTaG93aW5nIG9ubHkgcHJvYmVzIGFkanVzdGVkIHAtdmFsdWUgPCAwLjUuIERhc2hlZCBibHVlIGxpbmU6IDAuMDEgY3V0LW9mZiIsCiAgICAgICB5ID0gIi1sb2cxMCh8RGlmZmVyZW5jZSBvZiByYXcgcC12YWx1ZXMgVHdvLXRhaWxlZCB0LXRlc3QgLSBPbmUgdGFpbGVkIHQtdGVzdHwpIiwgCiAgICAgICB4ID0gIi1sb2cxMChBZGp1c3RlZCBQLXZhbHVlIC0gT25lIHRhaWxlZCB0LXRlc3QpIikgCgpgYGAKCiMjIENoZWNrIGRpZmZlcmVuY2Ugb2YgbWVhbiBETkEgbWV0aHlsYXRpb24gCmBgYHtyLCBjb2xzLnByaW50PTIwfQpyYW5nZShkaWZmLnByb2JlJFByaW1hcnkuc29saWQuVHVtb3JfTWludXNfU29saWQuVGlzc3VlLk5vcm1hbCkKcmFuZ2UoSHlwZXIucHJvYmUkUHJpbWFyeS5zb2xpZC5UdW1vcl9NaW51c19Tb2xpZC5UaXNzdWUuTm9ybWFsKQpyYW5nZShIeXBvLnByb2JlJFByaW1hcnkuc29saWQuVHVtb3JfTWludXNfU29saWQuVGlzc3VlLk5vcm1hbCkKYGBgCgo=