Imports

# if (!require("BiocManager", quietly = TRUE))
#     install.packages("BiocManager")

# Load packages
library(DiffBind)

Sample Sheets

Create sample sheets and comparison contrasts for erythroid ATAC-seq and erythroid RAD21 ChIP-seq

Erythroid ATAC-seq

ery_atac_bam_dir <- "Example_Data/Erythroid_ATAC/BAMs/"
ery_atac_peak_dir <- "Example_Data/Erythroid_ATAC/LanceOtron_Peaks"

ery_atac_bam_dir <- "/ceph/project/Wellcome_Discovery/datashare/towilson/Public_Data/Human/Erythroid/50_Donors_Erythroid/ZEN_T_Wilson_2026/ATAC/hg38/BAMs/"
ery_atac_peak_dir <- "/ceph/project/Wellcome_Discovery/datashare/towilson/Public_Data/Human/Erythroid/50_Donors_Erythroid/ZEN_T_Wilson_2026/ATAC/hg38/LanceOtron_Peaks"

# Set sample name GSM
gsm_ids <- paste0("GSM", 9320314:9320327)

# Sample names
samples <- c(paste0("Don002_ATAC_d13_rep", 1:7),
             paste0("Don003_ATAC_d13_rep", 1:7))

# Erythroid ATAC-seq sample sheet
ery_atac_samples <- data.frame(SampleID = c(paste0("Don002_ATAC_d13_rep", 1:7),
                                            paste0("Don003_ATAC_d13_rep", 1:7)),
                               Tissue = rep("CD34_erythroid", 14),
                               Factor = c(rep("donor_2", 7), 
                                          rep("donor_3", 7)),
                               Condition = rep("healthy", 14),
                               Treatment = rep("bulk", 14),
                               Replicate = c(1:7, 1:7),
                               bamReads = file.path(ery_atac_bam_dir,
                                                    paste0(gsm_ids, "_", samples, ".bam")),
                               Peaks = file.path(ery_atac_peak_dir,
                                                 paste0(gsm_ids, "_", samples, "_L-tron.bed")),
                               PeakCaller = rep("bed", 14))

# Set samples and contrast for donor 2 replicate comparison
ery_don2_samples <- ery_atac_samples[(ery_atac_samples["Factor"] == "donor_2"),][1:6,]
ery_don2_samples["Factor"] = c(rep("group_1", 3), rep("group_2", 3))
ery_don2_contrast <- list(Factor = "group_1")

# Set samples and contrast for donor 2 vs donor 3 replicate comparison
ery_don2_vs_don3_samples <- ery_atac_samples
ery_don2_vs_don3_contrast <- list(Factor = "donor_2")

Erythroid RAD21 ChIP-seq

ery_rad21_bam_dir <- "Example_Data/Erythroid_RAD21/BAMs"
ery_rad21_peak_dir <- "Example_Data/Erythroid_RAD21/LanceOtron_Peaks"

# Erythroid RAD21 ChIP-seq sample sheet
ery_rad21_samples <- data.frame(SampleID = c(paste0("Don001_RAD21_d13_rep", 1:3),
                                             paste0("Don002_RAD21_d13_rep", 1:3),
                                             "Don030_RAD21_d13_rep_1",
                                             "Don030_RAD21_d13_rep_3"),
                                Tissue = rep("CD34_erythroid", 8),
                                Factor = c(rep("donor_1", 3),
                                           rep("donor_2", 3),
                                           rep("donor_30", 2)),
                                Condition = rep("healthy", 8),
                                Treatment = rep("bulk", 8),
                                Replicate = c(1:3, 1:3, 1, 3),
                                bamReads = c(file.path(ery_rad21_bam_dir, paste0("Don001_RAD21_d13_rep", 1:3, ".bam")),
                                             file.path(ery_rad21_bam_dir, paste0("Don002_RAD21_d13_rep", 1:3, ".bam")),
                                             file.path(ery_rad21_bam_dir, "Don030_RAD21_d13_rep1.bam"),
                                             file.path(ery_rad21_bam_dir, "Don030_RAD21_d13_rep3.bam")),
                                Peaks = c(file.path(ery_rad21_peak_dir, paste0("Don001_RAD21_d13_rep", 1:3, ".bed")),
                                          file.path(ery_rad21_peak_dir, paste0("Don002_RAD21_d13_rep", 1:3, ".bed")),
                                          file.path(ery_rad21_peak_dir, paste0("Don030_RAD21_d13_rep1", ".bed")),
                                          file.path(ery_rad21_peak_dir, paste0("Don030_RAD21_d13_rep3", ".bed"))),
                            PeakCaller = rep("bed", 8))

