Import Excel files
Use readxl::read_excel() to import Excel files. You can
specify the sheet name or number, and optionally a range of cells.
DGE_CaseControl <- read_excel("DGEtables.xlsx", sheet = "CaseControl")
head(DGE_CaseControl)
Read a specific range of cells in Excel
DGE_subset <- read_excel("DGEtables.xlsx",
sheet = "CaseControl",
range = "A1:F50")
head(DGE_subset)
Read all sheets and combine
A more advanced example merging all sheets from excel into one table,
and naming the source sheet in a new column:
#name of each sheet in excel file
sheet_names <- excel_sheets("DGEtables.xlsx")
cat("sheet names are ", paste(sheet_names, collapse = ", "), "\n")
sheet names are CaseExposed, CaseControl
#takes sheet names and run read_excel for each sheet,
#we use map_fdr to combine all the tables into one,
#and we add a new column with the sheet name to keep
#track of the source of each row
DGE_all <- sheet_names %>%
set_names() %>%
map_dfr(
~read_excel("DGEtables.xlsx", sheet = .x),
.id = "sheet"
)
summary(DGE_all)
sheet ...1 logFC
Length:13344 Length:13344 Min. :-15.2190
Class :character Class :character 1st Qu.: -2.4412
Mode :character Mode :character Median : -0.0223
Mean : -0.1515
3rd Qu.: 2.1338
Max. : 14.8596
logCPM F PValue
Min. :-0.6586 Min. : 0.0000 Min. :0.00000
1st Qu.: 3.2794 1st Qu.: 0.2718 1st Qu.:0.06444
Median : 4.7527 Median : 1.2249 Median :0.26843
Mean : 4.7831 Mean : 2.2634 Mean :0.34949
3rd Qu.: 6.2484 3rd Qu.: 3.4201 3rd Qu.:0.60215
Max. :17.0813 Max. :43.1210 Max. :1.00000
FDR diffexpr geneType
Min. :0.0000004 Length:13344 Length:13344
1st Qu.:0.2617545 Class :character Class :character
Median :0.5351169 Mode :character Mode :character
Mean :0.5344405
3rd Qu.:0.8014345
Max. :1.0000000
Core tidyverse table manipulation and piping
Those are operations to manipulate tables. You can chain them
together with the pipe operator (%>%). What does the
pipe do?
Look below: we define significant_DGE as a sequence of piped
operations. Their order is from the first to the last, and in tidyverse
names recall very clearly what the operations do. The output of each
operation is piped into the next. Here we
- use the DGE tibble (tidyverse table)
- THEN rename the first column to
gene_name
- THEN clean up column names with
clean_names()
- THEN mutate the
gene_type column into a factor
(category)
- THEN select only the columns of interest
- THEN filter the rows by FDR and gene type
- THEN arrange the rows by descending FDR
glimpse will give an overview of the tibble’s structure
and the first few values.
significant_DGE <- DGE %>%
rename(gene_name = 1) %>% #rename column 1 to gene_name
janitor::clean_names() %>% #clean up column names
mutate(gene_type = factor(gene_type)) %>% #factorize categories of gene types
select(gene_name, log_fc, fdr, gene_type) %>% #select only some columns of interest
filter(fdr < .05 & gene_type=="protein-coding") %>% #filter by fdr and gene type
arrange(desc(fdr)) #arrange by descending pvalue
glimpse(significant_DGE)
Rows: 47
Columns: 4
$ gene_name <chr> "VPS39", "GLT1D1", "SDHAF3", "PI3", "NES", …
$ log_fc <dbl> 11.886819, 12.711685, 11.179818, 11.815255,…
$ fdr <dbl> 0.04961619, 0.04961619, 0.04961619, 0.04961…
$ gene_type <fct> protein-coding, protein-coding, protein-cod…
Create new columns with mutate
You can also create a new column with mutte. Let’s say we want to
define a DGE tibble like above, but without filtering. Instead we create
a category saying SIGN(.001), SIGN(.01), SIGN(.05) or NOT.SIGN, all
depending on the pvalue, and we also want that the logfold change is at
least above 1 or below -1.
You can use mutate to create a new column based on those
criteria:
extended_DGE <- DGE %>%
rename(gene_name = 1) %>% #rename column 1 to gene_name
janitor::clean_names() %>% #clean up column names
mutate(gene_type = factor(gene_type)) %>% #factorize categories of gene types
select(gene_name, log_fc, fdr, gene_type) %>% #select only some columns of interest
mutate( significance_level = case_when(
fdr < .001 & abs(log_fc) > 1 ~ "SIGN(.001)",
fdr < .01 & abs(log_fc) > 1 ~ "SIGN(.01)",
fdr < .05 & abs(log_fc) > 1 ~ "SIGN(.05)",
TRUE ~ "NOT.SIGN"
)) %>% #create a new column with the significance level
mutate( significance_level = factor(significance_level)) %>%
arrange(desc(fdr)) #arrange by descending pvalue
glimpse(extended_DGE)
Rows: 6,672
Columns: 5
$ gene_name <chr> "MIR1184-1", "SLC16A7", "TSPAN33",…
$ log_fc <dbl> 0.000000000, -0.001326973, -0.0009…
$ fdr <dbl> 1.0000000, 0.9997601, 0.9997601, 0…
$ gene_type <fct> ncRNA, protein-coding, protein-cod…
$ significance_level <fct> NOT.SIGN, NOT.SIGN, NOT.SIGN, NOT.…
Summarize by group
You can summarize by group and get group statistics. For example the
number of genes in each gene type and their median fdr and log_fc.
summary_DGE <- extended_DGE %>%
group_by(gene_type) %>%
summarise(
n = n(),
median_lfc = median(log_fc, na.rm = TRUE),
median_fdr = median(fdr, na.rm = TRUE),
.groups = "drop"
)
summary_DGE
Plotting with ggplot2
You can also plot your data with ggplot2, which is part of the
tidyverse. For example, a scatter plot of log fold change vs fdr,
colored by gene type:
ggplot(extended_DGE, aes(x = log_fc, y = -log10(fdr), color = gene_type)) +
geom_point(size=3) +
theme_minimal() +
labs(title = "DGE Scatter Plot", x = "Log Fold Change", y = "-Log10(FDR)")

