library(DESeq2)
library(dplyr)
library(readr)
library(tibble)
library(tidyr)
library(ggplot2)
library(writexl)
library(decoupleR)
library(ComplexHeatmap)
library(circlize)
Aim
In Day 1 we asked which gene sets were enriched among the
differential expression results. Today we ask a different question:
which upstream pathways and transcription factors look active?
- infer pathway activity with PROGENy and
decoupleR
- infer transcription factor activity with DoRothEA and
decoupleR
- compare contrast-level activity scores with sample-level activity
scores
- connect activity scores back to the ORA, GSEA, and GSVA results from
Day 1
1. Load Differential Expression Results
res <- read_tsv("DESeq_result_full.tsv", show_col_types = FALSE)
res
Remove rows that cannot be used for activity inference. If a gene
appears more than once, keep the row with the strongest DESeq2
statistic.
res_clean <- res |>
filter(!is.na(gene_name), gene_name != "", !is.na(stat)) |>
group_by(gene_name) |>
slice_max(order_by = abs(stat), n = 1, with_ties = FALSE) |>
ungroup()
nrow(res)
[1] 17666
nrow(res_clean)
[1] 17666
4. Load Activity Models
PROGENy connects pathways to responsive genes. DoRothEA connects
transcription factors to regulated target genes.
progeny_model <- read_tsv("progeny_human_top500.tsv", show_col_types = FALSE)
dorothea_network <- read_tsv("dorothea_human_ABC.tsv", show_col_types = FALSE)
progeny_model
dorothea_network
Check how many targets each pathway or transcription factor has.
progeny_model |>
count(source, sort = TRUE)
dorothea_network |>
count(source, sort = TRUE)
5. PROGENy On The DE Contrast
Run decoupleR on the contrast matrix. The score is an
inferred pathway activity score for the MEKi versus control
comparison.
# Practice:
# Use run_mlm().
# mat should be contrast_matrix.
# network should be progeny_model.
# Use weight as the direction and strength column.
# Arrange the result by score.
progeny_contrast
progeny_contrast |>
ggplot(aes(x = score, y = reorder(source, score), fill = score > 0)) +
geom_col() +
scale_fill_manual(values = c("TRUE" = "firebrick", "FALSE" = "steelblue"), guide = "none") +
labs(
x = "PROGENy activity score",
y = NULL,
title = "Pathway activity from the DESeq2 statistic"
) +
theme_minimal()

Task: Which pathways are lower in MEKi? Which
pathways are higher? Does the MAPK result match the treatment?
6. PROGENy At Sample Level
Run the same model on the variance-stabilized expression matrix. This
gives one pathway activity score per sample.
# Practice:
# Use run_mlm() again.
# This time mat should be expression_matrix.
# Convert the long result into a matrix with pivot_wider().
# Rows should be pathways and columns should be samples.
progeny_sample
condition_colors <- c(control = "grey70", MEKi = "firebrick")
sample_annotation <- HeatmapAnnotation(
condition = sample_info$condition,
col = list(condition = condition_colors)
)
Heatmap(
progeny_sample_matrix,
name = "activity",
col = colorRamp2(c(-4, 0, 4), c("steelblue", "white", "firebrick")),
top_annotation = sample_annotation,
column_split = sample_info$condition,
cluster_columns = FALSE,
row_names_gp = grid::gpar(fontsize = 9),
column_names_gp = grid::gpar(fontsize = 9)
)

Task: Which pathways separate control and MEKi
samples? Are these the same pathways that were strongest in the
contrast-level plot?
7. DoRothEA On The DE Contrast
Now infer transcription factor activity from the same DESeq2
statistic matrix.
# Practice:
# Use run_ulm().
# mat should be contrast_matrix.
# network should be dorothea_network.
# Arrange the result by the strongest absolute scores.
tf_contrast
tf_contrast_top |>
ggplot(aes(x = score, y = reorder(source, score), fill = score > 0)) +
geom_col() +
scale_fill_manual(values = c("TRUE" = "firebrick", "FALSE" = "steelblue"), guide = "none") +
labs(
x = "TF activity score",
y = NULL,
title = "Top transcription factor activities from the DESeq2 statistic"
) +
theme_minimal()

Positive scores mean that the target-gene pattern is higher in MEKi.
Negative scores mean that the target-gene pattern is lower in MEKi.
8. Inspect One Transcription Factor
Pick the strongest transcription factor and look at its target genes
in the differential expression table.
# Practice:
# Choose one transcription factor from tf_contrast.
# Filter dorothea_network to this transcription factor.
# Join the targets to res_clean.
# Arrange by padj.
selected_tf
[1] "STAT2"
STAT2
selected_tf_targets
Task: Are the target genes mostly moving in the same
direction as the transcription factor activity score suggests?
9. DoRothEA At Sample Level
Run the transcription factor model on the variance-stabilized
expression matrix. For the heatmap, show the transcription factors with
the strongest contrast-level scores.
# Practice:
# Use run_ulm() again.
# This time mat should be expression_matrix.
# Convert the long result into a matrix with pivot_wider().
# Keep the strongest transcription factors from tf_contrast for the heatmap.
tf_sample
Heatmap(
tf_heatmap_scaled,
name = "TF\nz-score",
col = colorRamp2(c(-2, 0, 2), c("steelblue", "white", "firebrick")),
top_annotation = sample_annotation,
column_split = sample_info$condition,
cluster_columns = FALSE,
row_names_gp = grid::gpar(fontsize = 8),
column_names_gp = grid::gpar(fontsize = 9)
)