# Set the contrast
contrast <- list(Factor = "donor_1")

Extract LIB, RLE and TMM Scaling Factors

Extract scaling factors to rescale bigWigs by full library size (LIB), RLE and TMM normalisation

# Set sample sheets per dataset
sample_sheets <- list("Erythroid_ATAC" = ery_atac_samples, "Erythroid_RAD21" = ery_rad21_samples)
# Autosomal and sex chromosomes
chromosomes <- c(paste0("chr", 1:22), "chrX", "chrY")
# Normalisation methods to test
norm_methods <- c(DBA_NORM_LIB, DBA_NORM_RLE, DBA_NORM_TMM)

scaling_factors <- list()

for (data in c("Erythroid_ATAC", "Erythroid_RAD21")) {
  # Create DBA object
  dba_object <- dba(sampleSheet = sample_sheets[[data]])
  
  # Find chromosomes to remove
  peakset <- dba.peakset(dba_object, bRetrieve = TRUE)
  greylist <- peakset[!(seqnames(peakset) %in% chromosomes)]
  
  # Apply ENCODE blacklist and keep only standard chromosomes
  dba_object <- dba.blacklist(dba_object, blacklist = DBA_BLACKLIST_HG38, greylist = greylist)
  
  # Re-center peaks and count reads
  dba_object <- dba.count(dba_object)
  
  # Normalise by each method
  for (norm in norm_methods) {
    dba_object <- dba.normalize(dba_object, normalize = norm)
    # Extract the scaling factors
    norm_info <- dba.normalize(dba_object, bRetrieve = TRUE)
    scalers <- norm_info$norm.factors
    names(scalers) <- dba_object$samples$SampleID
    scaling_factors[[data]][[norm]] <- scalers
  }
}
Error in if (file.info(peaks)$size > 0) { : 
  missing value where TRUE/FALSE needed
# View scaling factors per dataset and normalisation method
scaling_factors

Differential Accessibility Analysis

ZEN Scaling Factors

# Scaling factors per sample for ZEN normalisation
ery_atac_zen <- c(Don002_ATAC_d13_rep1 = 0.2795583724430078,
                  Don002_ATAC_d13_rep2 = 0.24549477454191823,
                  Don002_ATAC_d13_rep3 = 0.1651864697590268,
                  Don002_ATAC_d13_rep4 = 0.09541567508135224,
                  Don002_ATAC_d13_rep5 = 0.16076437035969782,
                  Don002_ATAC_d13_rep6 = 0.1551683098985989,
                  Don002_ATAC_d13_rep7 = 0.143536842576444,
                  Don003_ATAC_d13_rep1 = 0.2582363354917962,
                  Don003_ATAC_d13_rep2 = 0.25053836607363844,
                  Don003_ATAC_d13_rep3 = 0.17587857961294,
                  Don003_ATAC_d13_rep4 = 0.11435196335506045,
                  Don003_ATAC_d13_rep5 = 0.10978229659749278,
                  Don003_ATAC_d13_rep6 = 0.1178921511723179,
                  Don003_ATAC_d13_rep7 = 0.0877359143756193)

Run DiffBind

# Create DBA object
sheet <- ery_don2_vs_don3_samples
contrast <- ery_don2_vs_don3_contrast
  
dba_object <- dba(sampleSheet = sheet)
dba_object
14 Samples, 101677 sites in matrix (396696 total):
# Clustering by peak calls
dba.plotHeatmap(dba_object)
# Find chromosomes to remove
chromosomes <- c(paste0("chr", 1:22), "chrX", "chrY")
peakset <- dba.peakset(dba_object, bRetrieve = TRUE)
greylist <- peakset[!(seqnames(peakset) %in% chromosomes)]

# Apply ENCODE blacklist and keep only standard chromosomes
dba_object <- dba.blacklist(dba_object, blacklist = DBA_BLACKLIST_HG38, greylist = greylist)

# Re-center peaks and count reads
dba_object <- dba.count(dba_object)
dba_object
14 Samples, 65625 sites in matrix:
# DBA_NORM_LIB (default), DBA_NORM_RLE (DESeq2), DBA_NORM_TMM (edgeR) or custom vector (ZEN)
norm_method <- "ZEN"
scalars <- ery_atac_zen
  
if (norm_method == "ZEN") {
  # Select scaling factors for the specific replicates
  norm_sub <- scalars[names(scalars) %in% sheet$SampleID]
} else {
  norm_sub <- norm_method
}

dba_object <- dba.normalize(dba_object, normalize = norm_sub)
norm_info <- dba.normalize(dba_object, bRetrieve = TRUE)
# View the scaling factors
norm_info
$norm.method
[1] "user"

$norm.factors
Don002_ATAC_d13_rep1 Don002_ATAC_d13_rep2 Don002_ATAC_d13_rep3 Don002_ATAC_d13_rep4 Don002_ATAC_d13_rep5 Don002_ATAC_d13_rep6 
          0.27955837           0.24549477           0.16518647           0.09541568           0.16076437           0.15516831 
Don002_ATAC_d13_rep7 Don003_ATAC_d13_rep1 Don003_ATAC_d13_rep2 Don003_ATAC_d13_rep3 Don003_ATAC_d13_rep4 Don003_ATAC_d13_rep5 
          0.14353684           0.25823634           0.25053837           0.17587858           0.11435196           0.10978230 
Don003_ATAC_d13_rep6 Don003_ATAC_d13_rep7 
          0.11789215           0.08773591 

$lib.method
[1] "full"

$lib.sizes
 [1] 22105785 32805795 49429595 38990930 16896174 12451638 27350017 22723762 33719954 61605892 19314496 14912872 12046132
[14] 25140080

$filter.value
[1] 1
# Clustering by count scores
plot(dba_object)
# Set the contrast
dba_object <- dba.contrast(dba_object, reorderMeta = contrast)
dba_object <- dba.analyze(dba_object)
dba.show(dba_object, bContrasts = TRUE)
plot(dba_object, contrast = 1)
results <- dba.report(dba_object, contrast = 1)
results
GRanges object with 145 ranges and 6 metadata columns:
        seqnames              ranges strand |      Conc Conc_donor_3 Conc_donor_2      Fold     p-value         FDR
           <Rle>           <IRanges>  <Rle> | <numeric>    <numeric>    <numeric> <numeric>   <numeric>   <numeric>
    590     chr1   25285078-25285478      * |   8.91678      0.00000      9.91678  -8.79572 2.77988e-21 1.82430e-16
  51349     chr6   79614820-79615220      * |   9.26869      5.13925     10.22687  -4.93362 3.44500e-17 7.62786e-13
    588     chr1   25279697-25280097      * |   8.60247      2.21490      9.59383  -7.13503 3.48702e-17 7.62786e-13
   2415     chr1 120850923-120851323      * |   6.98049      7.98049      0.00000   7.24046 5.86071e-16 9.61523e-12
  43780     chr4   68864486-68864886      * |   8.84793      4.97343      9.79789  -4.67314 4.17293e-15 4.98268e-11
    ...      ...                 ...    ... .       ...          ...          ...       ...         ...         ...
  54010     chr7   26556232-26556632      * |   6.65763      7.40864      5.00028  1.194607 8.61785e-05   0.0401097
   2670     chr1 153617552-153617952      * |   6.62390      4.96119      7.37592 -1.123389 8.71989e-05   0.0402988
   8093    chr11   16596208-16596608      * |   6.47146      4.62599      7.25532 -1.230685 9.04683e-05   0.0415174
   3180     chr1 171683840-171684240      * |   6.55215      5.14395      7.25101 -0.875443 1.06984e-04   0.0487557
  16477    chr14   21796913-21797313      * |   6.38132      4.73246      7.13073 -0.986939 1.08884e-04   0.0492796
  -------
  seqinfo: 23 sequences from an unspecified genome; no seqlengths
output_file <- "Erythroid_ATAC/DiffBind_Erythroid_Donor2_vs_Donor3_RLE.csv"

results_df <- as(results, "data.frame")
results_df <- results_df[c("seqnames", "start", "end", "Fold", "p-value", "FDR")]
names(results_df)[names(results_df) == "seqnames"] <- "chrom"
print(paste("Significant:", nrow(results_df[results_df$FDR < 0.05, ])))
write.csv(results_df, output_file, row.names = FALSE)
results_df
LS0tCnRpdGxlOiAiRGlmZkJpbmQgQW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgSW1wb3J0cwoKYGBge3J9CiMgaWYgKCFyZXF1aXJlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkKIyAgICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQoKIyBMb2FkIHBhY2thZ2VzCmxpYnJhcnkoRGlmZkJpbmQpCmBgYAoKIyBTYW1wbGUgU2hlZXRzCkNyZWF0ZSBzYW1wbGUgc2hlZXRzIGFuZCBjb21wYXJpc29uIGNvbnRyYXN0cyBmb3IgZXJ5dGhyb2lkIEFUQUMtc2VxIGFuZCBlcnl0aHJvaWQgUkFEMjEgQ2hJUC1zZXEKCiMjIEVyeXRocm9pZCBBVEFDLXNlcQoKYGBge3J9CmVyeV9hdGFjX2JhbV9kaXIgPC0gIkV4YW1wbGVfRGF0YS9Fcnl0aHJvaWRfQVRBQy9CQU1zLyIKZXJ5X2F0YWNfcGVha19kaXIgPC0gIkV4YW1wbGVfRGF0YS9Fcnl0aHJvaWRfQVRBQy9MYW5jZU90cm9uX1BlYWtzIgoKZXJ5X2F0YWNfYmFtX2RpciA8LSAiL2NlcGgvcHJvamVjdC9XZWxsY29tZV9EaXNjb3ZlcnkvZGF0YXNoYXJlL3Rvd2lsc29uL1B1YmxpY19EYXRhL0h1bWFuL0VyeXRocm9pZC81MF9Eb25vcnNfRXJ5dGhyb2lkL1pFTl9UX1dpbHNvbl8yMDI2L0FUQUMvaGczOC9CQU1zLyIKZXJ5X2F0YWNfcGVha19kaXIgPC0gIi9jZXBoL3Byb2plY3QvV2VsbGNvbWVfRGlzY292ZXJ5L2RhdGFzaGFyZS90b3dpbHNvbi9QdWJsaWNfRGF0YS9IdW1hbi9Fcnl0aHJvaWQvNTBfRG9ub3JzX0VyeXRocm9pZC9aRU5fVF9XaWxzb25fMjAyNi9BVEFDL2hnMzgvTGFuY2VPdHJvbl9QZWFrcyIKCiMgU2V0IHNhbXBsZSBuYW1lIEdTTQpnc21faWRzIDwtIHBhc3RlMCgiR1NNIiwgOTMyMDMxNDo5MzIwMzI3KQoKIyBTYW1wbGUgbmFtZXMKc2FtcGxlcyA8LSBjKHBhc3RlMCgiRG9uMDAyX0FUQUNfZDEzX3JlcCIsIDE6NyksCiAgICAgICAgICAgICBwYXN0ZTAoIkRvbjAwM19BVEFDX2QxM19yZXAiLCAxOjcpKQoKIyBFcnl0aHJvaWQgQVRBQy1zZXEgc2FtcGxlIHNoZWV0CmVyeV9hdGFjX3NhbXBsZXMgPC0gZGF0YS5mcmFtZShTYW1wbGVJRCA9IGMocGFzdGUwKCJEb24wMDJfQVRBQ19kMTNfcmVwIiwgMTo3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIkRvbjAwM19BVEFDX2QxM19yZXAiLCAxOjcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpc3N1ZSA9IHJlcCgiQ0QzNF9lcnl0aHJvaWQiLCAxNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGYWN0b3IgPSBjKHJlcCgiZG9ub3JfMiIsIDcpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJkb25vcl8zIiwgNykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29uZGl0aW9uID0gcmVwKCJoZWFsdGh5IiwgMTQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJlYXRtZW50ID0gcmVwKCJidWxrIiwgMTQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVwbGljYXRlID0gYygxOjcsIDE6NyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYW1SZWFkcyA9IGZpbGUucGF0aChlcnlfYXRhY19iYW1fZGlyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKGdzbV9pZHMsICJfIiwgc2FtcGxlcywgIi5iYW0iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQZWFrcyA9IGZpbGUucGF0aChlcnlfYXRhY19wZWFrX2RpciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChnc21faWRzLCAiXyIsIHNhbXBsZXMsICJfTC10cm9uLmJlZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBlYWtDYWxsZXIgPSByZXAoImJlZCIsIDE0KSkKCiMgU2V0IHNhbXBsZXMgYW5kIGNvbnRyYXN0IGZvciBkb25vciAyIHJlcGxpY2F0ZSBjb21wYXJpc29uCmVyeV9kb24yX3NhbXBsZXMgPC0gZXJ5X2F0YWNfc2FtcGxlc1soZXJ5X2F0YWNfc2FtcGxlc1siRmFjdG9yIl0gPT0gImRvbm9yXzIiKSxdWzE6NixdCmVyeV9kb24yX3NhbXBsZXNbIkZhY3RvciJdID0gYyhyZXAoImdyb3VwXzEiLCAzKSwgcmVwKCJncm91cF8yIiwgMykpCmVyeV9kb24yX2NvbnRyYXN0IDwtIGxpc3QoRmFjdG9yID0gImdyb3VwXzEiKQoKIyBTZXQgc2FtcGxlcyBhbmQgY29udHJhc3QgZm9yIGRvbm9yIDIgdnMgZG9ub3IgMyByZXBsaWNhdGUgY29tcGFyaXNvbgplcnlfZG9uMl92c19kb24zX3NhbXBsZXMgPC0gZXJ5X2F0YWNfc2FtcGxlcwplcnlfZG9uMl92c19kb24zX2NvbnRyYXN0IDwtIGxpc3QoRmFjdG9yID0gImRvbm9yXzIiKQpgYGAKCiMjIEVyeXRocm9pZCBSQUQyMSBDaElQLXNlcQoKYGBge3J9CmVyeV9yYWQyMV9iYW1fZGlyIDwtICJFeGFtcGxlX0RhdGEvRXJ5dGhyb2lkX1JBRDIxL0JBTXMiCmVyeV9yYWQyMV9wZWFrX2RpciA8LSAiRXhhbXBsZV9EYXRhL0VyeXRocm9pZF9SQUQyMS9MYW5jZU90cm9uX1BlYWtzIgoKIyBFcnl0aHJvaWQgUkFEMjEgQ2hJUC1zZXEgc2FtcGxlIHNoZWV0CmVyeV9yYWQyMV9zYW1wbGVzIDwtIGRhdGEuZnJhbWUoU2FtcGxlSUQgPSBjKHBhc3RlMCgiRG9uMDAxX1JBRDIxX2QxM19yZXAiLCAxOjMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIkRvbjAwMl9SQUQyMV9kMTNfcmVwIiwgMTozKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRvbjAzMF9SQUQyMV9kMTNfcmVwXzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRG9uMDMwX1JBRDIxX2QxM19yZXBfMyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpc3N1ZSA9IHJlcCgiQ0QzNF9lcnl0aHJvaWQiLCA4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGYWN0b3IgPSBjKHJlcCgiZG9ub3JfMSIsIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJkb25vcl8yIiwgMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImRvbm9yXzMwIiwgMikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvbmRpdGlvbiA9IHJlcCgiaGVhbHRoeSIsIDgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyZWF0bWVudCA9IHJlcCgiYnVsayIsIDgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlcGxpY2F0ZSA9IGMoMTozLCAxOjMsIDEsIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhbVJlYWRzID0gYyhmaWxlLnBhdGgoZXJ5X3JhZDIxX2JhbV9kaXIsIHBhc3RlMCgiRG9uMDAxX1JBRDIxX2QxM19yZXAiLCAxOjMsICIuYmFtIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgoZXJ5X3JhZDIxX2JhbV9kaXIsIHBhc3RlMCgiRG9uMDAyX1JBRDIxX2QxM19yZXAiLCAxOjMsICIuYmFtIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgoZXJ5X3JhZDIxX2JhbV9kaXIsICJEb24wMzBfUkFEMjFfZDEzX3JlcDEuYmFtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChlcnlfcmFkMjFfYmFtX2RpciwgIkRvbjAzMF9SQUQyMV9kMTNfcmVwMy5iYW0iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGVha3MgPSBjKGZpbGUucGF0aChlcnlfcmFkMjFfcGVha19kaXIsIHBhc3RlMCgiRG9uMDAxX1JBRDIxX2QxM19yZXAiLCAxOjMsICIuYmVkIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgoZXJ5X3JhZDIxX3BlYWtfZGlyLCBwYXN0ZTAoIkRvbjAwMl9SQUQyMV9kMTNfcmVwIiwgMTozLCAiLmJlZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKGVyeV9yYWQyMV9wZWFrX2RpciwgcGFzdGUwKCJEb24wMzBfUkFEMjFfZDEzX3JlcDEiLCAiLmJlZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKGVyeV9yYWQyMV9wZWFrX2RpciwgcGFzdGUwKCJEb24wMzBfUkFEMjFfZDEzX3JlcDMiLCAiLmJlZCIpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQZWFrQ2FsbGVyID0gcmVwKCJiZWQiLCA4KSkKCiMgU2V0IHRoZSBjb250cmFzdApjb250cmFzdCA8LSBsaXN0KEZhY3RvciA9ICJkb25vcl8xIikKYGBgCgojIEV4dHJhY3QgTElCLCBSTEUgYW5kIFRNTSBTY2FsaW5nIEZhY3RvcnMKRXh0cmFjdCBzY2FsaW5nIGZhY3RvcnMgdG8gcmVzY2FsZSBiaWdXaWdzIGJ5IGZ1bGwgbGlicmFyeSBzaXplIChMSUIpLCBSTEUgYW5kIFRNTSBub3JtYWxpc2F0aW9uCgpgYGB7cn0KIyBTZXQgc2FtcGxlIHNoZWV0cyBwZXIgZGF0YXNldApzYW1wbGVfc2hlZXRzIDwtIGxpc3QoIkVyeXRocm9pZF9BVEFDIiA9IGVyeV9hdGFjX3NhbXBsZXMsICJFcnl0aHJvaWRfUkFEMjEiID0gZXJ5X3JhZDIxX3NhbXBsZXMpCiMgQXV0b3NvbWFsIGFuZCBzZXggY2hyb21vc29tZXMKY2hyb21vc29tZXMgPC0gYyhwYXN0ZTAoImNociIsIDE6MjIpLCAiY2hyWCIsICJjaHJZIikKIyBOb3JtYWxpc2F0aW9uIG1ldGhvZHMgdG8gdGVzdApub3JtX21ldGhvZHMgPC0gYyhEQkFfTk9STV9MSUIsIERCQV9OT1JNX1JMRSwgREJBX05PUk1fVE1NKQoKc2NhbGluZ19mYWN0b3JzIDwtIGxpc3QoKQoKZm9yIChkYXRhIGluIGMoIkVyeXRocm9pZF9BVEFDIiwgIkVyeXRocm9pZF9SQUQyMSIpKSB7CiAgIyBDcmVhdGUgREJBIG9iamVjdAogIGRiYV9vYmplY3QgPC0gZGJhKHNhbXBsZVNoZWV0ID0gc2FtcGxlX3NoZWV0c1tbZGF0YV1dKQogIAogICMgRmluZCBjaHJvbW9zb21lcyB0byByZW1vdmUKICBwZWFrc2V0IDwtIGRiYS5wZWFrc2V0KGRiYV9vYmplY3QsIGJSZXRyaWV2ZSA9IFRSVUUpCiAgZ3JleWxpc3QgPC0gcGVha3NldFshKHNlcW5hbWVzKHBlYWtzZXQpICVpbiUgY2hyb21vc29tZXMpXQogIAogICMgQXBwbHkgRU5DT0RFIGJsYWNrbGlzdCBhbmQga2VlcCBvbmx5IHN0YW5kYXJkIGNocm9tb3NvbWVzCiAgZGJhX29iamVjdCA8LSBkYmEuYmxhY2tsaXN0KGRiYV9vYmplY3QsIGJsYWNrbGlzdCA9IERCQV9CTEFDS0xJU1RfSEczOCwgZ3JleWxpc3QgPSBncmV5bGlzdCkKICAKICAjIFJlLWNlbnRlciBwZWFrcyBhbmQgY291bnQgcmVhZHMKICBkYmFfb2JqZWN0IDwtIGRiYS5jb3VudChkYmFfb2JqZWN0KQogIAogICMgTm9ybWFsaXNlIGJ5IGVhY2ggbWV0aG9kCiAgZm9yIChub3JtIGluIG5vcm1fbWV0aG9kcykgewogICAgZGJhX29iamVjdCA8LSBkYmEubm9ybWFsaXplKGRiYV9vYmplY3QsIG5vcm1hbGl6ZSA9IG5vcm0pCiAgICAjIEV4dHJhY3QgdGhlIHNjYWxpbmcgZmFjdG9ycwogICAgbm9ybV9pbmZvIDwtIGRiYS5ub3JtYWxpemUoZGJhX29iamVjdCwgYlJldHJpZXZlID0gVFJVRSkKICAgIHNjYWxlcnMgPC0gbm9ybV9pbmZvJG5vcm0uZmFjdG9ycwogICAgbmFtZXMoc2NhbGVycykgPC0gZGJhX29iamVjdCRzYW1wbGVzJFNhbXBsZUlECiAgICBzY2FsaW5nX2ZhY3RvcnNbW2RhdGFdXVtbbm9ybV1dIDwtIHNjYWxlcnMKICB9Cn0KYGBgCgpgYGB7cn0KIyBWaWV3IHNjYWxpbmcgZmFjdG9ycyBwZXIgZGF0YXNldCBhbmQgbm9ybWFsaXNhdGlvbiBtZXRob2QKc2NhbGluZ19mYWN0b3JzCmBgYAoKIyBEaWZmZXJlbnRpYWwgQWNjZXNzaWJpbGl0eSBBbmFseXNpcwoKIyMgWkVOIFNjYWxpbmcgRmFjdG9ycwoKYGBge3J9CiMgU2NhbGluZyBmYWN0b3JzIHBlciBzYW1wbGUgZm9yIFpFTiBub3JtYWxpc2F0aW9uCmVyeV9hdGFjX3plbiA8LSBjKERvbjAwMl9BVEFDX2QxM19yZXAxID0gMC4yNzk1NTgzNzI0NDMwMDc4LAogICAgICAgICAgICAgICAgICBEb24wMDJfQVRBQ19kMTNfcmVwMiA9IDAuMjQ1NDk0Nzc0NTQxOTE4MjMsCiAgICAgICAgICAgICAgICAgIERvbjAwMl9BVEFDX2QxM19yZXAzID0gMC4xNjUxODY0Njk3NTkwMjY4LAogICAgICAgICAgICAgICAgICBEb24wMDJfQVRBQ19kMTNfcmVwNCA9IDAuMDk1NDE1Njc1MDgxMzUyMjQsCiAgICAgICAgICAgICAgICAgIERvbjAwMl9BVEFDX2QxM19yZXA1ID0gMC4xNjA3NjQzNzAzNTk2OTc4MiwKICAgICAgICAgICAgICAgICAgRG9uMDAyX0FUQUNfZDEzX3JlcDYgPSAwLjE1NTE2ODMwOTg5ODU5ODksCiAgICAgICAgICAgICAgICAgIERvbjAwMl9BVEFDX2QxM19yZXA3ID0gMC4xNDM1MzY4NDI1NzY0NDQsCiAgICAgICAgICAgICAgICAgIERvbjAwM19BVEFDX2QxM19yZXAxID0gMC4yNTgyMzYzMzU0OTE3OTYyLAogICAgICAgICAgICAgICAgICBEb24wMDNfQVRBQ19kMTNfcmVwMiA9IDAuMjUwNTM4MzY2MDczNjM4NDQsCiAgICAgICAgICAgICAgICAgIERvbjAwM19BVEFDX2QxM19yZXAzID0gMC4xNzU4Nzg1Nzk2MTI5NCwKICAgICAgICAgICAgICAgICAgRG9uMDAzX0FUQUNfZDEzX3JlcDQgPSAwLjExNDM1MTk2MzM1NTA2MDQ1LAogICAgICAgICAgICAgICAgICBEb24wMDNfQVRBQ19kMTNfcmVwNSA9IDAuMTA5NzgyMjk2NTk3NDkyNzgsCiAgICAgICAgICAgICAgICAgIERvbjAwM19BVEFDX2QxM19yZXA2ID0gMC4xMTc4OTIxNTExNzIzMTc5LAogICAgICAgICAgICAgICAgICBEb24wMDNfQVRBQ19kMTNfcmVwNyA9IDAuMDg3NzM1OTE0Mzc1NjE5MykKYGBgCgojIyBSdW4gRGlmZkJpbmQKCmBgYHtyfQojIENyZWF0ZSBEQkEgb2JqZWN0CnNoZWV0IDwtIGVyeV9kb24yX3ZzX2RvbjNfc2FtcGxlcwpjb250cmFzdCA8LSBlcnlfZG9uMl92c19kb24zX2NvbnRyYXN0CiAgCmRiYV9vYmplY3QgPC0gZGJhKHNhbXBsZVNoZWV0ID0gc2hlZXQpCmRiYV9vYmplY3QKYGBgCgpgYGB7cn0KIyBDbHVzdGVyaW5nIGJ5IHBlYWsgY2FsbHMKZGJhLnBsb3RIZWF0bWFwKGRiYV9vYmplY3QpCmBgYAoKYGBge3J9CiMgRmluZCBjaHJvbW9zb21lcyB0byByZW1vdmUKY2hyb21vc29tZXMgPC0gYyhwYXN0ZTAoImNociIsIDE6MjIpLCAiY2hyWCIsICJjaHJZIikKcGVha3NldCA8LSBkYmEucGVha3NldChkYmFfb2JqZWN0LCBiUmV0cmlldmUgPSBUUlVFKQpncmV5bGlzdCA8LSBwZWFrc2V0WyEoc2VxbmFtZXMocGVha3NldCkgJWluJSBjaHJvbW9zb21lcyldCgojIEFwcGx5IEVOQ09ERSBibGFja2xpc3QgYW5kIGtlZXAgb25seSBzdGFuZGFyZCBjaHJvbW9zb21lcwpkYmFfb2JqZWN0IDwtIGRiYS5ibGFja2xpc3QoZGJhX29iamVjdCwgYmxhY2tsaXN0ID0gREJBX0JMQUNLTElTVF9IRzM4LCBncmV5bGlzdCA9IGdyZXlsaXN0KQoKIyBSZS1jZW50ZXIgcGVha3MgYW5kIGNvdW50IHJlYWRzCmRiYV9vYmplY3QgPC0gZGJhLmNvdW50KGRiYV9vYmplY3QpCmRiYV9vYmplY3QKYGBgCgpgYGB7cn0KIyBEQkFfTk9STV9MSUIgKGRlZmF1bHQpLCBEQkFfTk9STV9STEUgKERFU2VxMiksIERCQV9OT1JNX1RNTSAoZWRnZVIpIG9yIGN1c3RvbSB2ZWN0b3IgKFpFTikKbm9ybV9tZXRob2QgPC0gIlpFTiIKc2NhbGFycyA8LSBlcnlfYXRhY196ZW4KICAKaWYgKG5vcm1fbWV0aG9kID09ICJaRU4iKSB7CiAgIyBTZWxlY3Qgc2NhbGluZyBmYWN0b3JzIGZvciB0aGUgc3BlY2lmaWMgcmVwbGljYXRlcwogIG5vcm1fc3ViIDwtIHNjYWxhcnNbbmFtZXMoc2NhbGFycykgJWluJSBzaGVldCRTYW1wbGVJRF0KfSBlbHNlIHsKICBub3JtX3N1YiA8LSBub3JtX21ldGhvZAp9CgpkYmFfb2JqZWN0IDwtIGRiYS5ub3JtYWxpemUoZGJhX29iamVjdCwgbm9ybWFsaXplID0gbm9ybV9zdWIpCm5vcm1faW5mbyA8LSBkYmEubm9ybWFsaXplKGRiYV9vYmplY3QsIGJSZXRyaWV2ZSA9IFRSVUUpCiMgVmlldyB0aGUgc2NhbGluZyBmYWN0b3JzCm5vcm1faW5mbwpgYGAKCmBgYHtyfQojIENsdXN0ZXJpbmcgYnkgY291bnQgc2NvcmVzCnBsb3QoZGJhX29iamVjdCkKYGBgCgpgYGB7cn0KIyBTZXQgdGhlIGNvbnRyYXN0CmRiYV9vYmplY3QgPC0gZGJhLmNvbnRyYXN0KGRiYV9vYmplY3QsIHJlb3JkZXJNZXRhID0gY29udHJhc3QpCmRiYV9vYmplY3QgPC0gZGJhLmFuYWx5emUoZGJhX29iamVjdCkKZGJhLnNob3coZGJhX29iamVjdCwgYkNvbnRyYXN0cyA9IFRSVUUpCmBgYAoKYGBge3J9CnBsb3QoZGJhX29iamVjdCwgY29udHJhc3QgPSAxKQpgYGAKCmBgYHtyfQpyZXN1bHRzIDwtIGRiYS5yZXBvcnQoZGJhX29iamVjdCwgY29udHJhc3QgPSAxKQpyZXN1bHRzCmBgYAoKYGBge3J9Cm91dHB1dF9maWxlIDwtICJFcnl0aHJvaWRfQVRBQy9EaWZmQmluZF9Fcnl0aHJvaWRfRG9ub3IyX3ZzX0Rvbm9yM19STEUuY3N2IgoKcmVzdWx0c19kZiA8LSBhcyhyZXN1bHRzLCAiZGF0YS5mcmFtZSIpCnJlc3VsdHNfZGYgPC0gcmVzdWx0c19kZltjKCJzZXFuYW1lcyIsICJzdGFydCIsICJlbmQiLCAiRm9sZCIsICJwLXZhbHVlIiwgIkZEUiIpXQpuYW1lcyhyZXN1bHRzX2RmKVtuYW1lcyhyZXN1bHRzX2RmKSA9PSAic2VxbmFtZXMiXSA8LSAiY2hyb20iCnByaW50KHBhc3RlKCJTaWduaWZpY2FudDoiLCBucm93KHJlc3VsdHNfZGZbcmVzdWx0c19kZiRGRFIgPCAwLjA1LCBdKSkpCndyaXRlLmNzdihyZXN1bHRzX2RmLCBvdXRwdXRfZmlsZSwgcm93Lm5hbWVzID0gRkFMU0UpCnJlc3VsdHNfZGYKYGBg