index.html annotation.html sample_estimations.html

In this document, we will perform a series of differential expression analyses using the data which survived sample estimation.

1 Extract significantly changed genes

My original work in this context was to perform all possible contrasts using the entire data set. After discussion with Najib and Santuza, it was initially agreed that we would use a smaller subset in order to evaluate the methods for DE along with batch effects etc.

## cl_all_kexptv1 comes from sample_estimations when we removed an
## outlier sample (hpgl0490).
cl_all_filt <- sm(normalize_expt(cl_all_kexptv1, filter="cbcb"))
cl_all_de_sva <- sm(all_pairwise(cl_all_filt, model_batch="sva",
                                 which_voom="limma",
                                 edger_method="long"))

2 Choose contrasts to keep and evaluate

I am going to split these results into 3 categories: clbrener analyses over time, cl14 over time, comparisons of the two strains.

clb_times_keepers <- list(
    "clbr_tryp_to_a60" = c("CLBr.A60","CLBr.Tryp"),
##    "clbr_tryp_to_a96" = c("CLBr.A96","CLBr.Tryp"),
    "clbr_a60_to_a96" = c("CLBr.A96","CLBr.A60"),
    "clbr_a96_to_tryp" = c("CLBr.Tryp","CLBr.A96"))
cl14_times_keepers <- list(
    "cl14_tryp_to_a60" = c("CL14.A60","CL14.Tryp"),
##    "cl14_tryp_to_a96" = c("CL14.A96","CL14.Tryp"),
    "cl14_a60_to_a96" = c("CL14.A96","CL14.A60"),
    "cl14_a96_to_tryp" = c("CL14.Tryp","CL14.A96"))
strains_keepers <- list(
    "a60_clbr_over_cl14" = c("CLBr.A60", "CL14.A60"),
    "a96_clbr_over_cl14" = c("CLBr.A96", "CL14.A96"),
    "tryp_clbr_over_cl14" = c("CLBr.Tryp", "CL14.Tryp"))

3 Extract strain comparisons

strain_comparisons <- sm(combine_de_tables(cl_all_de_sva,
                                           excel=paste0("excel/strain_comparisons-v",
                                                        ver, ".xlsx"),
                                           keepers=strains_keepers))
strain_only_limma <- sm(combine_de_tables(cl_all_de_sva,
                                          excel=paste0("excel/strain_comparison_limma-v",
                                                       ver, ".xlsx"),
                                          keepers=strains_keepers,
                                          include_basic=FALSE,
                                          include_deseq=FALSE,
                                          include_edger=FALSE))

4 CLBrener time comparisons

clb_compare_times <- sm(combine_de_tables(cl_all_de_sva,
                                          excel=paste0("excel/clb_compare_times-v",
                                                       ver, ".xlsx"),
                                          keepers=clb_times_keepers))
clb_only_limma <- sm(combine_de_tables(cl_all_de_sva,
                                       excel=paste0("excel/clb_compare_times_limma-v",
                                                    ver, ".xlsx"),
                                       keepers=clb_times_keepers,
                                       include_basic=FALSE,
                                       include_deseq=FALSE,
                                       include_edger=FALSE))

5 CL14 time comparisons

cl14_compare_times <- sm(combine_de_tables(cl_all_de_sva,
                                           excel=paste0("excel/cl14_compare_times-v",
                                                        ver, ".xlsx"),
                                           keepers=cl14_times_keepers))
cl14_only_limma <- sm(combine_de_tables(cl_all_de_sva,
                                        excel=paste0("excel/cl14_compare_times_limma-v",
                                                     ver, ".xlsx"),
                                        keepers=cl14_times_keepers,
                                        include_basic=FALSE,
                                        include_deseq=FALSE,
                                        include_edger=FALSE))

6 Boxplots of CLB/CL14 gene families

Hmm I think the goal laid out by Najib is to have some plots which show in a more concise fashion the changes over time in these specific gene families and be able to compare those differences from CL14 to CLBrener.

I messed up the semantic copy number filter with this.

## In this case, I want 'random' to be a sampling of all data
extract_families_clbr <- sm(semantic_copynumber_extract(clb_compare_times,
                                                        semantic_column="genedescription"))
extract_families_cl14 <- sm(semantic_copynumber_extract(cl14_compare_times,
                                                        semantic_column="genedescription"))

dgf_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$DGF$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$DGF$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$DGF$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$DGF$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$DGF$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$DGF$limma_logfc
)
masp_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$MASP$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$MASP$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$MASP$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$MASP$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$MASP$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$MASP$limma_logfc
)
mucin_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$mucin$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$mucin$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$mucin$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$mucin$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$mucin$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$mucin$limma_logfc
)
sialidase_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$sialidase$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$sialidase$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$sialidase$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$sialidase$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$sialidase$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$sialidase$limma_logfc
)
rhs_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$RHS$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$RHS$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$RHS$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$RHS$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$RHS$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$RHS$limma_logfc
)
gp63_df <- data.frame(
    "clbr_a60" = extract_families_clbr$data$clbr_a60_to_a96$GP63$limma_logfc,
    "cl14_a60" = extract_families_cl14$data$cl14_a60_to_a96$GP63$limma_logfc,
    "clbr_a96" = extract_families_clbr$data$clbr_a96_to_tryp$GP63$limma_logfc,
    "cl14_a96" = extract_families_cl14$data$cl14_a96_to_tryp$GP63$limma_logfc,
    "clbr_tryp" = extract_families_clbr$data$clbr_tryp_to_a60$GP63$limma_logfc,
    "cl14_tryp" = extract_families_cl14$data$cl14_tryp_to_a60$GP63$limma_logfc
)

dgf_box <- plot_boxplot(dgf_df)
dgf_box

dgf_bean <- beanplot::beanplot(dgf_df, method="jitter")

masp_box <- plot_boxplot(masp_df)
masp_box

masp_bean <- beanplot::beanplot(masp_df, method="jitter")

mucin_box <- plot_boxplot(mucin_df)
mucin_box

mucin_bean <- beanplot::beanplot(mucin_df, method="jitter")

sialidase_box <- plot_boxplot(sialidase_df)
sialidase_box

sialidase_bean <- beanplot::beanplot(sialidase_df, method="jitter")

rhs_box <- plot_boxplot(rhs_df)
rhs_box

rhs_bean <- beanplot::beanplot(rhs_df, method="jitter")

gp_box <- plot_boxplot(gp63_df)
gp_box

gp_bean <- beanplot::beanplot(gp63_df, method="jitter")