Task: Which transcription factors separate control
and MEKi samples? Which ones are also strong in the contrast-level
result?
10. Save Result Tables
write_tsv(progeny_contrast, "PROGENy_contrast_activity.tsv")
write_xlsx(progeny_contrast, "PROGENy_contrast_activity.xlsx")
write_tsv(progeny_sample, "PROGENy_sample_activity.tsv")
write_xlsx(progeny_sample, "PROGENy_sample_activity.xlsx")
write_tsv(tf_contrast, "DoRothEA_contrast_activity.tsv")
write_xlsx(tf_contrast, "DoRothEA_contrast_activity.xlsx")
write_tsv(tf_sample, "DoRothEA_sample_activity.tsv")
write_xlsx(tf_sample, "DoRothEA_sample_activity.xlsx")
11. Final Interpretation
Use the pathway and transcription factor activity results together
with the Day 1 ORA, GSEA, and GSVA results.
Answer these questions:
- Which PROGENy pathways best explain the MEKi effect?
- Which transcription factors support the same interpretation?
- Which activity scores are visible both in the contrast-level results
and at sample level?
- Which findings agree with the Hallmark and GO results from Day
1?
- Which findings are new compared with enrichment analysis?
- Which conclusions should be treated cautiously because they depend
on one model or one transcription factor?
LS0tCnRpdGxlOiAiV003IFJlZ3VsYXRvciBBY3Rpdml0eSIKc3VidGl0bGU6ICJQYXRod2F5IGFuZCB0cmFuc2NyaXB0aW9uIGZhY3RvciBhY3Rpdml0eSB3aXRoIGRlY291cGxlUiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwotLS0KCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh3cml0ZXhsKQpsaWJyYXJ5KGRlY291cGxlUikKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKYGBgCgojIyBBaW0KCkluIERheSAxIHdlIGFza2VkIHdoaWNoIGdlbmUgc2V0cyB3ZXJlIGVucmljaGVkIGFtb25nIHRoZSBkaWZmZXJlbnRpYWwKZXhwcmVzc2lvbiByZXN1bHRzLiBUb2RheSB3ZSBhc2sgYSBkaWZmZXJlbnQgcXVlc3Rpb246IHdoaWNoIHVwc3RyZWFtIHBhdGh3YXlzCmFuZCB0cmFuc2NyaXB0aW9uIGZhY3RvcnMgbG9vayBhY3RpdmU/CgotIGluZmVyIHBhdGh3YXkgYWN0aXZpdHkgd2l0aCBQUk9HRU55IGFuZCBgZGVjb3VwbGVSYAotIGluZmVyIHRyYW5zY3JpcHRpb24gZmFjdG9yIGFjdGl2aXR5IHdpdGggRG9Sb3RoRUEgYW5kIGBkZWNvdXBsZVJgCi0gY29tcGFyZSBjb250cmFzdC1sZXZlbCBhY3Rpdml0eSBzY29yZXMgd2l0aCBzYW1wbGUtbGV2ZWwgYWN0aXZpdHkgc2NvcmVzCi0gY29ubmVjdCBhY3Rpdml0eSBzY29yZXMgYmFjayB0byB0aGUgT1JBLCBHU0VBLCBhbmQgR1NWQSByZXN1bHRzIGZyb20gRGF5IDEKCiMjIDEuIExvYWQgRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gUmVzdWx0cwoKYGBge3IgbG9hZC1yZXN1bHRzfQpyZXMgPC0gcmVhZF90c3YoIkRFU2VxX3Jlc3VsdF9mdWxsLnRzdiIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCgpyZXMKYGBgCgpSZW1vdmUgcm93cyB0aGF0IGNhbm5vdCBiZSB1c2VkIGZvciBhY3Rpdml0eSBpbmZlcmVuY2UuIElmIGEgZ2VuZSBhcHBlYXJzIG1vcmUKdGhhbiBvbmNlLCBrZWVwIHRoZSByb3cgd2l0aCB0aGUgc3Ryb25nZXN0IERFU2VxMiBzdGF0aXN0aWMuCgpgYGB7ciBjbGVhbi1yZXN1bHRzfQpyZXNfY2xlYW4gPC0gcmVzIHw+CiAgZmlsdGVyKCFpcy5uYShnZW5lX25hbWUpLCBnZW5lX25hbWUgIT0gIiIsICFpcy5uYShzdGF0KSkgfD4KICBncm91cF9ieShnZW5lX25hbWUpIHw+CiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYWJzKHN0YXQpLCBuID0gMSwgd2l0aF90aWVzID0gRkFMU0UpIHw+CiAgdW5ncm91cCgpCgpucm93KHJlcykKbnJvdyhyZXNfY2xlYW4pCmBgYAoKIyMgMi4gTWFrZSBBIENvbnRyYXN0LUxldmVsIElucHV0IE1hdHJpeAoKRm9yIGBkZWNvdXBsZVJgLCByb3dzIGFyZSBnZW5lcyBhbmQgY29sdW1ucyBhcmUgc2FtcGxlcyBvciBjb250cmFzdHMuIEZpcnN0IHVzZQp0aGUgREVTZXEyIFdhbGQgc3RhdGlzdGljIGFzIGEgb25lLWNvbHVtbiBjb250cmFzdCBtYXRyaXguCgpgYGB7ciBjb250cmFzdC1tYXRyaXgtaGlkZGVuLCBpbmNsdWRlPUZBTFNFfQpjb250cmFzdF9tYXRyaXggPC0gcmVzX2NsZWFuIHw+CiAgc2VsZWN0KGdlbmVfbmFtZSwgc3RhdCkgfD4KICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmVfbmFtZSIpIHw+CiAgYXMubWF0cml4KCkKCmNvbG5hbWVzKGNvbnRyYXN0X21hdHJpeCkgPC0gIk1FS2lfdnNfY29udHJvbCIKYGBgCgpgYGB7ciBjb250cmFzdC1tYXRyaXgsIGV2YWw9RkFMU0V9CiMgUHJhY3RpY2U6CiMgU3RhcnQgZnJvbSByZXNfY2xlYW4uCiMgS2VlcCBnZW5lX25hbWUgYW5kIHN0YXQuCiMgTW92ZSBnZW5lX25hbWUgaW50byB0aGUgcm93IG5hbWVzIHdpdGggY29sdW1uX3RvX3Jvd25hbWVzKCkuCiMgQ29udmVydCB0aGUgcmVzdWx0IHRvIGEgbWF0cml4IHdpdGggYXMubWF0cml4KCkuCiMgR2l2ZSB0aGUgY29sdW1uIHRoZSBuYW1lIE1FS2lfdnNfY29udHJvbC4KYGBgCgpgYGB7ciBzaG93LWNvbnRyYXN0LW1hdHJpeH0KZGltKGNvbnRyYXN0X21hdHJpeCkKaGVhZChjb250cmFzdF9tYXRyaXgpCmBgYAoKUG9zaXRpdmUgdmFsdWVzIG1lYW4gaGlnaGVyIGV4cHJlc3Npb24gaW4gTUVLaS4gTmVnYXRpdmUgdmFsdWVzIG1lYW4gbG93ZXIKZXhwcmVzc2lvbiBpbiBNRUtpLgoKIyMgMy4gTWFrZSBBIFNhbXBsZS1MZXZlbCBJbnB1dCBNYXRyaXgKCkZvciBzYW1wbGUtbGV2ZWwgYWN0aXZpdHkgc2NvcmVzLCB1c2UgdmFyaWFuY2Utc3RhYmlsaXplZCBjb3VudHMsIGFzIGluIHRoZSBQQ0EKYW5kIEdTVkEgd29ya2Zsb3dzLgoKYGBge3IgbG9hZC1kZHN9CmRkcyA8LSByZWFkUkRTKCJkZHMucmRzIikKCnNhbXBsZV9pbmZvIDwtIGNvbERhdGEoZGRzKSB8PgogIGFzLmRhdGEuZnJhbWUoKSB8PgogIHNlbGVjdChzYW1wbGUsIGNvbmRpdGlvbikKCnNhbXBsZV9pbmZvCmBgYAoKYGBge3IgcHJlcGFyZS12c3QtbWF0cml4fQp2c3RfY291bnRzIDwtIHZzdChkZHMsIGJsaW5kID0gRkFMU0UpCgpleHByZXNzaW9uX21hdHJpeCA8LSBhc3NheSh2c3RfY291bnRzKSB8PgogIGFzLmRhdGEuZnJhbWUoKSB8PgogIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZV9pZCIpIHw+CiAgaW5uZXJfam9pbihyZXNfY2xlYW4gfD4gc2VsZWN0KGdlbmVfaWQsIGdlbmVfbmFtZSksIGJ5ID0gImdlbmVfaWQiKSB8PgogIHNlbGVjdChnZW5lX25hbWUsIGFsbF9vZihzYW1wbGVfaW5mbyRzYW1wbGUpKSB8PgogIGdyb3VwX2J5KGdlbmVfbmFtZSkgfD4KICBzdW1tYXJpemUoYWNyb3NzKGFsbF9vZihzYW1wbGVfaW5mbyRzYW1wbGUpLCBtZWFuKSwgLmdyb3VwcyA9ICJkcm9wIikgfD4KICBjb2x1bW5fdG9fcm93bmFtZXMoImdlbmVfbmFtZSIpIHw+CiAgYXMubWF0cml4KCkKCmRpbShleHByZXNzaW9uX21hdHJpeCkKYGBgCgojIyA0LiBMb2FkIEFjdGl2aXR5IE1vZGVscwoKUFJPR0VOeSBjb25uZWN0cyBwYXRod2F5cyB0byByZXNwb25zaXZlIGdlbmVzLiBEb1JvdGhFQSBjb25uZWN0cyB0cmFuc2NyaXB0aW9uCmZhY3RvcnMgdG8gcmVndWxhdGVkIHRhcmdldCBnZW5lcy4KCmBgYHtyIGxvYWQtbW9kZWxzfQpwcm9nZW55X21vZGVsIDwtIHJlYWRfdHN2KCJwcm9nZW55X2h1bWFuX3RvcDUwMC50c3YiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpkb3JvdGhlYV9uZXR3b3JrIDwtIHJlYWRfdHN2KCJkb3JvdGhlYV9odW1hbl9BQkMudHN2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKCnByb2dlbnlfbW9kZWwKZG9yb3RoZWFfbmV0d29yawpgYGAKCkNoZWNrIGhvdyBtYW55IHRhcmdldHMgZWFjaCBwYXRod2F5IG9yIHRyYW5zY3JpcHRpb24gZmFjdG9yIGhhcy4KCmBgYHtyIG1vZGVsLXNpemVzfQpwcm9nZW55X21vZGVsIHw+CiAgY291bnQoc291cmNlLCBzb3J0ID0gVFJVRSkKCmRvcm90aGVhX25ldHdvcmsgfD4KICBjb3VudChzb3VyY2UsIHNvcnQgPSBUUlVFKQpgYGAKCiMjIDUuIFBST0dFTnkgT24gVGhlIERFIENvbnRyYXN0CgpSdW4gYGRlY291cGxlUmAgb24gdGhlIGNvbnRyYXN0IG1hdHJpeC4gVGhlIHNjb3JlIGlzIGFuIGluZmVycmVkIHBhdGh3YXkKYWN0aXZpdHkgc2NvcmUgZm9yIHRoZSBNRUtpIHZlcnN1cyBjb250cm9sIGNvbXBhcmlzb24uCgpgYGB7ciBwcm9nZW55LWNvbnRyYXN0LWhpZGRlbiwgaW5jbHVkZT1GQUxTRX0KcHJvZ2VueV9jb250cmFzdCA8LSBydW5fbWxtKAogIG1hdCA9IGNvbnRyYXN0X21hdHJpeCwKICBuZXR3b3JrID0gcHJvZ2VueV9tb2RlbCwKICAubW9yID0gd2VpZ2h0LAogIG1pbnNpemUgPSA1CikgfD4KICBhcnJhbmdlKHNjb3JlKQpgYGAKCmBgYHtyIHByb2dlbnktY29udHJhc3QsIGV2YWw9RkFMU0V9CiMgUHJhY3RpY2U6CiMgVXNlIHJ1bl9tbG0oKS4KIyBtYXQgc2hvdWxkIGJlIGNvbnRyYXN0X21hdHJpeC4KIyBuZXR3b3JrIHNob3VsZCBiZSBwcm9nZW55X21vZGVsLgojIFVzZSB3ZWlnaHQgYXMgdGhlIGRpcmVjdGlvbiBhbmQgc3RyZW5ndGggY29sdW1uLgojIEFycmFuZ2UgdGhlIHJlc3VsdCBieSBzY29yZS4KYGBgCgpgYGB7ciBzaG93LXByb2dlbnktY29udHJhc3R9CnByb2dlbnlfY29udHJhc3QKYGBgCgpgYGB7ciBwcm9nZW55LWNvbnRyYXN0LXBsb3QsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CnByb2dlbnlfY29udHJhc3QgfD4KICBnZ3Bsb3QoYWVzKHggPSBzY29yZSwgeSA9IHJlb3JkZXIoc291cmNlLCBzY29yZSksIGZpbGwgPSBzY29yZSA+IDApKSArCiAgZ2VvbV9jb2woKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiZmlyZWJyaWNrIiwgIkZBTFNFIiA9ICJzdGVlbGJsdWUiKSwgZ3VpZGUgPSAibm9uZSIpICsKICBsYWJzKAogICAgeCA9ICJQUk9HRU55IGFjdGl2aXR5IHNjb3JlIiwKICAgIHkgPSBOVUxMLAogICAgdGl0bGUgPSAiUGF0aHdheSBhY3Rpdml0eSBmcm9tIHRoZSBERVNlcTIgc3RhdGlzdGljIgogICkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCioqVGFzazoqKiBXaGljaCBwYXRod2F5cyBhcmUgbG93ZXIgaW4gTUVLaT8gV2hpY2ggcGF0aHdheXMgYXJlIGhpZ2hlcj8gRG9lcyB0aGUKTUFQSyByZXN1bHQgbWF0Y2ggdGhlIHRyZWF0bWVudD8KCiMjIDYuIFBST0dFTnkgQXQgU2FtcGxlIExldmVsCgpSdW4gdGhlIHNhbWUgbW9kZWwgb24gdGhlIHZhcmlhbmNlLXN0YWJpbGl6ZWQgZXhwcmVzc2lvbiBtYXRyaXguIFRoaXMgZ2l2ZXMgb25lCnBhdGh3YXkgYWN0aXZpdHkgc2NvcmUgcGVyIHNhbXBsZS4KCmBgYHtyIHByb2dlbnktc2FtcGxlLWhpZGRlbiwgaW5jbHVkZT1GQUxTRX0KcHJvZ2VueV9zYW1wbGUgPC0gcnVuX21sbSgKICBtYXQgPSBleHByZXNzaW9uX21hdHJpeCwKICBuZXR3b3JrID0gcHJvZ2VueV9tb2RlbCwKICAubW9yID0gd2VpZ2h0LAogIG1pbnNpemUgPSA1CikKCnByb2dlbnlfc2FtcGxlX21hdHJpeCA8LSBwcm9nZW55X3NhbXBsZSB8PgogIHNlbGVjdChzb3VyY2UsIGNvbmRpdGlvbiwgc2NvcmUpIHw+CiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNvbmRpdGlvbiwgdmFsdWVzX2Zyb20gPSBzY29yZSkgfD4KICBjb2x1bW5fdG9fcm93bmFtZXMoInNvdXJjZSIpIHw+CiAgYXMubWF0cml4KCkKCnByb2dlbnlfc2FtcGxlX21hdHJpeCA8LSBwcm9nZW55X3NhbXBsZV9tYXRyaXhbLCBzYW1wbGVfaW5mbyRzYW1wbGVdCmBgYAoKYGBge3IgcHJvZ2VueS1zYW1wbGUsIGV2YWw9RkFMU0V9CiMgUHJhY3RpY2U6CiMgVXNlIHJ1bl9tbG0oKSBhZ2Fpbi4KIyBUaGlzIHRpbWUgbWF0IHNob3VsZCBiZSBleHByZXNzaW9uX21hdHJpeC4KIyBDb252ZXJ0IHRoZSBsb25nIHJlc3VsdCBpbnRvIGEgbWF0cml4IHdpdGggcGl2b3Rfd2lkZXIoKS4KIyBSb3dzIHNob3VsZCBiZSBwYXRod2F5cyBhbmQgY29sdW1ucyBzaG91bGQgYmUgc2FtcGxlcy4KYGBgCgpgYGB7ciBzaG93LXByb2dlbnktc2FtcGxlfQpwcm9nZW55X3NhbXBsZQpgYGAKCmBgYHtyIHByb2dlbnktc2FtcGxlLWhlYXRtYXAsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CmNvbmRpdGlvbl9jb2xvcnMgPC0gYyhjb250cm9sID0gImdyZXk3MCIsIE1FS2kgPSAiZmlyZWJyaWNrIikKCnNhbXBsZV9hbm5vdGF0aW9uIDwtIEhlYXRtYXBBbm5vdGF0aW9uKAogIGNvbmRpdGlvbiA9IHNhbXBsZV9pbmZvJGNvbmRpdGlvbiwKICBjb2wgPSBsaXN0KGNvbmRpdGlvbiA9IGNvbmRpdGlvbl9jb2xvcnMpCikKCkhlYXRtYXAoCiAgcHJvZ2VueV9zYW1wbGVfbWF0cml4LAogIG5hbWUgPSAiYWN0aXZpdHkiLAogIGNvbCA9IGNvbG9yUmFtcDIoYygtNCwgMCwgNCksIGMoInN0ZWVsYmx1ZSIsICJ3aGl0ZSIsICJmaXJlYnJpY2siKSksCiAgdG9wX2Fubm90YXRpb24gPSBzYW1wbGVfYW5ub3RhdGlvbiwKICBjb2x1bW5fc3BsaXQgPSBzYW1wbGVfaW5mbyRjb25kaXRpb24sCiAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgcm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDkpLAogIGNvbHVtbl9uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSA5KQopCmBgYAoKKipUYXNrOioqIFdoaWNoIHBhdGh3YXlzIHNlcGFyYXRlIGNvbnRyb2wgYW5kIE1FS2kgc2FtcGxlcz8gQXJlIHRoZXNlIHRoZSBzYW1lCnBhdGh3YXlzIHRoYXQgd2VyZSBzdHJvbmdlc3QgaW4gdGhlIGNvbnRyYXN0LWxldmVsIHBsb3Q/CgojIyA3LiBEb1JvdGhFQSBPbiBUaGUgREUgQ29udHJhc3QKCk5vdyBpbmZlciB0cmFuc2NyaXB0aW9uIGZhY3RvciBhY3Rpdml0eSBmcm9tIHRoZSBzYW1lIERFU2VxMiBzdGF0aXN0aWMgbWF0cml4LgoKYGBge3IgdGYtY29udHJhc3QtaGlkZGVuLCBpbmNsdWRlPUZBTFNFfQp0Zl9jb250cmFzdCA8LSBydW5fdWxtKAogIG1hdCA9IGNvbnRyYXN0X21hdHJpeCwKICBuZXR3b3JrID0gZG9yb3RoZWFfbmV0d29yaywKICBtaW5zaXplID0gNQopIHw+CiAgYXJyYW5nZShkZXNjKGFicyhzY29yZSkpKQoKdGZfY29udHJhc3RfdG9wIDwtIGJpbmRfcm93cygKICB0Zl9jb250cmFzdCB8PiBzbGljZV9tYXgoc2NvcmUsIG4gPSAxNSksCiAgdGZfY29udHJhc3QgfD4gc2xpY2VfbWluKHNjb3JlLCBuID0gMTUpCikgfD4KICBkaXN0aW5jdChzb3VyY2UsIC5rZWVwX2FsbCA9IFRSVUUpCmBgYAoKYGBge3IgdGYtY29udHJhc3QsIGV2YWw9RkFMU0V9CiMgUHJhY3RpY2U6CiMgVXNlIHJ1bl91bG0oKS4KIyBtYXQgc2hvdWxkIGJlIGNvbnRyYXN0X21hdHJpeC4KIyBuZXR3b3JrIHNob3VsZCBiZSBkb3JvdGhlYV9uZXR3b3JrLgojIEFycmFuZ2UgdGhlIHJlc3VsdCBieSB0aGUgc3Ryb25nZXN0IGFic29sdXRlIHNjb3Jlcy4KYGBgCgpgYGB7ciBzaG93LXRmLWNvbnRyYXN0fQp0Zl9jb250cmFzdApgYGAKCmBgYHtyIHRmLWNvbnRyYXN0LXBsb3QsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CnRmX2NvbnRyYXN0X3RvcCB8PgogIGdncGxvdChhZXMoeCA9IHNjb3JlLCB5ID0gcmVvcmRlcihzb3VyY2UsIHNjb3JlKSwgZmlsbCA9IHNjb3JlID4gMCkpICsKICBnZW9tX2NvbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICJmaXJlYnJpY2siLCAiRkFMU0UiID0gInN0ZWVsYmx1ZSIpLCBndWlkZSA9ICJub25lIikgKwogIGxhYnMoCiAgICB4ID0gIlRGIGFjdGl2aXR5IHNjb3JlIiwKICAgIHkgPSBOVUxMLAogICAgdGl0bGUgPSAiVG9wIHRyYW5zY3JpcHRpb24gZmFjdG9yIGFjdGl2aXRpZXMgZnJvbSB0aGUgREVTZXEyIHN0YXRpc3RpYyIKICApICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpQb3NpdGl2ZSBzY29yZXMgbWVhbiB0aGF0IHRoZSB0YXJnZXQtZ2VuZSBwYXR0ZXJuIGlzIGhpZ2hlciBpbiBNRUtpLiBOZWdhdGl2ZQpzY29yZXMgbWVhbiB0aGF0IHRoZSB0YXJnZXQtZ2VuZSBwYXR0ZXJuIGlzIGxvd2VyIGluIE1FS2kuCgojIyA4LiBJbnNwZWN0IE9uZSBUcmFuc2NyaXB0aW9uIEZhY3RvcgoKUGljayB0aGUgc3Ryb25nZXN0IHRyYW5zY3JpcHRpb24gZmFjdG9yIGFuZCBsb29rIGF0IGl0cyB0YXJnZXQgZ2VuZXMgaW4gdGhlCmRpZmZlcmVudGlhbCBleHByZXNzaW9uIHRhYmxlLgoKYGBge3IgdGYtdGFyZ2V0cy1oaWRkZW4sIGluY2x1ZGU9RkFMU0V9CnNlbGVjdGVkX3RmIDwtIHRmX2NvbnRyYXN0IHw+CiAgc2xpY2UoMSkgfD4KICBwdWxsKHNvdXJjZSkKCnNlbGVjdGVkX3RmX3RhcmdldHMgPC0gZG9yb3RoZWFfbmV0d29yayB8PgogIGZpbHRlcihzb3VyY2UgPT0gc2VsZWN0ZWRfdGYpIHw+CiAgaW5uZXJfam9pbihyZXNfY2xlYW4sIGJ5ID0gYygidGFyZ2V0IiA9ICJnZW5lX25hbWUiKSkgfD4KICBhcnJhbmdlKHBhZGopIHw+CiAgc2VsZWN0KHNvdXJjZSwgY29uZmlkZW5jZSwgdGFyZ2V0LCBtb3IsIGxvZzJGb2xkQ2hhbmdlLCBzdGF0LCBwYWRqKQpgYGAKCmBgYHtyIHRmLXRhcmdldHMsIGV2YWw9RkFMU0V9CiMgUHJhY3RpY2U6CiMgQ2hvb3NlIG9uZSB0cmFuc2NyaXB0aW9uIGZhY3RvciBmcm9tIHRmX2NvbnRyYXN0LgojIEZpbHRlciBkb3JvdGhlYV9uZXR3b3JrIHRvIHRoaXMgdHJhbnNjcmlwdGlvbiBmYWN0b3IuCiMgSm9pbiB0aGUgdGFyZ2V0cyB0byByZXNfY2xlYW4uCiMgQXJyYW5nZSBieSBwYWRqLgpgYGAKCmBgYHtyIHNob3ctdGYtdGFyZ2V0c30Kc2VsZWN0ZWRfdGYKc2VsZWN0ZWRfdGZfdGFyZ2V0cwpgYGAKCioqVGFzazoqKiBBcmUgdGhlIHRhcmdldCBnZW5lcyBtb3N0bHkgbW92aW5nIGluIHRoZSBzYW1lIGRpcmVjdGlvbiBhcyB0aGUKdHJhbnNjcmlwdGlvbiBmYWN0b3IgYWN0aXZpdHkgc2NvcmUgc3VnZ2VzdHM/CgojIyA5LiBEb1JvdGhFQSBBdCBTYW1wbGUgTGV2ZWwKClJ1biB0aGUgdHJhbnNjcmlwdGlvbiBmYWN0b3IgbW9kZWwgb24gdGhlIHZhcmlhbmNlLXN0YWJpbGl6ZWQgZXhwcmVzc2lvbiBtYXRyaXguCkZvciB0aGUgaGVhdG1hcCwgc2hvdyB0aGUgdHJhbnNjcmlwdGlvbiBmYWN0b3JzIHdpdGggdGhlIHN0cm9uZ2VzdCBjb250cmFzdC1sZXZlbApzY29yZXMuCgpgYGB7ciB0Zi1zYW1wbGUtaGlkZGVuLCBpbmNsdWRlPUZBTFNFfQp0Zl9zYW1wbGUgPC0gcnVuX3VsbSgKICBtYXQgPSBleHByZXNzaW9uX21hdHJpeCwKICBuZXR3b3JrID0gZG9yb3RoZWFfbmV0d29yaywKICBtaW5zaXplID0gNQopCgp0Zl9zYW1wbGVfbWF0cml4IDwtIHRmX3NhbXBsZSB8PgogIHNlbGVjdChzb3VyY2UsIGNvbmRpdGlvbiwgc2NvcmUpIHw+CiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNvbmRpdGlvbiwgdmFsdWVzX2Zyb20gPSBzY29yZSkgfD4KICBjb2x1bW5fdG9fcm93bmFtZXMoInNvdXJjZSIpIHw+CiAgYXMubWF0cml4KCkKCnRmX3NhbXBsZV9tYXRyaXggPC0gdGZfc2FtcGxlX21hdHJpeFssIHNhbXBsZV9pbmZvJHNhbXBsZV0KCnRvcF90ZnMgPC0gdGZfY29udHJhc3QgfD4KICBzbGljZV9oZWFkKG4gPSAzMCkgfD4KICBwdWxsKHNvdXJjZSkKCnRmX2hlYXRtYXBfbWF0cml4IDwtIHRmX3NhbXBsZV9tYXRyaXhbdG9wX3RmcywgXQp0Zl9oZWF0bWFwX3NjYWxlZCA8LSB0KHNjYWxlKHQodGZfaGVhdG1hcF9tYXRyaXgpKSkKdGZfaGVhdG1hcF9zY2FsZWRbaXMubmEodGZfaGVhdG1hcF9zY2FsZWQpXSA8LSAwCmBgYAoKYGBge3IgdGYtc2FtcGxlLCBldmFsPUZBTFNFfQojIFByYWN0aWNlOgojIFVzZSBydW5fdWxtKCkgYWdhaW4uCiMgVGhpcyB0aW1lIG1hdCBzaG91bGQgYmUgZXhwcmVzc2lvbl9tYXRyaXguCiMgQ29udmVydCB0aGUgbG9uZyByZXN1bHQgaW50byBhIG1hdHJpeCB3aXRoIHBpdm90X3dpZGVyKCkuCiMgS2VlcCB0aGUgc3Ryb25nZXN0IHRyYW5zY3JpcHRpb24gZmFjdG9ycyBmcm9tIHRmX2NvbnRyYXN0IGZvciB0aGUgaGVhdG1hcC4KYGBgCgpgYGB7ciBzaG93LXRmLXNhbXBsZX0KdGZfc2FtcGxlCmBgYAoKYGBge3IgdGYtc2FtcGxlLWhlYXRtYXAsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTh9CkhlYXRtYXAoCiAgdGZfaGVhdG1hcF9zY2FsZWQsCiAgbmFtZSA9ICJURlxuei1zY29yZSIsCiAgY29sID0gY29sb3JSYW1wMihjKC0yLCAwLCAyKSwgYygic3RlZWxibHVlIiwgIndoaXRlIiwgImZpcmVicmljayIpKSwKICB0b3BfYW5ub3RhdGlvbiA9IHNhbXBsZV9hbm5vdGF0aW9uLAogIGNvbHVtbl9zcGxpdCA9IHNhbXBsZV9pbmZvJGNvbmRpdGlvbiwKICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICByb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gOCksCiAgY29sdW1uX25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDkpCikKYGBgCgoqKlRhc2s6KiogV2hpY2ggdHJhbnNjcmlwdGlvbiBmYWN0b3JzIHNlcGFyYXRlIGNvbnRyb2wgYW5kIE1FS2kgc2FtcGxlcz8gV2hpY2gKb25lcyBhcmUgYWxzbyBzdHJvbmcgaW4gdGhlIGNvbnRyYXN0LWxldmVsIHJlc3VsdD8KCiMjIDEwLiBTYXZlIFJlc3VsdCBUYWJsZXMKCmBgYHtyIHNhdmUtcmVzdWx0c30Kd3JpdGVfdHN2KHByb2dlbnlfY29udHJhc3QsICJQUk9HRU55X2NvbnRyYXN0X2FjdGl2aXR5LnRzdiIpCndyaXRlX3hsc3gocHJvZ2VueV9jb250cmFzdCwgIlBST0dFTnlfY29udHJhc3RfYWN0aXZpdHkueGxzeCIpCgp3cml0ZV90c3YocHJvZ2VueV9zYW1wbGUsICJQUk9HRU55X3NhbXBsZV9hY3Rpdml0eS50c3YiKQp3cml0ZV94bHN4KHByb2dlbnlfc2FtcGxlLCAiUFJPR0VOeV9zYW1wbGVfYWN0aXZpdHkueGxzeCIpCgp3cml0ZV90c3YodGZfY29udHJhc3QsICJEb1JvdGhFQV9jb250cmFzdF9hY3Rpdml0eS50c3YiKQp3cml0ZV94bHN4KHRmX2NvbnRyYXN0LCAiRG9Sb3RoRUFfY29udHJhc3RfYWN0aXZpdHkueGxzeCIpCgp3cml0ZV90c3YodGZfc2FtcGxlLCAiRG9Sb3RoRUFfc2FtcGxlX2FjdGl2aXR5LnRzdiIpCndyaXRlX3hsc3godGZfc2FtcGxlLCAiRG9Sb3RoRUFfc2FtcGxlX2FjdGl2aXR5Lnhsc3giKQpgYGAKCiMjIDExLiBGaW5hbCBJbnRlcnByZXRhdGlvbgoKVXNlIHRoZSBwYXRod2F5IGFuZCB0cmFuc2NyaXB0aW9uIGZhY3RvciBhY3Rpdml0eSByZXN1bHRzIHRvZ2V0aGVyIHdpdGggdGhlCkRheSAxIE9SQSwgR1NFQSwgYW5kIEdTVkEgcmVzdWx0cy4KCkFuc3dlciB0aGVzZSBxdWVzdGlvbnM6CgoxLiBXaGljaCBQUk9HRU55IHBhdGh3YXlzIGJlc3QgZXhwbGFpbiB0aGUgTUVLaSBlZmZlY3Q/CjIuIFdoaWNoIHRyYW5zY3JpcHRpb24gZmFjdG9ycyBzdXBwb3J0IHRoZSBzYW1lIGludGVycHJldGF0aW9uPwozLiBXaGljaCBhY3Rpdml0eSBzY29yZXMgYXJlIHZpc2libGUgYm90aCBpbiB0aGUgY29udHJhc3QtbGV2ZWwgcmVzdWx0cyBhbmQgYXQKICAgc2FtcGxlIGxldmVsPwo0LiBXaGljaCBmaW5kaW5ncyBhZ3JlZSB3aXRoIHRoZSBIYWxsbWFyayBhbmQgR08gcmVzdWx0cyBmcm9tIERheSAxPwo1LiBXaGljaCBmaW5kaW5ncyBhcmUgbmV3IGNvbXBhcmVkIHdpdGggZW5yaWNobWVudCBhbmFseXNpcz8KNi4gV2hpY2ggY29uY2x1c2lvbnMgc2hvdWxkIGJlIHRyZWF0ZWQgY2F1dGlvdXNseSBiZWNhdXNlIHRoZXkgZGVwZW5kIG9uIG9uZQogICBtb2RlbCBvciBvbmUgdHJhbnNjcmlwdGlvbiBmYWN0b3I/Cg==