ggplot takes the dataframe/tibble as input and adds layers of the
plot using the symbol +. There are a lot of ways to customize the plot
or do other types of plots.
We can add a column where we write the name of the genes which are
differentially expressed. We can do this with the mutate function and
case_when. Then we add to the plot a layer of text.
extended_DGE <- extended_DGE %>%
mutate( plot_label = case_when(
significance_level == "NOT.SIGN" ~ NA,
TRUE ~ gene_name
) )
glimpse(extended_DGE)
Rows: 6,672
Columns: 6
$ gene_name <chr> "MIR1184-1", "SLC16A7", "TSPAN33",…
$ log_fc <dbl> 0.000000000, -0.001326973, -0.0009…
$ fdr <dbl> 1.0000000, 0.9997601, 0.9997601, 0…
$ gene_type <fct> ncRNA, protein-coding, protein-cod…
$ significance_level <fct> NOT.SIGN, NOT.SIGN, NOT.SIGN, NOT.…
$ plot_label <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA…
ggplot(extended_DGE, aes(x = log_fc, y = -log10(fdr), color = gene_type)) +
geom_point() +
ggrepel::geom_text_repel(aes(label = plot_label), size = 3, ) + #add labels to significant genes
theme_minimal() +
geom_hline(yintercept=-log10(0.05)) + geom_vline(xintercept=c(1,-1)) + #vertical line ggplot
labs(title = "DGE Scatter Plot", x = "Log Fold Change", y = "-Log10(FDR)")

Themes
You can change theme for adapting the appearence. All standard themes
are here: https://ggplot2.tidyverse.org/reference/ggtheme.html.
For example, it is popular to use the gray theme
<!-- rnb-plot-begin eyJoZWlnaHQiOjQzMi42MzI5LCJ3aWR0aCI6NzAwLCJkcGkiOi0xLCJzaXplX2JlaGF2aW9yIjowLCJjb25kaXRpb25zIjpbWzEsIlx1MDAxYlsxbVx1MDAxYlszM21XYXJuaW5nXHUwMDFiWzM5bTpcdTAwMWJbMjJtXG5cdTAwMWJbMzg7NTsyMzJtUmVtb3ZlZCA2NjE5IHJvd3MgY29udGFpbmluZyBtaXNzaW5nIHZhbHVlcyBvciB2YWx1ZXMgb3V0c2lkZSB0aGUgc2NhbGUgcmFuZ2VcbihgZ2VvbV90ZXh0X3JlcGVsKClgKS5cdTAwMWJbMzltXG5cbiJdXX0= -->
<img src=\data:image/png;base64

You can do nicer themes using the ones developed here https://github.com/koundy/ggplot_theme_Publication,
where someone has developed its own themes. We have imported them at the
beginning of this notebook. For example you can use a theme developed
for publications (nicer sizes and font of text and nicer legend).
<!-- rnb-plot-begin eyJoZWlnaHQiOjQzMi42MzI5LCJ3aWR0aCI6NzAwLCJkcGkiOi0xLCJzaXplX2JlaGF2aW9yIjowLCJjb25kaXRpb25zIjpbWzEsIlx1MDAxYlsxbVx1MDAxYlszM21XYXJuaW5nXHUwMDFiWzM5bTpcdTAwMWJbMjJtXG5cdTAwMWJbMzg7NTsyMzJtUmVtb3ZlZCA2NjE5IHJvd3MgY29udGFpbmluZyBtaXNzaW5nIHZhbHVlcyBvciB2YWx1ZXMgb3V0c2lkZSB0aGUgc2NhbGUgcmFuZ2VcbihgZ2VvbV90ZXh0X3JlcGVsKClgKS5cdTAwMWJbMzltXG5cbiJdXX0= -->
<img src=\data:image/png;base64

Or combine publication theme with a color palette for discrete
variables (gene type) from the same author. You can look at the webpage
for the themes to see more examples.
<!-- rnb-plot-begin eyJoZWlnaHQiOjQzMi42MzI5LCJ3aWR0aCI6NzAwLCJkcGkiOi0xLCJzaXplX2JlaGF2aW9yIjowLCJjb25kaXRpb25zIjpbWzEsIlx1MDAxYlsxbVx1MDAxYlszM21XYXJuaW5nXHUwMDFiWzM5bTpcdTAwMWJbMjJtXG5cdTAwMWJbMzg7NTsyMzJtUmVtb3ZlZCA2NjE5IHJvd3MgY29udGFpbmluZyBtaXNzaW5nIHZhbHVlcyBvciB2YWx1ZXMgb3V0c2lkZSB0aGUgc2NhbGUgcmFuZ2VcbihgZ2VvbV90ZXh0X3JlcGVsKClgKS5cdTAwMWJbMzltXG5cbiJdXX0= -->
<img src=\data:image/png;base64

Still not enough? The package ggthemes has even more ways of
combining color palettes and themes. Look here https://github.com/jrnold/ggthemes where the author
makes a lot of examples and try one of them!
saving ggplots
You can save a ggplot with the dedicated command, but to do that you
need to assign the plot to a variable. For example:
volcano_plot <- ggplot(extended_DGE, aes(x = log_fc, y = -log10(fdr), color = gene_type)) +
geom_point() +
ggrepel::geom_text_repel(aes(label = plot_label), size = 3, ) + #add labels to significant genes
theme_gray() +
geom_hline(yintercept=-log10(0.05)) + geom_vline(xintercept=c(1,-1)) + #vertical line ggplot
labs(title = "DGE Scatter Plot", x = "Log Fold Change", y = "-Log10(FDR)")
ggsave(filename = "./lifeExp.png", plot = volcano_plot, width = 12, height = 10, dpi = 300, units = "cm")
Some other plots: barplots, boxplots, density plots, …
There is a wide range of plot types you can do with ggplot, and it
really depends on your data and what you want to visualize. For example,
you can do a bar plot of the number of genes in each gene type:
ggplot(summary_DGE, aes(x = gene_type, y = log(n), fill = gene_type)) +
geom_bar(stat = "identity") +
scale_fill_Publication() +
theme_dark_blue()

Note that above we needed only one value per gene type to plot the
bar. If we had more values per gene type, we would need to use
stat = "summary" and specify a summary function (for
example fun = "mean" or fun = "median"). For
example, if we want to plot the median log fold change for each gene
type:
ggplot(extended_DGE, aes(x = gene_type, y = log_fc, fill = gene_type)) +
geom_bar(stat = "summary", fun = "median") +
scale_fill_Publication() +
theme_dark_blue() +
#chnge x axis angle to 45
theme(axis.text.x = element_text(angle = 45, hjust = 1))