## Compare DGF distributions across strains
cor.test(dgf_df[["clbr_tryp"]], dgf_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  dgf_df[["clbr_tryp"]] and dgf_df[["cl14_tryp"]]
## t = 19, df = 500, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5895 0.6920
## sample estimates:
##    cor
## 0.6436
t.test(dgf_df[["clbr_tryp"]], dgf_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  dgf_df[["clbr_tryp"]] and dgf_df[["cl14_tryp"]]
## t = -16, df = 990, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.9319 -0.7318
## sample estimates:
## mean of x mean of y
##    0.5374    1.3692
ks.test(dgf_df[["clbr_tryp"]], dgf_df[["cl14_tryp"]])
## Warning in ks.test(dgf_df[["clbr_tryp"]], dgf_df[["cl14_tryp"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  dgf_df[["clbr_tryp"]] and dgf_df[["cl14_tryp"]]
## D = 0.44, p-value <2e-16
## alternative hypothesis: two-sided
cor.test(dgf_df[["clbr_a60"]], dgf_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  dgf_df[["clbr_a60"]] and dgf_df[["cl14_a60"]]
## t = -1.3, df = 500, p-value = 0.2
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.14585  0.02788
## sample estimates:
##      cor
## -0.05943
t.test(dgf_df[["clbr_a60"]], dgf_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  dgf_df[["clbr_a60"]] and dgf_df[["cl14_a60"]]
## t = -7.6, df = 740, p-value = 1e-13
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.6233 -0.3661
## sample estimates:
## mean of x mean of y
##   -0.1449    0.3498
ks.test(dgf_df[["clbr_a60"]], dgf_df[["cl14_a60"]])
## Warning in ks.test(dgf_df[["clbr_a60"]], dgf_df[["cl14_a60"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  dgf_df[["clbr_a60"]] and dgf_df[["cl14_a60"]]
## D = 0.24, p-value = 3e-13
## alternative hypothesis: two-sided
cor.test(dgf_df[["clbr_a96"]], dgf_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  dgf_df[["clbr_a96"]] and dgf_df[["cl14_a96"]]
## t = 8.1, df = 500, p-value = 4e-15
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.2599 0.4143
## sample estimates:
##    cor
## 0.3394
t.test(dgf_df[["clbr_a96"]], dgf_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  dgf_df[["clbr_a96"]] and dgf_df[["cl14_a96"]]
## t = 16, df = 610, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  1.166 1.487
## sample estimates:
## mean of x mean of y
##   -0.3925   -1.7190
ks.test(dgf_df[["clbr_a96"]], dgf_df[["cl14_a96"]])
## Warning in ks.test(dgf_df[["clbr_a96"]], dgf_df[["cl14_a96"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  dgf_df[["clbr_a96"]] and dgf_df[["cl14_a96"]]
## D = 0.58, p-value <2e-16
## alternative hypothesis: two-sided
## Compare MASP distributions across strains
cor.test(masp_df[["clbr_tryp"]], masp_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  masp_df[["clbr_tryp"]] and masp_df[["cl14_tryp"]]
## t = 45, df = 1300, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7565 0.7994
## sample estimates:
##    cor
## 0.7789
t.test(masp_df[["clbr_tryp"]], masp_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  masp_df[["clbr_tryp"]] and masp_df[["cl14_tryp"]]
## t = -1.2, df = 2600, p-value = 0.2
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.18991  0.04508
## sample estimates:
## mean of x mean of y
##    -2.523    -2.451
ks.test(masp_df[["clbr_tryp"]], masp_df[["cl14_tryp"]])
## Warning in ks.test(masp_df[["clbr_tryp"]], masp_df[["cl14_tryp"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  masp_df[["clbr_tryp"]] and masp_df[["cl14_tryp"]]
## D = 0.047, p-value = 0.1
## alternative hypothesis: two-sided
cor.test(masp_df[["clbr_a60"]], masp_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  masp_df[["clbr_a60"]] and masp_df[["cl14_a60"]]
## t = 5.4, df = 1300, p-value = 8e-08
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.09487 0.20130
## sample estimates:
##    cor
## 0.1485
t.test(masp_df[["clbr_a60"]], masp_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  masp_df[["clbr_a60"]] and masp_df[["cl14_a60"]]
## t = 20, df = 2400, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.9367 1.1370
## sample estimates:
## mean of x mean of y
##    1.8801    0.8432
ks.test(masp_df[["clbr_a60"]], masp_df[["cl14_a60"]])
## Warning in ks.test(masp_df[["clbr_a60"]], masp_df[["cl14_a60"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  masp_df[["clbr_a60"]] and masp_df[["cl14_a60"]]
## D = 0.39, p-value <2e-16
## alternative hypothesis: two-sided
cor.test(masp_df[["clbr_a96"]], masp_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  masp_df[["clbr_a96"]] and masp_df[["cl14_a96"]]
## t = 13, df = 1300, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.2859 0.3825
## sample estimates:
##    cor
## 0.3351
t.test(masp_df[["clbr_a96"]], masp_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  masp_df[["clbr_a96"]] and masp_df[["cl14_a96"]]
## t = -16, df = 2300, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -1.0807 -0.8481
## sample estimates:
## mean of x mean of y
##    0.6429    1.6073
ks.test(masp_df[["clbr_a96"]], masp_df[["cl14_a96"]])
## Warning in ks.test(masp_df[["clbr_a96"]], masp_df[["cl14_a96"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  masp_df[["clbr_a96"]] and masp_df[["cl14_a96"]]
## D = 0.44, p-value <2e-16
## alternative hypothesis: two-sided
## Compare MUCIN distributions across strains
cor.test(mucin_df[["clbr_tryp"]], mucin_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  mucin_df[["clbr_tryp"]] and mucin_df[["cl14_tryp"]]
## t = 60, df = 2100, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7786 0.8100
## sample estimates:
##    cor
## 0.7948
t.test(mucin_df[["clbr_tryp"]], mucin_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  mucin_df[["clbr_tryp"]] and mucin_df[["cl14_tryp"]]
## t = -3, df = 4200, p-value = 0.003
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.23422 -0.04918
## sample estimates:
## mean of x mean of y
##    -2.515    -2.373
ks.test(mucin_df[["clbr_tryp"]], mucin_df[["cl14_tryp"]])
## Warning in ks.test(mucin_df[["clbr_tryp"]], mucin_df[["cl14_tryp"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  mucin_df[["clbr_tryp"]] and mucin_df[["cl14_tryp"]]
## D = 0.055, p-value = 0.003
## alternative hypothesis: two-sided
cor.test(mucin_df[["clbr_a60"]], mucin_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  mucin_df[["clbr_a60"]] and mucin_df[["cl14_a60"]]
## t = 7, df = 2100, p-value = 4e-12
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.1081 0.1915
## sample estimates:
##    cor
## 0.1501
t.test(mucin_df[["clbr_a60"]], mucin_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  mucin_df[["clbr_a60"]] and mucin_df[["cl14_a60"]]
## t = 24, df = 4000, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.9014 1.0585
## sample estimates:
## mean of x mean of y
##    1.7615    0.7815
ks.test(mucin_df[["clbr_a60"]], mucin_df[["cl14_a60"]])
## Warning in ks.test(mucin_df[["clbr_a60"]], mucin_df[["cl14_a60"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  mucin_df[["clbr_a60"]] and mucin_df[["cl14_a60"]]
## D = 0.35, p-value <2e-16
## alternative hypothesis: two-sided
cor.test(mucin_df[["clbr_a96"]], mucin_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  mucin_df[["clbr_a96"]] and mucin_df[["cl14_a96"]]
## t = 20, df = 2100, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3559 0.4281
## sample estimates:
##    cor
## 0.3926
t.test(mucin_df[["clbr_a96"]], mucin_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  mucin_df[["clbr_a96"]] and mucin_df[["cl14_a96"]]
## t = -18, df = 3800, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.9305 -0.7459
## sample estimates:
## mean of x mean of y
##    0.7536    1.5918
ks.test(mucin_df[["clbr_a96"]], mucin_df[["cl14_a96"]])
## Warning in ks.test(mucin_df[["clbr_a96"]], mucin_df[["cl14_a96"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  mucin_df[["clbr_a96"]] and mucin_df[["cl14_a96"]]
## D = 0.36, p-value <2e-16
## alternative hypothesis: two-sided
## Compare SIALIDASE distributions across strains
cor.test(sialidase_df[["clbr_tryp"]], sialidase_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  sialidase_df[["clbr_tryp"]] and sialidase_df[["cl14_tryp"]]
## t = 79, df = 1500, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.8909 0.9103
## sample estimates:
##   cor
## 0.901
t.test(sialidase_df[["clbr_tryp"]], sialidase_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  sialidase_df[["clbr_tryp"]] and sialidase_df[["cl14_tryp"]]
## t = -7.3, df = 2900, p-value = 5e-13
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.6938 -0.3990
## sample estimates:
## mean of x mean of y
##    -2.125    -1.579
ks.test(sialidase_df[["clbr_tryp"]], sialidase_df[["cl14_tryp"]])
## Warning in ks.test(sialidase_df[["clbr_tryp"]], sialidase_df[["cl14_tryp"]]): p-value will
## be approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  sialidase_df[["clbr_tryp"]] and sialidase_df[["cl14_tryp"]]
## D = 0.11, p-value = 6e-08
## alternative hypothesis: two-sided
cor.test(sialidase_df[["clbr_a60"]], sialidase_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  sialidase_df[["clbr_a60"]] and sialidase_df[["cl14_a60"]]
## t = -0.022, df = 1500, p-value = 1
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.05185  0.05072
## sample estimates:
##        cor
## -0.0005688
t.test(sialidase_df[["clbr_a60"]], sialidase_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  sialidase_df[["clbr_a60"]] and sialidase_df[["cl14_a60"]]
## t = 10, df = 2800, p-value <2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.4233 0.6212
## sample estimates:
## mean of x mean of y
##    0.9379    0.4157
ks.test(sialidase_df[["clbr_a60"]], sialidase_df[["cl14_a60"]])
## Warning in ks.test(sialidase_df[["clbr_a60"]], sialidase_df[["cl14_a60"]]): p-value will
## be approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  sialidase_df[["clbr_a60"]] and sialidase_df[["cl14_a60"]]
## D = 0.27, p-value <2e-16
## alternative hypothesis: two-sided
cor.test(sialidase_df[["clbr_a96"]], sialidase_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  sialidase_df[["clbr_a96"]] and sialidase_df[["cl14_a96"]]
## t = 33, df = 1500, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6277 0.6859
## sample estimates:
##    cor
## 0.6578
t.test(sialidase_df[["clbr_a96"]], sialidase_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  sialidase_df[["clbr_a96"]] and sialidase_df[["cl14_a96"]]
## t = 0.31, df = 2300, p-value = 0.8
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.1290  0.1773
## sample estimates:
## mean of x mean of y
##     1.187     1.163
ks.test(sialidase_df[["clbr_a96"]], sialidase_df[["cl14_a96"]])
## Warning in ks.test(sialidase_df[["clbr_a96"]], sialidase_df[["cl14_a96"]]): p-value will
## be approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  sialidase_df[["clbr_a96"]] and sialidase_df[["cl14_a96"]]
## D = 0.088, p-value = 3e-05
## alternative hypothesis: two-sided
## Compare RHS distributions across strains
cor.test(rhs_df[["clbr_tryp"]], rhs_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  rhs_df[["clbr_tryp"]] and rhs_df[["cl14_tryp"]]
## t = 20, df = 710, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5416 0.6372
## sample estimates:
##    cor
## 0.5915
t.test(rhs_df[["clbr_tryp"]], rhs_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  rhs_df[["clbr_tryp"]] and rhs_df[["cl14_tryp"]]
## t = -3, df = 1400, p-value = 0.003
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.19026 -0.03871
## sample estimates:
## mean of x mean of y
##  -0.01416   0.10033
ks.test(rhs_df[["clbr_tryp"]], rhs_df[["cl14_tryp"]])
## Warning in ks.test(rhs_df[["clbr_tryp"]], rhs_df[["cl14_tryp"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  rhs_df[["clbr_tryp"]] and rhs_df[["cl14_tryp"]]
## D = 0.073, p-value = 0.05
## alternative hypothesis: two-sided
cor.test(rhs_df[["clbr_a60"]], rhs_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  rhs_df[["clbr_a60"]] and rhs_df[["cl14_a60"]]
## t = -2.4, df = 710, p-value = 0.02
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.16247 -0.01702
## sample estimates:
##      cor
## -0.09022
t.test(rhs_df[["clbr_a60"]], rhs_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  rhs_df[["clbr_a60"]] and rhs_df[["cl14_a60"]]
## t = -4.6, df = 950, p-value = 4e-06
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.3899 -0.1573
## sample estimates:
## mean of x mean of y
##    0.1558    0.4294
ks.test(rhs_df[["clbr_a60"]], rhs_df[["cl14_a60"]])
## Warning in ks.test(rhs_df[["clbr_a60"]], rhs_df[["cl14_a60"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  rhs_df[["clbr_a60"]] and rhs_df[["cl14_a60"]]
## D = 0.12, p-value = 1e-04
## alternative hypothesis: two-sided
cor.test(rhs_df[["clbr_a96"]], rhs_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  rhs_df[["clbr_a96"]] and rhs_df[["cl14_a96"]]
## t = 10, df = 710, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.2976 0.4250
## sample estimates:
##   cor
## 0.363
t.test(rhs_df[["clbr_a96"]], rhs_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  rhs_df[["clbr_a96"]] and rhs_df[["cl14_a96"]]
## t = 5.6, df = 850, p-value = 4e-08
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.2512 0.5250
## sample estimates:
## mean of x mean of y
##   -0.1416   -0.5297
ks.test(rhs_df[["clbr_a96"]], rhs_df[["cl14_a96"]])
## Warning in ks.test(rhs_df[["clbr_a96"]], rhs_df[["cl14_a96"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  rhs_df[["clbr_a96"]] and rhs_df[["cl14_a96"]]
## D = 0.18, p-value = 3e-10
## alternative hypothesis: two-sided
## Compare GP63 distributions across strains
cor.test(gp63_df[["clbr_tryp"]], gp63_df[["cl14_tryp"]])
##
##  Pearson's product-moment correlation
##
## data:  gp63_df[["clbr_tryp"]] and gp63_df[["cl14_tryp"]]
## t = 30, df = 330, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.8195 0.8790
## sample estimates:
##   cor
## 0.852
t.test(gp63_df[["clbr_tryp"]], gp63_df[["cl14_tryp"]])
##
##  Welch Two Sample t-test
##
## data:  gp63_df[["clbr_tryp"]] and gp63_df[["cl14_tryp"]]
## t = -2, df = 650, p-value = 0.05
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.509576 -0.001369
## sample estimates:
## mean of x mean of y
##   -0.9837   -0.7282
ks.test(gp63_df[["clbr_tryp"]], gp63_df[["cl14_tryp"]])
## Warning in ks.test(gp63_df[["clbr_tryp"]], gp63_df[["cl14_tryp"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  gp63_df[["clbr_tryp"]] and gp63_df[["cl14_tryp"]]
## D = 0.09, p-value = 0.1
## alternative hypothesis: two-sided
cor.test(gp63_df[["clbr_a60"]], gp63_df[["cl14_a60"]])
##
##  Pearson's product-moment correlation
##
## data:  gp63_df[["clbr_a60"]] and gp63_df[["cl14_a60"]]
## t = 0.68, df = 330, p-value = 0.5
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.07065  0.14433
## sample estimates:
##     cor
## 0.03728
t.test(gp63_df[["clbr_a60"]], gp63_df[["cl14_a60"]])
##
##  Welch Two Sample t-test
##
## data:  gp63_df[["clbr_a60"]] and gp63_df[["cl14_a60"]]
## t = 2.9, df = 560, p-value = 0.004
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.0744 0.3888
## sample estimates:
## mean of x mean of y
##    0.4949    0.2633
ks.test(gp63_df[["clbr_a60"]], gp63_df[["cl14_a60"]])
## Warning in ks.test(gp63_df[["clbr_a60"]], gp63_df[["cl14_a60"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  gp63_df[["clbr_a60"]] and gp63_df[["cl14_a60"]]
## D = 0.16, p-value = 6e-04
## alternative hypothesis: two-sided
cor.test(gp63_df[["clbr_a96"]], gp63_df[["cl14_a96"]])
##
##  Pearson's product-moment correlation
##
## data:  gp63_df[["clbr_a96"]] and gp63_df[["cl14_a96"]]
## t = 17, df = 330, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6090 0.7275
## sample estimates:
##    cor
## 0.6726
t.test(gp63_df[["clbr_a96"]], gp63_df[["cl14_a96"]])
##
##  Welch Two Sample t-test
##
## data:  gp63_df[["clbr_a96"]] and gp63_df[["cl14_a96"]]
## t = 0.22, df = 620, p-value = 0.8
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.1915  0.2393
## sample estimates:
## mean of x mean of y
##    0.4888    0.4649
ks.test(gp63_df[["clbr_a96"]], gp63_df[["cl14_a96"]])
## Warning in ks.test(gp63_df[["clbr_a96"]], gp63_df[["cl14_a96"]]): p-value will be
## approximate in the presence of ties
##
##  Two-sample Kolmogorov-Smirnov test
##
## data:  gp63_df[["clbr_a96"]] and gp63_df[["cl14_a96"]]
## D = 0.11, p-value = 0.03
## alternative hypothesis: two-sided

7 Strain significance

strains_sig <- sm(extract_significant_genes(strain_comparisons, according_to="limma",
                                            excel=paste0("excel/strain_comparisons_sig-v",
                                                         ver, ".xlsx")))

8 CLBr significance

clbr_times_sig <- sm(extract_significant_genes(clb_compare_times, according_to="limma",
                                               excel=paste0("excel/clb_times_sig-v",
                                                            ver, ".xlsx")))

9 CL14 significance

cl14_times_sig <- sm(extract_significant_genes(cl14_compare_times, according_to="limma",
                                               excel=paste0("excel/cl14_times_sig-v",
                                                            ver, ".xlsx")))

10 Sanity check on route to an improved non-rpkm expression value

I want to make 100% certain that when I plot what I call the coefficient scatter plot, that the dots on the screen are in fact representative of the post-limma/deseq/edger values.

I keep a set of tables in my limma output called ‘identity_tables’ which in theory are the pre-contrast values for each gene by condition. If I am 100% correct, then I should be able to recreate the logFC from topTable() by takinng two of these and subtracting them.

test_genes_clbr_tryp <- cl_all_de_sva[["limma"]][["identity_tables"]][["CLBr.Tryp"]]
test_genes_clbr_a60 <- cl_all_de_sva[["limma"]][["identity_tables"]][["CLBr.A60"]]
test_genes_clbr_contrast <- cl_all_de_sva[["limma"]][["all_tables"]][["CLBr.Tryp_vs_CLBr.A60"]]

test_genes_clbr_tryp["TcCLB.511211.160", ]
##                  logFC AveExpr     t  P.Value adj.P.Val     B    qvalue
## TcCLB.511211.160 10.77   11.39 143.6 5.14e-32 4.168e-28 61.94 4.823e-30
test_genes_clbr_a60["TcCLB.511211.160", ]
##                  logFC AveExpr     t   P.Value adj.P.Val     B    qvalue
## TcCLB.511211.160 11.64   11.39 166.2 2.661e-33 3.072e-29 64.52 1.376e-30
test_genes_clbr_contrast["TcCLB.511211.160", ]
##                    logFC AveExpr      t  P.Value adj.P.Val     B    qvalue
## TcCLB.511211.160 -0.8763   11.39 -7.934 1.19e-07 1.277e-06 7.192 3.125e-07
10.77 - 11.64
## [1] -0.87

On the other hand, I also want to have a standard error / variance estimate to come along with this data. I have two likely places to acquire that:

  1. As per Hector’s email, take the logFC from the identity table and divide it by the t statistic in the same table. This should provide standard error.
  2. eBayes() or perhaps contrast.fit() I am not sure which, generates a table named ‘stdev.unscaled’ for every gene/condition. This may be collected.

With that in mind, I wrote a little function get_pairwise_gene_abundances() that collects these in four tables: expression_values, t_values, error_values, and stdev_values.

abundances <- get_pairwise_gene_abundances(cl_all_de_sva)
expression_written <- write_xls(data=abundances[["expression_values"]],
                                sheet="expression_values",
                                title="Values making up the contrast logFCs")
error_written <- write_xls(data=abundances[["error_values"]], start_col=18,
                           title="Error value obtained by dividing the expression / t-statistic",
                           sheet="expression_values",
                           wb=expression_written[["workbook"]])
## The sheet: expression_values is in expression_values.
openxlsx::saveWorkbook(wb=expression_written[["workbook"]],
                       file="excel/written_abundance_test.xlsx", overwrite=TRUE)

##canaries <- c("TcCLB.511511.6", "TcCLB.511511.3", "TcCLB.511727.190", "TcCLB.469785.40",
##              "TcCLB.506563.10", "TcCLB.511127.10", "TcCLB.504005.6", "TcCLB.507611.300")
canaries <- c("TcCLB.511727.190", "TcCLB.469785.40",
              "TcCLB.506563.10", "TcCLB.511127.10",
              "TcCLB.504005.6", "TcCLB.507611.300")
## Reorder the data to match the existing figure
conditions <- c("CLBr.A60", "CLBr.A96", "CLBr.Tryp",
                "CL14.A60", "CL14.A96", "CL14.Tryp")
expressions <- abundances[["expression_values"]][, conditions]
stdevs <- abundances[["stdev_values"]][, conditions]
## Error in `[.data.frame`(abundances[["stdev_values"]], , conditions): undefined columns selected
errs <- abundances[["error_values"]][, conditions]
adjp_values <- list()
library(ggplot2)
for (num in 1:length(canaries)) {
    canary <- canaries[num]
    point <- 2 ^ expressions[canary, ]
    ##stdev <- 2 ^ stdevs[canary, ]
    err <- 2 ^ errs[canary, ]
    my_colors <- c("blue","green","red","blue","green","red")
    canary_df <- data.frame(
        "id" = colnames(point),
        "values" = as.numeric(point),
        "colors" = my_colors,
        "err" = as.numeric(err),
        "plus_err" = as.numeric(err) + as.numeric(point),
        "minus_err" = as.numeric(point) - as.numeric(err))
    print(canary_df)
    fun_barplot <- ggplot2::ggplot(data=canary_df, colour=my_colors,
                                   aes_string(x="id", y="values")) +
        ggplot2::geom_bar(stat="identity", colour="black", fill=my_colors) +
        ggplot2::theme_bw() + ggplot2::ylab("Expression Value") +
        ggplot2::ggtitle(canary) +
        ggplot2::geom_errorbar(aes(ymax=plus_err, ymin=minus_err), width=0.3)
    pdf_filename <- paste0("images/", num, "_", canary, "_expression.pdf")
    pdf(file=pdf_filename)
    print(fun_barplot)
    dev.off()
    ## Now extract the adjusted p-values from the pairwise contrasts...
    ## test_genes_clbr_contrast <- cl_all_de_sva[["limma"]][["all_tables"]][["CLBr.Tryp_vs_CLBr.A60"]]
    adjps <- c()
    the_contrasts <- c("CLBr.Tryp_vs_CL14.Tryp", "CLBr.A60_vs_CL14.A60", "CLBr.A96_vs_CL14.A96")
    for (contr in the_contrasts) {
        adjp <- cl_all_de_sva[["limma"]][["all_tables"]][[contr]][canary, "adj.P.Val"]
        adjps[[contr]] <- adjp
    }
    adjp_values[[canary]] <- adjps
}
##          id values colors   err plus_err minus_err
## 1  CLBr.A60 170.19   blue 1.034   171.22    169.16
## 2  CLBr.A96 113.77  green 1.022   114.79    112.75
## 3 CLBr.Tryp  22.58    red 1.035    23.62     21.55
## 4  CL14.A60 151.27   blue 1.038   152.31    150.23
## 5  CL14.A96 159.56  green 1.034   160.60    158.53
## 6 CL14.Tryp  32.04    red 1.040    33.08     31.00
##          id values colors   err plus_err minus_err
## 1  CLBr.A60 54.229   blue 1.086   55.316    53.143
## 2  CLBr.A96 23.785  green 1.047   24.832    22.739
## 3 CLBr.Tryp  7.449    red 1.076    8.525     6.373
## 4  CL14.A60 43.381   blue 1.094   44.475    42.287
## 5  CL14.A96 35.432  green 1.089   36.522    34.343
## 6 CL14.Tryp 10.520    red 1.102   11.622     9.417
##          id values colors   err plus_err minus_err
## 1  CLBr.A60  54.99   blue 1.087    56.07     53.90
## 2  CLBr.A96  81.91  green 1.042    82.95     80.87
## 3 CLBr.Tryp  24.81    red 1.069    25.88     23.74
## 4  CL14.A60  54.72   blue 1.087    55.81     53.63
## 5  CL14.A96  48.50  green 1.087    49.59     47.42
## 6 CL14.Tryp  19.47    red 1.095    20.56     18.37
##          id values colors   err plus_err minus_err
## 1  CLBr.A60  1.520   blue 1.454    2.974   0.06662
## 2  CLBr.A96  3.583  green 1.142    4.725   2.44051
## 3 CLBr.Tryp  3.345    red 1.205    4.550   2.14023
## 4  CL14.A60  1.462   blue 1.484    2.946  -0.02217
## 5  CL14.A96  1.618  green 1.498    3.116   0.12028
## 6 CL14.Tryp  1.206    red 1.477    2.683  -0.27112
##          id values colors   err plus_err minus_err
## 1  CLBr.A60  42.05   blue 1.167    43.22     40.88
## 2  CLBr.A96 101.13  green 1.071   102.20    100.05
## 3 CLBr.Tryp  25.90    red 1.120    27.02     24.78
## 4  CL14.A60  39.31   blue 1.159    40.47     38.16
## 5  CL14.A96  82.77  green 1.144    83.91     81.62
## 6 CL14.Tryp  44.42    red 1.168    45.58     43.25
##          id values colors   err plus_err minus_err
## 1  CLBr.A60  17.02   blue 1.224    18.24     15.79
## 2  CLBr.A96  21.10  green 1.086    22.18     20.01
## 3 CLBr.Tryp  20.31    red 1.127    21.44     19.18
## 4  CL14.A60  20.38   blue 1.195    21.57     19.18
## 5  CL14.A96  12.05  green 1.235    13.28     10.82
## 6 CL14.Tryp  68.40    red 1.210    69.61     67.19
## A query from Santuza, generate p-values between some of these bars.
## How do I do that when I extracted the values and variances from limma without the
## associated raw values?
## hmm...
adjp_values
## $TcCLB.511727.190
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##              5.528e-04              5.050e-01              7.645e-05
##
## $TcCLB.469785.40
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##               0.030550               0.439600               0.002574
##
## $TcCLB.506563.10
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##              7.648e-02              9.923e-01              6.433e-05
##
## $TcCLB.511127.10
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##                0.06265                0.98770                0.13790
##
## $TcCLB.504005.6
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##               0.005835               0.916200               0.177100
##
## $TcCLB.507611.300
## CLBr.Tryp_vs_CL14.Tryp   CLBr.A60_vs_CL14.A60   CLBr.A96_vs_CL14.A96
##              6.526e-06              7.914e-01              1.510e-02

11 Significance bar plots

clbr_bars <- sm(significant_barplots(clb_compare_times))
pdf(file="images/limma.pdf")
clbr_bars$limma
dev.off()
## png
##   2
clbr_inv <- sm(significant_barplots(clb_compare_times))
pdf(file="images/limma_invert.pdf")
clbr_inv$limma
dev.off()
## png
##   2
cl14_bars <- sm(significant_barplots(cl14_compare_times))
strain_bars <- sm(significant_barplots(strain_comparisons))

clbr_bars$limma

cl14_bars$limma

strain_bars$limma

12 New item

Redo GO analyses excluding multigene family members. I believe we discussed that the best way to do this was to:

  1. generate DE tables with multigene family members filtered out
  2. Redo GO/KEGG on remainder.
##clbr_times_filtered <- semantic_copynumber_filter(clbr_times_sig$limma, semantic_column="genedescription")
##cl14_times_filtered <- semantic_copynumber_filter(cl14_times_sig$limma, semantic_column="genedescription")
##strains_filtered <- semantic_copynumber_filter(strains_sig$limma, semantic_column="genedescription")
clbr_times_filtered <- sm(semantic_copynumber_filter(clb_compare_times,
                                                     semantic_column="genedescription"))
cl14_times_filtered <- sm(semantic_copynumber_filter(cl14_compare_times,
                                                     semantic_column="genedescription"))
strains_filtered <- sm(semantic_copynumber_filter(strain_comparisons,
                                                  semantic_column="genedescription"))

clbr_times_sigfilt <- sm(extract_significant_genes(clbr_times_filtered, according_to="limma",
                                                   excel=paste0("excel/clb_times_filtered_sig-v",
                                                                ver, ".xlsx")))
cl14_times_sigfilt <- sm(extract_significant_genes(cl14_times_filtered, according_to="limma",
                                                   excel=paste0("excel/cl14_times_filtered_sig-v",
                                                                ver, ".xlsx")))
strains_sigfilt <- sm(extract_significant_genes(strains_filtered, according_to="limma",
                                                excel=paste0("excel/strain_comparisons_filtered_sig-v",
                                                             ver, ".xlsx")))

## Najib wants to know how many entries for each family were removed by the semantic filtering
## from the significance tables.
semantic_names <- c("mucin","sialidase","RHS","MASP","DGF","GP63")
find_numbers <- function(datum, direction="ups", table_name="clbr_tryp_to_a60") {
    for (name in semantic_names) {
        table <- datum[["limma"]][[direction]][[table_name]]
        search <- grepl(pattern=name, x=table[["genedescription"]])
        number <- sum(search)
        message(paste0("The ", direction, " table ", table_name,
                       " was pruned for ",
                       name, " by ", number, " genes."))
    }
}
find_numbers(clbr_times_sig)
## The ups table clbr_tryp_to_a60 was pruned for mucin by 14 genes.
## The ups table clbr_tryp_to_a60 was pruned for sialidase by 38 genes.
## The ups table clbr_tryp_to_a60 was pruned for RHS by 40 genes.
## The ups table clbr_tryp_to_a60 was pruned for MASP by 11 genes.
## The ups table clbr_tryp_to_a60 was pruned for DGF by 82 genes.
## The ups table clbr_tryp_to_a60 was pruned for GP63 by 17 genes.
find_numbers(clbr_times_sig, direction="downs")
## The downs table clbr_tryp_to_a60 was pruned for mucin by 1640 genes.
## The downs table clbr_tryp_to_a60 was pruned for sialidase by 870 genes.
## The downs table clbr_tryp_to_a60 was pruned for RHS by 38 genes.
## The downs table clbr_tryp_to_a60 was pruned for MASP by 1024 genes.
## The downs table clbr_tryp_to_a60 was pruned for DGF by 11 genes.
## The downs table clbr_tryp_to_a60 was pruned for GP63 by 108 genes.
find_numbers(clbr_times_sig, table_name="clbr_a60_to_a96")
## The ups table clbr_a60_to_a96 was pruned for mucin by 1286 genes.
## The ups table clbr_a60_to_a96 was pruned for sialidase by 511 genes.
## The ups table clbr_a60_to_a96 was pruned for RHS by 52 genes.
## The ups table clbr_a60_to_a96 was pruned for MASP by 859 genes.
## The ups table clbr_a60_to_a96 was pruned for DGF by 14 genes.
## The ups table clbr_a60_to_a96 was pruned for GP63 by 73 genes.
find_numbers(clbr_times_sig, direction="downs", table_name="clbr_a60_to_a96")
## The downs table clbr_a60_to_a96 was pruned for mucin by 43 genes.
## The downs table clbr_a60_to_a96 was pruned for sialidase by 34 genes.
## The downs table clbr_a60_to_a96 was pruned for RHS by 11 genes.
## The downs table clbr_a60_to_a96 was pruned for MASP by 27 genes.
## The downs table clbr_a60_to_a96 was pruned for DGF by 20 genes.
## The downs table clbr_a60_to_a96 was pruned for GP63 by 7 genes.
find_numbers(clbr_times_sig, table_name="clbr_a96_to_tryp")
## The ups table clbr_a96_to_tryp was pruned for mucin by 746 genes.
## The ups table clbr_a96_to_tryp was pruned for sialidase by 699 genes.
## The ups table clbr_a96_to_tryp was pruned for RHS by 17 genes.
## The ups table clbr_a96_to_tryp was pruned for MASP by 377 genes.
## The ups table clbr_a96_to_tryp was pruned for DGF by 12 genes.
## The ups table clbr_a96_to_tryp was pruned for GP63 by 68 genes.
find_numbers(clbr_times_sig, direction="downs", table_name="clbr_a96_to_tryp")
## The downs table clbr_a96_to_tryp was pruned for mucin by 112 genes.
## The downs table clbr_a96_to_tryp was pruned for sialidase by 51 genes.
## The downs table clbr_a96_to_tryp was pruned for RHS by 41 genes.
## The downs table clbr_a96_to_tryp was pruned for MASP by 63 genes.
## The downs table clbr_a96_to_tryp was pruned for DGF by 48 genes.
## The downs table clbr_a96_to_tryp was pruned for GP63 by 15 genes.
find_numbers(cl14_times_sig, table_name="cl14_tryp_to_a60")
## The ups table cl14_tryp_to_a60 was pruned for mucin by 19 genes.
## The ups table cl14_tryp_to_a60 was pruned for sialidase by 42 genes.
## The ups table cl14_tryp_to_a60 was pruned for RHS by 47 genes.
## The ups table cl14_tryp_to_a60 was pruned for MASP by 12 genes.
## The ups table cl14_tryp_to_a60 was pruned for DGF by 300 genes.
## The ups table cl14_tryp_to_a60 was pruned for GP63 by 15 genes.
find_numbers(cl14_times_sig, direction="downs", table_name="cl14_tryp_to_a60")
## The downs table cl14_tryp_to_a60 was pruned for mucin by 1612 genes.
## The downs table cl14_tryp_to_a60 was pruned for sialidase by 763 genes.
## The downs table cl14_tryp_to_a60 was pruned for RHS by 22 genes.
## The downs table cl14_tryp_to_a60 was pruned for MASP by 1042 genes.
## The downs table cl14_tryp_to_a60 was pruned for DGF by 3 genes.
## The downs table cl14_tryp_to_a60 was pruned for GP63 by 88 genes.
find_numbers(cl14_times_sig, table_name="cl14_a60_to_a96")
## The ups table cl14_a60_to_a96 was pruned for mucin by 185 genes.
## The ups table cl14_a60_to_a96 was pruned for sialidase by 130 genes.
## The ups table cl14_a60_to_a96 was pruned for RHS by 87 genes.
## The ups table cl14_a60_to_a96 was pruned for MASP by 131 genes.
## The ups table cl14_a60_to_a96 was pruned for DGF by 41 genes.
## The ups table cl14_a60_to_a96 was pruned for GP63 by 6 genes.
find_numbers(cl14_times_sig, direction="downs", table_name="cl14_a60_to_a96")
## The downs table cl14_a60_to_a96 was pruned for mucin by 9 genes.
## The downs table cl14_a60_to_a96 was pruned for sialidase by 40 genes.
## The downs table cl14_a60_to_a96 was pruned for RHS by 34 genes.
## The downs table cl14_a60_to_a96 was pruned for MASP by 5 genes.
## The downs table cl14_a60_to_a96 was pruned for DGF by 16 genes.
## The downs table cl14_a60_to_a96 was pruned for GP63 by 1 genes.
find_numbers(cl14_times_sig, table_name="cl14_a96_to_tryp")
## The ups table cl14_a96_to_tryp was pruned for mucin by 897 genes.
## The ups table cl14_a96_to_tryp was pruned for sialidase by 574 genes.
## The ups table cl14_a96_to_tryp was pruned for RHS by 43 genes.
## The ups table cl14_a96_to_tryp was pruned for MASP by 615 genes.
## The ups table cl14_a96_to_tryp was pruned for DGF by 5 genes.
## The ups table cl14_a96_to_tryp was pruned for GP63 by 49 genes.
find_numbers(cl14_times_sig, direction="downs", table_name="cl14_a96_to_tryp")
## The downs table cl14_a96_to_tryp was pruned for mucin by 61 genes.
## The downs table cl14_a96_to_tryp was pruned for sialidase by 112 genes.
## The downs table cl14_a96_to_tryp was pruned for RHS by 135 genes.
## The downs table cl14_a96_to_tryp was pruned for MASP by 41 genes.
## The downs table cl14_a96_to_tryp was pruned for DGF by 242 genes.
## The downs table cl14_a96_to_tryp was pruned for GP63 by 14 genes.

12.1 Many many MA plots!

filenames <- c("mucin.txt", "masp.txt", "gp63.txt", "transsialidase.txt",
               "retrotransposon.txt", "dispersed.txt")
family_colors <- c("blue", "red", "green", "purple", "brown", "yellow")
names(family_colors) <- c("mucin", "MASP", "GP63", "trans_sialidase", "rhs", "DGF")
for (num in 1:length(names(clb_times_keepers))) {
    contrast_names <- names(clb_times_keepers)
    contrast <- contrast_names[[num]]
    for (file_num in 1:length(filenames)) {
        color <- family_colors[[file_num]]
        families <- names(family_colors)
        family <- families[[file_num]]
        file <- filenames[[file_num]]
        filename <- paste0("reference/families/", file)
        output <- paste0("images/", contrast, "_", family, "_ma-v", ver, ".png")
        svg_output <- paste0("images/", contrast, "_", family, "_ma-v", ver, ".svg")
        family <- read.csv(filename, header=FALSE, sep=":")
        family <- family[[1]]
        limma_plot <- extract_de_ma(clb_compare_times, type="limma",
                                    table=contrast, family=family,
                                    insig_color="lightgrey", sig_color="#444444",
                                    family_color=color, label_numbers=FALSE)
        the_plot <- limma_plot$plot + ylim(-10, 10) + theme(legend.position="none")
        png(file=output)
        plot(the_plot)
        dev.off()
        svg(file=svg_output)
        plot(the_plot)
        dev.off()
    }
}
## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).
## Warning: Removed 2 rows containing missing values (geom_point).
## Warning: Removed 3 rows containing missing values (geom_point).
## Warning: Removed 2 rows containing missing values (geom_point).
## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input
## Warning: Removed 3 rows containing missing values (geom_point).

## Warning: Removed 3 rows containing missing values (geom_point).
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input

## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input
for (num in 1:length(names(cl14_times_keepers))) {
    contrast_names <- names(cl14_times_keepers)
    contrast <- contrast_names[[num]]
    for (file_num in 1:length(filenames)) {
        color <- family_colors[[file_num]]
        families <- names(family_colors)
        family <- families[[file_num]]
        file <- filenames[[file_num]]
        filename <- paste0("reference/families/", file)
        output <- paste0("images/", contrast, "_", family, "_ma-v", ver, ".png")
        svg_output <- paste0("images/", contrast, "_", family, "_ma-v", ver, ".svg")
        family <- read.csv(filename, header=FALSE, sep=":")
        family <- family[[1]]
        limma_plot <- extract_de_ma(cl14_compare_times, type="limma",
                                    table=contrast, family=family,
                                    insig_color="lightgrey", sig_color="#444444",
                                    family_color=color, label_numbers=FALSE)
        the_plot <- limma_plot$plot + ylim(-10, 10) + theme(legend.position="none")
        png(file=output)
        plot(the_plot)
        dev.off()
        svg(file=svg_output)
        plot(the_plot)
        dev.off()
    }
}
## Warning: Removed 1 rows containing missing values (geom_point).
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input
## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).
## Warning: Removed 5 rows containing missing values (geom_point).
## Warning: Removed 12 rows containing missing values (geom_point).
## Warning: Removed 5 rows containing missing values (geom_point).
## Warning: Removed 12 rows containing missing values (geom_point).
## Warning: Removed 2 rows containing missing values (geom_point).
## Warning: Removed 12 rows containing missing values (geom_point).
## Warning: Removed 2 rows containing missing values (geom_point).
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : embedded
## nul(s) found in input
## Warning: Removed 12 rows containing missing values (geom_point).

## Warning: Removed 12 rows containing missing values (geom_point).
tt <- sm(saveme(filename=this_save))

13 Other haplotypes

I think I am the only person who care about these analyses, so I am telling knitr to stop running them.

cl_esmer_kexpt <- sm(normalize_expt(cl_esmer_kexpt, filter=TRUE))
cl_esmer_de <- sm(all_pairwise(cl_esmer_kexpt, model_batch="sva"))
cl_nonesmer_kexpt <- sm(normalize_expt(cl_nonesmer_kexpt, filter=TRUE))
cl_nonesmer_de <- sm(all_pairwise(cl_nonesmer_kexpt, model_batch="sva"))
cl_all_kexpt <- sm(normalize_expt(cl_all_kexpt, filter=TRUE))
cl_all_de <- sm(all_pairwise(cl_all_kexpt, model_batch="sva"))
clbr_esmer_kexpt <- sm(normalize_expt(clbr_esmer_kexpt, filter=TRUE))
clbr_esmer_de <- sm(all_pairwise(clbr_esmer_kexpt, model_batch="sva"))
clbr_nonesmer_kexpt <- sm(normalize_expt(clbr_nonesmer_kexpt, filter=TRUE))
clbr_nonesmer_de <- sm(all_pairwise(clbr_nonesmer_kexpt, model_batch="sva"))
cl14_esmer_kexpt <- sm(normalize_expt(cl14_esmer_kexpt, filter=TRUE))
cl14_esmer_de <- sm(all_pairwise(cl14_esmer_kexpt, model_batch="sva"))
cl14_nonesmer_kexpt <- sm(normalize_expt(cl14_nonesmer_kexpt, filter=TRUE))
cl14_nonesmer_de <- sm(all_pairwise(cl14_nonesmer_kexpt, model_batch="sva"))
cl14_all_kexpt <- sm(normalize_expt(cl14_all_kexpt, filter=TRUE))
cl14_all_de <- sm(all_pairwise(cl14_all_kexpt, model_batch="sva"))
hs_norm <- sm(normalize_expt(hs_expt, filter=TRUE))
tt <- sm(graph_metrics(hs_norm))

hs_de <- sm(all_pairwise(hs_norm, model_batch="svaseq"))

13.2 Extract single-tons

I want to take the set of up/down genes as provided above in changed_counts and pull out of them the sets of low/single copy genes. In order to do this, I will likely use the same fasta36 scripts I have used previously with Ginger etc. I might also/instead attempt using the needleman/wunsch implementation in bioconductor.

Either way, a significant portion of the work will require extracting the gene IDs from changed_counts for each up/down group, pulling the relevant primary sequence, and performing whatever search.

13.3 General gene expression (RPKM)

Santuza would like to poke at the general gene expression in various conditions. Therefore this is calculating and printing the rpkm and raw counts to an excel workbook.

## Santuza asked for a listing of the rpkm(normalized(counts)) in order to get an idea of the highly expressed genes
## Also include clbrener epimastigotes and do average(rpkm) by sample type
## The base expression set we will use is cl_all_filt

cl_all_rpkm <- sm(normalize_expt(cl_all_filt, filter=TRUE, convert="rpkm"))
rpkm_df <- merge(Biobase::fData(cl_all_filt$expressionset),
                 Biobase::exprs(cl_all_rpkm[["expressionset"]]),
                 by.x="row.names", by.y="row.names")
rownames(rpkm_df) <- rpkm_df[["Row.names"]]
rpkm_df = rpkm_df[, -1]
median_rpkm <- median_by_factor(data=cl_all_rpkm)
rpkm_df <- merge(rpkm_df, median_rpkm, by="row.names")
rownames(rpkm_df) <- rpkm_df[["Row.names"]]
rpkm_df <- rpkm_df[, -1]
raw_counts <- as.data.frame(Biobase::exprs(cl_all_filt$expressionset))
rpkm_df <- merge(raw_counts, rpkm_df, by="row.names")
rownames(rpkm_df) <- rpkm_df[["Row.names"]]
rpkm_df <- rpkm_df[, -1]

xls_ret <- write_xls(as.data.frame(rpkm_df), sheet="raw_to_rpkm_counts",
                     title="Table SXXX: Raw data to RPKM(data)")
openxlsx::saveWorkbook(wb=xls_ret[["workbook"]],
                       file=paste0("excel/rpkm_counts_base10-v", ver, ".xlsx"), overwrite=TRUE)

14 Remove everything from here down?

I think everything from here to the end of this document is no longer useful. But I refuse to delete it.

14.1 Larger subset

Lets try for a convenient method of including only the contrasts Santuza is interested in. These include (but may not be limited to):

I spoke with Santuza right before leaving for the evening, this is exactly the opposite of what she wanted.

CLB(tryp/a60) CL14(tryp/a60) CLB(a60/a96) CL14(a60/a96) CLB(a96/tryp) CL14(a96/tryp) a96(CL14/CLB) a60(CL14/CLB) tryp(CL14/CLB)

I am hoping to convince Najib and Santuza that the epi samples are salvageable.

15 Voom/limma invocation

The following few comparisons are going to use the ‘all’ data set. When I do a larger set of limma contrasts, I will just use the ‘kept’ set.

16 Simple pairwise comparisons

The following blocks are no longer being evaluated because they remove most of the samples from the data and therefore over-estimate significances. But they do provide reasonable examples of how one might perform simple pairwise comparisons in data.

16.1 Compare epimastigotes

epi_subset <- expt_subset(all_qcpml2, "condition=='clbr_epi'|condition=='cl14_epi'")
epi_graphs <- graph_metrics(epi_subset)
epi_graphs$norm_pcaplot
epi_graphs$norm_disheat
epi_graphs$norm_corheat
epi_comparison <- simple_comparison(epi_subset)
epi_table <- epi_comparison$table
epi_comparison$pvalue_histogram
epi_comparison$volcano_plot
epi_comparison$ma_plot
epi_comparison$coefficient_scatter

16.2 Compare Trypomastigotes

tryp_subset <- expt_subset(all_qcpml2, "condition=='clbr_tryp'|condition=='cl14_tryp'")
tryp_graphs <- graph_metrics(expt=tryp_subset)
tryp_graphs$norm_pcaplot
tryp_graphs$norm_disheat
tryp_graphs$norm_corheat
tryp_comparison <- simple_comparison(tryp_subset)
tryp_table = tryp_comparison$table
tryp_comparison$pvalue_histogram
tryp_comparison$volcano_plot
tryp_comparison$ma_plot
tryp_comparison$coefficient_scatter

16.3 Compare Amastigotes 60 hours

a60_subset <- expt_subset(all_qcpml2, "condition=='clbr_a60'|condition=='cl14_a60'")
a60_graphs <- graph_metrics(expt=a60_subset)
a60_graphs$norm_pcaplot
a60_graphs$norm_corheat
a60_graphs$norm_disheat
a60_comparison <- simple_comparison(a60_subset)
a60_table <- a60_comparison$table
a60_comparison$pvalue_histogram
a60_comparison$volcano_plot
a60_comparison$ma_plot
a60_comparison$coefficient_scatter

17 Single-factor all the conditions and batches

A more appropriate method for performing the various comparisons of strains across time is to put all the extant data into a single contrast. The following block does that and attempts to take into account the relative contribution of each batch and sample.

The variables which were created to hold the relative contributions of these samples were also used to perform the various subtractions. Thus, when limma is actually run, it will provide data structures of the abundances of each sample type as well as the various comparisons.

## This data structure will be used for the following playing
kept_data <- exprs(kept_qcpml2$expressionset)
## acb stands for "all_conditions_batches"  which takes too long to
## type when setting up the contrasts.
acb <- paste0(kept_qcpml2$conditions, kept_qcpml2$batches)
table(acb)
## The invocation of table() keptows me to count up the contribution of
## each condition/batch combination to the whole data set.

## Doing this (as I understand it) means I do nothave to worry about
## balanced samples so much, but must be more careful to understand
## the relative contribution of each sample type to the entire data
## set.

complete_model <- model.matrix(~0 + acb)
complete_fit <- lmFit(kept_data, complete_model)
complete_voom <- hpgl_voom(kept_data, complete_model)
complete_voom$plot
complete_model

epi_cl14 <- "acbcl14_epiF"
epi_clbr <- "acbclbr_epiE"
tryp_cl14 <- "(acbcl14_trypB + acbcl14_trypD + acbcl14_trypG) / 3"
tryp_clbr <- "acbclbr_trypG"
a60_cl14 <- "(acbcl14_a60A * 2/3) + (acbcl14_a60B * 1/3)"
a60_clbr <- "acbclbr_a60A"
a96_cl14 <- "acbcl14_a96C"
a96_clbr <- "acbclbr_a96C"
epi_cl14clbr <- paste0("(",epi_cl14,")", "  -  ", "(",epi_clbr,")")
tryp_cl14clbr <- paste0("(",tryp_cl14,")", "  -  ", "(",tryp_clbr,")")
a60_cl14clbr <- paste0("(",a60_cl14,")", "  -  ", "(",a60_clbr,")")
a96_cl14clbr <- paste0("(",a96_cl14,")", "  -  ", "(",a96_clbr,")")
epitryp_cl14 <- paste0("(",tryp_cl14,")", "  -  ", "(",epi_cl14,")")
epitryp_clbr <- paste0("(",tryp_clbr,")", "  -  ", "(",epi_clbr,")")
epia60_cl14 <- paste0("(",a60_cl14,")", "  -  ", "(",epi_cl14,")")
epia60_clbr <- paste0("(",a60_clbr,")", "  -  ", "(",epi_clbr,")")
a60a96_cl14 <- paste0("(",a96_cl14,")", "  -  ", "(",a60_cl14,")")
a60a96_clbr <- paste0("(",a96_clbr,")", "  -  ", "(",a60_clbr,")")
a60tryp_cl14 <- paste0("(",tryp_cl14,")", "  -  ", "(",a60_cl14,")")
a60tryp_clbr <- paste0("(",tryp_clbr,")", "  -  ", "(",a60_clbr,")")
a96tryp_cl14 <- paste0("(",tryp_cl14,")", "  -  ", "(",a96_cl14,")")
a96tryp_clbr <- paste0("(",tryp_clbr,")", "  -  ", "(",a96_clbr,")")

## The following contrast is messed up in some as of yet unknown way.
epitryp_cl14clbr <- paste0("(",epitryp_cl14,")", "  -  ", "(",epitryp_clbr,")")
## So I will add some more contrasts using data which doesn't get screwed up
epia60_cl14clbr <- paste0("(",epia60_cl14,")", "  -  ", "(",epia60_clbr,")")
a60tryp_cl14clbr <- paste0("(",a60tryp_cl14,")", "  -  ", "(",a60tryp_clbr,")")
a60a96_cl14clbr <- paste0("(",a60a96_cl14,")", "  -  ", "(",a60a96_clbr,")")

complete_contrasts_v2 <- makeContrasts(
    epi_cl14=epi_cl14,
    epi_clbr=epi_clbr,
    tryp_cl14=tryp_cl14,
    tryp_clbr=tryp_clbr,
    a60_cl14=a60_cl14,
    a60_clbr=a60_clbr,
    a96_cl14=a96_cl14,
    a96_clbr=a96_clbr,
    epi_cl14clbr=epi_cl14clbr,
    tryp_cl14clbr=tryp_cl14clbr,
    a60_cl14clbr=a60_cl14clbr,
    a96_cl14clbr=a96_cl14clbr,
    epitryp_cl14=epitryp_cl14,
    epitryp_clbr=epitryp_clbr,
    epia60_cl14=epia60_cl14,
    epia60_clbr=epia60_clbr,
    a60a96_cl14=a60a96_cl14,
    a60a96_clbr=a60a96_clbr,
    a60tryp_cl14=a60tryp_cl14,
    a60tryp_clbr=a60tryp_clbr,
    a96tryp_cl14=a96tryp_cl14,
    a96tryp_clbr=a96tryp_clbr,
    epitryp_cl14clbr=epitryp_cl14clbr,
    epia60_cl14clbr=epia60_cl14clbr,
    a60tryp_cl14clbr=a60tryp_cl14clbr,
    a60a96_cl14clbr=a60a96_cl14clbr,
    levels=complete_voom$design)
## This colnames() is annoyingly necessary to avoid really obnoxious contrast names.
colnames(complete_contrasts_v2) <- c("epi_cl14","epi_clbr","tryp_cl14","tryp_clbr","a60_cl14","a60_clbr","a96_cl14","a96_clbr","epi_cl14clbr","tryp_cl14clbr","a60_cl14clbr","a96_cl14clbr","epitryp_cl14","epitryp_clbr","epia60_cl14","epia60_clbr","a60tryp_cl14","a60tryp_clbr","a96tryp_cl14","a96tryp_clbr","a60a96_cl14","a60a96_clbr","epitryp_cl14clbr","epia60_cl14clbr","a60tryp_cl14clbr","a60a96_cl14clbr")
kept_fits <- contrasts.fit(complete_fit, complete_contrasts_v2)
kept_comparisons <- eBayes(kept_fits)

18 Analysis with only condition in the model

con <- kept_qcpml2$conditions
condition_model <- model.matrix(~0 + con)
condition_voom <- hpgl_voom(kept_data, condition_model)
condition_lmfit <- lmFit(condition_voom, condition_model)
des <- condition_voom$design
condition_contrasts <- makeContrasts(
    epi_cl14=concl14_epi,
    epi_clbr=conclbr_epi,
    a60_cl14=concl14_a60,
    a60_clbr=conclbr_a60,
    a96_cl14=concl14_a96,
    a96_clbr=conclbr_a96,
    tryp_cl14=concl14_tryp,
    tryp_clbr=conclbr_tryp,
    epi_cl14clbr=concl14_epi - conclbr_epi,
    tryp_cl14clbr=concl14_tryp - conclbr_tryp,
    a60_cl14clbr=concl14_a60 - conclbr_a60,
    a96_cl14clbr=concl14_a96 - conclbr_a96,
    a60epi_clbr=conclbr_a60 - conclbr_epi,
    trypepi_clbr=conclbr_tryp - conclbr_epi,
    a96a60_cl14=concl14_a96 - concl14_a60,
    a96a60_clbr=conclbr_a96 - conclbr_a60,
    trypa96_cl14=concl14_tryp - concl14_a96,
    trypa96_clbr=conclbr_tryp - conclbr_a96,
    a96a60_cl14clbr=(concl14_a96-concl14_a60)-(conclbr_a96-conclbr_a60),
    trypa96_cl14clbr=(concl14_tryp-concl14_a96)-(conclbr_tryp-conclbr_a96),
    levels=des)
colnames(condition_contrasts) <- c("epi_cl14","epi_clbr","a60_cl14","a60_clbr","a96_cl14","a96_clbr","tryp_cl14","tryp_clbr","epi_cl14clbr","tryp_cl14clbr","a60_cl14clbr","a96_cl14clbr","a60epi_clbr","trypepi_clbr","a60a96_cl14","a60a96_clbr","a96tryp_cl14","a96_tryp_clbr","a60a96_cl14clbr","a96tryp_cl14clbr")
condition_fits <- contrasts.fit(condition_lmfit, condition_contrasts)
condition_comparisons <- eBayes(condition_fits)
condition_table <- topTable(condition_comparisons, adjust="fdr", n=nrow(kept_data))
condition_tables <- write_limma(condition_comparisons, excel=TRUE, csv=FALSE, annotation=tooltip_data)

gene_lengths <- genes[,c("ID","width")]
go_ids <- read.csv(file="reference/go/tcruzi_all_go.tab.gz", sep="\t", header=FALSE)
colnames(go_ids) <- c("ID","GOID","ontology","name","evidence","code")
go_ids <- go_ids[,c("ID","GOID")]
colnames(go_ids) <- c("ID","GO")
condition_ontology <- limma_ontology(condition_tables, gene_lengths=gene_lengths, goids=go_ids, n=200, excel=TRUE, csv=FALSE, do_trees=FALSE, do_cluster=TRUE, do_topgo=TRUE)

a60_cl14clbr_ls <- hpgl_linear_scatter(condition_table[,c("a60_cl14", "a60_clbr")], loess=TRUE)
a60_cl14clbr_ls$scatter
a60_cl14clbr_ls$both_histogram$plot
a60_cl14clbr_ls$lm_model
a60_cl14clbr_ls$lm_summary
a60_cl14clbr_ls$correlation

a96_cl14clbr_ls <- hpgl_linear_scatter(condition_table[,c("a96_cl14", "a96_clbr")], loess=TRUE)
a96_cl14clbr_ls$scatter
a96_cl14clbr_ls$both_histogram$plot
a96_cl14clbr_ls$lm_model
a96_cl14clbr_ls$lm_summary
a96_cl14clbr_ls$correlation

tryp_cl14clbr_ls <- hpgl_linear_scatter(condition_table[,c("tryp_cl14", "tryp_clbr")], loess=TRUE)
tryp_cl14clbr_ls$scatter
tryp_cl14clbr_ls$both_histogram$plot
tryp_cl14clbr_ls$lm_model
tryp_cl14clbr_ls$lm_summary
tryp_cl14clbr_ls$correlation

18.1 Write out the results of the contrasts

topTable() will get called quite a lot in order to generate the various tables of interest. write_xls() will follow to write out the results into some excel spreadsheets.

## I wrote a function 'write_limma' which takes care of making a data structure of all the tables and printing the results in excel.
## Lets use that rather than this stupid list of topTable() calls.
## In addition, I am adding q-values and other metrics to improve the output from toptable, so it is a win I think.

kept_table <- topTable(kept_comparisons, adjust="fdr", n=nrow(kept_data))
## Use the coef argument to pull out adjusted p-values for subsections of the data
all_tables <- write_limma(kept_comparisons)

18.2 Plot some results

The function hpgl_linear_scatter() provides an easy way to perform some simple visualizations of the contrasts

18.2.1 Compare Epimastigotes from CL14 to CLBrener

## Make some scatter plots of the input data to see if these tables seem sane.
epi_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("epi_cl14", "epi_clbr")], gvis_filename="html/epi_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
epi_cl14clbr_ls$scatter
epi_cl14clbr_ls$both_histogram$plot
epi_cl14clbr_ls$lm_model
epi_cl14clbr_ls$lm_summary
epi_cl14clbr_ls$correlation

18.2.2 Compare trypomastigotes from CL14 to CLBrener

tryp_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("tryp_cl14", "tryp_clbr")], gvis_filename="html/tryp_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
tryp_cl14clbr_ls$scatter
tryp_cl14clbr_ls$both_histogram$plot
tryp_cl14clbr_ls$lm_model
tryp_cl14clbr_ls$lm_summary
tryp_cl14clbr_ls$correlation

18.2.3 Compare Amastigote 60 hr from CL14 to CLBrener

a60_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("a60_cl14", "a60_clbr")], gvis_filename="html/a60_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a60_cl14clbr_ls$scatter
a60_cl14clbr_ls$both_histogram$plot
a60_cl14clbr_ls$lm_model
a60_cl14clbr_ls$lm_summary
a60_cl14clbr_ls$correlation

18.2.4 Compare Amastigote 96 hr CL14 to CLBrener

a96_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("a96_cl14", "a96_clbr")], gvis_filename="html/a96_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a96_cl14clbr_ls$scatter
a96_cl14clbr_ls$both_histogram$plot
a96_cl14clbr_ls$lm_model
a96_cl14clbr_ls$lm_summary
a96_cl14clbr_ls$correlation

18.2.5 Compare Epimastigote to Trypomastigote in CL14

epitryp_cl14_ls <- hpgl_linear_scatter(kept_table[,c("epi_cl14", "tryp_cl14")], gvis_filename="html/epitryp_cl14.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
epitryp_cl14_ls$scatter
epitryp_cl14_ls$both_histogram$plot
epitryp_cl14_ls$lm_model
epitryp_cl14_ls$lm_summary
epitryp_cl14_ls$correlation

18.2.6 Compare Epimastigotes to Trypomastigotes in CLBrener

epitryp_clbr_ls <- hpgl_linear_scatter(kept_table[,c("epi_clbr", "tryp_clbr")], gvis_filename="html/epitryp_clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
epitryp_clbr_ls$scatter
epitryp_clbr_ls$both_histogram$plot
epitryp_clbr_ls$lm_model
epitryp_clbr_ls$lm_summary
epitryp_clbr_ls$correlation

18.2.7 Compare Amastigote 96 hr to Trypomastigotes in CLBrener

a96tryp_clbr_ls <- hpgl_linear_scatter(kept_table[,c("a96_clbr", "tryp_clbr")], gvis_filename="html/a96tryp_clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a96tryp_clbr_ls$scatter
a96tryp_clbr_ls$both_histogram$plot
a96tryp_clbr_ls$lm_model
a96tryp_clbr_ls$lm_summary
a96tryp_clbr_ls$correlation

18.2.8 Compare Amastigote 96 hr to Trypomastigotes in CL14

a96tryp_cl14_ls <- hpgl_linear_scatter(kept_table[,c("a96_cl14", "tryp_cl14")], gvis_filename="html/a96tryp_cl14.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a96tryp_cl14_ls$scatter
a96tryp_cl14_ls$both_histogram$plot
a96tryp_cl14_ls$lm_model
a96tryp_cl14_ls$lm_summary
a96tryp_cl14_ls$correlation

18.2.9 Compare Amastigotes 60 to 96 hours in CL14

a60a96_cl14_ls <- hpgl_linear_scatter(kept_table[,c("a60_cl14", "a96_cl14")], gvis_filename="html/a60a96_cl14.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a60a96_cl14_ls$scatter
a60a96_cl14_ls$both_histogram$plot
a60a96_cl14_ls$lm_model
a60a96_cl14_ls$lm_summary
a60a96_cl14_ls$correlation

18.2.10 Compare Amastigote 60 to 96 hours in CLBrener

a60a96_clbr_ls <- hpgl_linear_scatter(kept_table[,c("a60_clbr", "a96_clbr")], gvis_filename="html/a60a96_clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a60a96_clbr_ls$scatter
a60a96_clbr_ls$both_histogram$plot
a60a96_clbr_ls$lm_model
a60a96_clbr_ls$lm_summary
a60a96_clbr_ls$correlation

18.2.11 Compare (epi/tryp)cl14 / (epi/tryp)clbr

## Something is messed up here
## I am going to add some more contrasts to figure out what went wrong
epitryp_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("epitryp_cl14", "epitryp_clbr")], gvis_filename="html/epitryp_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
epitryp_cl14clbr_ls$scatter
epitryp_cl14clbr_ls$both_histogram$plot
epitryp_cl14clbr_ls$lm_model
epitryp_cl14clbr_ls$lm_summary
epitryp_cl14clbr_ls$correlation

18.2.12 Compare (epi/a60)cl14 / (epi/a60)clbr

## OK, so the following two are solidly telling me that the epimastigote data is the weirdo, I think we can assume the CL14.
epia60_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("epia60_cl14", "epia60_clbr")], gvis_filename="html/epia60_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
epia60_cl14clbr_ls$scatter
epia60_cl14clbr_ls$both_histogram$plot
epia60_cl14clbr_ls$lm_model
epia60_cl14clbr_ls$lm_summary
epia60_cl14clbr_ls$correlation

18.2.13 Compare (tryp/a60)cl14 / (tryp/a60)clbr err the other way around…

a60tryp_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("a60tryp_cl14", "a60tryp_clbr")], gvis_filename="html/a60tryp_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a60tryp_cl14clbr_ls$scatter
a60tryp_cl14clbr_ls$both_histogram$plot
a60tryp_cl14clbr_ls$lm_model
a60tryp_cl14clbr_ls$lm_summary
a60tryp_cl14clbr_ls$correlation

18.2.14 Compare (a60/a96)cl14 / (a60/a96)clbr

a60a96_cl14clbr_ls <- hpgl_linear_scatter(kept_table[,c("a60a96_cl14", "a60a96_clbr")], gvis_filename="html/a60a96_cl14clbr.html", tooltip_data=tooltip_data, loess=TRUE, gvis_trendline="linear")
a60a96_cl14clbr_ls$scatter
a60a96_cl14clbr_ls$both_histogram$plot
a60a96_cl14clbr_ls$lm_model
a60a96_cl14clbr_ls$lm_summary
a60a96_cl14clbr_ls$correlation

I removed a section regarding batch effect removal from here. This section is not needed because I included its functionality in myr::graph_metrics()

19 My email to Kwame

The following is the text of a message I sent Kwame, which lays out my concerns in this data:

I just wanted to ping you – I poked further at my concern. I am 99% certain I set up the model matrix correctly and assigned the relative contributions of each sample in makeContrasts() correctly. The results I get when performing the contrasts look for the most part very much like what I would expect. My only concern is when I perform operations like: (x-y)-(a-b); in most instances they too look very much like what I expect, but in one instance one term(the x from my example) is consistently (~4/3 * a) which leaves an apparently linear relationship when there really should not be one. This caused me to be concerned that I misattributed the samples in makeContrasts(). Upon further examination I came to the conclusion that they were in fact correct. My second guess was (given things I have heard you/Hector/Najib say about the relationship between normalization and read depth) that either the x or a term was much higher or lower in depth than the others. I checked and this is not true (there are libsize differences, but they don’t look significant to me). My last guess is that one of the samples in x does not cluster as nicely as all the rest of the samples in the data set and this is somehow leading to a consistent effect throughout the dataset, but for the life of me I cannot find a reason why.

LS0tCnRpdGxlOiAiUk5Bc2VxIG9mIFQuY3J1emkgQ0wxNC9DTEJyOiBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbi4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICAgY29sbGFwc2VkOiBmYWxzZQogICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgPCEtLSBEb2N1bWVudCBwcmVsdWRlIHJldmlzaW9uIDIwMTctMDIgLS0+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CiMjIFRoZXNlIGFyZSB0aGUgb3B0aW9ucyBJIHRlbmQgdG8gZmF2b3IKbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gc20oZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldCgKICAgIHByb2dyZXNzID0gVFJVRSwKICAgIHZlcmJvc2UgPSBUUlVFLAogICAgd2lkdGggPSA5MCwKICAgIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlcnJvciA9IFRSVUUsCiAgICBmaWcud2lkdGggPSA4LAogICAgZmlnLmhlaWdodCA9IDgsCiAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucygKICAgIGRpZ2l0cyA9IDQsCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsCiAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpzZXQuc2VlZCgxKQpwcmV2aW91c19maWxlIDwtICJzYW1wbGVfZXN0aW1hdGlvbi5SbWQiCnJtZF9maWxlIDwtICJkaWZmZXJlbnRpYWxfZXhwcmVzc2lvbi5SbWQiCnZlciA8LSAiMjAxNzAzMDMiCnByZXZpb3VzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iLnJkYS54eiIsIHg9cHJldmlvdXNfZmlsZSkpCnRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIucmRhLnh6IiwgeD1ybWRfZmlsZSkpCmBgYAoKW2luZGV4Lmh0bWxdKGluZGV4Lmh0bWwpIFthbm5vdGF0aW9uLmh0bWxdKGFubm90YXRpb24uaHRtbCkgIFtzYW1wbGVfZXN0aW1hdGlvbnMuaHRtbF0oc2FtcGxlX2VzdGltYXRpb25zLmh0bWwpCgpgYGB7ciByZW5kZXJpbmcsIGluY2x1ZGU9RkFMU0UsIGV2YWw9RkFMU0V9CiMjIFRoaXMgYmxvY2sgaXMgdXNlZCB0byByZW5kZXIgYSBkb2N1bWVudCBmcm9tIHdpdGhpbiBpdC4Kcm1hcmtkb3duOjpyZW5kZXIocm1kX2ZpbGUpCgojIyBBbiBleHRyYSByZW5kZXJlciBmb3IgcGRmIG91dHB1dHIKbWFya2Rvd246OnJlbmRlcihybWRfZmlsZSwgb3V0cHV0X2Zvcm1hdD0icGRmX2RvY3VtZW50Iiwgb3V0cHV0X29wdGlvbnM9Yygic2tpcF9odG1sIikpCiMjIE9yIHRvIHNhdmUvbG9hZCBsYXJnZSBSZGF0YSBmaWxlcy4KaHBnbHRvb2xzOjo6c2F2ZW1lKCkKaHBnbHRvb2xzOjo6bG9hZG1lKCkKcm0obGlzdD1scygpKQpgYGAKCkluIHRoaXMgZG9jdW1lbnQsIHdlIHdpbGwgcGVyZm9ybSBhIHNlcmllcyBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNlcyB1c2luZyB0aGUgZGF0YSB3aGljaCBzdXJ2aXZlZCBzYW1wbGUgZXN0aW1hdGlvbi4KCmBgYHtyIGxvYWRtZSwgaW5jbHVkZT1GQUxTRX0KdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wcmV2aW91c19zYXZlKSkKYGBgCgojIEV4dHJhY3Qgc2lnbmlmaWNhbnRseSBjaGFuZ2VkIGdlbmVzCgpNeSBvcmlnaW5hbCB3b3JrIGluIHRoaXMgY29udGV4dCB3YXMgdG8gcGVyZm9ybSBhbGwgcG9zc2libGUgY29udHJhc3RzIHVzaW5nIHRoZSBlbnRpcmUgZGF0YQpzZXQuIEFmdGVyIGRpc2N1c3Npb24gd2l0aCBOYWppYiBhbmQgU2FudHV6YSwgaXQgd2FzIGluaXRpYWxseSBhZ3JlZWQgdGhhdCB3ZSB3b3VsZCB1c2UgYSBzbWFsbGVyCnN1YnNldCBpbiBvcmRlciB0byBldmFsdWF0ZSB0aGUgbWV0aG9kcyBmb3IgREUgYWxvbmcgd2l0aCBiYXRjaCBlZmZlY3RzIGV0Yy4KCmBgYHtyIERFX3J1bn0KIyMgY2xfYWxsX2tleHB0djEgY29tZXMgZnJvbSBzYW1wbGVfZXN0aW1hdGlvbnMgd2hlbiB3ZSByZW1vdmVkIGFuCiMjIG91dGxpZXIgc2FtcGxlIChocGdsMDQ5MCkuCmNsX2FsbF9maWx0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsX2FsbF9rZXhwdHYxLCBmaWx0ZXI9ImNiY2IiKSkKY2xfYWxsX2RlX3N2YSA8LSBzbShhbGxfcGFpcndpc2UoY2xfYWxsX2ZpbHQsIG1vZGVsX2JhdGNoPSJzdmEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaF92b29tPSJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkZ2VyX21ldGhvZD0ibG9uZyIpKQpgYGAKCiMgQ2hvb3NlIGNvbnRyYXN0cyB0byBrZWVwIGFuZCBldmFsdWF0ZQoKSSBhbSBnb2luZyB0byBzcGxpdCB0aGVzZSByZXN1bHRzIGludG8gMyBjYXRlZ29yaWVzOiBjbGJyZW5lciBhbmFseXNlcyBvdmVyIHRpbWUsIGNsMTQgb3ZlciB0aW1lLApjb21wYXJpc29ucyBvZiB0aGUgdHdvIHN0cmFpbnMuCgpgYGB7ciBjaG9vc2VfY29udHJhc3RzfQpjbGJfdGltZXNfa2VlcGVycyA8LSBsaXN0KAogICAgImNsYnJfdHJ5cF90b19hNjAiID0gYygiQ0xCci5BNjAiLCJDTEJyLlRyeXAiKSwKIyMgICAgImNsYnJfdHJ5cF90b19hOTYiID0gYygiQ0xCci5BOTYiLCJDTEJyLlRyeXAiKSwKICAgICJjbGJyX2E2MF90b19hOTYiID0gYygiQ0xCci5BOTYiLCJDTEJyLkE2MCIpLAogICAgImNsYnJfYTk2X3RvX3RyeXAiID0gYygiQ0xCci5UcnlwIiwiQ0xCci5BOTYiKSkKY2wxNF90aW1lc19rZWVwZXJzIDwtIGxpc3QoCiAgICAiY2wxNF90cnlwX3RvX2E2MCIgPSBjKCJDTDE0LkE2MCIsIkNMMTQuVHJ5cCIpLAojIyAgICAiY2wxNF90cnlwX3RvX2E5NiIgPSBjKCJDTDE0LkE5NiIsIkNMMTQuVHJ5cCIpLAogICAgImNsMTRfYTYwX3RvX2E5NiIgPSBjKCJDTDE0LkE5NiIsIkNMMTQuQTYwIiksCiAgICAiY2wxNF9hOTZfdG9fdHJ5cCIgPSBjKCJDTDE0LlRyeXAiLCJDTDE0LkE5NiIpKQpzdHJhaW5zX2tlZXBlcnMgPC0gbGlzdCgKICAgICJhNjBfY2xicl9vdmVyX2NsMTQiID0gYygiQ0xCci5BNjAiLCAiQ0wxNC5BNjAiKSwKICAgICJhOTZfY2xicl9vdmVyX2NsMTQiID0gYygiQ0xCci5BOTYiLCAiQ0wxNC5BOTYiKSwKICAgICJ0cnlwX2NsYnJfb3Zlcl9jbDE0IiA9IGMoIkNMQnIuVHJ5cCIsICJDTDE0LlRyeXAiKSkKYGBgCgojIEV4dHJhY3Qgc3RyYWluIGNvbXBhcmlzb25zCgpgYGB7ciBzdHJhaW5fY29tcGFyaXNvbl9leHRyYWN0LCBmaWcuc2hvdz0iaGlkZSJ9CnN0cmFpbl9jb21wYXJpc29ucyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhjbF9hbGxfZGVfc3ZhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9zdHJhaW5fY29tcGFyaXNvbnMtdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAiLnhsc3giKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnM9c3RyYWluc19rZWVwZXJzKSkKc3RyYWluX29ubHlfbGltbWEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoY2xfYWxsX2RlX3N2YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9zdHJhaW5fY29tcGFyaXNvbl9saW1tYS12IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnM9c3RyYWluc19rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlX2Jhc2ljPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlX2Rlc2VxPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlX2VkZ2VyPUZBTFNFKSkKYGBgCgojIENMQnJlbmVyIHRpbWUgY29tcGFyaXNvbnMKCmBgYHtyIGNsYnJfdGltZV9jb21wYXJpc29uX2V4dHJhY3QsIGZpZy5zaG93PSJoaWRlIn0KY2xiX2NvbXBhcmVfdGltZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoY2xfYWxsX2RlX3N2YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9jbGJfY29tcGFyZV90aW1lcy12IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnM9Y2xiX3RpbWVzX2tlZXBlcnMpKQpjbGJfb25seV9saW1tYSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhjbF9hbGxfZGVfc3ZhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL2NsYl9jb21wYXJlX3RpbWVzX2xpbW1hLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAiLnhsc3giKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycz1jbGJfdGltZXNfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZV9iYXNpYz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZV9kZXNlcT1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZV9lZGdlcj1GQUxTRSkpCmBgYAoKIyBDTDE0IHRpbWUgY29tcGFyaXNvbnMKCmBgYHtyIGNsMTRfdGltZV9jb21wYXJpc29uX2V4dHJhY3QsIGZpZy5zaG93PSJoaWRlIn0KY2wxNF9jb21wYXJlX3RpbWVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKGNsX2FsbF9kZV9zdmEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL2NsMTRfY29tcGFyZV90aW1lcy12IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXIsICIueGxzeCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycz1jbDE0X3RpbWVzX2tlZXBlcnMpKQpjbDE0X29ubHlfbGltbWEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoY2xfYWxsX2RlX3N2YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPXBhc3RlMCgiZXhjZWwvY2wxNF9jb21wYXJlX3RpbWVzX2xpbW1hLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzPWNsMTRfdGltZXNfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVfYmFzaWM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlX2Rlc2VxPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZV9lZGdlcj1GQUxTRSkpCmBgYAoKIyBCb3hwbG90cyBvZiBDTEIvQ0wxNCBnZW5lIGZhbWlsaWVzCgpIbW0gSSB0aGluayB0aGUgZ29hbCBsYWlkIG91dCBieSBOYWppYiBpcyB0byBoYXZlIHNvbWUgcGxvdHMgd2hpY2ggc2hvdyBpbiBhIG1vcmUgY29uY2lzZSBmYXNoaW9uCnRoZSBjaGFuZ2VzIG92ZXIgdGltZSBpbiB0aGVzZSBzcGVjaWZpYyBnZW5lIGZhbWlsaWVzIGFuZCBiZSBhYmxlIHRvIGNvbXBhcmUgdGhvc2UgZGlmZmVyZW5jZXMgZnJvbQpDTDE0IHRvIENMQnJlbmVyLgoKSSBtZXNzZWQgdXAgdGhlIHNlbWFudGljIGNvcHkgbnVtYmVyIGZpbHRlciB3aXRoIHRoaXMuCgpgYGB7ciBmYW1pbHlfYm94cGxvdHN9CiMjIEluIHRoaXMgY2FzZSwgSSB3YW50ICdyYW5kb20nIHRvIGJlIGEgc2FtcGxpbmcgb2YgYWxsIGRhdGEKZXh0cmFjdF9mYW1pbGllc19jbGJyIDwtIHNtKHNlbWFudGljX2NvcHludW1iZXJfZXh0cmFjdChjbGJfY29tcGFyZV90aW1lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW1hbnRpY19jb2x1bW49ImdlbmVkZXNjcmlwdGlvbiIpKQpleHRyYWN0X2ZhbWlsaWVzX2NsMTQgPC0gc20oc2VtYW50aWNfY29weW51bWJlcl9leHRyYWN0KGNsMTRfY29tcGFyZV90aW1lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW1hbnRpY19jb2x1bW49ImdlbmVkZXNjcmlwdGlvbiIpKQoKZGdmX2RmIDwtIGRhdGEuZnJhbWUoCiAgICAiY2xicl9hNjAiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hNjBfdG9fYTk2JERHRiRsaW1tYV9sb2dmYywKICAgICJjbDE0X2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X2E2MF90b19hOTYkREdGJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfYTk2IiA9IGV4dHJhY3RfZmFtaWxpZXNfY2xiciRkYXRhJGNsYnJfYTk2X3RvX3RyeXAkREdGJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfYTk2IiA9IGV4dHJhY3RfZmFtaWxpZXNfY2wxNCRkYXRhJGNsMTRfYTk2X3RvX3RyeXAkREdGJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX3RyeXBfdG9fYTYwJERHRiRsaW1tYV9sb2dmYywKICAgICJjbDE0X3RyeXAiID0gZXh0cmFjdF9mYW1pbGllc19jbDE0JGRhdGEkY2wxNF90cnlwX3RvX2E2MCRER0YkbGltbWFfbG9nZmMKKQptYXNwX2RmIDwtIGRhdGEuZnJhbWUoCiAgICAiY2xicl9hNjAiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hNjBfdG9fYTk2JE1BU1AkbGltbWFfbG9nZmMsCiAgICAiY2wxNF9hNjAiID0gZXh0cmFjdF9mYW1pbGllc19jbDE0JGRhdGEkY2wxNF9hNjBfdG9fYTk2JE1BU1AkbGltbWFfbG9nZmMsCiAgICAiY2xicl9hOTYiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hOTZfdG9fdHJ5cCRNQVNQJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfYTk2IiA9IGV4dHJhY3RfZmFtaWxpZXNfY2wxNCRkYXRhJGNsMTRfYTk2X3RvX3RyeXAkTUFTUCRsaW1tYV9sb2dmYywKICAgICJjbGJyX3RyeXAiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl90cnlwX3RvX2E2MCRNQVNQJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X3RyeXBfdG9fYTYwJE1BU1AkbGltbWFfbG9nZmMKKQptdWNpbl9kZiA8LSBkYXRhLmZyYW1lKAogICAgImNsYnJfYTYwIiA9IGV4dHJhY3RfZmFtaWxpZXNfY2xiciRkYXRhJGNsYnJfYTYwX3RvX2E5NiRtdWNpbiRsaW1tYV9sb2dmYywKICAgICJjbDE0X2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X2E2MF90b19hOTYkbXVjaW4kbGltbWFfbG9nZmMsCiAgICAiY2xicl9hOTYiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hOTZfdG9fdHJ5cCRtdWNpbiRsaW1tYV9sb2dmYywKICAgICJjbDE0X2E5NiIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X2E5Nl90b190cnlwJG11Y2luJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX3RyeXBfdG9fYTYwJG11Y2luJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X3RyeXBfdG9fYTYwJG11Y2luJGxpbW1hX2xvZ2ZjCikKc2lhbGlkYXNlX2RmIDwtIGRhdGEuZnJhbWUoCiAgICAiY2xicl9hNjAiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hNjBfdG9fYTk2JHNpYWxpZGFzZSRsaW1tYV9sb2dmYywKICAgICJjbDE0X2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X2E2MF90b19hOTYkc2lhbGlkYXNlJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfYTk2IiA9IGV4dHJhY3RfZmFtaWxpZXNfY2xiciRkYXRhJGNsYnJfYTk2X3RvX3RyeXAkc2lhbGlkYXNlJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfYTk2IiA9IGV4dHJhY3RfZmFtaWxpZXNfY2wxNCRkYXRhJGNsMTRfYTk2X3RvX3RyeXAkc2lhbGlkYXNlJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX3RyeXBfdG9fYTYwJHNpYWxpZGFzZSRsaW1tYV9sb2dmYywKICAgICJjbDE0X3RyeXAiID0gZXh0cmFjdF9mYW1pbGllc19jbDE0JGRhdGEkY2wxNF90cnlwX3RvX2E2MCRzaWFsaWRhc2UkbGltbWFfbG9nZmMKKQpyaHNfZGYgPC0gZGF0YS5mcmFtZSgKICAgICJjbGJyX2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX2E2MF90b19hOTYkUkhTJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfYTYwIiA9IGV4dHJhY3RfZmFtaWxpZXNfY2wxNCRkYXRhJGNsMTRfYTYwX3RvX2E5NiRSSFMkbGltbWFfbG9nZmMsCiAgICAiY2xicl9hOTYiID0gZXh0cmFjdF9mYW1pbGllc19jbGJyJGRhdGEkY2xicl9hOTZfdG9fdHJ5cCRSSFMkbGltbWFfbG9nZmMsCiAgICAiY2wxNF9hOTYiID0gZXh0cmFjdF9mYW1pbGllc19jbDE0JGRhdGEkY2wxNF9hOTZfdG9fdHJ5cCRSSFMkbGltbWFfbG9nZmMsCiAgICAiY2xicl90cnlwIiA9IGV4dHJhY3RfZmFtaWxpZXNfY2xiciRkYXRhJGNsYnJfdHJ5cF90b19hNjAkUkhTJGxpbW1hX2xvZ2ZjLAogICAgImNsMTRfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X3RyeXBfdG9fYTYwJFJIUyRsaW1tYV9sb2dmYwopCmdwNjNfZGYgPC0gZGF0YS5mcmFtZSgKICAgICJjbGJyX2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX2E2MF90b19hOTYkR1A2MyRsaW1tYV9sb2dmYywKICAgICJjbDE0X2E2MCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsMTQkZGF0YSRjbDE0X2E2MF90b19hOTYkR1A2MyRsaW1tYV9sb2dmYywKICAgICJjbGJyX2E5NiIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX2E5Nl90b190cnlwJEdQNjMkbGltbWFfbG9nZmMsCiAgICAiY2wxNF9hOTYiID0gZXh0cmFjdF9mYW1pbGllc19jbDE0JGRhdGEkY2wxNF9hOTZfdG9fdHJ5cCRHUDYzJGxpbW1hX2xvZ2ZjLAogICAgImNsYnJfdHJ5cCIgPSBleHRyYWN0X2ZhbWlsaWVzX2NsYnIkZGF0YSRjbGJyX3RyeXBfdG9fYTYwJEdQNjMkbGltbWFfbG9nZmMsCiAgICAiY2wxNF90cnlwIiA9IGV4dHJhY3RfZmFtaWxpZXNfY2wxNCRkYXRhJGNsMTRfdHJ5cF90b19hNjAkR1A2MyRsaW1tYV9sb2dmYwopCgpkZ2ZfYm94IDwtIHBsb3RfYm94cGxvdChkZ2ZfZGYpCmRnZl9ib3gKZGdmX2JlYW4gPC0gYmVhbnBsb3Q6OmJlYW5wbG90KGRnZl9kZiwgbWV0aG9kPSJqaXR0ZXIiKQptYXNwX2JveCA8LSBwbG90X2JveHBsb3QobWFzcF9kZikKbWFzcF9ib3gKbWFzcF9iZWFuIDwtIGJlYW5wbG90OjpiZWFucGxvdChtYXNwX2RmLCBtZXRob2Q9ImppdHRlciIpCm11Y2luX2JveCA8LSBwbG90X2JveHBsb3QobXVjaW5fZGYpCm11Y2luX2JveAptdWNpbl9iZWFuIDwtIGJlYW5wbG90OjpiZWFucGxvdChtdWNpbl9kZiwgbWV0aG9kPSJqaXR0ZXIiKQpzaWFsaWRhc2VfYm94IDwtIHBsb3RfYm94cGxvdChzaWFsaWRhc2VfZGYpCnNpYWxpZGFzZV9ib3gKc2lhbGlkYXNlX2JlYW4gPC0gYmVhbnBsb3Q6OmJlYW5wbG90KHNpYWxpZGFzZV9kZiwgbWV0aG9kPSJqaXR0ZXIiKQpyaHNfYm94IDwtIHBsb3RfYm94cGxvdChyaHNfZGYpCnJoc19ib3gKcmhzX2JlYW4gPC0gYmVhbnBsb3Q6OmJlYW5wbG90KHJoc19kZiwgbWV0aG9kPSJqaXR0ZXIiKQpncF9ib3ggPC0gcGxvdF9ib3hwbG90KGdwNjNfZGYpCmdwX2JveApncF9iZWFuIDwtIGJlYW5wbG90OjpiZWFucGxvdChncDYzX2RmLCBtZXRob2Q9ImppdHRlciIpCgojIyBDb21wYXJlIERHRiBkaXN0cmlidXRpb25zIGFjcm9zcyBzdHJhaW5zCmNvci50ZXN0KGRnZl9kZltbImNsYnJfdHJ5cCJdXSwgZGdmX2RmW1siY2wxNF90cnlwIl1dKQp0LnRlc3QoZGdmX2RmW1siY2xicl90cnlwIl1dLCBkZ2ZfZGZbWyJjbDE0X3RyeXAiXV0pCmtzLnRlc3QoZGdmX2RmW1siY2xicl90cnlwIl1dLCBkZ2ZfZGZbWyJjbDE0X3RyeXAiXV0pCmNvci50ZXN0KGRnZl9kZltbImNsYnJfYTYwIl1dLCBkZ2ZfZGZbWyJjbDE0X2E2MCJdXSkKdC50ZXN0KGRnZl9kZltbImNsYnJfYTYwIl1dLCBkZ2ZfZGZbWyJjbDE0X2E2MCJdXSkKa3MudGVzdChkZ2ZfZGZbWyJjbGJyX2E2MCJdXSwgZGdmX2RmW1siY2wxNF9hNjAiXV0pCmNvci50ZXN0KGRnZl9kZltbImNsYnJfYTk2Il1dLCBkZ2ZfZGZbWyJjbDE0X2E5NiJdXSkKdC50ZXN0KGRnZl9kZltbImNsYnJfYTk2Il1dLCBkZ2ZfZGZbWyJjbDE0X2E5NiJdXSkKa3MudGVzdChkZ2ZfZGZbWyJjbGJyX2E5NiJdXSwgZGdmX2RmW1siY2wxNF9hOTYiXV0pCgojIyBDb21wYXJlIE1BU1AgZGlzdHJpYnV0aW9ucyBhY3Jvc3Mgc3RyYWlucwpjb3IudGVzdChtYXNwX2RmW1siY2xicl90cnlwIl1dLCBtYXNwX2RmW1siY2wxNF90cnlwIl1dKQp0LnRlc3QobWFzcF9kZltbImNsYnJfdHJ5cCJdXSwgbWFzcF9kZltbImNsMTRfdHJ5cCJdXSkKa3MudGVzdChtYXNwX2RmW1siY2xicl90cnlwIl1dLCBtYXNwX2RmW1siY2wxNF90cnlwIl1dKQpjb3IudGVzdChtYXNwX2RmW1siY2xicl9hNjAiXV0sIG1hc3BfZGZbWyJjbDE0X2E2MCJdXSkKdC50ZXN0KG1hc3BfZGZbWyJjbGJyX2E2MCJdXSwgbWFzcF9kZltbImNsMTRfYTYwIl1dKQprcy50ZXN0KG1hc3BfZGZbWyJjbGJyX2E2MCJdXSwgbWFzcF9kZltbImNsMTRfYTYwIl1dKQpjb3IudGVzdChtYXNwX2RmW1siY2xicl9hOTYiXV0sIG1hc3BfZGZbWyJjbDE0X2E5NiJdXSkKdC50ZXN0KG1hc3BfZGZbWyJjbGJyX2E5NiJdXSwgbWFzcF9kZltbImNsMTRfYTk2Il1dKQprcy50ZXN0KG1hc3BfZGZbWyJjbGJyX2E5NiJdXSwgbWFzcF9kZltbImNsMTRfYTk2Il1dKQoKIyMgQ29tcGFyZSBNVUNJTiBkaXN0cmlidXRpb25zIGFjcm9zcyBzdHJhaW5zCmNvci50ZXN0KG11Y2luX2RmW1siY2xicl90cnlwIl1dLCBtdWNpbl9kZltbImNsMTRfdHJ5cCJdXSkKdC50ZXN0KG11Y2luX2RmW1siY2xicl90cnlwIl1dLCBtdWNpbl9kZltbImNsMTRfdHJ5cCJdXSkKa3MudGVzdChtdWNpbl9kZltbImNsYnJfdHJ5cCJdXSwgbXVjaW5fZGZbWyJjbDE0X3RyeXAiXV0pCmNvci50ZXN0KG11Y2luX2RmW1siY2xicl9hNjAiXV0sIG11Y2luX2RmW1siY2wxNF9hNjAiXV0pCnQudGVzdChtdWNpbl9kZltbImNsYnJfYTYwIl1dLCBtdWNpbl9kZltbImNsMTRfYTYwIl1dKQprcy50ZXN0KG11Y2luX2RmW1siY2xicl9hNjAiXV0sIG11Y2luX2RmW1siY2wxNF9hNjAiXV0pCmNvci50ZXN0KG11Y2luX2RmW1siY2xicl9hOTYiXV0sIG11Y2luX2RmW1siY2wxNF9hOTYiXV0pCnQudGVzdChtdWNpbl9kZltbImNsYnJfYTk2Il1dLCBtdWNpbl9kZltbImNsMTRfYTk2Il1dKQprcy50ZXN0KG11Y2luX2RmW1siY2xicl9hOTYiXV0sIG11Y2luX2RmW1siY2wxNF9hOTYiXV0pCgojIyBDb21wYXJlIFNJQUxJREFTRSBkaXN0cmlidXRpb25zIGFjcm9zcyBzdHJhaW5zCmNvci50ZXN0KHNpYWxpZGFzZV9kZltbImNsYnJfdHJ5cCJdXSwgc2lhbGlkYXNlX2RmW1siY2wxNF90cnlwIl1dKQp0LnRlc3Qoc2lhbGlkYXNlX2RmW1siY2xicl90cnlwIl1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X3RyeXAiXV0pCmtzLnRlc3Qoc2lhbGlkYXNlX2RmW1siY2xicl90cnlwIl1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X3RyeXAiXV0pCmNvci50ZXN0KHNpYWxpZGFzZV9kZltbImNsYnJfYTYwIl1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X2E2MCJdXSkKdC50ZXN0KHNpYWxpZGFzZV9kZltbImNsYnJfYTYwIl1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X2E2MCJdXSkKa3MudGVzdChzaWFsaWRhc2VfZGZbWyJjbGJyX2E2MCJdXSwgc2lhbGlkYXNlX2RmW1siY2wxNF9hNjAiXV0pCmNvci50ZXN0KHNpYWxpZGFzZV9kZltbImNsYnJfYTk2Il1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X2E5NiJdXSkKdC50ZXN0KHNpYWxpZGFzZV9kZltbImNsYnJfYTk2Il1dLCBzaWFsaWRhc2VfZGZbWyJjbDE0X2E5NiJdXSkKa3MudGVzdChzaWFsaWRhc2VfZGZbWyJjbGJyX2E5NiJdXSwgc2lhbGlkYXNlX2RmW1siY2wxNF9hOTYiXV0pCgojIyBDb21wYXJlIFJIUyBkaXN0cmlidXRpb25zIGFjcm9zcyBzdHJhaW5zCmNvci50ZXN0KHJoc19kZltbImNsYnJfdHJ5cCJdXSwgcmhzX2RmW1siY2wxNF90cnlwIl1dKQp0LnRlc3QocmhzX2RmW1siY2xicl90cnlwIl1dLCByaHNfZGZbWyJjbDE0X3RyeXAiXV0pCmtzLnRlc3QocmhzX2RmW1siY2xicl90cnlwIl1dLCByaHNfZGZbWyJjbDE0X3RyeXAiXV0pCmNvci50ZXN0KHJoc19kZltbImNsYnJfYTYwIl1dLCByaHNfZGZbWyJjbDE0X2E2MCJdXSkKdC50ZXN0KHJoc19kZltbImNsYnJfYTYwIl1dLCByaHNfZGZbWyJjbDE0X2E2MCJdXSkKa3MudGVzdChyaHNfZGZbWyJjbGJyX2E2MCJdXSwgcmhzX2RmW1siY2wxNF9hNjAiXV0pCmNvci50ZXN0KHJoc19kZltbImNsYnJfYTk2Il1dLCByaHNfZGZbWyJjbDE0X2E5NiJdXSkKdC50ZXN0KHJoc19kZltbImNsYnJfYTk2Il1dLCByaHNfZGZbWyJjbDE0X2E5NiJdXSkKa3MudGVzdChyaHNfZGZbWyJjbGJyX2E5NiJdXSwgcmhzX2RmW1siY2wxNF9hOTYiXV0pCgojIyBDb21wYXJlIEdQNjMgZGlzdHJpYnV0aW9ucyBhY3Jvc3Mgc3RyYWlucwpjb3IudGVzdChncDYzX2RmW1siY2xicl90cnlwIl1dLCBncDYzX2RmW1siY2wxNF90cnlwIl1dKQp0LnRlc3QoZ3A2M19kZltbImNsYnJfdHJ5cCJdXSwgZ3A2M19kZltbImNsMTRfdHJ5cCJdXSkKa3MudGVzdChncDYzX2RmW1siY2xicl90cnlwIl1dLCBncDYzX2RmW1siY2wxNF90cnlwIl1dKQpjb3IudGVzdChncDYzX2RmW1siY2xicl9hNjAiXV0sIGdwNjNfZGZbWyJjbDE0X2E2MCJdXSkKdC50ZXN0KGdwNjNfZGZbWyJjbGJyX2E2MCJdXSwgZ3A2M19kZltbImNsMTRfYTYwIl1dKQprcy50ZXN0KGdwNjNfZGZbWyJjbGJyX2E2MCJdXSwgZ3A2M19kZltbImNsMTRfYTYwIl1dKQpjb3IudGVzdChncDYzX2RmW1siY2xicl9hOTYiXV0sIGdwNjNfZGZbWyJjbDE0X2E5NiJdXSkKdC50ZXN0KGdwNjNfZGZbWyJjbGJyX2E5NiJdXSwgZ3A2M19kZltbImNsMTRfYTk2Il1dKQprcy50ZXN0KGdwNjNfZGZbWyJjbGJyX2E5NiJdXSwgZ3A2M19kZltbImNsMTRfYTk2Il1dKQpgYGAKCiMgU3RyYWluIHNpZ25pZmljYW5jZQoKYGBge3Igc3RyYWluX3NpZ25pZmljYW5jZV9leHRyYWN0LCBmaWcuc2hvdz0iaGlkZSJ9CnN0cmFpbnNfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoc3RyYWluX2NvbXBhcmlzb25zLCBhY2NvcmRpbmdfdG89ImxpbW1hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL3N0cmFpbl9jb21wYXJpc29uc19zaWctdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IikpKQpgYGAKCiMgQ0xCciBzaWduaWZpY2FuY2UKCmBgYHtyIGNsYnJfc2lnbmlmaWNhbmNlX2V4dHJhY3QsIGZpZy5zaG93PSJoaWRlIn0KY2xicl90aW1lc19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhjbGJfY29tcGFyZV90aW1lcywgYWNjb3JkaW5nX3RvPSJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9jbGJfdGltZXNfc2lnLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXIsICIueGxzeCIpKSkKYGBgCiMgQ0wxNCBzaWduaWZpY2FuY2UKCmBgYHtyIGNsMTRfc2lnbmlmaWNhbmNlX2V4dHJhY3QsIGZpZy5zaG93PSJoaWRlIn0KY2wxNF90aW1lc19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhjbDE0X2NvbXBhcmVfdGltZXMsIGFjY29yZGluZ190bz0ibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPXBhc3RlMCgiZXhjZWwvY2wxNF90aW1lc19zaWctdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IikpKQpgYGAKCiMgU2FuaXR5IGNoZWNrIG9uIHJvdXRlIHRvIGFuIGltcHJvdmVkIG5vbi1ycGttIGV4cHJlc3Npb24gdmFsdWUKCkkgd2FudCB0byBtYWtlIDEwMCUgY2VydGFpbiB0aGF0IHdoZW4gSSBwbG90IHdoYXQgSSBjYWxsIHRoZSBjb2VmZmljaWVudCBzY2F0dGVyIHBsb3QsIHRoYXQgdGhlCmRvdHMgb24gdGhlIHNjcmVlbiBhcmUgaW4gZmFjdCByZXByZXNlbnRhdGl2ZSBvZiB0aGUgcG9zdC1saW1tYS9kZXNlcS9lZGdlciB2YWx1ZXMuCgpJIGtlZXAgYSBzZXQgb2YgdGFibGVzIGluIG15IGxpbW1hIG91dHB1dCBjYWxsZWQgJ2lkZW50aXR5X3RhYmxlcycgd2hpY2ggaW4gdGhlb3J5IGFyZSB0aGUKcHJlLWNvbnRyYXN0IHZhbHVlcyBmb3IgZWFjaCBnZW5lIGJ5IGNvbmRpdGlvbi4gIElmIEkgYW0gMTAwJSBjb3JyZWN0LCB0aGVuIEkgc2hvdWxkIGJlIGFibGUgdG8KcmVjcmVhdGUgdGhlIGxvZ0ZDIGZyb20gdG9wVGFibGUoKSBieSB0YWtpbm5nIHR3byBvZiB0aGVzZSBhbmQgc3VidHJhY3RpbmcgdGhlbS4KCmBgYHtyIHNhbml0eV9jaGVja19ub19ycGttfQp0ZXN0X2dlbmVzX2NsYnJfdHJ5cCA8LSBjbF9hbGxfZGVfc3ZhW1sibGltbWEiXV1bWyJpZGVudGl0eV90YWJsZXMiXV1bWyJDTEJyLlRyeXAiXV0KdGVzdF9nZW5lc19jbGJyX2E2MCA8LSBjbF9hbGxfZGVfc3ZhW1sibGltbWEiXV1bWyJpZGVudGl0eV90YWJsZXMiXV1bWyJDTEJyLkE2MCJdXQp0ZXN0X2dlbmVzX2NsYnJfY29udHJhc3QgPC0gY2xfYWxsX2RlX3N2YVtbImxpbW1hIl1dW1siYWxsX3RhYmxlcyJdXVtbIkNMQnIuVHJ5cF92c19DTEJyLkE2MCJdXQoKdGVzdF9nZW5lc19jbGJyX3RyeXBbIlRjQ0xCLjUxMTIxMS4xNjAiLCBdCnRlc3RfZ2VuZXNfY2xicl9hNjBbIlRjQ0xCLjUxMTIxMS4xNjAiLCBdCnRlc3RfZ2VuZXNfY2xicl9jb250cmFzdFsiVGNDTEIuNTExMjExLjE2MCIsIF0KMTAuNzcgLSAxMS42NApgYGAKCk9uIHRoZSBvdGhlciBoYW5kLCBJIGFsc28gd2FudCB0byBoYXZlIGEgc3RhbmRhcmQgZXJyb3IgLyB2YXJpYW5jZSBlc3RpbWF0ZSB0byBjb21lIGFsb25nIHdpdGggdGhpcwpkYXRhLiAgSSBoYXZlIHR3byBsaWtlbHkgcGxhY2VzIHRvIGFjcXVpcmUgdGhhdDoKCjEuICBBcyBwZXIgSGVjdG9yJ3MgZW1haWwsIHRha2UgdGhlIGxvZ0ZDIGZyb20gdGhlIGlkZW50aXR5IHRhYmxlIGFuZCBkaXZpZGUgaXQgYnkgdGhlIHQgc3RhdGlzdGljCiAgICBpbiB0aGUgc2FtZSB0YWJsZS4gIFRoaXMgc2hvdWxkIHByb3ZpZGUgc3RhbmRhcmQgZXJyb3IuCjIuICBlQmF5ZXMoKSBvciBwZXJoYXBzIGNvbnRyYXN0LmZpdCgpIEkgYW0gbm90IHN1cmUgd2hpY2gsIGdlbmVyYXRlcyBhIHRhYmxlIG5hbWVkICdzdGRldi51bnNjYWxlZCcgZm9yCiAgICBldmVyeSBnZW5lL2NvbmRpdGlvbi4gIFRoaXMgbWF5IGJlIGNvbGxlY3RlZC4KCldpdGggdGhhdCBpbiBtaW5kLCBJIHdyb3RlIGEgbGl0dGxlIGZ1bmN0aW9uIGdldF9wYWlyd2lzZV9nZW5lX2FidW5kYW5jZXMoKSB0aGF0IGNvbGxlY3RzIHRoZXNlIGluCmZvdXIgdGFibGVzOiBleHByZXNzaW9uX3ZhbHVlcywgdF92YWx1ZXMsIGVycm9yX3ZhbHVlcywgYW5kIHN0ZGV2X3ZhbHVlcy4KCmBgYHtyIGdldF9wYWlyd2lzZV9nZW5lX2FidW5kYW5jZXN9CmFidW5kYW5jZXMgPC0gZ2V0X3BhaXJ3aXNlX2dlbmVfYWJ1bmRhbmNlcyhjbF9hbGxfZGVfc3ZhKQpleHByZXNzaW9uX3dyaXR0ZW4gPC0gd3JpdGVfeGxzKGRhdGE9YWJ1bmRhbmNlc1tbImV4cHJlc3Npb25fdmFsdWVzIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0PSJleHByZXNzaW9uX3ZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9IlZhbHVlcyBtYWtpbmcgdXAgdGhlIGNvbnRyYXN0IGxvZ0ZDcyIpCmVycm9yX3dyaXR0ZW4gPC0gd3JpdGVfeGxzKGRhdGE9YWJ1bmRhbmNlc1tbImVycm9yX3ZhbHVlcyJdXSwgc3RhcnRfY29sPTE4LAogICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iRXJyb3IgdmFsdWUgb2J0YWluZWQgYnkgZGl2aWRpbmcgdGhlIGV4cHJlc3Npb24gLyB0LXN0YXRpc3RpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0PSJleHByZXNzaW9uX3ZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHdiPWV4cHJlc3Npb25fd3JpdHRlbltbIndvcmtib29rIl1dKQpvcGVueGxzeDo6c2F2ZVdvcmtib29rKHdiPWV4cHJlc3Npb25fd3JpdHRlbltbIndvcmtib29rIl1dLAogICAgICAgICAgICAgICAgICAgICAgIGZpbGU9ImV4Y2VsL3dyaXR0ZW5fYWJ1bmRhbmNlX3Rlc3QueGxzeCIsIG92ZXJ3cml0ZT1UUlVFKQoKIyNjYW5hcmllcyA8LSBjKCJUY0NMQi41MTE1MTEuNiIsICJUY0NMQi41MTE1MTEuMyIsICJUY0NMQi41MTE3MjcuMTkwIiwgIlRjQ0xCLjQ2OTc4NS40MCIsCiMjICAgICAgICAgICAgICAiVGNDTEIuNTA2NTYzLjEwIiwgIlRjQ0xCLjUxMTEyNy4xMCIsICJUY0NMQi41MDQwMDUuNiIsICJUY0NMQi41MDc2MTEuMzAwIikKY2FuYXJpZXMgPC0gYygiVGNDTEIuNTExNzI3LjE5MCIsICJUY0NMQi40Njk3ODUuNDAiLAogICAgICAgICAgICAgICJUY0NMQi41MDY1NjMuMTAiLCAiVGNDTEIuNTExMTI3LjEwIiwKICAgICAgICAgICAgICAiVGNDTEIuNTA0MDA1LjYiLCAiVGNDTEIuNTA3NjExLjMwMCIpCiMjIFJlb3JkZXIgdGhlIGRhdGEgdG8gbWF0Y2ggdGhlIGV4aXN0aW5nIGZpZ3VyZQpjb25kaXRpb25zIDwtIGMoIkNMQnIuQTYwIiwgIkNMQnIuQTk2IiwgIkNMQnIuVHJ5cCIsCiAgICAgICAgICAgICAgICAiQ0wxNC5BNjAiLCAiQ0wxNC5BOTYiLCAiQ0wxNC5UcnlwIikKZXhwcmVzc2lvbnMgPC0gYWJ1bmRhbmNlc1tbImV4cHJlc3Npb25fdmFsdWVzIl1dWywgY29uZGl0aW9uc10Kc3RkZXZzIDwtIGFidW5kYW5jZXNbWyJzdGRldl92YWx1ZXMiXV1bLCBjb25kaXRpb25zXQplcnJzIDwtIGFidW5kYW5jZXNbWyJlcnJvcl92YWx1ZXMiXV1bLCBjb25kaXRpb25zXQphZGpwX3ZhbHVlcyA8LSBsaXN0KCkKbGlicmFyeShnZ3Bsb3QyKQpmb3IgKG51bSBpbiAxOmxlbmd0aChjYW5hcmllcykpIHsKICAgIGNhbmFyeSA8LSBjYW5hcmllc1tudW1dCiAgICBwb2ludCA8LSAyIF4gZXhwcmVzc2lvbnNbY2FuYXJ5LCBdCiAgICAjI3N0ZGV2IDwtIDIgXiBzdGRldnNbY2FuYXJ5LCBdCiAgICBlcnIgPC0gMiBeIGVycnNbY2FuYXJ5LCBdCiAgICBteV9jb2xvcnMgPC0gYygiYmx1ZSIsImdyZWVuIiwicmVkIiwiYmx1ZSIsImdyZWVuIiwicmVkIikKICAgIGNhbmFyeV9kZiA8LSBkYXRhLmZyYW1lKAogICAgICAgICJpZCIgPSBjb2xuYW1lcyhwb2ludCksCiAgICAgICAgInZhbHVlcyIgPSBhcy5udW1lcmljKHBvaW50KSwKICAgICAgICAiY29sb3JzIiA9IG15X2NvbG9ycywKICAgICAgICAiZXJyIiA9IGFzLm51bWVyaWMoZXJyKSwKICAgICAgICAicGx1c19lcnIiID0gYXMubnVtZXJpYyhlcnIpICsgYXMubnVtZXJpYyhwb2ludCksCiAgICAgICAgIm1pbnVzX2VyciIgPSBhcy5udW1lcmljKHBvaW50KSAtIGFzLm51bWVyaWMoZXJyKSkKICAgIHByaW50KGNhbmFyeV9kZikKICAgIGZ1bl9iYXJwbG90IDwtIGdncGxvdDI6OmdncGxvdChkYXRhPWNhbmFyeV9kZiwgY29sb3VyPW15X2NvbG9ycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXNfc3RyaW5nKHg9ImlkIiwgeT0idmFsdWVzIikpICsKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGNvbG91cj0iYmxhY2siLCBmaWxsPW15X2NvbG9ycykgKwogICAgICAgIGdncGxvdDI6OnRoZW1lX2J3KCkgKyBnZ3Bsb3QyOjp5bGFiKCJFeHByZXNzaW9uIFZhbHVlIikgKwogICAgICAgIGdncGxvdDI6OmdndGl0bGUoY2FuYXJ5KSArCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcihhZXMoeW1heD1wbHVzX2VyciwgeW1pbj1taW51c19lcnIpLCB3aWR0aD0wLjMpCiAgICBwZGZfZmlsZW5hbWUgPC0gcGFzdGUwKCJpbWFnZXMvIiwgbnVtLCAiXyIsIGNhbmFyeSwgIl9leHByZXNzaW9uLnBkZiIpCiAgICBwZGYoZmlsZT1wZGZfZmlsZW5hbWUpCiAgICBwcmludChmdW5fYmFycGxvdCkKICAgIGRldi5vZmYoKQogICAgIyMgTm93IGV4dHJhY3QgdGhlIGFkanVzdGVkIHAtdmFsdWVzIGZyb20gdGhlIHBhaXJ3aXNlIGNvbnRyYXN0cy4uLgogICAgIyMgdGVzdF9nZW5lc19jbGJyX2NvbnRyYXN0IDwtIGNsX2FsbF9kZV9zdmFbWyJsaW1tYSJdXVtbImFsbF90YWJsZXMiXV1bWyJDTEJyLlRyeXBfdnNfQ0xCci5BNjAiXV0KICAgIGFkanBzIDwtIGMoKQogICAgdGhlX2NvbnRyYXN0cyA8LSBjKCJDTEJyLlRyeXBfdnNfQ0wxNC5UcnlwIiwgIkNMQnIuQTYwX3ZzX0NMMTQuQTYwIiwgIkNMQnIuQTk2X3ZzX0NMMTQuQTk2IikKICAgIGZvciAoY29udHIgaW4gdGhlX2NvbnRyYXN0cykgewogICAgICAgIGFkanAgPC0gY2xfYWxsX2RlX3N2YVtbImxpbW1hIl1dW1siYWxsX3RhYmxlcyJdXVtbY29udHJdXVtjYW5hcnksICJhZGouUC5WYWwiXQogICAgICAgIGFkanBzW1tjb250cl1dIDwtIGFkanAKICAgIH0KICAgIGFkanBfdmFsdWVzW1tjYW5hcnldXSA8LSBhZGpwcwp9CiMjIEEgcXVlcnkgZnJvbSBTYW50dXphLCBnZW5lcmF0ZSBwLXZhbHVlcyBiZXR3ZWVuIHNvbWUgb2YgdGhlc2UgYmFycy4KIyMgSG93IGRvIEkgZG8gdGhhdCB3aGVuIEkgZXh0cmFjdGVkIHRoZSB2YWx1ZXMgYW5kIHZhcmlhbmNlcyBmcm9tIGxpbW1hIHdpdGhvdXQgdGhlCiMjIGFzc29jaWF0ZWQgcmF3IHZhbHVlcz8KIyMgaG1tLi4uCmFkanBfdmFsdWVzCmBgYAoKIyBTaWduaWZpY2FuY2UgYmFyIHBsb3RzCgpgYGB7ciBzaWdiYXJfcGxvdHN9CmNsYnJfYmFycyA8LSBzbShzaWduaWZpY2FudF9iYXJwbG90cyhjbGJfY29tcGFyZV90aW1lcykpCnBkZihmaWxlPSJpbWFnZXMvbGltbWEucGRmIikKY2xicl9iYXJzJGxpbW1hCmRldi5vZmYoKQoKY2xicl9pbnYgPC0gc20oc2lnbmlmaWNhbnRfYmFycGxvdHMoY2xiX2NvbXBhcmVfdGltZXMpKQpwZGYoZmlsZT0iaW1hZ2VzL2xpbW1hX2ludmVydC5wZGYiKQpjbGJyX2ludiRsaW1tYQpkZXYub2ZmKCkKCmNsMTRfYmFycyA8LSBzbShzaWduaWZpY2FudF9iYXJwbG90cyhjbDE0X2NvbXBhcmVfdGltZXMpKQpzdHJhaW5fYmFycyA8LSBzbShzaWduaWZpY2FudF9iYXJwbG90cyhzdHJhaW5fY29tcGFyaXNvbnMpKQoKY2xicl9iYXJzJGxpbW1hCmNsMTRfYmFycyRsaW1tYQpzdHJhaW5fYmFycyRsaW1tYQpgYGAKCiMgTmV3IGl0ZW0KClJlZG8gR08gYW5hbHlzZXMgZXhjbHVkaW5nIG11bHRpZ2VuZSBmYW1pbHkgbWVtYmVycy4gSSBiZWxpZXZlIHdlIGRpc2N1c3NlZCB0aGF0IHRoZSBiZXN0IHdheSB0byBkbwp0aGlzIHdhcyB0bzoKCjEpIGdlbmVyYXRlIERFIHRhYmxlcyB3aXRoIG11bHRpZ2VuZSBmYW1pbHkgbWVtYmVycyBmaWx0ZXJlZCBvdXQKMikgUmVkbyBHTy9LRUdHIG9uIHJlbWFpbmRlci4KCmBgYHtyIHJlbW92ZV9tdWx0aWdlbmVzfQojI2NsYnJfdGltZXNfZmlsdGVyZWQgPC0gc2VtYW50aWNfY29weW51bWJlcl9maWx0ZXIoY2xicl90aW1lc19zaWckbGltbWEsIHNlbWFudGljX2NvbHVtbj0iZ2VuZWRlc2NyaXB0aW9uIikKIyNjbDE0X3RpbWVzX2ZpbHRlcmVkIDwtIHNlbWFudGljX2NvcHludW1iZXJfZmlsdGVyKGNsMTRfdGltZXNfc2lnJGxpbW1hLCBzZW1hbnRpY19jb2x1bW49ImdlbmVkZXNjcmlwdGlvbiIpCiMjc3RyYWluc19maWx0ZXJlZCA8LSBzZW1hbnRpY19jb3B5bnVtYmVyX2ZpbHRlcihzdHJhaW5zX3NpZyRsaW1tYSwgc2VtYW50aWNfY29sdW1uPSJnZW5lZGVzY3JpcHRpb24iKQpjbGJyX3RpbWVzX2ZpbHRlcmVkIDwtIHNtKHNlbWFudGljX2NvcHludW1iZXJfZmlsdGVyKGNsYl9jb21wYXJlX3RpbWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbWFudGljX2NvbHVtbj0iZ2VuZWRlc2NyaXB0aW9uIikpCmNsMTRfdGltZXNfZmlsdGVyZWQgPC0gc20oc2VtYW50aWNfY29weW51bWJlcl9maWx0ZXIoY2wxNF9jb21wYXJlX3RpbWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbWFudGljX2NvbHVtbj0iZ2VuZWRlc2NyaXB0aW9uIikpCnN0cmFpbnNfZmlsdGVyZWQgPC0gc20oc2VtYW50aWNfY29weW51bWJlcl9maWx0ZXIoc3RyYWluX2NvbXBhcmlzb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbWFudGljX2NvbHVtbj0iZ2VuZWRlc2NyaXB0aW9uIikpCgpjbGJyX3RpbWVzX3NpZ2ZpbHQgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhjbGJyX3RpbWVzX2ZpbHRlcmVkLCBhY2NvcmRpbmdfdG89ImxpbW1hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9jbGJfdGltZXNfZmlsdGVyZWRfc2lnLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAiLnhsc3giKSkpCmNsMTRfdGltZXNfc2lnZmlsdCA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGNsMTRfdGltZXNfZmlsdGVyZWQsIGFjY29yZGluZ190bz0ibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL2NsMTRfdGltZXNfZmlsdGVyZWRfc2lnLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAiLnhsc3giKSkpCnN0cmFpbnNfc2lnZmlsdCA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKHN0cmFpbnNfZmlsdGVyZWQsIGFjY29yZGluZ190bz0ibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL3N0cmFpbl9jb21wYXJpc29uc19maWx0ZXJlZF9zaWctdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXIsICIueGxzeCIpKSkKCiMjIE5hamliIHdhbnRzIHRvIGtub3cgaG93IG1hbnkgZW50cmllcyBmb3IgZWFjaCBmYW1pbHkgd2VyZSByZW1vdmVkIGJ5IHRoZSBzZW1hbnRpYyBmaWx0ZXJpbmcKIyMgZnJvbSB0aGUgc2lnbmlmaWNhbmNlIHRhYmxlcy4Kc2VtYW50aWNfbmFtZXMgPC0gYygibXVjaW4iLCJzaWFsaWRhc2UiLCJSSFMiLCJNQVNQIiwiREdGIiwiR1A2MyIpCmZpbmRfbnVtYmVycyA8LSBmdW5jdGlvbihkYXR1bSwgZGlyZWN0aW9uPSJ1cHMiLCB0YWJsZV9uYW1lPSJjbGJyX3RyeXBfdG9fYTYwIikgewogICAgZm9yIChuYW1lIGluIHNlbWFudGljX25hbWVzKSB7CiAgICAgICAgdGFibGUgPC0gZGF0dW1bWyJsaW1tYSJdXVtbZGlyZWN0aW9uXV1bW3RhYmxlX25hbWVdXQogICAgICAgIHNlYXJjaCA8LSBncmVwbChwYXR0ZXJuPW5hbWUsIHg9dGFibGVbWyJnZW5lZGVzY3JpcHRpb24iXV0pCiAgICAgICAgbnVtYmVyIDwtIHN1bShzZWFyY2gpCiAgICAgICAgbWVzc2FnZShwYXN0ZTAoIlRoZSAiLCBkaXJlY3Rpb24sICIgdGFibGUgIiwgdGFibGVfbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAiIHdhcyBwcnVuZWQgZm9yICIsCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSwgIiBieSAiLCBudW1iZXIsICIgZ2VuZXMuIikpCiAgICB9Cn0KZmluZF9udW1iZXJzKGNsYnJfdGltZXNfc2lnKQpmaW5kX251bWJlcnMoY2xicl90aW1lc19zaWcsIGRpcmVjdGlvbj0iZG93bnMiKQpmaW5kX251bWJlcnMoY2xicl90aW1lc19zaWcsIHRhYmxlX25hbWU9ImNsYnJfYTYwX3RvX2E5NiIpCmZpbmRfbnVtYmVycyhjbGJyX3RpbWVzX3NpZywgZGlyZWN0aW9uPSJkb3ducyIsIHRhYmxlX25hbWU9ImNsYnJfYTYwX3RvX2E5NiIpCmZpbmRfbnVtYmVycyhjbGJyX3RpbWVzX3NpZywgdGFibGVfbmFtZT0iY2xicl9hOTZfdG9fdHJ5cCIpCmZpbmRfbnVtYmVycyhjbGJyX3RpbWVzX3NpZywgZGlyZWN0aW9uPSJkb3ducyIsIHRhYmxlX25hbWU9ImNsYnJfYTk2X3RvX3RyeXAiKQoKZmluZF9udW1iZXJzKGNsMTRfdGltZXNfc2lnLCB0YWJsZV9uYW1lPSJjbDE0X3RyeXBfdG9fYTYwIikKZmluZF9udW1iZXJzKGNsMTRfdGltZXNfc2lnLCBkaXJlY3Rpb249ImRvd25zIiwgdGFibGVfbmFtZT0iY2wxNF90cnlwX3RvX2E2MCIpCmZpbmRfbnVtYmVycyhjbDE0X3RpbWVzX3NpZywgdGFibGVfbmFtZT0iY2wxNF9hNjBfdG9fYTk2IikKZmluZF9udW1iZXJzKGNsMTRfdGltZXNfc2lnLCBkaXJlY3Rpb249ImRvd25zIiwgdGFibGVfbmFtZT0iY2wxNF9hNjBfdG9fYTk2IikKZmluZF9udW1iZXJzKGNsMTRfdGltZXNfc2lnLCB0YWJsZV9uYW1lPSJjbDE0X2E5Nl90b190cnlwIikKZmluZF9udW1iZXJzKGNsMTRfdGltZXNfc2lnLCBkaXJlY3Rpb249ImRvd25zIiwgdGFibGVfbmFtZT0iY2wxNF9hOTZfdG9fdHJ5cCIpCmBgYAoKIyMgTWFueSBtYW55IE1BIHBsb3RzIQoKYGBge3IgbWFueV9tYXN9CmZpbGVuYW1lcyA8LSBjKCJtdWNpbi50eHQiLCAibWFzcC50eHQiLCAiZ3A2My50eHQiLCAidHJhbnNzaWFsaWRhc2UudHh0IiwKICAgICAgICAgICAgICAgInJldHJvdHJhbnNwb3Nvbi50eHQiLCAiZGlzcGVyc2VkLnR4dCIpCmZhbWlseV9jb2xvcnMgPC0gYygiYmx1ZSIsICJyZWQiLCAiZ3JlZW4iLCAicHVycGxlIiwgImJyb3duIiwgInllbGxvdyIpCm5hbWVzKGZhbWlseV9jb2xvcnMpIDwtIGMoIm11Y2luIiwgIk1BU1AiLCAiR1A2MyIsICJ0cmFuc19zaWFsaWRhc2UiLCAicmhzIiwgIkRHRiIpCmZvciAobnVtIGluIDE6bGVuZ3RoKG5hbWVzKGNsYl90aW1lc19rZWVwZXJzKSkpIHsKICAgIGNvbnRyYXN0X25hbWVzIDwtIG5hbWVzKGNsYl90aW1lc19rZWVwZXJzKQogICAgY29udHJhc3QgPC0gY29udHJhc3RfbmFtZXNbW251bV1dCiAgICBmb3IgKGZpbGVfbnVtIGluIDE6bGVuZ3RoKGZpbGVuYW1lcykpIHsKICAgICAgICBjb2xvciA8LSBmYW1pbHlfY29sb3JzW1tmaWxlX251bV1dCiAgICAgICAgZmFtaWxpZXMgPC0gbmFtZXMoZmFtaWx5X2NvbG9ycykKICAgICAgICBmYW1pbHkgPC0gZmFtaWxpZXNbW2ZpbGVfbnVtXV0KICAgICAgICBmaWxlIDwtIGZpbGVuYW1lc1tbZmlsZV9udW1dXQogICAgICAgIGZpbGVuYW1lIDwtIHBhc3RlMCgicmVmZXJlbmNlL2ZhbWlsaWVzLyIsIGZpbGUpCiAgICAgICAgb3V0cHV0IDwtIHBhc3RlMCgiaW1hZ2VzLyIsIGNvbnRyYXN0LCAiXyIsIGZhbWlseSwgIl9tYS12IiwgdmVyLCAiLnBuZyIpCiAgICAgICAgc3ZnX291dHB1dCA8LSBwYXN0ZTAoImltYWdlcy8iLCBjb250cmFzdCwgIl8iLCBmYW1pbHksICJfbWEtdiIsIHZlciwgIi5zdmciKQogICAgICAgIGZhbWlseSA8LSByZWFkLmNzdihmaWxlbmFtZSwgaGVhZGVyPUZBTFNFLCBzZXA9IjoiKQogICAgICAgIGZhbWlseSA8LSBmYW1pbHlbWzFdXQogICAgICAgIGxpbW1hX3Bsb3QgPC0gZXh0cmFjdF9kZV9tYShjbGJfY29tcGFyZV90aW1lcywgdHlwZT0ibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZT1jb250cmFzdCwgZmFtaWx5PWZhbWlseSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5zaWdfY29sb3I9ImxpZ2h0Z3JleSIsIHNpZ19jb2xvcj0iIzQ0NDQ0NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseV9jb2xvcj1jb2xvciwgbGFiZWxfbnVtYmVycz1GQUxTRSkKICAgICAgICB0aGVfcGxvdCA8LSBsaW1tYV9wbG90JHBsb3QgKyB5bGltKC0xMCwgMTApICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKICAgICAgICBwbmcoZmlsZT1vdXRwdXQpCiAgICAgICAgcGxvdCh0aGVfcGxvdCkKICAgICAgICBkZXYub2ZmKCkKICAgICAgICBzdmcoZmlsZT1zdmdfb3V0cHV0KQogICAgICAgIHBsb3QodGhlX3Bsb3QpCiAgICAgICAgZGV2Lm9mZigpCiAgICB9Cn0KZm9yIChudW0gaW4gMTpsZW5ndGgobmFtZXMoY2wxNF90aW1lc19rZWVwZXJzKSkpIHsKICAgIGNvbnRyYXN0X25hbWVzIDwtIG5hbWVzKGNsMTRfdGltZXNfa2VlcGVycykKICAgIGNvbnRyYXN0IDwtIGNvbnRyYXN0X25hbWVzW1tudW1dXQogICAgZm9yIChmaWxlX251bSBpbiAxOmxlbmd0aChmaWxlbmFtZXMpKSB7CiAgICAgICAgY29sb3IgPC0gZmFtaWx5X2NvbG9yc1tbZmlsZV9udW1dXQogICAgICAgIGZhbWlsaWVzIDwtIG5hbWVzKGZhbWlseV9jb2xvcnMpCiAgICAgICAgZmFtaWx5IDwtIGZhbWlsaWVzW1tmaWxlX251bV1dCiAgICAgICAgZmlsZSA8LSBmaWxlbmFtZXNbW2ZpbGVfbnVtXV0KICAgICAgICBmaWxlbmFtZSA8LSBwYXN0ZTAoInJlZmVyZW5jZS9mYW1pbGllcy8iLCBmaWxlKQogICAgICAgIG91dHB1dCA8LSBwYXN0ZTAoImltYWdlcy8iLCBjb250cmFzdCwgIl8iLCBmYW1pbHksICJfbWEtdiIsIHZlciwgIi5wbmciKQogICAgICAgIHN2Z19vdXRwdXQgPC0gcGFzdGUwKCJpbWFnZXMvIiwgY29udHJhc3QsICJfIiwgZmFtaWx5LCAiX21hLXYiLCB2ZXIsICIuc3ZnIikKICAgICAgICBmYW1pbHkgPC0gcmVhZC5jc3YoZmlsZW5hbWUsIGhlYWRlcj1GQUxTRSwgc2VwPSI6IikKICAgICAgICBmYW1pbHkgPC0gZmFtaWx5W1sxXV0KICAgICAgICBsaW1tYV9wbG90IDwtIGV4dHJhY3RfZGVfbWEoY2wxNF9jb21wYXJlX3RpbWVzLCB0eXBlPSJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlPWNvbnRyYXN0LCBmYW1pbHk9ZmFtaWx5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnNpZ19jb2xvcj0ibGlnaHRncmV5Iiwgc2lnX2NvbG9yPSIjNDQ0NDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5X2NvbG9yPWNvbG9yLCBsYWJlbF9udW1iZXJzPUZBTFNFKQogICAgICAgIHRoZV9wbG90IDwtIGxpbW1hX3Bsb3QkcGxvdCArIHlsaW0oLTEwLCAxMCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQogICAgICAgIHBuZyhmaWxlPW91dHB1dCkKICAgICAgICBwbG90KHRoZV9wbG90KQogICAgICAgIGRldi5vZmYoKQogICAgICAgIHN2ZyhmaWxlPXN2Z19vdXRwdXQpCiAgICAgICAgcGxvdCh0aGVfcGxvdCkKICAgICAgICBkZXYub2ZmKCkKICAgIH0KfQpgYGAKCmBgYHtyIHNhdmVfbm93fQp0dCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCgojIE90aGVyIGhhcGxvdHlwZXMKCkkgdGhpbmsgSSBhbSB0aGUgb25seSBwZXJzb24gd2hvIGNhcmUgYWJvdXQgdGhlc2UgYW5hbHlzZXMsIHNvIEkgYW0gdGVsbGluZyBrbml0ciB0byBzdG9wCnJ1bm5pbmcgdGhlbS4KCmBgYHtyIG90aGVyX2hhcGxvdHlwZXNfY2xfZXNtZXIsIGV2YWw9RkFMU0V9CmNsX2VzbWVyX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsX2VzbWVyX2tleHB0LCBmaWx0ZXI9VFJVRSkpCmNsX2VzbWVyX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShjbF9lc21lcl9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbF9ub25lc21lciwgZXZhbD1GQUxTRX0KY2xfbm9uZXNtZXJfa2V4cHQgPC0gc20obm9ybWFsaXplX2V4cHQoY2xfbm9uZXNtZXJfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2xfbm9uZXNtZXJfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGNsX25vbmVzbWVyX2tleHB0LCBtb2RlbF9iYXRjaD0ic3ZhIikpCmBgYAoKYGBge3Igb3RoZXJfaGFwX2NsX2FsbCwgZXZhbD1GQUxTRX0KY2xfYWxsX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsX2FsbF9rZXhwdCwgZmlsdGVyPVRSVUUpKQpjbF9hbGxfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGNsX2FsbF9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbGJyX2VzbWVyLCBldmFsPUZBTFNFfQpjbGJyX2VzbWVyX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsYnJfZXNtZXJfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2xicl9lc21lcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoY2xicl9lc21lcl9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbGJyX25vbmVzbWVyLCBldmFsPUZBTFNFfQpjbGJyX25vbmVzbWVyX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsYnJfbm9uZXNtZXJfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2xicl9ub25lc21lcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoY2xicl9ub25lc21lcl9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbDE0X2VzbWVyLCBldmFsPUZBTFNFfQpjbDE0X2VzbWVyX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsMTRfZXNtZXJfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2wxNF9lc21lcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoY2wxNF9lc21lcl9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbDE0X25vbmVzbWVyLCBldmFsPUZBTFNFfQpjbDE0X25vbmVzbWVyX2tleHB0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KGNsMTRfbm9uZXNtZXJfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2wxNF9ub25lc21lcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoY2wxNF9ub25lc21lcl9rZXhwdCwgbW9kZWxfYmF0Y2g9InN2YSIpKQpgYGAKCmBgYHtyIG90aGVyX2hhcF9jbDE0X2FsbCwgZXZhbD1GQUxTRX0KY2wxNF9hbGxfa2V4cHQgPC0gc20obm9ybWFsaXplX2V4cHQoY2wxNF9hbGxfa2V4cHQsIGZpbHRlcj1UUlVFKSkKY2wxNF9hbGxfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGNsMTRfYWxsX2tleHB0LCBtb2RlbF9iYXRjaD0ic3ZhIikpCmBgYAoKYGBge3IgZGVfaHVtYW59CmhzX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfZXhwdCwgZmlsdGVyPVRSVUUpKQp0dCA8LSBzbShncmFwaF9tZXRyaWNzKGhzX25vcm0pKQpoc19kZSA8LSBzbShhbGxfcGFpcndpc2UoaHNfbm9ybSwgbW9kZWxfYmF0Y2g9InN2YXNlcSIpKQpgYGAKCiMjIFByaW50IEh1bWFuIGRhdGEKCiMjIyBNaWQgdnMgdW5pbmZlY3RlZAoKYGBge3IgZXh0cmFjdF9odW1hbl9jb250cmFzdHNfbWlkfQpoc19rZWVwZXJzIDwtIGxpc3QoCiAgICAiY2wxNF9taWR2c3VuaW5mIiA9IGMoIkNMMTQuQTYwIiwgIlVuaW5mZWN0ZWQiKSwKICAgICJjbGJyX21pZHZzdW5pbmYiID0gYygiQ0xCci5BNjAiLCAiVW5pbmZlY3RlZCIpKQpoc190YWJsZXNfbWlkIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKGhzX2RlLCBrZWVwZXJzPWhzX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9oc19taWRfY29tcGFyaXNvbnMtdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIyBMYXRlIHZzIHVuaW5mZWN0ZWQKCmBgYHtyIGV4dHJhY3RfaHVtYW5fY29udHJhc3RzX2xhdGV9CmhzX2tlZXBlcnMgPC0gbGlzdCgKICAgICJjbDE0X2xhdGV2c3VuaW5mIiA9IGMoIkNMMTQuQTk2IiwgIlVuaW5mZWN0ZWQiKSwKICAgICJjbGJyX2xhdGV2c3VuaW5mIiA9IGMoIkNMQnIuQTk2IiwgIlVuaW5mZWN0ZWQiKSkKaHNfdGFibGVzX2xhdGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoaHNfZGUsIGtlZXBlcnM9aHNfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9oc19sYXRlX2NvbXBhcmlzb25zLXYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAiLnhsc3giKSkpCmBgYAoKIyMjIExhdGUgdnMgbWlkCgpgYGB7ciBleHRyYWN0X2h1bWFuX2NvbnRyYXN0c19taWRsYXRlfQpoc19rZWVwZXJzIDwtIGxpc3QoCiAgICAiY2wxNF9sYXRldnNtaWQiID0gYygiQ0wxNC5BOTYiLCAiQ0wxNC5BNjAiKSwKICAgICJjbGJyX2xhdGV2c21pZCIgPSBjKCJDTEJyLkE5NiIsICJDTEJyLkE2MCIpKQpoc190YWJsZXNfbWlkbGF0ZSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhoc19kZSwga2VlcGVycz1oc19rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL2hzX21pZGxhdGVfY29tcGFyaXNvbnMtdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyMgU3RyYWlucwoKYGBge3IgZXh0cmFjdF9odW1hbl9jb250cmFzdHNfc3RyYWluc30KaHNfa2VlcGVycyA8LSBsaXN0KAogICAgIm1pZF9jbGJydnNjbDE0IiA9IGMoIkNMQnIuQTYwIiwgIkNMMTQuQTYwIiksCiAgICAibGF0ZV9jbGJydnNjbDE0IiA9IGMoIkNMQnIuQTk2IiwgIkNMMTQuQTk2IikpCmhzX3RhYmxlc19jbGJyY2wxNCA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhoc19kZSwga2VlcGVycz1oc19rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9oc19jbDE0Y2xicl9jb21wYXJpc29ucy12IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBFeHRyYWN0IHNpbmdsZS10b25zCgpJIHdhbnQgdG8gdGFrZSB0aGUgc2V0IG9mIHVwL2Rvd24gZ2VuZXMgYXMgcHJvdmlkZWQgYWJvdmUgaW4gY2hhbmdlZF9jb3VudHMgYW5kIHB1bGwgb3V0IG9mIHRoZW0gdGhlCnNldHMgb2YgbG93L3NpbmdsZSBjb3B5IGdlbmVzLiAgSW4gb3JkZXIgdG8gZG8gdGhpcywgSSB3aWxsIGxpa2VseSB1c2UgdGhlIHNhbWUgZmFzdGEzNiBzY3JpcHRzIEkKaGF2ZSB1c2VkIHByZXZpb3VzbHkgd2l0aCBHaW5nZXIgZXRjLiAgSSBtaWdodCBhbHNvL2luc3RlYWQgYXR0ZW1wdCB1c2luZyB0aGUgbmVlZGxlbWFuL3d1bnNjaAppbXBsZW1lbnRhdGlvbiBpbiBiaW9jb25kdWN0b3IuCgpFaXRoZXIgd2F5LCBhIHNpZ25pZmljYW50IHBvcnRpb24gb2YgdGhlIHdvcmsgd2lsbCByZXF1aXJlIGV4dHJhY3RpbmcgdGhlIGdlbmUgSURzIGZyb20KY2hhbmdlZF9jb3VudHMgZm9yIGVhY2ggdXAvZG93biBncm91cCwgcHVsbGluZyB0aGUgcmVsZXZhbnQgcHJpbWFyeSBzZXF1ZW5jZSwgYW5kIHBlcmZvcm1pbmcKd2hhdGV2ZXIgc2VhcmNoLgoKIyMgR2VuZXJhbCBnZW5lIGV4cHJlc3Npb24gKFJQS00pCgpTYW50dXphIHdvdWxkIGxpa2UgdG8gcG9rZSBhdCB0aGUgZ2VuZXJhbCBnZW5lIGV4cHJlc3Npb24gaW4gdmFyaW91cyBjb25kaXRpb25zLiAgVGhlcmVmb3JlIHRoaXMgaXMgY2FsY3VsYXRpbmcKYW5kIHByaW50aW5nIHRoZSBycGttIGFuZCByYXcgY291bnRzIHRvIGFuIGV4Y2VsIHdvcmtib29rLgoKCmBgYHtyIGdldF9ycGttLCBldmFsPUZBTFNFfQojIyBTYW50dXphIGFza2VkIGZvciBhIGxpc3Rpbmcgb2YgdGhlIHJwa20obm9ybWFsaXplZChjb3VudHMpKSBpbiBvcmRlciB0byBnZXQgYW4gaWRlYSBvZiB0aGUgaGlnaGx5IGV4cHJlc3NlZCBnZW5lcwojIyBBbHNvIGluY2x1ZGUgY2xicmVuZXIgZXBpbWFzdGlnb3RlcyBhbmQgZG8gYXZlcmFnZShycGttKSBieSBzYW1wbGUgdHlwZQojIyBUaGUgYmFzZSBleHByZXNzaW9uIHNldCB3ZSB3aWxsIHVzZSBpcyBjbF9hbGxfZmlsdAoKY2xfYWxsX3Jwa20gPC0gc20obm9ybWFsaXplX2V4cHQoY2xfYWxsX2ZpbHQsIGZpbHRlcj1UUlVFLCBjb252ZXJ0PSJycGttIikpCnJwa21fZGYgPC0gbWVyZ2UoQmlvYmFzZTo6ZkRhdGEoY2xfYWxsX2ZpbHQkZXhwcmVzc2lvbnNldCksCiAgICAgICAgICAgICAgICAgQmlvYmFzZTo6ZXhwcnMoY2xfYWxsX3Jwa21bWyJleHByZXNzaW9uc2V0Il1dKSwKICAgICAgICAgICAgICAgICBieS54PSJyb3cubmFtZXMiLCBieS55PSJyb3cubmFtZXMiKQpyb3duYW1lcyhycGttX2RmKSA8LSBycGttX2RmW1siUm93Lm5hbWVzIl1dCnJwa21fZGYgPSBycGttX2RmWywgLTFdCm1lZGlhbl9ycGttIDwtIG1lZGlhbl9ieV9mYWN0b3IoZGF0YT1jbF9hbGxfcnBrbSkKcnBrbV9kZiA8LSBtZXJnZShycGttX2RmLCBtZWRpYW5fcnBrbSwgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKHJwa21fZGYpIDwtIHJwa21fZGZbWyJSb3cubmFtZXMiXV0KcnBrbV9kZiA8LSBycGttX2RmWywgLTFdCnJhd19jb3VudHMgPC0gYXMuZGF0YS5mcmFtZShCaW9iYXNlOjpleHBycyhjbF9hbGxfZmlsdCRleHByZXNzaW9uc2V0KSkKcnBrbV9kZiA8LSBtZXJnZShyYXdfY291bnRzLCBycGttX2RmLCBieT0icm93Lm5hbWVzIikKcm93bmFtZXMocnBrbV9kZikgPC0gcnBrbV9kZltbIlJvdy5uYW1lcyJdXQpycGttX2RmIDwtIHJwa21fZGZbLCAtMV0KCnhsc19yZXQgPC0gd3JpdGVfeGxzKGFzLmRhdGEuZnJhbWUocnBrbV9kZiksIHNoZWV0PSJyYXdfdG9fcnBrbV9jb3VudHMiLAogICAgICAgICAgICAgICAgICAgICB0aXRsZT0iVGFibGUgU1hYWDogUmF3IGRhdGEgdG8gUlBLTShkYXRhKSIpCm9wZW54bHN4OjpzYXZlV29ya2Jvb2sod2I9eGxzX3JldFtbIndvcmtib29rIl1dLAogICAgICAgICAgICAgICAgICAgICAgIGZpbGU9cGFzdGUwKCJleGNlbC9ycGttX2NvdW50c19iYXNlMTAtdiIsIHZlciwgIi54bHN4IiksIG92ZXJ3cml0ZT1UUlVFKQpgYGAKCiMgUmVtb3ZlIGV2ZXJ5dGhpbmcgZnJvbSBoZXJlIGRvd24/CgpJIHRoaW5rIGV2ZXJ5dGhpbmcgZnJvbSBoZXJlIHRvIHRoZSBlbmQgb2YgdGhpcyBkb2N1bWVudCBpcyBubyBsb25nZXIgdXNlZnVsLgpCdXQgSSByZWZ1c2UgdG8gZGVsZXRlIGl0LgoKIyMgTGFyZ2VyIHN1YnNldAoKTGV0cyB0cnkgZm9yIGEgY29udmVuaWVudCBtZXRob2Qgb2YgaW5jbHVkaW5nIG9ubHkgdGhlIGNvbnRyYXN0cyBTYW50dXphIGlzIGludGVyZXN0ZWQgaW4uClRoZXNlIGluY2x1ZGUgKGJ1dCBtYXkgbm90IGJlIGxpbWl0ZWQgdG8pOgoKSSBzcG9rZSB3aXRoIFNhbnR1emEgcmlnaHQgYmVmb3JlIGxlYXZpbmcgZm9yIHRoZSBldmVuaW5nLCB0aGlzIGlzIGV4YWN0bHkgdGhlIG9wcG9zaXRlIG9mIHdoYXQgc2hlIHdhbnRlZC4KCkNMQih0cnlwL2E2MCkKQ0wxNCh0cnlwL2E2MCkKQ0xCKGE2MC9hOTYpCkNMMTQoYTYwL2E5NikKQ0xCKGE5Ni90cnlwKQpDTDE0KGE5Ni90cnlwKQphOTYoQ0wxNC9DTEIpCmE2MChDTDE0L0NMQikKdHJ5cChDTDE0L0NMQikKCkkgYW0gaG9waW5nIHRvIGNvbnZpbmNlIE5hamliIGFuZCBTYW50dXphIHRoYXQgdGhlIGVwaSBzYW1wbGVzIGFyZSBzYWx2YWdlYWJsZS4KCiMgVm9vbS9saW1tYSBpbnZvY2F0aW9uCgpUaGUgZm9sbG93aW5nIGZldyBjb21wYXJpc29ucyBhcmUgZ29pbmcgdG8gdXNlIHRoZSAnYWxsJyBkYXRhIHNldC4KV2hlbiBJIGRvIGEgbGFyZ2VyIHNldCBvZiBsaW1tYSBjb250cmFzdHMsIEkgd2lsbCBqdXN0IHVzZSB0aGUgJ2tlcHQnIHNldC4KCiMgU2ltcGxlIHBhaXJ3aXNlIGNvbXBhcmlzb25zCgpUaGUgZm9sbG93aW5nIGJsb2NrcyBhcmUgbm8gbG9uZ2VyIGJlaW5nIGV2YWx1YXRlZCBiZWNhdXNlIHRoZXkgcmVtb3ZlCm1vc3Qgb2YgdGhlIHNhbXBsZXMgZnJvbSB0aGUgZGF0YSBhbmQgdGhlcmVmb3JlIG92ZXItZXN0aW1hdGUgc2lnbmlmaWNhbmNlcy4KQnV0IHRoZXkgZG8gcHJvdmlkZSByZWFzb25hYmxlIGV4YW1wbGVzIG9mIGhvdyBvbmUgbWlnaHQgcGVyZm9ybSBzaW1wbGUKcGFpcndpc2UgY29tcGFyaXNvbnMgaW4gZGF0YS4KCiMjIENvbXBhcmUgZXBpbWFzdGlnb3RlcwoKCmBgYHtyIHNpbXBsZV9lcGksIGV2YWw9RkFMU0V9CmVwaV9zdWJzZXQgPC0gZXhwdF9zdWJzZXQoYWxsX3FjcG1sMiwgImNvbmRpdGlvbj09J2NsYnJfZXBpJ3xjb25kaXRpb249PSdjbDE0X2VwaSciKQplcGlfZ3JhcGhzIDwtIGdyYXBoX21ldHJpY3MoZXBpX3N1YnNldCkKZXBpX2dyYXBocyRub3JtX3BjYXBsb3QKZXBpX2dyYXBocyRub3JtX2Rpc2hlYXQKZXBpX2dyYXBocyRub3JtX2NvcmhlYXQKZXBpX2NvbXBhcmlzb24gPC0gc2ltcGxlX2NvbXBhcmlzb24oZXBpX3N1YnNldCkKZXBpX3RhYmxlIDwtIGVwaV9jb21wYXJpc29uJHRhYmxlCmVwaV9jb21wYXJpc29uJHB2YWx1ZV9oaXN0b2dyYW0KZXBpX2NvbXBhcmlzb24kdm9sY2Fub19wbG90CmVwaV9jb21wYXJpc29uJG1hX3Bsb3QKZXBpX2NvbXBhcmlzb24kY29lZmZpY2llbnRfc2NhdHRlcgpgYGAKCiMjIENvbXBhcmUgVHJ5cG9tYXN0aWdvdGVzCgpgYGB7ciBzaW1wbGVfdHJ5cCwgZXZhbD1GQUxTRX0KdHJ5cF9zdWJzZXQgPC0gZXhwdF9zdWJzZXQoYWxsX3FjcG1sMiwgImNvbmRpdGlvbj09J2NsYnJfdHJ5cCd8Y29uZGl0aW9uPT0nY2wxNF90cnlwJyIpCnRyeXBfZ3JhcGhzIDwtIGdyYXBoX21ldHJpY3MoZXhwdD10cnlwX3N1YnNldCkKdHJ5cF9ncmFwaHMkbm9ybV9wY2FwbG90CnRyeXBfZ3JhcGhzJG5vcm1fZGlzaGVhdAp0cnlwX2dyYXBocyRub3JtX2NvcmhlYXQKdHJ5cF9jb21wYXJpc29uIDwtIHNpbXBsZV9jb21wYXJpc29uKHRyeXBfc3Vic2V0KQp0cnlwX3RhYmxlID0gdHJ5cF9jb21wYXJpc29uJHRhYmxlCnRyeXBfY29tcGFyaXNvbiRwdmFsdWVfaGlzdG9ncmFtCnRyeXBfY29tcGFyaXNvbiR2b2xjYW5vX3Bsb3QKdHJ5cF9jb21wYXJpc29uJG1hX3Bsb3QKdHJ5cF9jb21wYXJpc29uJGNvZWZmaWNpZW50X3NjYXR0ZXIKYGBgCgojIyBDb21wYXJlIEFtYXN0aWdvdGVzIDYwIGhvdXJzCgpgYGB7ciBzaW1wbGVfYTYwLCBldmFsPUZBTFNFfQphNjBfc3Vic2V0IDwtIGV4cHRfc3Vic2V0KGFsbF9xY3BtbDIsICJjb25kaXRpb249PSdjbGJyX2E2MCd8Y29uZGl0aW9uPT0nY2wxNF9hNjAnIikKYTYwX2dyYXBocyA8LSBncmFwaF9tZXRyaWNzKGV4cHQ9YTYwX3N1YnNldCkKYTYwX2dyYXBocyRub3JtX3BjYXBsb3QKYTYwX2dyYXBocyRub3JtX2NvcmhlYXQKYTYwX2dyYXBocyRub3JtX2Rpc2hlYXQKYTYwX2NvbXBhcmlzb24gPC0gc2ltcGxlX2NvbXBhcmlzb24oYTYwX3N1YnNldCkKYTYwX3RhYmxlIDwtIGE2MF9jb21wYXJpc29uJHRhYmxlCmE2MF9jb21wYXJpc29uJHB2YWx1ZV9oaXN0b2dyYW0KYTYwX2NvbXBhcmlzb24kdm9sY2Fub19wbG90CmE2MF9jb21wYXJpc29uJG1hX3Bsb3QKYTYwX2NvbXBhcmlzb24kY29lZmZpY2llbnRfc2NhdHRlcgpgYGAKCiMgU2luZ2xlLWZhY3RvciBhbGwgdGhlIGNvbmRpdGlvbnMgYW5kIGJhdGNoZXMKCkEgbW9yZSBhcHByb3ByaWF0ZSBtZXRob2QgZm9yIHBlcmZvcm1pbmcgdGhlIHZhcmlvdXMgY29tcGFyaXNvbnMgb2YKc3RyYWlucyBhY3Jvc3MgdGltZSBpcyB0byBwdXQgYWxsIHRoZSBleHRhbnQgZGF0YSBpbnRvIGEgc2luZ2xlCmNvbnRyYXN0LiAgVGhlIGZvbGxvd2luZyBibG9jayBkb2VzIHRoYXQgYW5kIGF0dGVtcHRzIHRvIHRha2UgaW50bwphY2NvdW50IHRoZSByZWxhdGl2ZSBjb250cmlidXRpb24gb2YgZWFjaCBiYXRjaCBhbmQgc2FtcGxlLgoKVGhlIHZhcmlhYmxlcyB3aGljaCB3ZXJlIGNyZWF0ZWQgdG8gaG9sZCB0aGUgcmVsYXRpdmUgY29udHJpYnV0aW9ucyBvZgp0aGVzZSBzYW1wbGVzIHdlcmUgYWxzbyB1c2VkIHRvIHBlcmZvcm0gdGhlIHZhcmlvdXMgc3VidHJhY3Rpb25zLgpUaHVzLCB3aGVuIGxpbW1hIGlzIGFjdHVhbGx5IHJ1biwgaXQgd2lsbCBwcm92aWRlIGRhdGEgc3RydWN0dXJlcyBvZgp0aGUgYWJ1bmRhbmNlcyBvZiBlYWNoIHNhbXBsZSB0eXBlIGFzIHdlbGwgYXMgdGhlIHZhcmlvdXMgY29tcGFyaXNvbnMuCgpgYGB7ciBkYXRhX3NoYXJlZCwgZXZhbD1GQUxTRX0KIyMgVGhpcyBkYXRhIHN0cnVjdHVyZSB3aWxsIGJlIHVzZWQgZm9yIHRoZSBmb2xsb3dpbmcgcGxheWluZwprZXB0X2RhdGEgPC0gZXhwcnMoa2VwdF9xY3BtbDIkZXhwcmVzc2lvbnNldCkKYGBgCgpgYGB7ciBzaW5nbGVfZmFjdG9yLCBldmFsPUZBTFNFfQojIyBhY2Igc3RhbmRzIGZvciAiYWxsX2NvbmRpdGlvbnNfYmF0Y2hlcyIgIHdoaWNoIHRha2VzIHRvbyBsb25nIHRvCiMjIHR5cGUgd2hlbiBzZXR0aW5nIHVwIHRoZSBjb250cmFzdHMuCmFjYiA8LSBwYXN0ZTAoa2VwdF9xY3BtbDIkY29uZGl0aW9ucywga2VwdF9xY3BtbDIkYmF0Y2hlcykKdGFibGUoYWNiKQojIyBUaGUgaW52b2NhdGlvbiBvZiB0YWJsZSgpIGtlcHRvd3MgbWUgdG8gY291bnQgdXAgdGhlIGNvbnRyaWJ1dGlvbiBvZgojIyBlYWNoIGNvbmRpdGlvbi9iYXRjaCBjb21iaW5hdGlvbiB0byB0aGUgd2hvbGUgZGF0YSBzZXQuCgojIyBEb2luZyB0aGlzIChhcyBJIHVuZGVyc3RhbmQgaXQpIG1lYW5zIEkgZG8gbm90aGF2ZSB0byB3b3JyeSBhYm91dAojIyBiYWxhbmNlZCBzYW1wbGVzIHNvIG11Y2gsIGJ1dCBtdXN0IGJlIG1vcmUgY2FyZWZ1bCB0byB1bmRlcnN0YW5kCiMjIHRoZSByZWxhdGl2ZSBjb250cmlidXRpb24gb2YgZWFjaCBzYW1wbGUgdHlwZSB0byB0aGUgZW50aXJlIGRhdGEKIyMgc2V0LgoKY29tcGxldGVfbW9kZWwgPC0gbW9kZWwubWF0cml4KH4wICsgYWNiKQpjb21wbGV0ZV9maXQgPC0gbG1GaXQoa2VwdF9kYXRhLCBjb21wbGV0ZV9tb2RlbCkKY29tcGxldGVfdm9vbSA8LSBocGdsX3Zvb20oa2VwdF9kYXRhLCBjb21wbGV0ZV9tb2RlbCkKY29tcGxldGVfdm9vbSRwbG90CmNvbXBsZXRlX21vZGVsCgplcGlfY2wxNCA8LSAiYWNiY2wxNF9lcGlGIgplcGlfY2xiciA8LSAiYWNiY2xicl9lcGlFIgp0cnlwX2NsMTQgPC0gIihhY2JjbDE0X3RyeXBCICsgYWNiY2wxNF90cnlwRCArIGFjYmNsMTRfdHJ5cEcpIC8gMyIKdHJ5cF9jbGJyIDwtICJhY2JjbGJyX3RyeXBHIgphNjBfY2wxNCA8LSAiKGFjYmNsMTRfYTYwQSAqIDIvMykgKyAoYWNiY2wxNF9hNjBCICogMS8zKSIKYTYwX2NsYnIgPC0gImFjYmNsYnJfYTYwQSIKYTk2X2NsMTQgPC0gImFjYmNsMTRfYTk2QyIKYTk2X2NsYnIgPC0gImFjYmNsYnJfYTk2QyIKZXBpX2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsZXBpX2NsMTQsIikiLCAiICAtICAiLCAiKCIsZXBpX2NsYnIsIikiKQp0cnlwX2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsdHJ5cF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLHRyeXBfY2xiciwiKSIpCmE2MF9jbDE0Y2xiciA8LSBwYXN0ZTAoIigiLGE2MF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGE2MF9jbGJyLCIpIikKYTk2X2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsYTk2X2NsMTQsIikiLCAiICAtICAiLCAiKCIsYTk2X2NsYnIsIikiKQplcGl0cnlwX2NsMTQgPC0gcGFzdGUwKCIoIix0cnlwX2NsMTQsIikiLCAiICAtICAiLCAiKCIsZXBpX2NsMTQsIikiKQplcGl0cnlwX2NsYnIgPC0gcGFzdGUwKCIoIix0cnlwX2NsYnIsIikiLCAiICAtICAiLCAiKCIsZXBpX2NsYnIsIikiKQplcGlhNjBfY2wxNCA8LSBwYXN0ZTAoIigiLGE2MF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGVwaV9jbDE0LCIpIikKZXBpYTYwX2NsYnIgPC0gcGFzdGUwKCIoIixhNjBfY2xiciwiKSIsICIgIC0gICIsICIoIixlcGlfY2xiciwiKSIpCmE2MGE5Nl9jbDE0IDwtIHBhc3RlMCgiKCIsYTk2X2NsMTQsIikiLCAiICAtICAiLCAiKCIsYTYwX2NsMTQsIikiKQphNjBhOTZfY2xiciA8LSBwYXN0ZTAoIigiLGE5Nl9jbGJyLCIpIiwgIiAgLSAgIiwgIigiLGE2MF9jbGJyLCIpIikKYTYwdHJ5cF9jbDE0IDwtIHBhc3RlMCgiKCIsdHJ5cF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGE2MF9jbDE0LCIpIikKYTYwdHJ5cF9jbGJyIDwtIHBhc3RlMCgiKCIsdHJ5cF9jbGJyLCIpIiwgIiAgLSAgIiwgIigiLGE2MF9jbGJyLCIpIikKYTk2dHJ5cF9jbDE0IDwtIHBhc3RlMCgiKCIsdHJ5cF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGE5Nl9jbDE0LCIpIikKYTk2dHJ5cF9jbGJyIDwtIHBhc3RlMCgiKCIsdHJ5cF9jbGJyLCIpIiwgIiAgLSAgIiwgIigiLGE5Nl9jbGJyLCIpIikKCiMjIFRoZSBmb2xsb3dpbmcgY29udHJhc3QgaXMgbWVzc2VkIHVwIGluIHNvbWUgYXMgb2YgeWV0IHVua25vd24gd2F5LgplcGl0cnlwX2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsZXBpdHJ5cF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGVwaXRyeXBfY2xiciwiKSIpCiMjIFNvIEkgd2lsbCBhZGQgc29tZSBtb3JlIGNvbnRyYXN0cyB1c2luZyBkYXRhIHdoaWNoIGRvZXNuJ3QgZ2V0IHNjcmV3ZWQgdXAKZXBpYTYwX2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsZXBpYTYwX2NsMTQsIikiLCAiICAtICAiLCAiKCIsZXBpYTYwX2NsYnIsIikiKQphNjB0cnlwX2NsMTRjbGJyIDwtIHBhc3RlMCgiKCIsYTYwdHJ5cF9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGE2MHRyeXBfY2xiciwiKSIpCmE2MGE5Nl9jbDE0Y2xiciA8LSBwYXN0ZTAoIigiLGE2MGE5Nl9jbDE0LCIpIiwgIiAgLSAgIiwgIigiLGE2MGE5Nl9jbGJyLCIpIikKCmNvbXBsZXRlX2NvbnRyYXN0c192MiA8LSBtYWtlQ29udHJhc3RzKAogICAgZXBpX2NsMTQ9ZXBpX2NsMTQsCiAgICBlcGlfY2xicj1lcGlfY2xiciwKICAgIHRyeXBfY2wxND10cnlwX2NsMTQsCiAgICB0cnlwX2NsYnI9dHJ5cF9jbGJyLAogICAgYTYwX2NsMTQ9YTYwX2NsMTQsCiAgICBhNjBfY2xicj1hNjBfY2xiciwKICAgIGE5Nl9jbDE0PWE5Nl9jbDE0LAogICAgYTk2X2NsYnI9YTk2X2NsYnIsCiAgICBlcGlfY2wxNGNsYnI9ZXBpX2NsMTRjbGJyLAogICAgdHJ5cF9jbDE0Y2xicj10cnlwX2NsMTRjbGJyLAogICAgYTYwX2NsMTRjbGJyPWE2MF9jbDE0Y2xiciwKICAgIGE5Nl9jbDE0Y2xicj1hOTZfY2wxNGNsYnIsCiAgICBlcGl0cnlwX2NsMTQ9ZXBpdHJ5cF9jbDE0LAogICAgZXBpdHJ5cF9jbGJyPWVwaXRyeXBfY2xiciwKICAgIGVwaWE2MF9jbDE0PWVwaWE2MF9jbDE0LAogICAgZXBpYTYwX2NsYnI9ZXBpYTYwX2NsYnIsCiAgICBhNjBhOTZfY2wxND1hNjBhOTZfY2wxNCwKICAgIGE2MGE5Nl9jbGJyPWE2MGE5Nl9jbGJyLAogICAgYTYwdHJ5cF9jbDE0PWE2MHRyeXBfY2wxNCwKICAgIGE2MHRyeXBfY2xicj1hNjB0cnlwX2NsYnIsCiAgICBhOTZ0cnlwX2NsMTQ9YTk2dHJ5cF9jbDE0LAogICAgYTk2dHJ5cF9jbGJyPWE5NnRyeXBfY2xiciwKICAgIGVwaXRyeXBfY2wxNGNsYnI9ZXBpdHJ5cF9jbDE0Y2xiciwKICAgIGVwaWE2MF9jbDE0Y2xicj1lcGlhNjBfY2wxNGNsYnIsCiAgICBhNjB0cnlwX2NsMTRjbGJyPWE2MHRyeXBfY2wxNGNsYnIsCiAgICBhNjBhOTZfY2wxNGNsYnI9YTYwYTk2X2NsMTRjbGJyLAogICAgbGV2ZWxzPWNvbXBsZXRlX3Zvb20kZGVzaWduKQojIyBUaGlzIGNvbG5hbWVzKCkgaXMgYW5ub3lpbmdseSBuZWNlc3NhcnkgdG8gYXZvaWQgcmVhbGx5IG9ibm94aW91cyBjb250cmFzdCBuYW1lcy4KY29sbmFtZXMoY29tcGxldGVfY29udHJhc3RzX3YyKSA8LSBjKCJlcGlfY2wxNCIsImVwaV9jbGJyIiwidHJ5cF9jbDE0IiwidHJ5cF9jbGJyIiwiYTYwX2NsMTQiLCJhNjBfY2xiciIsImE5Nl9jbDE0IiwiYTk2X2NsYnIiLCJlcGlfY2wxNGNsYnIiLCJ0cnlwX2NsMTRjbGJyIiwiYTYwX2NsMTRjbGJyIiwiYTk2X2NsMTRjbGJyIiwiZXBpdHJ5cF9jbDE0IiwiZXBpdHJ5cF9jbGJyIiwiZXBpYTYwX2NsMTQiLCJlcGlhNjBfY2xiciIsImE2MHRyeXBfY2wxNCIsImE2MHRyeXBfY2xiciIsImE5NnRyeXBfY2wxNCIsImE5NnRyeXBfY2xiciIsImE2MGE5Nl9jbDE0IiwiYTYwYTk2X2NsYnIiLCJlcGl0cnlwX2NsMTRjbGJyIiwiZXBpYTYwX2NsMTRjbGJyIiwiYTYwdHJ5cF9jbDE0Y2xiciIsImE2MGE5Nl9jbDE0Y2xiciIpCmtlcHRfZml0cyA8LSBjb250cmFzdHMuZml0KGNvbXBsZXRlX2ZpdCwgY29tcGxldGVfY29udHJhc3RzX3YyKQprZXB0X2NvbXBhcmlzb25zIDwtIGVCYXllcyhrZXB0X2ZpdHMpCmBgYAoKIyBBbmFseXNpcyB3aXRoIG9ubHkgY29uZGl0aW9uIGluIHRoZSBtb2RlbAoKYGBge3IgY29uZGl0aW9uX29ubHksIGV2YWw9RkFMU0V9CmNvbiA8LSBrZXB0X3FjcG1sMiRjb25kaXRpb25zCmNvbmRpdGlvbl9tb2RlbCA8LSBtb2RlbC5tYXRyaXgofjAgKyBjb24pCmNvbmRpdGlvbl92b29tIDwtIGhwZ2xfdm9vbShrZXB0X2RhdGEsIGNvbmRpdGlvbl9tb2RlbCkKY29uZGl0aW9uX2xtZml0IDwtIGxtRml0KGNvbmRpdGlvbl92b29tLCBjb25kaXRpb25fbW9kZWwpCmRlcyA8LSBjb25kaXRpb25fdm9vbSRkZXNpZ24KY29uZGl0aW9uX2NvbnRyYXN0cyA8LSBtYWtlQ29udHJhc3RzKAogICAgZXBpX2NsMTQ9Y29uY2wxNF9lcGksCiAgICBlcGlfY2xicj1jb25jbGJyX2VwaSwKICAgIGE2MF9jbDE0PWNvbmNsMTRfYTYwLAogICAgYTYwX2NsYnI9Y29uY2xicl9hNjAsCiAgICBhOTZfY2wxND1jb25jbDE0X2E5NiwKICAgIGE5Nl9jbGJyPWNvbmNsYnJfYTk2LAogICAgdHJ5cF9jbDE0PWNvbmNsMTRfdHJ5cCwKICAgIHRyeXBfY2xicj1jb25jbGJyX3RyeXAsCiAgICBlcGlfY2wxNGNsYnI9Y29uY2wxNF9lcGkgLSBjb25jbGJyX2VwaSwKICAgIHRyeXBfY2wxNGNsYnI9Y29uY2wxNF90cnlwIC0gY29uY2xicl90cnlwLAogICAgYTYwX2NsMTRjbGJyPWNvbmNsMTRfYTYwIC0gY29uY2xicl9hNjAsCiAgICBhOTZfY2wxNGNsYnI9Y29uY2wxNF9hOTYgLSBjb25jbGJyX2E5NiwKICAgIGE2MGVwaV9jbGJyPWNvbmNsYnJfYTYwIC0gY29uY2xicl9lcGksCiAgICB0cnlwZXBpX2NsYnI9Y29uY2xicl90cnlwIC0gY29uY2xicl9lcGksCiAgICBhOTZhNjBfY2wxND1jb25jbDE0X2E5NiAtIGNvbmNsMTRfYTYwLAogICAgYTk2YTYwX2NsYnI9Y29uY2xicl9hOTYgLSBjb25jbGJyX2E2MCwKICAgIHRyeXBhOTZfY2wxND1jb25jbDE0X3RyeXAgLSBjb25jbDE0X2E5NiwKICAgIHRyeXBhOTZfY2xicj1jb25jbGJyX3RyeXAgLSBjb25jbGJyX2E5NiwKICAgIGE5NmE2MF9jbDE0Y2xicj0oY29uY2wxNF9hOTYtY29uY2wxNF9hNjApLShjb25jbGJyX2E5Ni1jb25jbGJyX2E2MCksCiAgICB0cnlwYTk2X2NsMTRjbGJyPShjb25jbDE0X3RyeXAtY29uY2wxNF9hOTYpLShjb25jbGJyX3RyeXAtY29uY2xicl9hOTYpLAogICAgbGV2ZWxzPWRlcykKY29sbmFtZXMoY29uZGl0aW9uX2NvbnRyYXN0cykgPC0gYygiZXBpX2NsMTQiLCJlcGlfY2xiciIsImE2MF9jbDE0IiwiYTYwX2NsYnIiLCJhOTZfY2wxNCIsImE5Nl9jbGJyIiwidHJ5cF9jbDE0IiwidHJ5cF9jbGJyIiwiZXBpX2NsMTRjbGJyIiwidHJ5cF9jbDE0Y2xiciIsImE2MF9jbDE0Y2xiciIsImE5Nl9jbDE0Y2xiciIsImE2MGVwaV9jbGJyIiwidHJ5cGVwaV9jbGJyIiwiYTYwYTk2X2NsMTQiLCJhNjBhOTZfY2xiciIsImE5NnRyeXBfY2wxNCIsImE5Nl90cnlwX2NsYnIiLCJhNjBhOTZfY2wxNGNsYnIiLCJhOTZ0cnlwX2NsMTRjbGJyIikKY29uZGl0aW9uX2ZpdHMgPC0gY29udHJhc3RzLmZpdChjb25kaXRpb25fbG1maXQsIGNvbmRpdGlvbl9jb250cmFzdHMpCmNvbmRpdGlvbl9jb21wYXJpc29ucyA8LSBlQmF5ZXMoY29uZGl0aW9uX2ZpdHMpCmNvbmRpdGlvbl90YWJsZSA8LSB0b3BUYWJsZShjb25kaXRpb25fY29tcGFyaXNvbnMsIGFkanVzdD0iZmRyIiwgbj1ucm93KGtlcHRfZGF0YSkpCmNvbmRpdGlvbl90YWJsZXMgPC0gd3JpdGVfbGltbWEoY29uZGl0aW9uX2NvbXBhcmlzb25zLCBleGNlbD1UUlVFLCBjc3Y9RkFMU0UsIGFubm90YXRpb249dG9vbHRpcF9kYXRhKQoKZ2VuZV9sZW5ndGhzIDwtIGdlbmVzWyxjKCJJRCIsIndpZHRoIildCmdvX2lkcyA8LSByZWFkLmNzdihmaWxlPSJyZWZlcmVuY2UvZ28vdGNydXppX2FsbF9nby50YWIuZ3oiLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFKQpjb2xuYW1lcyhnb19pZHMpIDwtIGMoIklEIiwiR09JRCIsIm9udG9sb2d5IiwibmFtZSIsImV2aWRlbmNlIiwiY29kZSIpCmdvX2lkcyA8LSBnb19pZHNbLGMoIklEIiwiR09JRCIpXQpjb2xuYW1lcyhnb19pZHMpIDwtIGMoIklEIiwiR08iKQpjb25kaXRpb25fb250b2xvZ3kgPC0gbGltbWFfb250b2xvZ3koY29uZGl0aW9uX3RhYmxlcywgZ2VuZV9sZW5ndGhzPWdlbmVfbGVuZ3RocywgZ29pZHM9Z29faWRzLCBuPTIwMCwgZXhjZWw9VFJVRSwgY3N2PUZBTFNFLCBkb190cmVlcz1GQUxTRSwgZG9fY2x1c3Rlcj1UUlVFLCBkb190b3Bnbz1UUlVFKQoKYTYwX2NsMTRjbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoY29uZGl0aW9uX3RhYmxlWyxjKCJhNjBfY2wxNCIsICJhNjBfY2xiciIpXSwgbG9lc3M9VFJVRSkKYTYwX2NsMTRjbGJyX2xzJHNjYXR0ZXIKYTYwX2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTYwX2NsMTRjbGJyX2xzJGxtX21vZGVsCmE2MF9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CmE2MF9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgoKYTk2X2NsMTRjbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoY29uZGl0aW9uX3RhYmxlWyxjKCJhOTZfY2wxNCIsICJhOTZfY2xiciIpXSwgbG9lc3M9VFJVRSkKYTk2X2NsMTRjbGJyX2xzJHNjYXR0ZXIKYTk2X2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTk2X2NsMTRjbGJyX2xzJGxtX21vZGVsCmE5Nl9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CmE5Nl9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgoKdHJ5cF9jbDE0Y2xicl9scyA8LSBocGdsX2xpbmVhcl9zY2F0dGVyKGNvbmRpdGlvbl90YWJsZVssYygidHJ5cF9jbDE0IiwgInRyeXBfY2xiciIpXSwgbG9lc3M9VFJVRSkKdHJ5cF9jbDE0Y2xicl9scyRzY2F0dGVyCnRyeXBfY2wxNGNsYnJfbHMkYm90aF9oaXN0b2dyYW0kcGxvdAp0cnlwX2NsMTRjbGJyX2xzJGxtX21vZGVsCnRyeXBfY2wxNGNsYnJfbHMkbG1fc3VtbWFyeQp0cnlwX2NsMTRjbGJyX2xzJGNvcnJlbGF0aW9uCmBgYAoKIyMgV3JpdGUgb3V0IHRoZSByZXN1bHRzIG9mIHRoZSBjb250cmFzdHMKCnRvcFRhYmxlKCkgd2lsbCBnZXQgY2FsbGVkIHF1aXRlIGEgbG90IGluIG9yZGVyIHRvIGdlbmVyYXRlIHRoZQp2YXJpb3VzIHRhYmxlcyBvZiBpbnRlcmVzdC4gIHdyaXRlX3hscygpIHdpbGwgZm9sbG93IHRvIHdyaXRlIG91dCB0aGUKcmVzdWx0cyBpbnRvIHNvbWUgZXhjZWwgc3ByZWFkc2hlZXRzLgoKYGBge3Igd3JpdGVfcmVzdWx0cywgZXZhbD1GQUxTRX0KIyMgSSB3cm90ZSBhIGZ1bmN0aW9uICd3cml0ZV9saW1tYScgd2hpY2ggdGFrZXMgY2FyZSBvZiBtYWtpbmcgYSBkYXRhIHN0cnVjdHVyZSBvZiBhbGwgdGhlIHRhYmxlcyBhbmQgcHJpbnRpbmcgdGhlIHJlc3VsdHMgaW4gZXhjZWwuCiMjIExldHMgdXNlIHRoYXQgcmF0aGVyIHRoYW4gdGhpcyBzdHVwaWQgbGlzdCBvZiB0b3BUYWJsZSgpIGNhbGxzLgojIyBJbiBhZGRpdGlvbiwgSSBhbSBhZGRpbmcgcS12YWx1ZXMgYW5kIG90aGVyIG1ldHJpY3MgdG8gaW1wcm92ZSB0aGUgb3V0cHV0IGZyb20gdG9wdGFibGUsIHNvIGl0IGlzIGEgd2luIEkgdGhpbmsuCgprZXB0X3RhYmxlIDwtIHRvcFRhYmxlKGtlcHRfY29tcGFyaXNvbnMsIGFkanVzdD0iZmRyIiwgbj1ucm93KGtlcHRfZGF0YSkpCiMjIFVzZSB0aGUgY29lZiBhcmd1bWVudCB0byBwdWxsIG91dCBhZGp1c3RlZCBwLXZhbHVlcyBmb3Igc3Vic2VjdGlvbnMgb2YgdGhlIGRhdGEKYWxsX3RhYmxlcyA8LSB3cml0ZV9saW1tYShrZXB0X2NvbXBhcmlzb25zKQpgYGAKCiMjIFBsb3Qgc29tZSByZXN1bHRzCgpUaGUgZnVuY3Rpb24gaHBnbF9saW5lYXJfc2NhdHRlcigpIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIHBlcmZvcm0gc29tZQpzaW1wbGUgdmlzdWFsaXphdGlvbnMgb2YgdGhlIGNvbnRyYXN0cwoKIyMjIENvbXBhcmUgRXBpbWFzdGlnb3RlcyBmcm9tIENMMTQgdG8gQ0xCcmVuZXIKCmBgYHtyIGxpbmVhcl9zY2F0dGVyc19lcGlfY2wxNGNsYnIsIGV2YWw9RkFMU0V9CiMjIE1ha2Ugc29tZSBzY2F0dGVyIHBsb3RzIG9mIHRoZSBpbnB1dCBkYXRhIHRvIHNlZSBpZiB0aGVzZSB0YWJsZXMgc2VlbSBzYW5lLgplcGlfY2wxNGNsYnJfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJlcGlfY2wxNCIsICJlcGlfY2xiciIpXSwgZ3Zpc19maWxlbmFtZT0iaHRtbC9lcGlfY2wxNGNsYnIuaHRtbCIsIHRvb2x0aXBfZGF0YT10b29sdGlwX2RhdGEsIGxvZXNzPVRSVUUsIGd2aXNfdHJlbmRsaW5lPSJsaW5lYXIiKQplcGlfY2wxNGNsYnJfbHMkc2NhdHRlcgplcGlfY2wxNGNsYnJfbHMkYm90aF9oaXN0b2dyYW0kcGxvdAplcGlfY2wxNGNsYnJfbHMkbG1fbW9kZWwKZXBpX2NsMTRjbGJyX2xzJGxtX3N1bW1hcnkKZXBpX2NsMTRjbGJyX2xzJGNvcnJlbGF0aW9uCmBgYAoKIyMjIENvbXBhcmUgdHJ5cG9tYXN0aWdvdGVzIGZyb20gQ0wxNCB0byBDTEJyZW5lcgoKYGBge3IgbGluZWFyX3NjYXR0ZXJzX3RyeXBfY2wxNGNsYnIsIGV2YWw9RkFMU0V9CnRyeXBfY2wxNGNsYnJfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJ0cnlwX2NsMTQiLCAidHJ5cF9jbGJyIildLCBndmlzX2ZpbGVuYW1lPSJodG1sL3RyeXBfY2wxNGNsYnIuaHRtbCIsIHRvb2x0aXBfZGF0YT10b29sdGlwX2RhdGEsIGxvZXNzPVRSVUUsIGd2aXNfdHJlbmRsaW5lPSJsaW5lYXIiKQp0cnlwX2NsMTRjbGJyX2xzJHNjYXR0ZXIKdHJ5cF9jbDE0Y2xicl9scyRib3RoX2hpc3RvZ3JhbSRwbG90CnRyeXBfY2wxNGNsYnJfbHMkbG1fbW9kZWwKdHJ5cF9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CnRyeXBfY2wxNGNsYnJfbHMkY29ycmVsYXRpb24KYGBgCgojIyMgQ29tcGFyZSBBbWFzdGlnb3RlIDYwIGhyIGZyb20gQ0wxNCB0byBDTEJyZW5lcgoKYGBge3IgbGluZWFyX3NjYXR0ZXJzX2E2MF9jbDE0Y2xiciwgZXZhbD1GQUxTRX0KYTYwX2NsMTRjbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoa2VwdF90YWJsZVssYygiYTYwX2NsMTQiLCAiYTYwX2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTYwX2NsMTRjbGJyLmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKYTYwX2NsMTRjbGJyX2xzJHNjYXR0ZXIKYTYwX2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTYwX2NsMTRjbGJyX2xzJGxtX21vZGVsCmE2MF9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CmE2MF9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIEFtYXN0aWdvdGUgOTYgaHIgQ0wxNCB0byBDTEJyZW5lcgoKYGBge3IgbGluZWFyX3NjYXR0ZXJzX2E5Nl9jbDE0Y2xiciwgZXZhbD1GQUxTRX0KYTk2X2NsMTRjbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoa2VwdF90YWJsZVssYygiYTk2X2NsMTQiLCAiYTk2X2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTk2X2NsMTRjbGJyLmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKYTk2X2NsMTRjbGJyX2xzJHNjYXR0ZXIKYTk2X2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTk2X2NsMTRjbGJyX2xzJGxtX21vZGVsCmE5Nl9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CmE5Nl9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIEVwaW1hc3RpZ290ZSB0byBUcnlwb21hc3RpZ290ZSBpbiBDTDE0CgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfZXBpdHJ5cF9jbDE0LCBldmFsPUZBTFNFfQplcGl0cnlwX2NsMTRfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJlcGlfY2wxNCIsICJ0cnlwX2NsMTQiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvZXBpdHJ5cF9jbDE0Lmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKZXBpdHJ5cF9jbDE0X2xzJHNjYXR0ZXIKZXBpdHJ5cF9jbDE0X2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKZXBpdHJ5cF9jbDE0X2xzJGxtX21vZGVsCmVwaXRyeXBfY2wxNF9scyRsbV9zdW1tYXJ5CmVwaXRyeXBfY2wxNF9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIEVwaW1hc3RpZ290ZXMgdG8gVHJ5cG9tYXN0aWdvdGVzIGluIENMQnJlbmVyCgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfZXBpdHJ5cF9jbGJyLCBldmFsPUZBTFNFfQplcGl0cnlwX2NsYnJfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJlcGlfY2xiciIsICJ0cnlwX2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvZXBpdHJ5cF9jbGJyLmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKZXBpdHJ5cF9jbGJyX2xzJHNjYXR0ZXIKZXBpdHJ5cF9jbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKZXBpdHJ5cF9jbGJyX2xzJGxtX21vZGVsCmVwaXRyeXBfY2xicl9scyRsbV9zdW1tYXJ5CmVwaXRyeXBfY2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIEFtYXN0aWdvdGUgOTYgaHIgdG8gVHJ5cG9tYXN0aWdvdGVzIGluIENMQnJlbmVyCgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfYTk2dHJ5cF9jbGJyLCBldmFsPUZBTFNFfQphOTZ0cnlwX2NsYnJfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJhOTZfY2xiciIsICJ0cnlwX2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTk2dHJ5cF9jbGJyLmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKYTk2dHJ5cF9jbGJyX2xzJHNjYXR0ZXIKYTk2dHJ5cF9jbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTk2dHJ5cF9jbGJyX2xzJGxtX21vZGVsCmE5NnRyeXBfY2xicl9scyRsbV9zdW1tYXJ5CmE5NnRyeXBfY2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIEFtYXN0aWdvdGUgOTYgaHIgdG8gVHJ5cG9tYXN0aWdvdGVzIGluIENMMTQKCmBgYHtyIGxpbmVhcl9zY2F0dGVyc19hOTZ0cnlwX2NsMTQsIGV2YWw9RkFMU0V9CmE5NnRyeXBfY2wxNF9scyA8LSBocGdsX2xpbmVhcl9zY2F0dGVyKGtlcHRfdGFibGVbLGMoImE5Nl9jbDE0IiwgInRyeXBfY2wxNCIpXSwgZ3Zpc19maWxlbmFtZT0iaHRtbC9hOTZ0cnlwX2NsMTQuaHRtbCIsIHRvb2x0aXBfZGF0YT10b29sdGlwX2RhdGEsIGxvZXNzPVRSVUUsIGd2aXNfdHJlbmRsaW5lPSJsaW5lYXIiKQphOTZ0cnlwX2NsMTRfbHMkc2NhdHRlcgphOTZ0cnlwX2NsMTRfbHMkYm90aF9oaXN0b2dyYW0kcGxvdAphOTZ0cnlwX2NsMTRfbHMkbG1fbW9kZWwKYTk2dHJ5cF9jbDE0X2xzJGxtX3N1bW1hcnkKYTk2dHJ5cF9jbDE0X2xzJGNvcnJlbGF0aW9uCmBgYAoKIyMjIENvbXBhcmUgQW1hc3RpZ290ZXMgNjAgdG8gOTYgaG91cnMgaW4gQ0wxNAoKYGBge3IgbGluZWFyX3NjYXR0ZXJzX2E2MGE5Nl9jbDE0LCBldmFsPUZBTFNFfQphNjBhOTZfY2wxNF9scyA8LSBocGdsX2xpbmVhcl9zY2F0dGVyKGtlcHRfdGFibGVbLGMoImE2MF9jbDE0IiwgImE5Nl9jbDE0IildLCBndmlzX2ZpbGVuYW1lPSJodG1sL2E2MGE5Nl9jbDE0Lmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKYTYwYTk2X2NsMTRfbHMkc2NhdHRlcgphNjBhOTZfY2wxNF9scyRib3RoX2hpc3RvZ3JhbSRwbG90CmE2MGE5Nl9jbDE0X2xzJGxtX21vZGVsCmE2MGE5Nl9jbDE0X2xzJGxtX3N1bW1hcnkKYTYwYTk2X2NsMTRfbHMkY29ycmVsYXRpb24KYGBgCgojIyMgQ29tcGFyZSBBbWFzdGlnb3RlIDYwIHRvIDk2IGhvdXJzIGluIENMQnJlbmVyCgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfYTYwYTk2X2NsYnIsIGV2YWw9RkFMU0V9CmE2MGE5Nl9jbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoa2VwdF90YWJsZVssYygiYTYwX2NsYnIiLCAiYTk2X2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTYwYTk2X2NsYnIuaHRtbCIsIHRvb2x0aXBfZGF0YT10b29sdGlwX2RhdGEsIGxvZXNzPVRSVUUsIGd2aXNfdHJlbmRsaW5lPSJsaW5lYXIiKQphNjBhOTZfY2xicl9scyRzY2F0dGVyCmE2MGE5Nl9jbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTYwYTk2X2NsYnJfbHMkbG1fbW9kZWwKYTYwYTk2X2NsYnJfbHMkbG1fc3VtbWFyeQphNjBhOTZfY2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIChlcGkvdHJ5cCljbDE0IC8gKGVwaS90cnlwKWNsYnIKCmBgYHtyIGxpbmVhcl9zY2F0dGVyc19lcGl0cnlwX2NsMTRiciwgZXZhbD1GQUxTRX0KIyMgU29tZXRoaW5nIGlzIG1lc3NlZCB1cCBoZXJlCiMjIEkgYW0gZ29pbmcgdG8gYWRkIHNvbWUgbW9yZSBjb250cmFzdHMgdG8gZmlndXJlIG91dCB3aGF0IHdlbnQgd3JvbmcKZXBpdHJ5cF9jbDE0Y2xicl9scyA8LSBocGdsX2xpbmVhcl9zY2F0dGVyKGtlcHRfdGFibGVbLGMoImVwaXRyeXBfY2wxNCIsICJlcGl0cnlwX2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvZXBpdHJ5cF9jbDE0Y2xici5odG1sIiwgdG9vbHRpcF9kYXRhPXRvb2x0aXBfZGF0YSwgbG9lc3M9VFJVRSwgZ3Zpc190cmVuZGxpbmU9ImxpbmVhciIpCmVwaXRyeXBfY2wxNGNsYnJfbHMkc2NhdHRlcgplcGl0cnlwX2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKZXBpdHJ5cF9jbDE0Y2xicl9scyRsbV9tb2RlbAplcGl0cnlwX2NsMTRjbGJyX2xzJGxtX3N1bW1hcnkKZXBpdHJ5cF9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIChlcGkvYTYwKWNsMTQgLyAoZXBpL2E2MCljbGJyCgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfZXBpYTYwX2NsMTRiciwgZXZhbD1GQUxTRX0KIyMgT0ssIHNvIHRoZSBmb2xsb3dpbmcgdHdvIGFyZSBzb2xpZGx5IHRlbGxpbmcgbWUgdGhhdCB0aGUgZXBpbWFzdGlnb3RlIGRhdGEgaXMgdGhlIHdlaXJkbywgSSB0aGluayB3ZSBjYW4gYXNzdW1lIHRoZSBDTDE0LgplcGlhNjBfY2wxNGNsYnJfbHMgPC0gaHBnbF9saW5lYXJfc2NhdHRlcihrZXB0X3RhYmxlWyxjKCJlcGlhNjBfY2wxNCIsICJlcGlhNjBfY2xiciIpXSwgZ3Zpc19maWxlbmFtZT0iaHRtbC9lcGlhNjBfY2wxNGNsYnIuaHRtbCIsIHRvb2x0aXBfZGF0YT10b29sdGlwX2RhdGEsIGxvZXNzPVRSVUUsIGd2aXNfdHJlbmRsaW5lPSJsaW5lYXIiKQplcGlhNjBfY2wxNGNsYnJfbHMkc2NhdHRlcgplcGlhNjBfY2wxNGNsYnJfbHMkYm90aF9oaXN0b2dyYW0kcGxvdAplcGlhNjBfY2wxNGNsYnJfbHMkbG1fbW9kZWwKZXBpYTYwX2NsMTRjbGJyX2xzJGxtX3N1bW1hcnkKZXBpYTYwX2NsMTRjbGJyX2xzJGNvcnJlbGF0aW9uCmBgYAoKIyMjIENvbXBhcmUgKHRyeXAvYTYwKWNsMTQgLyAodHJ5cC9hNjApY2xiciBlcnIgdGhlIG90aGVyIHdheSBhcm91bmQuLi4KCmBgYHtyIGxpbmVhcl9zY2F0dGVyc190cnlwYTYwX2NsMTRiciwgZXZhbD1GQUxTRX0KYTYwdHJ5cF9jbDE0Y2xicl9scyA8LSBocGdsX2xpbmVhcl9zY2F0dGVyKGtlcHRfdGFibGVbLGMoImE2MHRyeXBfY2wxNCIsICJhNjB0cnlwX2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTYwdHJ5cF9jbDE0Y2xici5odG1sIiwgdG9vbHRpcF9kYXRhPXRvb2x0aXBfZGF0YSwgbG9lc3M9VFJVRSwgZ3Zpc190cmVuZGxpbmU9ImxpbmVhciIpCmE2MHRyeXBfY2wxNGNsYnJfbHMkc2NhdHRlcgphNjB0cnlwX2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTYwdHJ5cF9jbDE0Y2xicl9scyRsbV9tb2RlbAphNjB0cnlwX2NsMTRjbGJyX2xzJGxtX3N1bW1hcnkKYTYwdHJ5cF9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCiMjIyBDb21wYXJlIChhNjAvYTk2KWNsMTQgLyAoYTYwL2E5NiljbGJyCgpgYGB7ciBsaW5lYXJfc2NhdHRlcnNfYTYwYTk2X2NsMTRiciwgZXZhbD1GQUxTRX0KYTYwYTk2X2NsMTRjbGJyX2xzIDwtIGhwZ2xfbGluZWFyX3NjYXR0ZXIoa2VwdF90YWJsZVssYygiYTYwYTk2X2NsMTQiLCAiYTYwYTk2X2NsYnIiKV0sIGd2aXNfZmlsZW5hbWU9Imh0bWwvYTYwYTk2X2NsMTRjbGJyLmh0bWwiLCB0b29sdGlwX2RhdGE9dG9vbHRpcF9kYXRhLCBsb2Vzcz1UUlVFLCBndmlzX3RyZW5kbGluZT0ibGluZWFyIikKYTYwYTk2X2NsMTRjbGJyX2xzJHNjYXR0ZXIKYTYwYTk2X2NsMTRjbGJyX2xzJGJvdGhfaGlzdG9ncmFtJHBsb3QKYTYwYTk2X2NsMTRjbGJyX2xzJGxtX21vZGVsCmE2MGE5Nl9jbDE0Y2xicl9scyRsbV9zdW1tYXJ5CmE2MGE5Nl9jbDE0Y2xicl9scyRjb3JyZWxhdGlvbgpgYGAKCkkgcmVtb3ZlZCBhIHNlY3Rpb24gcmVnYXJkaW5nIGJhdGNoIGVmZmVjdCByZW1vdmFsIGZyb20gaGVyZS4KVGhpcyBzZWN0aW9uIGlzIG5vdCBuZWVkZWQgYmVjYXVzZSBJIGluY2x1ZGVkIGl0cyBmdW5jdGlvbmFsaXR5IGluCm15cjo6Z3JhcGhfbWV0cmljcygpCgojIE15IGVtYWlsIHRvIEt3YW1lCgpUaGUgZm9sbG93aW5nIGlzIHRoZSB0ZXh0IG9mIGEgbWVzc2FnZSBJIHNlbnQgS3dhbWUsIHdoaWNoIGxheXMgb3V0IG15IGNvbmNlcm5zIGluIHRoaXMgZGF0YToKCiAgSSBqdXN0IHdhbnRlZCB0byBwaW5nIHlvdSAtLSBJIHBva2VkIGZ1cnRoZXIgYXQgbXkgY29uY2Vybi4gIEkgYW0KICA5OSUgY2VydGFpbiBJIHNldCB1cCB0aGUgbW9kZWwgbWF0cml4IGNvcnJlY3RseSBhbmQgYXNzaWduZWQgdGhlCiAgcmVsYXRpdmUgY29udHJpYnV0aW9ucyBvZiBlYWNoIHNhbXBsZSBpbiBtYWtlQ29udHJhc3RzKCkgY29ycmVjdGx5LgogIFRoZSByZXN1bHRzIEkgZ2V0IHdoZW4gcGVyZm9ybWluZyB0aGUgY29udHJhc3RzIGxvb2sgZm9yIHRoZSBtb3N0CiAgcGFydCB2ZXJ5IG11Y2ggbGlrZSB3aGF0IEkgd291bGQgZXhwZWN0LiAgTXkgb25seSBjb25jZXJuIGlzIHdoZW4gSQogIHBlcmZvcm0gb3BlcmF0aW9ucyBsaWtlOiAoeC15KS0oYS1iKTsgaW4gbW9zdCBpbnN0YW5jZXMgdGhleSB0b28KICBsb29rIHZlcnkgbXVjaCBsaWtlIHdoYXQgSSBleHBlY3QsIGJ1dCBpbiBvbmUgaW5zdGFuY2Ugb25lIHRlcm0odGhlCiAgeCBmcm9tIG15IGV4YW1wbGUpIGlzIGNvbnNpc3RlbnRseSAofjQvMyAqIGEpIHdoaWNoIGxlYXZlcyBhbgogIGFwcGFyZW50bHkgbGluZWFyIHJlbGF0aW9uc2hpcCB3aGVuIHRoZXJlIHJlYWxseSBzaG91bGQgbm90IGJlIG9uZS4KICBUaGlzIGNhdXNlZCBtZSB0byBiZSBjb25jZXJuZWQgdGhhdCBJIG1pc2F0dHJpYnV0ZWQgdGhlIHNhbXBsZXMgaW4KICBtYWtlQ29udHJhc3RzKCkuICBVcG9uIGZ1cnRoZXIgZXhhbWluYXRpb24gSSBjYW1lIHRvIHRoZSBjb25jbHVzaW9uCiAgdGhhdCB0aGV5IHdlcmUgaW4gZmFjdCBjb3JyZWN0LiAgTXkgc2Vjb25kIGd1ZXNzIHdhcyAoZ2l2ZW4gdGhpbmdzIEkKICBoYXZlIGhlYXJkIHlvdS9IZWN0b3IvTmFqaWIgc2F5IGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbgogIG5vcm1hbGl6YXRpb24gYW5kIHJlYWQgZGVwdGgpIHRoYXQgZWl0aGVyIHRoZSB4IG9yIGEgdGVybSB3YXMgbXVjaAogIGhpZ2hlciBvciBsb3dlciBpbiBkZXB0aCB0aGFuIHRoZSBvdGhlcnMuICBJIGNoZWNrZWQgYW5kIHRoaXMgaXMgbm90CiAgdHJ1ZSAodGhlcmUgYXJlIGxpYnNpemUgZGlmZmVyZW5jZXMsIGJ1dCB0aGV5IGRvbid0IGxvb2sgc2lnbmlmaWNhbnQKICB0byBtZSkuICBNeSBsYXN0IGd1ZXNzIGlzIHRoYXQgb25lIG9mIHRoZSBzYW1wbGVzIGluIHggZG9lcyBub3QKICBjbHVzdGVyIGFzIG5pY2VseSBhcyBhbGwgdGhlIHJlc3Qgb2YgdGhlIHNhbXBsZXMgaW4gdGhlIGRhdGEgc2V0IGFuZAogIHRoaXMgaXMgc29tZWhvdyBsZWFkaW5nIHRvIGEgY29uc2lzdGVudCBlZmZlY3QgdGhyb3VnaG91dCB0aGUKICBkYXRhc2V0LCBidXQgZm9yIHRoZSBsaWZlIG9mIG1lIEkgY2Fubm90IGZpbmQgYSByZWFzb24gd2h5Lgo=