Faceting
Faceting is a powerful way to create multiple plots based on a
categorical variable. For example, we can facet the scatter plot by gene
type:
ggplot(extended_DGE, aes(x = log_fc, y = -log10(fdr), color = gene_type)) +
geom_point() +
ggrepel::geom_text_repel(aes(label = plot_label)) +
theme_minimal() +
geom_hline(yintercept=-log10(0.05)) + geom_vline(xintercept=c(1,-1)) + #vertical line ggplot
labs(title = "DGE Scatter Plot", x = "Log Fold Change", y = "-Log10(FDR)") +
facet_wrap(~ gene_type)

A density plot of log fold change by gene type:
ggplot(extended_DGE, aes(x = log_fc, fill = gene_type)) +
geom_density(alpha = 0.5) +
scale_fill_Publication() +
theme_excel_new() +
labs(title = "Density Plot of Log Fold Change\nby Gene Type", x = "Log Fold Change", y = "Density")

LS0tDQp0aXRsZTogIkltcG9ydGluZyBUYWJ1bGFyIERhdGEgaW4gUiINCmF1dGhvcjogIlNhbXVlbGUgU29yYWdnaSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCmVkaXRvcl9vcHRpb25zOg0KICBtYXJrZG93bjoNCiAgICB3cmFwOiA3Mg0KLS0tDQoNCiMjIEdvYWxzDQoNCkluIHRoaXMgdHV0b3JpYWwsIHlvdSB3aWxsIGxlYXJuIGhvdyB0bzoNCg0KMS4gSW1wb3J0IHRhYnVsYXIgZGF0YSBmcm9tIENTViBmaWxlcy4NCjIuIEltcG9ydCB0YWJ1bGFyIGRhdGEgZnJvbSBFeGNlbCBmaWxlcy4NCjMuIENsZWFuIGFuZCBtYW5pcHVsYXRlIHRhYmxlcyB3aXRoIHRoZSB0aWR5dmVyc2UuDQoNCiMjIDEuIFNldHVwDQoNCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLCByZWFkeGwsIHJlYWRyLCBqYW5pdG9yLCBnZ3JlcGVsLCBncmlkRXh0cmEsIGdndGhlbWVzLCBzY2FsZXMsIHdyaXRleGwpDQoNCnNvdXJjZSgiaHR0cHM6Ly9naXRodWIuY29tL2tvdW5keS9nZ3Bsb3RfdGhlbWVfUHVibGljYXRpb24vcmF3L3JlZnMvaGVhZHMvbWFzdGVyL2dncGxvdF90aGVtZV9QdWJsaWNhdGlvbi0yLlIiKQ0KYGBgDQoNCiMjIEltcG9ydCBDU1YgZmlsZXMNCg0KVXNlIGByZWFkcjo6cmVhZF9jc3YoKWAgZm9yIGZhc3QgYW5kIGZyaWVuZGx5IENTViBpbXBvcnQuIFRoZSBzZXBhcmF0b3IgKGRlbGltaXRlciBiZXR3ZWVuIGNvbHVtbnMpIGlzIGF1dG9tYXRpY2FsbHkgZGV0ZWN0ZWQgYXMgYSBjb21tYS4gSG93ZXZlciB5b3UgY2FuIHNwZWNpZnkgYW5vdGhlciBkZWxpbWl0ZXIgaW4gdGhlIG9wdGlvbnMgaWYgbmVlZGVkLg0KDQpgYGB7ciByZWFkLXNpbmdsZS1jc3Z9DQpER0UgPC0gcmVhZF9jc3YoIkRHRS5jc3YiKQ0KDQpoZWFkKERHRSkNCmBgYA0KDQpFeGFtcGxlIG9uIGhvdyB0byBzcGVjaWZ5IGEgZGlmZmVyZW50IGRlbGltaXRlciAoc2VtaWNvbG9uKToNCg0KYGBge3IgcmVhZC1kZWxpbSwgZXZhbD1GQUxTRX0NCiNER0UgPC0gcmVhZF9kZWxpbSgiREdFLmNzdiIsIGRlbGltID0gIjsiKQ0KYGBgDQoNCkEgZmlsZSBjYW4gYWxzbyBjb250YWluIHRoZSBmaXJzdCBsaW5lcyB3aXRoIGNvbW1lbnRzIHdoaWNoIHlvdSB3YW50IHRvIHNraXAuIFRoZW4geW91IGNhbiB1c2UgdGhlIGBza2lwYCBhcmd1bWVudCB0byBpZ25vcmUgdGhvc2UgbGluZXM6DQoNCmBgYHtyIHJlYWQtc2tpcH0NCkRHRV9za2lwIDwtIHJlYWRfY3N2KCJ3ZWlyZERHRS5jc3YiLCBza2lwID0gMykNCmBgYA0KDQojIyBJbXBvcnQgRXhjZWwgZmlsZXMNCg0KVXNlIGByZWFkeGw6OnJlYWRfZXhjZWwoKWAgdG8gaW1wb3J0IEV4Y2VsIGZpbGVzLiBZb3UgY2FuIHNwZWNpZnkgdGhlIHNoZWV0IG5hbWUgb3IgbnVtYmVyLCBhbmQgb3B0aW9uYWxseSBhIHJhbmdlIG9mIGNlbGxzLg0KDQpgYGB7ciByZWFkLWV4Y2VsLW9uZX0NCkRHRV9DYXNlQ29udHJvbCA8LSByZWFkX2V4Y2VsKCJER0V0YWJsZXMueGxzeCIsIHNoZWV0ID0gIkNhc2VDb250cm9sIikNCg0KaGVhZChER0VfQ2FzZUNvbnRyb2wpDQpgYGANCg0KIyMjIFJlYWQgYSBzcGVjaWZpYyByYW5nZSBvZiBjZWxscyBpbiBFeGNlbA0KDQpgYGB7ciByZWFkLWV4Y2VsLXJhbmdlfQ0KREdFX3N1YnNldCA8LSByZWFkX2V4Y2VsKCJER0V0YWJsZXMueGxzeCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiQ2FzZUNvbnRyb2wiLA0KICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSAiQTE6RjUwIikNCg0KaGVhZChER0Vfc3Vic2V0KQ0KYGBgDQoNCiMjIyBSZWFkIGFsbCBzaGVldHMgYW5kIGNvbWJpbmUNCg0KQSBtb3JlIGFkdmFuY2VkIGV4YW1wbGUgbWVyZ2luZyBhbGwgc2hlZXRzIGZyb20gZXhjZWwgaW50byBvbmUgdGFibGUsIGFuZCBuYW1pbmcgdGhlIHNvdXJjZSBzaGVldCBpbiBhIG5ldyBjb2x1bW46DQoNCmBgYHtyIHJlYWQtYWxsLXNoZWV0c30NCiNuYW1lIG9mIGVhY2ggc2hlZXQgaW4gZXhjZWwgZmlsZQ0Kc2hlZXRfbmFtZXMgPC0gZXhjZWxfc2hlZXRzKCJER0V0YWJsZXMueGxzeCIpDQpjYXQoInNoZWV0IG5hbWVzIGFyZSAiLCBwYXN0ZShzaGVldF9uYW1lcywgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikNCg0KI3Rha2VzIHNoZWV0IG5hbWVzIGFuZCBydW4gcmVhZF9leGNlbCBmb3IgZWFjaCBzaGVldCwgDQojd2UgdXNlIG1hcF9mZHIgdG8gY29tYmluZSBhbGwgdGhlIHRhYmxlcyBpbnRvIG9uZSwgDQojYW5kIHdlIGFkZCBhIG5ldyBjb2x1bW4gd2l0aCB0aGUgc2hlZXQgbmFtZSB0byBrZWVwIA0KI3RyYWNrIG9mIHRoZSBzb3VyY2Ugb2YgZWFjaCByb3cNCkRHRV9hbGwgPC0gc2hlZXRfbmFtZXMgJT4lDQoJc2V0X25hbWVzKCkgJT4lDQoJbWFwX2RmcigNCgkJfnJlYWRfZXhjZWwoIkRHRXRhYmxlcy54bHN4Iiwgc2hlZXQgPSAueCksDQoJCS5pZCA9ICJzaGVldCINCgkpDQoNCnN1bW1hcnkoREdFX2FsbCkNCmBgYA0KDQoNCiMjIENvcmUgdGlkeXZlcnNlIHRhYmxlIG1hbmlwdWxhdGlvbiBhbmQgcGlwaW5nDQoNClRob3NlIGFyZSBvcGVyYXRpb25zIHRvIG1hbmlwdWxhdGUgdGFibGVzLiBZb3UgY2FuIGNoYWluIHRoZW0gdG9nZXRoZXIgd2l0aCB0aGUgcGlwZSBvcGVyYXRvciAoYCU+JWApLiBXaGF0IGRvZXMgdGhlIHBpcGUgZG8/DQoNCkxvb2sgYmVsb3c6IHdlIGRlZmluZSBzaWduaWZpY2FudF9ER0UgYXMgYSBzZXF1ZW5jZSBvZiBwaXBlZCBvcGVyYXRpb25zLiBUaGVpciBvcmRlciBpcyBmcm9tIHRoZSBmaXJzdCB0byB0aGUgbGFzdCwgYW5kIGluIHRpZHl2ZXJzZSBuYW1lcyByZWNhbGwgdmVyeSBjbGVhcmx5IHdoYXQgdGhlIG9wZXJhdGlvbnMgZG8uIFRoZSBvdXRwdXQgb2YgZWFjaCBvcGVyYXRpb24gaXMgcGlwZWQgaW50byB0aGUgbmV4dC4gSGVyZSB3ZQ0KDQogLSAxLiB1c2UgdGhlIERHRSB0aWJibGUgKHRpZHl2ZXJzZSB0YWJsZSkNCiAtIDIuIFRIRU4gcmVuYW1lIHRoZSBmaXJzdCBjb2x1bW4gdG8gYGdlbmVfbmFtZWANCiAtIDMuIFRIRU4gY2xlYW4gdXAgY29sdW1uIG5hbWVzIHdpdGggYGNsZWFuX25hbWVzKClgDQogLSA0LiBUSEVOIG11dGF0ZSB0aGUgYGdlbmVfdHlwZWAgY29sdW1uIGludG8gYSBmYWN0b3IgKGNhdGVnb3J5KQ0KIC0gNS4gVEhFTiBzZWxlY3Qgb25seSB0aGUgY29sdW1ucyBvZiBpbnRlcmVzdA0KIC0gNi4gVEhFTiBmaWx0ZXIgdGhlIHJvd3MgYnkgRkRSIGFuZCBnZW5lIHR5cGUNCiAtIDcuIFRIRU4gYXJyYW5nZSB0aGUgcm93cyBieSBkZXNjZW5kaW5nIEZEUg0KIA0KYGdsaW1wc2VgIHdpbGwgZ2l2ZSBhbiBvdmVydmlldyBvZiB0aGUgdGliYmxlJ3Mgc3RydWN0dXJlIGFuZCB0aGUgZmlyc3QgZmV3IHZhbHVlcy4NCg0KYGBge3IgY29yZS12ZXJicy0xfQ0Kc2lnbmlmaWNhbnRfREdFIDwtIERHRSAlPiUNCiAgcmVuYW1lKGdlbmVfbmFtZSA9IDEpICU+JSAjcmVuYW1lIGNvbHVtbiAxIHRvIGdlbmVfbmFtZQ0KICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAjY2xlYW4gdXAgY29sdW1uIG5hbWVzDQogIG11dGF0ZShnZW5lX3R5cGUgPSBmYWN0b3IoZ2VuZV90eXBlKSkgJT4lICNmYWN0b3JpemUgY2F0ZWdvcmllcyBvZiBnZW5lIHR5cGVzDQoJc2VsZWN0KGdlbmVfbmFtZSwgbG9nX2ZjLCBmZHIsIGdlbmVfdHlwZSkgJT4lICNzZWxlY3Qgb25seSBzb21lIGNvbHVtbnMgb2YgaW50ZXJlc3QNCglmaWx0ZXIoZmRyIDwgLjA1ICYgZ2VuZV90eXBlPT0icHJvdGVpbi1jb2RpbmciKSAlPiUgI2ZpbHRlciBieSBmZHIgYW5kIGdlbmUgdHlwZQ0KCWFycmFuZ2UoZGVzYyhmZHIpKSAjYXJyYW5nZSBieSBkZXNjZW5kaW5nIHB2YWx1ZQ0KDQpnbGltcHNlKHNpZ25pZmljYW50X0RHRSkNCmBgYA0KDQojIyMgQ3JlYXRlIG5ldyBjb2x1bW5zIHdpdGggbXV0YXRlDQoNCllvdSBjYW4gYWxzbyBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggbXV0dGUuIExldCdzIHNheSB3ZSB3YW50IHRvIGRlZmluZSBhIERHRSB0aWJibGUgbGlrZSBhYm92ZSwgYnV0IHdpdGhvdXQgZmlsdGVyaW5nLiBJbnN0ZWFkIHdlIGNyZWF0ZSBhIGNhdGVnb3J5IHNheWluZyBTSUdOKC4wMDEpLCBTSUdOKC4wMSksIFNJR04oLjA1KSBvciBOT1QuU0lHTiwgYWxsIGRlcGVuZGluZyBvbiB0aGUgcHZhbHVlLCBhbmQgd2UgYWxzbyB3YW50IHRoYXQgdGhlIGxvZ2ZvbGQgY2hhbmdlIGlzIGF0IGxlYXN0IGFib3ZlIDEgb3IgYmVsb3cgLTEuDQoNCllvdSBjYW4gdXNlIG11dGF0ZSB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGJhc2VkIG9uIHRob3NlIGNyaXRlcmlhOg0KDQpgYGB7ciBtdXRhdGUtY29sc30NCmV4dGVuZGVkX0RHRSA8LSBER0UgJT4lDQogIHJlbmFtZShnZW5lX25hbWUgPSAxKSAlPiUgI3JlbmFtZSBjb2x1bW4gMSB0byBnZW5lX25hbWUNCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgI2NsZWFuIHVwIGNvbHVtbiBuYW1lcw0KICBtdXRhdGUoZ2VuZV90eXBlID0gZmFjdG9yKGdlbmVfdHlwZSkpICU+JSAjZmFjdG9yaXplIGNhdGVnb3JpZXMgb2YgZ2VuZSB0eXBlcw0KCXNlbGVjdChnZW5lX25hbWUsIGxvZ19mYywgZmRyLCBnZW5lX3R5cGUpICU+JSAjc2VsZWN0IG9ubHkgc29tZSBjb2x1bW5zIG9mIGludGVyZXN0DQogIG11dGF0ZSggc2lnbmlmaWNhbmNlX2xldmVsID0gY2FzZV93aGVuKA0KICAgIGZkciA8IC4wMDEgJiBhYnMobG9nX2ZjKSA+IDEgfiAiU0lHTiguMDAxKSIsDQogICAgZmRyIDwgLjAxICYgYWJzKGxvZ19mYykgPiAxIH4gIlNJR04oLjAxKSIsDQogICAgZmRyIDwgLjA1ICYgYWJzKGxvZ19mYykgPiAxIH4gIlNJR04oLjA1KSIsDQogICAgVFJVRSB+ICJOT1QuU0lHTiINCiAgKSkgJT4lICNjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggdGhlIHNpZ25pZmljYW5jZSBsZXZlbA0KICBtdXRhdGUoIHNpZ25pZmljYW5jZV9sZXZlbCA9IGZhY3RvcihzaWduaWZpY2FuY2VfbGV2ZWwpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGZkcikpICNhcnJhbmdlIGJ5IGRlc2NlbmRpbmcgcHZhbHVlDQoNCmdsaW1wc2UoZXh0ZW5kZWRfREdFKQ0KYGBgDQoNCiMjIyBTdW1tYXJpemUgYnkgZ3JvdXANCg0KWW91IGNhbiBzdW1tYXJpemUgYnkgZ3JvdXAgYW5kIGdldCBncm91cCBzdGF0aXN0aWNzLiBGb3IgZXhhbXBsZSB0aGUgbnVtYmVyIG9mIGdlbmVzIGluIGVhY2ggZ2VuZSB0eXBlIGFuZCB0aGVpciBtZWRpYW4gZmRyIGFuZCBsb2dfZmMuDQoNCmBgYHtyIHN1bW1hcml6ZS1ncm91cH0NCnN1bW1hcnlfREdFIDwtIGV4dGVuZGVkX0RHRSAlPiUNCglncm91cF9ieShnZW5lX3R5cGUpICU+JQ0KCXN1bW1hcmlzZSgNCgkJbiA9IG4oKSwNCgkJbWVkaWFuX2xmYyA9IG1lZGlhbihsb2dfZmMsIG5hLnJtID0gVFJVRSksDQoJCW1lZGlhbl9mZHIgPSBtZWRpYW4oZmRyLCBuYS5ybSA9IFRSVUUpLA0KCQkuZ3JvdXBzID0gImRyb3AiDQoJKQ0KDQpzdW1tYXJ5X0RHRQ0KYGBgDQojIyBQbG90dGluZyB3aXRoIGdncGxvdDINCg0KWW91IGNhbiBhbHNvIHBsb3QgeW91ciBkYXRhIHdpdGggZ2dwbG90Miwgd2hpY2ggaXMgcGFydCBvZiB0aGUgdGlkeXZlcnNlLiBGb3IgZXhhbXBsZSwgYSBzY2F0dGVyIHBsb3Qgb2YgbG9nIGZvbGQgY2hhbmdlIHZzIGZkciwgY29sb3JlZCBieSBnZW5lIHR5cGU6DQoNCmBgYHtyIGdncGxvdH0NCmdncGxvdChleHRlbmRlZF9ER0UsIGFlcyh4ID0gbG9nX2ZjLCB5ID0gLWxvZzEwKGZkciksIGNvbG9yID0gZ2VuZV90eXBlKSkgKw0KCWdlb21fcG9pbnQoc2l6ZT0zKSArDQoJdGhlbWVfbWluaW1hbCgpICsNCglsYWJzKHRpdGxlID0gIkRHRSBTY2F0dGVyIFBsb3QiLCB4ID0gIkxvZyBGb2xkIENoYW5nZSIsIHkgPSAiLUxvZzEwKEZEUikiKQ0KYGBgDQoNCmdncGxvdCB0YWtlcyB0aGUgZGF0YWZyYW1lL3RpYmJsZSBhcyBpbnB1dCBhbmQgYWRkcyBsYXllcnMgb2YgdGhlIHBsb3QgdXNpbmcgdGhlIHN5bWJvbCArLg0KVGhlcmUgYXJlIGEgbG90IG9mIHdheXMgdG8gY3VzdG9taXplIHRoZSBwbG90IG9yIGRvIG90aGVyIHR5cGVzIG9mIHBsb3RzLg0KDQpXZSBjYW4gYWRkIGEgY29sdW1uIHdoZXJlIHdlIHdyaXRlIHRoZSBuYW1lIG9mIHRoZSBnZW5lcyB3aGljaCBhcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkLiBXZSBjYW4gZG8gdGhpcyB3aXRoIHRoZSBtdXRhdGUgZnVuY3Rpb24gYW5kIGNhc2Vfd2hlbi4gVGhlbiB3ZSBhZGQgdG8gdGhlIHBsb3QgYSBsYXllciBvZiB0ZXh0Lg0KDQpgYGB7ciBsYWJlbC1uYW1lfQ0KZXh0ZW5kZWRfREdFIDwtIGV4dGVuZGVkX0RHRSAlPiUNCiAgbXV0YXRlKCBwbG90X2xhYmVsID0gY2FzZV93aGVuKA0KICAgIHNpZ25pZmljYW5jZV9sZXZlbCA9PSAgIk5PVC5TSUdOIiB+IE5BLA0KICAgIFRSVUUgfiBnZW5lX25hbWUNCiAgICApICkNCg0KZ2xpbXBzZShleHRlbmRlZF9ER0UpDQpgYGANCg0KYGBge3IgcGxvdC13aXRoLWxhYmVsc30NCmdncGxvdChleHRlbmRlZF9ER0UsIGFlcyh4ID0gbG9nX2ZjLCB5ID0gLWxvZzEwKGZkciksIGNvbG9yID0gZ2VuZV90eXBlKSkgKw0KCWdlb21fcG9pbnQoKSArDQogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBwbG90X2xhYmVsKSwgc2l6ZSA9IDMsICkgKyAjYWRkIGxhYmVscyB0byBzaWduaWZpY2FudCBnZW5lcw0KCXRoZW1lX21pbmltYWwoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0tbG9nMTAoMC4wNSkpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMSwtMSkpICsgICAgI3ZlcnRpY2FsIGxpbmUgZ2dwbG90DQoJbGFicyh0aXRsZSA9ICJER0UgU2NhdHRlciBQbG90IiwgeCA9ICJMb2cgRm9sZCBDaGFuZ2UiLCB5ID0gIi1Mb2cxMChGRFIpIikNCmBgYA0KIyMjIFRoZW1lcw0KDQpZb3UgY2FuIGNoYW5nZSB0aGVtZSBmb3IgYWRhcHRpbmcgdGhlIGFwcGVhcmVuY2UuIEFsbCBzdGFuZGFyZCB0aGVtZXMgYXJlIGhlcmU6IGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZ3RoZW1lLmh0bWwuIEZvciBleGFtcGxlLCBpdCBpcyBwb3B1bGFyIHRvIHVzZSB0aGUgZ3JheSB0aGVtZQ0KDQpgYGB7ciB0aGVtZS1nZ3Bsb3QgfQ0KZ2dwbG90KGV4dGVuZGVkX0RHRSwgYWVzKHggPSBsb2dfZmMsIHkgPSAtbG9nMTAoZmRyKSwgY29sb3IgPSBnZW5lX3R5cGUpKSArDQoJZ2VvbV9wb2ludCgpICsNCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHBsb3RfbGFiZWwpLCBzaXplID0gMywgKSArICNhZGQgbGFiZWxzIHRvIHNpZ25pZmljYW50IGdlbmVzDQoJdGhlbWVfZ3JheSgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS1sb2cxMCgwLjA1KSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygxLC0xKSkgKyAgICAjdmVydGljYWwgbGluZSBnZ3Bsb3QNCglsYWJzKHRpdGxlID0gIkRHRSBTY2F0dGVyIFBsb3QiLCB4ID0gIkxvZyBGb2xkIENoYW5nZSIsIHkgPSAiLUxvZzEwKEZEUikiKQ0KYGBgDQoNCllvdSBjYW4gZG8gbmljZXIgdGhlbWVzIHVzaW5nIHRoZSBvbmVzIGRldmVsb3BlZCBoZXJlIGh0dHBzOi8vZ2l0aHViLmNvbS9rb3VuZHkvZ2dwbG90X3RoZW1lX1B1YmxpY2F0aW9uLCB3aGVyZSBzb21lb25lIGhhcyBkZXZlbG9wZWQgaXRzIG93biB0aGVtZXMuIFdlIGhhdmUgaW1wb3J0ZWQgdGhlbSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoaXMgbm90ZWJvb2suIEZvciBleGFtcGxlIHlvdSBjYW4gdXNlIGEgdGhlbWUgZGV2ZWxvcGVkIGZvciBwdWJsaWNhdGlvbnMgKG5pY2VyIHNpemVzIGFuZCBmb250IG9mIHRleHQgYW5kIG5pY2VyIGxlZ2VuZCkuDQoNCmBgYHtyIHRoZW1lLXB1YmxpY2F0aW9ufQ0KZ2dwbG90KGV4dGVuZGVkX0RHRSwgYWVzKHggPSBsb2dfZmMsIHkgPSAtbG9nMTAoZmRyKSwgY29sb3IgPSBnZW5lX3R5cGUpKSArDQoJZ2VvbV9wb2ludCgpICsNCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHBsb3RfbGFiZWwpLCBzaXplID0gMywgKSArICNhZGQgbGFiZWxzIHRvIHNpZ25pZmljYW50IGdlbmVzDQoJdGhlbWVfUHVibGljYXRpb24oKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0tbG9nMTAoMC4wNSkpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMSwtMSkpICsgICAgI3ZlcnRpY2FsIGxpbmUgZ2dwbG90DQoJbGFicyh0aXRsZSA9ICJER0UgU2NhdHRlciBQbG90IiwgeCA9ICJMb2cgRm9sZCBDaGFuZ2UiLCB5ID0gIi1Mb2cxMChGRFIpIikNCmBgYA0KT3IgY29tYmluZSBwdWJsaWNhdGlvbiB0aGVtZSB3aXRoIGEgY29sb3IgcGFsZXR0ZSBmb3IgZGlzY3JldGUgdmFyaWFibGVzIChnZW5lIHR5cGUpIGZyb20gdGhlIHNhbWUgYXV0aG9yLiBZb3UgY2FuIGxvb2sgYXQgdGhlIHdlYnBhZ2UgZm9yIHRoZSB0aGVtZXMgdG8gc2VlIG1vcmUgZXhhbXBsZXMuDQoNCmBgYHtyIHRoZW1lLXB1YmxpY2F0aW9uLXBhbGV0dGV9DQpnZ3Bsb3QoZXh0ZW5kZWRfREdFLCBhZXMoeCA9IGxvZ19mYywgeSA9IC1sb2cxMChmZHIpLCBjb2xvciA9IGdlbmVfdHlwZSkpICsNCglnZW9tX3BvaW50KCkgKw0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gcGxvdF9sYWJlbCksIHNpemUgPSAzLCApICsgI2FkZCBsYWJlbHMgdG8gc2lnbmlmaWNhbnQgZ2VuZXMNCglzY2FsZV9maWxsX1B1YmxpY2F0aW9uKCkgKyB0aGVtZV9kYXJrX2JsdWUoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0tbG9nMTAoMC4wNSkpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMSwtMSkpICsgICAgI3ZlcnRpY2FsIGxpbmUgZ2dwbG90DQoJbGFicyh0aXRsZSA9ICJER0UgU2NhdHRlciBQbG90IiwgeCA9ICJMb2cgRm9sZCBDaGFuZ2UiLCB5ID0gIi1Mb2cxMChGRFIpIikgDQpgYGANClN0aWxsIG5vdCBlbm91Z2g/IFRoZSBwYWNrYWdlIGdndGhlbWVzIGhhcyBldmVuIG1vcmUgd2F5cyBvZiBjb21iaW5pbmcgY29sb3IgcGFsZXR0ZXMgYW5kIHRoZW1lcy4gTG9vayBoZXJlIGh0dHBzOi8vZ2l0aHViLmNvbS9qcm5vbGQvZ2d0aGVtZXMgd2hlcmUgdGhlIGF1dGhvciBtYWtlcyBhIGxvdCBvZiBleGFtcGxlcyBhbmQgdHJ5IG9uZSBvZiB0aGVtIQ0KDQojIyMgc2F2aW5nIGdncGxvdHMNCg0KWW91IGNhbiBzYXZlIGEgZ2dwbG90IHdpdGggdGhlIGRlZGljYXRlZCBjb21tYW5kLCBidXQgdG8gZG8gdGhhdCB5b3UgbmVlZCB0byBhc3NpZ24gdGhlIHBsb3QgdG8gYSB2YXJpYWJsZS4gRm9yIGV4YW1wbGU6DQoNCmBgYHtyIGdnc2F2ZX0NCnZvbGNhbm9fcGxvdCA8LSBnZ3Bsb3QoZXh0ZW5kZWRfREdFLCBhZXMoeCA9IGxvZ19mYywgeSA9IC1sb2cxMChmZHIpLCBjb2xvciA9IGdlbmVfdHlwZSkpICsNCglnZW9tX3BvaW50KCkgKw0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gcGxvdF9sYWJlbCksIHNpemUgPSAzLCApICsgI2FkZCBsYWJlbHMgdG8gc2lnbmlmaWNhbnQgZ2VuZXMNCgl0aGVtZV9ncmF5KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9LWxvZzEwKDAuMDUpKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKDEsLTEpKSArICAgICN2ZXJ0aWNhbCBsaW5lIGdncGxvdA0KCWxhYnModGl0bGUgPSAiREdFIFNjYXR0ZXIgUGxvdCIsIHggPSAiTG9nIEZvbGQgQ2hhbmdlIiwgeSA9ICItTG9nMTAoRkRSKSIpDQoNCmdnc2F2ZShmaWxlbmFtZSA9ICIuL2xpZmVFeHAucG5nIiwgcGxvdCA9IHZvbGNhbm9fcGxvdCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCwgdW5pdHMgPSAiY20iKQ0KYGBgDQoNCiMjIyBTb21lIG90aGVyIHBsb3RzOiBiYXJwbG90cywgYm94cGxvdHMsIGRlbnNpdHkgcGxvdHMsIC4uLg0KDQpUaGVyZSBpcyBhIHdpZGUgcmFuZ2Ugb2YgcGxvdCB0eXBlcyB5b3UgY2FuIGRvIHdpdGggZ2dwbG90LCBhbmQgaXQgcmVhbGx5IGRlcGVuZHMgb24geW91ciBkYXRhIGFuZCB3aGF0IHlvdSB3YW50IHRvIHZpc3VhbGl6ZS4gRm9yIGV4YW1wbGUsIHlvdSBjYW4gZG8gYSBiYXIgcGxvdCBvZiB0aGUgbnVtYmVyIG9mIGdlbmVzIGluIGVhY2ggZ2VuZSB0eXBlOg0KDQpgYGB7ciBiYXJwbG90fQ0KZ2dwbG90KHN1bW1hcnlfREdFLCBhZXMoeCA9IGdlbmVfdHlwZSwgeSA9IGxvZyhuKSwgZmlsbCA9IGdlbmVfdHlwZSkpICsNCglnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBzY2FsZV9maWxsX1B1YmxpY2F0aW9uKCkgKyANCiAgdGhlbWVfZGFya19ibHVlKCkNCmBgYA0KDQpOb3RlIHRoYXQgYWJvdmUgd2UgbmVlZGVkIG9ubHkgb25lIHZhbHVlIHBlciBnZW5lIHR5cGUgdG8gcGxvdCB0aGUgYmFyLiBJZiB3ZSBoYWQgbW9yZSB2YWx1ZXMgcGVyIGdlbmUgdHlwZSwgd2Ugd291bGQgbmVlZCB0byB1c2UgYHN0YXQgPSAic3VtbWFyeSJgIGFuZCBzcGVjaWZ5IGEgc3VtbWFyeSBmdW5jdGlvbiAoZm9yIGV4YW1wbGUgYGZ1biA9ICJtZWFuImAgb3IgYGZ1biA9ICJtZWRpYW4iYCkuIEZvciBleGFtcGxlLCBpZiB3ZSB3YW50IHRvIHBsb3QgdGhlIG1lZGlhbiBsb2cgZm9sZCBjaGFuZ2UgZm9yIGVhY2ggZ2VuZSB0eXBlOg0KDQpgYGB7ciBiYXJwbG90LW1lZGlhbn0NCmdncGxvdChleHRlbmRlZF9ER0UsIGFlcyh4ID0gZ2VuZV90eXBlLCB5ID0gbG9nX2ZjLCBmaWxsID0gZ2VuZV90eXBlKSkgKw0KCWdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWRpYW4iKSArDQogIHNjYWxlX2ZpbGxfUHVibGljYXRpb24oKSArIA0KICB0aGVtZV9kYXJrX2JsdWUoKSArDQojY2huZ2UgeCBheGlzIGFuZ2xlIHRvIDQ1DQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KIyMjIEZhY2V0aW5nDQoNCkZhY2V0aW5nIGlzIGEgcG93ZXJmdWwgd2F5IHRvIGNyZWF0ZSBtdWx0aXBsZSBwbG90cyBiYXNlZCBvbiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBGb3IgZXhhbXBsZSwgd2UgY2FuIGZhY2V0IHRoZSBzY2F0dGVyIHBsb3QgYnkgZ2VuZSB0eXBlOg0KDQpgYGB7ciBmYWNldC1nZ3Bsb3R9DQpnZ3Bsb3QoZXh0ZW5kZWRfREdFLCBhZXMoeCA9IGxvZ19mYywgeSA9IC1sb2cxMChmZHIpLCBjb2xvciA9IGdlbmVfdHlwZSkpICsNCglnZW9tX3BvaW50KCkgKw0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gcGxvdF9sYWJlbCkpICsNCiAgCXRoZW1lX21pbmltYWwoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0tbG9nMTAoMC4wNSkpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMSwtMSkpICsgICAgI3ZlcnRpY2FsIGxpbmUgZ2dwbG90DQogIAlsYWJzKHRpdGxlID0gIkRHRSBTY2F0dGVyIFBsb3QiLCB4ID0gIkxvZyBGb2xkIENoYW5nZSIsIHkgPSAiLUxvZzEwKEZEUikiKSArDQogIGZhY2V0X3dyYXAofiBnZW5lX3R5cGUpDQpgYGANCiAgDQogIA0KQSBkZW5zaXR5IHBsb3Qgb2YgbG9nIGZvbGQgY2hhbmdlIGJ5IGdlbmUgdHlwZToNCg0KYGBge3IgZGVuc2l0eS1nZ3Bsb3R9DQpnZ3Bsb3QoZXh0ZW5kZWRfREdFLCBhZXMoeCA9IGxvZ19mYywgZmlsbCA9IGdlbmVfdHlwZSkpICsNCiAgCWdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV9maWxsX1B1YmxpY2F0aW9uKCkgKw0KICB0aGVtZV9leGNlbF9uZXcoKSArDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90IG9mIExvZyBGb2xkIENoYW5nZVxuYnkgR2VuZSBUeXBlIiwgeCA9ICJMb2cgRm9sZCBDaGFuZ2UiLCB5ID0gIkRlbnNpdHkiKSANCmBgYA0KDQojIyBFeHBvcnQgY2xlYW5lZCByZXN1bHRzDQoNCmBgYHtyIGV4cG9ydCwgZXZhbD1GQUxTRX0NCiMgRXhwb3J0IHRvIENTVg0Kd3JpdGVfY3N2KGV4dGVuZGVkX0RHRSwgImZpbmFsX0RHRS5jc3YiKQ0KDQojIEV4cG9ydCB0byBFeGNlbCAobmVlZHMgd3JpdGV4bCBwYWNrYWdlKQ0Kd3JpdGV4bDo6d3JpdGVfeGxzeChleHRlbmRlZF9ER0UsICJmaW5hbF9ER0UueGxzeCIpDQpgYGANCg0KIyMgUXVpY2sgcHJhY3RpY2UgdGFza3MNCg0KMS4gSW1wb3J0IG9uZSBDU1Ygb3Igb25lIEV4Y2VsIGZpbGUgZnJvbSB5b3VyIG93biBwcm9qZWN0Lg0KMi4gVXNlIGBjbGVhbl9uYW1lcygpYCBhbmQgYG11dGF0ZSgpYCB0byBzdGFuZGFyZGl6ZS9jbGVhbnVwIGNvbHVtbnMNCjMuIGFwcGx5IHNvbWUgbGFiZWxzIG9mIGludGVyZXN0ZWQsIGFzIGluIHRoZSBleGFtcGxlIGZvciBzaWduaWZpY2FuY2UNCjQuIG1ha2UgYSBwbG90IHlvdSB3b3VsZCBsaWtlIHRvIHNlZSwgZm9yIGV4YW1wbGUgYSBzY2F0dGVyIHBsb3Qgb3IgYSBiYXIgcGxvdCwgYW5kIGN1c3RvbWl6ZSBpdCB3aXRoIHRoZW1lcyBhbmQgbGFiZWxzDQo1LiBFeHBvcnQgdGhlIGZpbmFsIGNsZWFuZWQgdGFibGUNCg0KIyMgVHJvdWJsZXNob290aW5nIHRpcHMNCg0KLSBJZiBpbXBvcnQgZmFpbHMgZHVlIHRvIHNlcGFyYXRvcnMsIHRyeSBgcmVhZF9kZWxpbSgpYCB3aXRoIHRoZSBjb3JyZWN0IGBkZWxpbWAuDQotIElmIHRleHQgYXBwZWFycyBicm9rZW4sIGNoZWNrIGVuY29kaW5nIHdpdGggYGxvY2FsZShlbmNvZGluZyA9ICJVVEYtOCIpYC4NCi0gSWYgY29sdW1uIHR5cGVzIGFyZSB3cm9uZywgZml4IHdpdGggYG11dGF0ZSgpYCBhbmQgYGFzLm51bWVyaWMoKWAsIGBhcy5mYWN0b3IoKWAsIGV0Yy4NCi0gSWYgam9pbnMgYWRkIG1hbnkgbWlzc2luZyB2YWx1ZXMsIHZlcmlmeSB0aGUga2V5IGNvbHVtbnMgKGZvciBleGFtcGxlIGBzYW1wbGVfaWRgKSBtYXRjaCBleGFjdGx5IGluIGJvdGggdGFibGVzLg0KDQojIyBTb21lIHJlc291cmNlcw0KDQpJIHdpbGwganVzdCBsaXN0IGEgZmV3IHRoaW5ncywgYXMgdGhlIGludGVybmV0IGlzIGEgd2lkZSBvY2VhbiwgYW5kIHlvdSBtaWdodCB3YW50IHRvIGZvY3VzIG9uIGZldyBzZWxlY3RlZCB0aGluZ3MuDQoNCi0gUiBub3ZpY2UgZ2FwIHJlbWluZGVyIGh0dHBzOi8vc3djYXJwZW50cnkuZ2l0aHViLmlvL3Itbm92aWNlLWdhcG1pbmRlci9pbmRleC5odG1sDQotIEEgc2xpZ2h0bHkgbW9yZSBpbiBkZXB0aCBSIGFuZCB0aWR5ciB3b3Jrc2hvcCB3ZSBqdXN0IGhhZCBhdCB0aGUgY29kaW5nIGNhZmU6IGh0dHBzOi8vYWJjLmF1LmRrL2RvY3VtZW50YXRpb24vMjAyNi0wMi0yNi10aWR5Ui1vbWljczEuaHRtbA0KLSB0aWR5ciBjaGVhdHNlZXQgZnJvbSBQb3NpdCAgaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvYmxvYi9tYWluL3RpZHlyLnBkZg0KLSB0aGUgaGVscCBwYW5lIG9mIFJzdHVkaW8gd2hlcmUgeW91IGNhbiBmaW5kIHRoZSBkb2N1bWVudGF0aW9uIG9mIGFsbCBmdW5jdGlvbg0KLSB0aGUgdGFiIGJ1dHRvbiBmb3IgYXV0b2NvbXBsZXRpbmcgZnVuY3Rpb25zIGFuZCBhcmd1bWVudHMgaW4gUnN0dWRpby4gSXQgaXMgdGhlIHN0YXJ0aW5nIGNvbmRpdGlvbiB0byBoYXZlIGFuIGVhc2llciBsaWZlLg0K