By: Owen Lo
# Install and load required packages
if(!requireNamespace("readxl", quietly = TRUE)) {
install.packages("readxl")
}
if (!requireNamespace("knitr", quietly = TRUE)) {
install.packages("knitr")
}
library(GEOquery)
library(tibble)
library(readxl)
library(dplyr)
library(tidyr)
library(knitr)
library(biomaRt)
library(DESeq2)
library(edgeR)
library(SummarizedExperiment)
library(ggplot2)
library(ComplexHeatmap)
library(circlize)
This workbook uses the GEOQuery (Davis and
Meltzer 2007), biomaRt (Durinck et al.
2005), tibble (Müller and Wickham
2025), readxl(Wickham and Bryan
2025), dplyr (Wickham et al. 2023),
tidyr(Wickham et al. 2025), knitr (Xie 2014), DESeq2(Love
et al. 2014), edgeR (Chen et al.
2025), SummarizedExperiment(Morgan et al.
2025), ggplot2 (Wickham 2016),
ComplexHeatmap (Gu 2022) and circlize
(Gu et al. 2014) packages in its code
chunks.
Introduction
Septic shock is a potentially fatal complication of sepsis, and
treatment largely depends on early supportive hemodynamic therapy.
Patient response to hemodynamic therapy varies, and the NCBI Gene
Expression Omnibus (GEO) (Barrett et al.
2012) series GSE110487 is a dataset from 2018 consisting of RNA
sequencing read counts of whole blood samples taken from 14 septic shock
patients who responded to hemodynamic therapy and 17 non-responders, at
two time points: immediately after ICU admission, and 48 hours later,
after hemodynamic therapy. (Barcella et al.
2018)
Fetching and assessing data
Downloading and formatting
We’ll use the GEOQuery package to retrieve the supplementary files
and metadata pertaining to the experiment from the GEO with its series
accession number, and then look at how it’s formatted.
geo_id <- "GSE110487"
# get metadata associated with gse and supplementary files
gse <- GEOquery::getGEO(geo_id, GSEMatrix=FALSE)
supp <- GEOquery::getGEOSuppFiles(geo_id, fetch_files=FALSE)
# download data if not already downloaded
current_dir <- file.path(getwd())
supp_file_path <- file.path(current_dir, geo_id, supp$fname[1])
if (!file.exists(supp_file_path)) {
data_file <- GEOquery::getGEOSuppFiles(GEO = geo_id)
}
# read data into a dataframe
raw_counts <- readxl::read_xlsx(supp_file_path)
# take a peek
knitr::kable(raw_counts[1:5, 1:10], format = "html", align = "c")
|
Geneid
|
E04T1
|
E04T2
|
E07T1
|
E07T2
|
E15T1
|
E15T2
|
E16T1
|
E16T2
|
E17T1
|
|
ENSG00000000003
|
1
|
0
|
1
|
1
|
2
|
4
|
1
|
4
|
4
|
|
ENSG00000000005
|
0
|
0
|
1
|
1
|
0
|
0
|
0
|
0
|
0
|
|
ENSG00000000419
|
259
|
208
|
599
|
576
|
734
|
534
|
630
|
653
|
283
|
|
ENSG00000000457
|
184
|
332
|
370
|
400
|
410
|
345
|
444
|
438
|
263
|
|
ENSG00000000460
|
89
|
81
|
245
|
185
|
117
|
167
|
177
|
134
|
127
|
# count genes and samples
cat(paste("Number of genes: ", nrow(raw_counts),
"\nNumber of samples: ", ncol(raw_counts)-1))
Number of genes: 58096
Number of samples: 62
Samples in the raw data are named according to patient identity and
time point, but don’t contain any information on whether the patient was
a responder or a non-responder, so we’ll map sample identifiers to both
response and time point.
# retrieve list of samples in the series, and compile condition data for each
samples <- gse@gsms
sample_sources <- do.call(rbind,
lapply(samples, FUN=function(x){
c(x@header$title,
x@header$source_name_ch1)}))
# Use this data to create a dataframe mapping sample titles to responder status and time point
sample_metadata <- as.data.frame(sample_sources, stringsAsFactors = FALSE)
colnames(sample_metadata) = c("sample", "source")
sample_metadata <- sample_metadata %>%
magrittr::set_rownames(.$sample) %>%
mutate(
response = ifelse(grepl("^Responder", source), "R", "NR"),
time_point = ifelse(grepl("T1", source), "T1", "T2"),
) %>%
dplyr::select(response, time_point)
# take a peek
knitr::kable(sample_metadata[1:5,], format = "html", align = "c")
|
|
response
|
time_point
|
|
E04T1
|
R
|
T1
|
|
E04T2
|
R
|
T2
|
|
E07T1
|
NR
|
T1
|
|
E07T2
|
NR
|
T2
|
|
E15T1
|
NR
|
T1
|
Quality assessment
Now, we’ll determine whether data quality varies across
conditions
# calculating summary statistics for each sample
sample_summaries <- data.frame(do.call(cbind, lapply(raw_counts[, 2:ncol(raw_counts)], summary)))
qual_overview <- as.data.frame(t(sample_summaries))
# Adding extra statistics for total reads, number of genes with zero expression, number of genes with low expression
qual_overview <- qual_overview %>%
dplyr::mutate(total_reads = colSums(raw_counts[2:ncol(raw_counts)]),
zero_exp = colSums(raw_counts[2:ncol(raw_counts)] == 0),
low_exp = colSums(raw_counts[2:ncol(raw_counts)]<10),
)
# adding metadata to sort by conditions
qual_overview <- merge(qual_overview, sample_metadata, by = 0)
# overview stats for samples from non-responders and responders
stats_by_response <- qual_overview %>%
dplyr::group_by(response,) %>%
summarize(
NumSamples = n(),
MeanLibSize = mean(total_reads),
SDLibSize = sd(total_reads),
PropZeroExp = mean(zero_exp) / nrow(raw_counts),
PropLowExp = mean(low_exp) / nrow(raw_counts),
)
# overview stats for samples from time point 1 and time point 2
stats_by_time <- qual_overview %>%
dplyr::group_by(time_point,) %>%
summarize(
NumSamples = n(),
MeanLibSize = mean(total_reads),
SDLibSize = sd(total_reads),
PropZeroExp = mean(zero_exp) / nrow(raw_counts),
PropLowExp = mean(low_exp) / nrow(raw_counts),
)
# merging tables and displaying
stats_by_condition <- bind_rows(
stats_by_response %>%
dplyr::mutate(group_type = "response") %>%
dplyr::rename(condition = response),
stats_by_time %>%
dplyr::mutate(group_type = "time_point") %>%
dplyr::rename(condition = time_point)
)
knitr::kable(stats_by_condition[,1:6], format = "html", align = "c")
|
condition
|
NumSamples
|
MeanLibSize
|
SDLibSize
|
PropZeroExp
|
PropLowExp
|
|
NR
|
28
|
13414209
|
3691198
|
0.5809215
|
0.7772332
|
|
R
|
34
|
13675120
|
3772593
|
0.5990009
|
0.7761170
|
|
T1
|
31
|
13725546
|
3630149
|
0.5940995
|
0.7795584
|
|
T2
|
31
|
13389033
|
3836210
|
0.5875725
|
0.7736838
|
Mean, standard deviation, and proportions of unexpressed and lowly
expressed genes are similar across patient responder status and time, so
special correction for data quality won’t be necessary.
Identifier mapping and cleaning
Mapping to HUGO symbols
The data uses Ensembl Gene IDs beginning with ENSG.
# get ensembl version 100 and the human gene dataset
ensembl <- biomaRt::useEnsembl(biomart = "ensembl")
ensembl <- biomaRt::useDataset("hsapiens_gene_ensembl", mart = ensembl)
Rather than Ensembl Gene IDs, we want to use HUGO Gene Nomenclature
Committee (HGNC) symbols to identify the genes in our dataset. We’ll use
the Ensembl human dataset to map as many ENSG IDs as possible to HGNC
symbols, and add those mappings to our read data.
# store ensembl IDs from the data as a vector
ensembl_ids <- raw_counts$Geneid
# check if an ensembl to hgnc conversion file exists already
conversion_stash <- "ensembl_to_hgnc.rds"
if (file.exists(conversion_stash)) {
# if the file exists, read conversion data from that
ensembl_to_hgnc <- readRDS(conversion_stash)
} else {
# if the file does not exist, get conversion data from biomaRt and cache it
ensembl_to_hgnc <- biomaRt::getBM(attributes = c("ensembl_gene_id", "hgnc_symbol"),
filters = c("ensembl_gene_id"),
values = ensembl_ids,
mart = ensembl)
saveRDS(ensembl_to_hgnc, conversion_stash)
}
# merge conversion df with data and rearrange such that both id columns come before samples
raw_counts_annot <- dplyr::left_join(raw_counts, ensembl_to_hgnc,
by = c("Geneid" = "ensembl_gene_id"))
raw_counts_cols <- dplyr::setdiff(names(raw_counts), "Geneid")
colnames(raw_counts_annot)[1] = "ensembl_gene_id"
raw_counts_annot <- raw_counts_annot[, c("ensembl_gene_id", "hgnc_symbol", raw_counts_cols)]
# peek at annotated counts
knitr::kable(raw_counts_annot[1:5, 1:10], format = "html", align = "c")
|
ensembl_gene_id
|
hgnc_symbol
|
E04T1
|
E04T2
|
E07T1
|
E07T2
|
E15T1
|
E15T2
|
E16T1
|
E16T2
|
|
ENSG00000000003
|
TSPAN6
|
1
|
0
|
1
|
1
|
2
|
4
|
1
|
4
|
|
ENSG00000000005
|
TNMD
|
0
|
0
|
1
|
1
|
0
|
0
|
0
|
0
|
|
ENSG00000000419
|
DPM1
|
259
|
208
|
599
|
576
|
734
|
534
|
630
|
653
|
|
ENSG00000000457
|
SCYL3
|
184
|
332
|
370
|
400
|
410
|
345
|
444
|
438
|
|
ENSG00000000460
|
C1orf112
|
89
|
81
|
245
|
185
|
117
|
167
|
177
|
134
|
Now rows are identified by both ENSG ID and HGNC symbol.
Cleaning out low expression and unmapped rows
Assaying for rows where mapping one ENSG ID to one HGNC symbol
failed:
# subset rows where one ensembl id maps to multiple hgnc symbols
ensembl_dups <- raw_counts_annot$ensembl_gene_id[duplicated(raw_counts_annot$ensembl_gene_id)]
multiple_hgnc <- raw_counts_annot %>%
filter(ensembl_gene_id %in% ensembl_dups)
# subset rows where multiple ensembl ids map to one hgnc symbol
hgnc_dups <- raw_counts_annot$hgnc_symbol[duplicated(raw_counts_annot$hgnc_symbol)]
same_hgnc <- raw_counts_annot %>%
filter(hgnc_symbol %in% hgnc_dups & hgnc_symbol != "")
# subset rows where ensembl id does not map to a hgnc symbol
unmapped <- raw_counts_annot %>%
filter(is.na(hgnc_symbol) | hgnc_symbol == "")
cat(paste(nrow(unmapped), "unmapped rows\n",
nrow(multiple_hgnc),
"rows where one ENSG ID maps to multiple HGNC symbols \n",
nrow(same_hgnc),
"rows where multiple ENSG IDs map to the same HGNC symbol"))
20178 unmapped rows
8 rows where one ENSG ID maps to multiple HGNC symbols
28 rows where multiple ENSG IDs map to the same HGNC symbol
A high proportion of the dataset’s rows do not map to any HGNC
symbol. These are likely to correspond to outdated aliases of current
symbols, or deprecated ORFs. By filtering low expression genes from the
data and comparing the proportions of mapped and unmapped genes that
remain, we can assess the significance of the unmapped rows.
# size of smallest condition group in the dataset: non-responders at time point 1/2
smallest_group_size <- 11
# keep only unmapped rows that have a count of at least 10 in 11 samples
rows_to_keep <- rowSums(unmapped >= 10) >= smallest_group_size
clean_unmapped <- unmapped[rows_to_keep,]
# subset mapped counts
mapped <- raw_counts_annot %>%
filter(!is.na(hgnc_symbol) & hgnc_symbol != "")
# apply same expression filter to mapped counts
rows_to_keep <- rowSums(mapped >= 10) >= smallest_group_size
clean_mapped <- mapped[rows_to_keep,]
# collate and display results of filtering
cleaning_results <- data.frame(
Type = c("mapped genes", "unmapped genes"),
PreCleanCount = c(nrow(mapped), nrow(unmapped)),
PostCleanCount = c(nrow(clean_mapped), nrow(clean_unmapped)),
SignificantProportion = c(nrow(clean_mapped)/nrow(mapped),
nrow(clean_unmapped)/nrow(unmapped))
)
knitr::kable(cleaning_results, format = "html", align = "c")
|
Type
|
PreCleanCount
|
PostCleanCount
|
SignificantProportion
|
|
mapped genes
|
37922
|
13673
|
0.3605559
|
|
unmapped genes
|
20178
|
1907
|
0.0945089
|
Less than a tenth of the unmapped rows had sufficient levels of
expression to not be filtered in early data cleaning, compared to more
than a third of the mapped rows.
Since unmapped rows are largely lowly expressed, we can discard them
without losing a great amount of information. ENSG IDs mapping to
multiple HGNC symbols may be transcripts that hybridize to more than one
gene, and since they are in such small proportion in the dataset, we
will treat them as multiple genes without significantly impacting
analysis. HGNC symbols mapped to by multiple ENSG IDs may be genes with
multiple splice variants. Since they are likewise in minuscule
proportion in the dataset, we will sum together rows that map to the
same HUGO gene.
# create a new dataframe where rows correspond to unique hgnc symbols
clean_counts_byhgnc <- clean_mapped %>%
dplyr::group_by(hgnc_symbol) %>%
# sum rows that map to the same hgnc symbol
dplyr::summarise(dplyr::across(dplyr::where(is.numeric), ~ sum(.x, na.rm = TRUE)))
knitr::kable(clean_counts_byhgnc[1:5, 1:10], format = "html", align = "c")
|
hgnc_symbol
|
E04T1
|
E04T2
|
E07T1
|
E07T2
|
E15T1
|
E15T2
|
E16T1
|
E16T2
|
E17T1
|
|
A1BG-AS1
|
6
|
7
|
19
|
11
|
20
|
9
|
13
|
20
|
7
|
|
A2M-AS1
|
2
|
1
|
2
|
2
|
2
|
5
|
2
|
2
|
3
|
|
AAAS
|
22
|
21
|
25
|
35
|
45
|
18
|
37
|
23
|
33
|
|
AACS
|
28
|
10
|
27
|
60
|
133
|
50
|
96
|
64
|
52
|
|
AAGAB
|
177
|
202
|
458
|
520
|
644
|
476
|
475
|
687
|
278
|
cat(paste("Number of genes: ", nrow(clean_counts_byhgnc),
"\nNumber of samples: ", ncol(clean_counts_byhgnc)-1))
Number of genes: 13673
Number of samples: 62
We now have a dataframe of read counts for genes with expression
levels above a baseline, identified by unique HUGO symbols.
Normalization
Converting data for DESeq2
Let’s create a DESeqDataSet object from our data, and continue our
analysis with the DESeq2 package, adapting methods from Love et al’s
RNASeq workflow (Love et al. 2015).
# extract counts as a matrix and set row and column names
clean_count_matrix <- as.matrix(clean_counts_byhgnc[,2:ncol(clean_counts_byhgnc)])
rownames(clean_count_matrix) <- clean_counts_byhgnc$hgnc_symbol
colnames(clean_count_matrix) <- colnames(clean_counts_byhgnc)[2:ncol(clean_counts_byhgnc)]
#create a variable in the metadata from the interaction of response and time_point
sample_metadata$group = interaction(sample_metadata$response,
sample_metadata$time_point,
sep = "_")
# create a DESeqDataSet object from the counts matrix and the sample metadata, using the interaction of response and time point as the design.
counts_dds <- DESeq2::DESeqDataSetFromMatrix(countData = clean_count_matrix,
colData = sample_metadata,
design = ~group)
Normalizing counts
We’ll implement relative log expression (RLE) normalization on the
counts using the DESeq2 package. RLE normalization is based on the
hypothesis that most genes are not differentially expressed, which is
suitable for this dataset, as the associated publication identifies a
low proportion of DE genes.
# estimate normalization factors and apply them to counts
counts_dds <- DESeq2::estimateSizeFactors(counts_dds)
norm_counts <- DESeq2::counts(counts_dds, normalized = TRUE)
Plotting sample clustering
In order to visualize the effects of normalization, we’ll generate
Multi-Dimensional Scaling (MDS) plots from the un-normalized and
normalized data.
# create SummarizedExperiment objects with un-normalized and normalized counts
unnorm_counts <- DESeq2::counts(counts_dds, normalized = FALSE)
unnorm_counts_se <- SummarizedExperiment(assays = list(counts = unnorm_counts),
colData = sample_metadata)
norm_counts_se <- SummarizedExperiment(assays = list(counts = norm_counts),
colData = sample_metadata)
# generate MDS data with un-normalized counts
unnorm_mds <- edgeR::plotMDS.SummarizedExperiment(unnorm_counts_se, plot = FALSE)
unnorm_mds_df <- data.frame(
Dim1 = unnorm_mds$x,
Dim2 = unnorm_mds$y,
Group = unnorm_counts_se$group,
Sample = colnames(unnorm_counts_se)
)
# generate MDS data with normalized counts
norm_mds <- edgeR::plotMDS.SummarizedExperiment(norm_counts_se, plot = FALSE)
norm_mds_df <- data.frame(
Dim1 = norm_mds$x,
Dim2 = norm_mds$y,
Group = norm_counts_se$group,
Sample = colnames(norm_counts_se)
)
# plot un-normalized MDS
ggplot2::ggplot(unnorm_mds_df, aes(x = Dim1, y = Dim2, color = Group)) +
geom_point(size = 3) +
theme_minimal() +
labs(
x = paste("Dim1 (", round(unnorm_mds$var.explained[1]*100, 1), "%)"),
y = paste("Dim2 (", round(unnorm_mds$var.explained[2]*100, 1), "%)"),
title = "MDS plot: un-normalized counts"
)

Figure 1: MDS plot generated from filtered RNA
sequencing read counts of whole blood samples from septic shock patients
who were responsive (R) and non-responsive (NR) to hemodynamic therapy,
taken at time points before and after treatment (T1 and T2), without
normalization.
# plot normalized MDS
ggplot2::ggplot(norm_mds_df, aes(x = Dim1, y = Dim2, color = Group)) +
geom_point(size = 3) +
theme_minimal() +
labs(
x = paste("Dim1 (", round(norm_mds$var.explained[1]*100, 1), "%)"),
y = paste("Dim2 (", round(norm_mds$var.explained[2]*100, 1), "%)"),
title = "MDS plot: normalized counts"
)

Figure 2: MDS plot generated from filtered RNA
sequencing read counts of whole blood samples from septic shock patients
who were responsive (R) and non-responsive (NR) to hemodynamic therapy,
taken at time points before and after treatment (T1 and T2), normalized
by relative log expression.
The MDS plots generated from the data pre and post normalization are
nearly identical. The low impact of normalization indicates little
technical bias in the dataset, and suggests that msot variation is
biological
Differential gene expression
Evaluating differential expression
From Fig. 1 and Fig. 2, some grouping is visible of samples within
the same set of conditions. Samples taken at the same time point from
patients with the same response behaviour loosely cluster together. As
such, we’ll use the four combinations of response and time point as
factors to evaluate differential expression.
# evaluate differential expression. Appropriate design already specified in counts_dds
counts_dds <- DESeq2::DESeq(counts_dds)
We’ll look for genes that are differentially expressed based on
patient response at each of the two time points, and look for genes that
are differentially expressed over time within each of the two patient
response groups.
# DE between R and NR at T1
response_T1 <- DESeq2::results(counts_dds, contrast = c("group", "NR_T1", "R_T1"), alpha = 0.05)
summary(response_T1)
# DE between R and NR at T2
response_T2 <- DESeq2::results(counts_dds, contrast = c("group", "NR_T2", "R_T2"), alpha = 0.05)
summary(response_T2)
# DE between T1 and T2 for NR patients
time_NR <- DESeq2::results(counts_dds, contrast = c("group", "NR_T1", "NR_T2"), alpha =0.05)
summary(time_NR)
# DE between T1 and T2 for R patients
time_R <- DESeq2::results(counts_dds, contrast = c("group", "R_T1", "R_T2"), alpha = 0.05)
summary(time_R)
# get genes with adjusted p-value < 0.05 for each test
sig_T1 <- response_T1[response_T1$padj < 0.05,]
sig_T2 <- response_T2[response_T2$padj < 0.05,]
sig_NR <- time_NR[time_NR$padj < 0.05,]
sig_R <- time_R[time_R$padj < 0.05,]
cat(paste(nrow(sig_T1), "DE genes between R and NR at T1\n",
nrow(sig_T2), "DE genes between R and NR at T2\n",
nrow(sig_NR), "DE genes from T1 to T2 in NR\n",
nrow(sig_R), "DE genes from T1 to T2 in R"))
0 DE genes between R and NR at T1
67 DE genes between R and NR at T2
846 DE genes from T1 to T2 in NR
1613 DE genes from T1 to T2 in R
DESeq2 implements multiple hypothesis testing via Benjamini-Hochberg
false discovery rate correction on p-values, producing adjusted p-values
that more accurately reflect significance in bulk RNA-sequencing data
than the original p-values given by the Wald test for differential
expression. The threshold we’ve used for differentially expressed genes
is genes with adjusted p-value < 0.05, a commonly used threshold
[cite cite].
In this analysis, we’ll work with the genes that were differentially
expressed between the R and NR groups at T2. Since no genes are
significantly differentially expressed between the R and NR groups at
T1, analyzing the genes that are differentially expressed between the
groups at T2 will tell us which genes were regulated differently between
responder and non-responder patients as a result of the same conditions,
yielding information on the differences between the two patient group’s
biological responses to the therapy.
Visualizing differentially expressed genes
We’ll create a volcano plot of the genes using the differential
expression statistics calculated between the R and NR groups at T2.
# convert DE results to data frame
difexp_info <- as.data.frame(response_T2)
# add column indicating whether genes are significantly up or downregulated
difexp_info$DE <- "no"
difexp_info$DE[difexp_info$log2FoldChange > 0 & difexp_info$padj < 0.05] <- "up"
difexp_info$DE[difexp_info$log2FoldChange < 0 & difexp_info$padj < 0.05] <- "down"
# generate volcano plot, -log10 of adjusted p-val vs log2 of FC
ggplot2::ggplot(data = difexp_info, mapping = aes(x = log2FoldChange, y = -log10(padj), col = DE)) +
geom_point() +
theme_minimal() +
geom_hline(yintercept = -log10(0.05), col = "black", linetype = 'dashed') +
scale_color_manual(values = c("blue", "grey", "red"),
labels = c("Downregulated in R group", "Not DE", "Upregulated in R group")) +
labs(color = "Expression",
x = "log 2 fold change",
y = "log 10 corrected p-value",
title = "Expression of genes in R vs. NR samples at T2")

Figure 3: FDR-corrected p-value (-log10) vs. fold
change (log2) in expression of genes in whole blood samples from septic
shock patients who responded to early supportive hemodynamic therapy (R
samples) and patients who did not respond (NR), taken 48 hours after
treatment. Threshold for differential expression was corrected p-value
< 0.05.
Next, we’ll create a heatmap of the genes differentially expressed
between the R and NR groups at T2, and see how they cluster according to
sample conditions.
# use normalized counts for heatmap matrix, filter for DE genes
normcounts_heatmap <- norm_counts[rownames(norm_counts) %in% rownames(sig_T2),]
# normalize rows
normcounts_heatmap <- t(scale(t(normcounts_heatmap)))
# set colours to scale from blue at min values to white at 0 to red at max values
heatmap_col = circlize::colorRamp2(c(min(normcounts_heatmap), 0, max(normcounts_heatmap)),
c("blue", "white", "red"))
# set colours to correspond to experimental conditions
group_colours <- rainbow(n = 4)
names(group_colours) <- unique(sample_metadata$group)
# add annotation with experimental conditions and corresponding colours
hannot <- ComplexHeatmap::HeatmapAnnotation(df = data.frame(
Group = sample_metadata$group),
col = list(
Group = group_colours
),
show_legend = TRUE)
# generate heatmap
DE_heatmap <- ComplexHeatmap::Heatmap(normcounts_heatmap,
col = heatmap_col,
show_column_names = FALSE,
show_row_names = FALSE,
top_annotation = hannot,
show_heatmap_legend = FALSE,
column_title = "Genes differentially expressed in R vs. NR groups at T1")
DE_heatmap

Figure 4: Heatmap of genes differentially expressed
in septic shock patients who responded to hemodynamic therapy and
patients who did not respond 48 hours after treatment (groups R_T2 and
NR_T2, respectively). Blue denotes low gene expression and red denotes
high gene expression.
The R_T2 and NR_T2 samples largely clustered apart from each other,
while the R_T1 and NR_T1 samples are not. This is as expected, since the
genes being plotted are differentially expressed between R and NR at T2,
while no genes are differentially expressed between R and NR at T1.
There is also significant separation between the T1 and T2 groups for R,
but not for NR, indicating that many of these genes change in expression
in responders over the 48 hours after hemodynamic therapy, but not in
non-responders.
Interpretation and documentation
This dataset was of interest because the distinct conditions
within it are not a result of differential treatment or circumstances,
but of differential biological response to a treatment, and the
inclusion of two different time points means that the dataset can be
used to analyze how pre-existing biological differences lead to
different epigenetic responses.
In this dataset, the control condition is patients who were
non-responders to early supportive hemodynamic therapy as treatment for
septic shock and the test condition is patients who were responders.
Samples collected at ICU admission also serve as a control for samples
collected 48h later.
There are 34 samples from responders and 28 samples from non
responders. There are 32 samples taken at time point 1 and 32 sample
staken at time point 2.
There were expression values that were not unique for specific
genes, but they were a very small proportion of the data. When multiple
expression values mapped to one gene, we used their sum as the
expression value for that gene. When an expression value mapped to
multiple genes, we duplicated it and used it as the expression value for
each gene it mapped to. Since there were very few such cases, the impact
of this transformation on library size was negligible.
A large proportion of the expression values could not be mapped
to HUGO symbols, but most of the unmapped values were very low, and were
removed when filtering out low expression genes.
There were no outliers in the dataset, according to the threshold
on Cook’s distance applied by DESeq2.
Biological replicates were grouped together in the design model
used for differential expression analysis. There were no technical
replicates.
The dataset covers 13673 genes across 62 samples.
Bibliography
Barcella, Matteo, Bernardo Bollen Pinto, Daniele Braga, et al. 2018.
“Identification of a Transcriptome Profile Associated with
Improvement of Organ Function in Septic Shock Patients After Early
Supportive Therapy.” Critical Care 22 (1).
https://doi.org/10.1186/s13054-018-2242-3.
Barrett, Tanya, Stephen E. Wilhite, Pierre Ledoux, et al. 2012.
“NCBI GEO: Archive for Functional Genomics Data
Sets—Update.” Nucleic Acids Research 41 (D1): D991–95.
https://doi.org/10.1093/nar/gks1193.
Chen, Yunshun, Lizhong Chen, Aaron T L Lun, Pedro Baldoni, and Gordon K
Smyth. 2025.
“edgeR V4: Powerful
Differential Analysis of Sequencing Data with Expanded Functionality and
Improved Support for Small Counts and Larger Datasets.”
Nucleic Acids Research 53 (2): gkaf018.
https://doi.org/10.1093/nar/gkaf018.
Davis, Sean, and Paul S. Meltzer. 2007.
“GEOquery: A Bridge
Between the Gene Expression Omnibus (GEO) and BioConductor.”
Bioinformatics 23 (14): 1846–47.
https://doi.org/10.1093/bioinformatics/btm254.
Durinck, Steffen, Yves Moreau, Arek Kasprzyk, et al. 2005.
“BioMart and Bioconductor: A Powerful Link Between Biological
Databases and Microarray Data Analysis.” Bioinformatics
21: 3439–40.
Gu, Zuguang. 2022.
“Complex Heatmap Visualization.”
iMeta, ahead of print.
https://doi.org/10.1002/imt2.43.
Gu, Zuguang, Lei Gu, Roland Eils, Matthias Schlesner, and Benedikt
Brors. 2014.
“Circlize Implements and Enhances Circular
Visualization in r.” Bioinformatics, ahead of print.
https://doi.org/10.1093/bioinformatics/btu393.
Love, Michael I., Simon Anders, Vladislav Kim, and Wolfgang Huber. 2015.
“RNA-Seq Workflow: Gene-Level Exploratory Analysis and
Differential Expression.” F1000Research 4 (October):
1070.
https://doi.org/10.12688/f1000research.7035.1.
Love, Michael I., Wolfgang Huber, and Simon Anders. 2014.
“Moderated Estimation of Fold Change and Dispersion for RNA-Seq
Data with DESeq2.” Genome Biology 15: 550.
https://doi.org/10.1186/s13059-014-0550-8.
Morgan, Martin, Valerie Obenchain, Jim Hester, and Hervé Pagès. 2025.
SummarizedExperiment: A Container (S4 Class) for Matrix-Like
Assays.
https://doi.org/10.18129/B9.bioc.SummarizedExperiment.
Müller, Kirill, and Hadley Wickham. 2025.
Tibble: Simple Data
Frames.
https://tibble.tidyverse.org/.
Wickham, Hadley. 2016.
Ggplot2: Elegant Graphics for Data
Analysis. Springer-Verlag New York.
https://ggplot2.tidyverse.org.
Wickham, Hadley, and Jennifer Bryan. 2025.
Readxl: Read Excel
Files.
https://readxl.tidyverse.org.
Wickham, Hadley, Romain François, Lionel Henry, Kirill Müller, and Davis
Vaughan. 2023.
Dplyr: A Grammar of Data Manipulation.
https://doi.org/10.32614/CRAN.package.dplyr.
Wickham, Hadley, Davis Vaughan, and Maximilian Girlich. 2025.
Tidyr:
Tidy Messy Data.
https://doi.org/10.32614/CRAN.package.tidyr.
Xie, Yihui. 2014. “Knitr: A Comprehensive Tool for Reproducible
Research in R.” In Implementing Reproducible
Computational Research, edited by Victoria Stodden, Friedrich
Leisch, and Roger D. Peng. Chapman; Hall/CRC.
LS0tCnRpdGxlOiAiRGlmZmVyZW50aWFsIEdlbmUgRXhwcmVzc2lvbiBpbiBTZXB0aWMgU2hvY2sgUGF0aWVudHMgQmFzZWQgb24gUmVzcG9uc2UgdG8gRWFybHkgU3VwcG9ydGl2ZSBIZW1vZHluYW1pYyBUaGVyYXB5IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgY29kZV9mb2xkaW5nOiBzaG93CmJpYmxpb2dyYXBoeTogQTFfYmliLmJpYgotLS0KCgoKQnk6ICoqT3dlbiBMbyoqCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30KIyBJbnN0YWxsIGFuZCBsb2FkIHJlcXVpcmVkIHBhY2thZ2VzCmlmKCFyZXF1aXJlTmFtZXNwYWNlKCJyZWFkeGwiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQp9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgia25pdHIiLCBxdWlldGx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCn0KCmxpYnJhcnkoR0VPcXVlcnkpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShrbml0cikKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShlZGdlUikKbGlicmFyeShTdW1tYXJpemVkRXhwZXJpbWVudCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpgYGAKClRoaXMgd29ya2Jvb2sgdXNlcyB0aGUgR0VPUXVlcnkgW0BEYXZpczIwMDddLCBiaW9tYVJ0IFtARHVyaW5jazIwMDVdLCB0aWJibGUgW0BNdWVsbGVyMjAyNV0sIHJlYWR4bFtAV2lja2hhbTIwMjVdLCBkcGx5ciBbQFdpY2toYW0yMDIzXSwgdGlkeXJbQFdpY2toYW0yMDI1YV0sIGtuaXRyIFtAWGllMjAxNF0sIERFU2VxMltATG92ZTIwMTRdLCBlZGdlUiBbQENoZW4yMDI1XSwgU3VtbWFyaXplZEV4cGVyaW1lbnRbQE1vcmdhbjIwMjVdLCBnZ3Bsb3QyIFtAV2lja2hhbTIwMTZdLCBDb21wbGV4SGVhdG1hcCBbQEd1MjAyMl0gYW5kIGNpcmNsaXplIFtAR3UyMDE0XSBwYWNrYWdlcyBpbiBpdHMgY29kZSBjaHVua3MuCgojIEludHJvZHVjdGlvbgoKU2VwdGljIHNob2NrIGlzIGEgcG90ZW50aWFsbHkgZmF0YWwgY29tcGxpY2F0aW9uIG9mIHNlcHNpcywgYW5kIHRyZWF0bWVudCBsYXJnZWx5IGRlcGVuZHMgb24gZWFybHkgc3VwcG9ydGl2ZSBoZW1vZHluYW1pYyB0aGVyYXB5LiBQYXRpZW50IHJlc3BvbnNlIHRvIGhlbW9keW5hbWljIHRoZXJhcHkgdmFyaWVzLCBhbmQgdGhlIE5DQkkgR2VuZSBFeHByZXNzaW9uIE9tbmlidXMgKEdFTykgW0BCYXJyZXR0MjAxMl0gc2VyaWVzIEdTRTExMDQ4NyBpcyBhIGRhdGFzZXQgZnJvbSAyMDE4IGNvbnNpc3Rpbmcgb2YgUk5BIHNlcXVlbmNpbmcgcmVhZCBjb3VudHMgb2Ygd2hvbGUgYmxvb2Qgc2FtcGxlcyB0YWtlbiBmcm9tIDE0IHNlcHRpYyBzaG9jayBwYXRpZW50cyB3aG8gcmVzcG9uZGVkIHRvIGhlbW9keW5hbWljIHRoZXJhcHkgYW5kIDE3IG5vbi1yZXNwb25kZXJzLCBhdCB0d28gdGltZSBwb2ludHM6IGltbWVkaWF0ZWx5IGFmdGVyIElDVSBhZG1pc3Npb24sIGFuZCA0OCBob3VycyBsYXRlciwgYWZ0ZXIgaGVtb2R5bmFtaWMgdGhlcmFweS4gW0BCYXJjZWxsYTIwMThdCgojIEZldGNoaW5nIGFuZCBhc3Nlc3NpbmcgZGF0YQoKIyMgRG93bmxvYWRpbmcgYW5kIGZvcm1hdHRpbmcKCldlJ2xsIHVzZSB0aGUgR0VPUXVlcnkgcGFja2FnZSB0byByZXRyaWV2ZSB0aGUgc3VwcGxlbWVudGFyeSBmaWxlcyBhbmQgbWV0YWRhdGEgcGVydGFpbmluZyB0byB0aGUgZXhwZXJpbWVudCBmcm9tIHRoZSBHRU8gd2l0aCBpdHMgc2VyaWVzIGFjY2Vzc2lvbiBudW1iZXIsIGFuZCB0aGVuIGxvb2sgYXQgaG93IGl0J3MgZm9ybWF0dGVkLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KZ2VvX2lkIDwtICJHU0UxMTA0ODciCgojIGdldCBtZXRhZGF0YSBhc3NvY2lhdGVkIHdpdGggZ3NlIGFuZCBzdXBwbGVtZW50YXJ5IGZpbGVzCmdzZSA8LSBHRU9xdWVyeTo6Z2V0R0VPKGdlb19pZCwgR1NFTWF0cml4PUZBTFNFKQpzdXBwIDwtIEdFT3F1ZXJ5OjpnZXRHRU9TdXBwRmlsZXMoZ2VvX2lkLCBmZXRjaF9maWxlcz1GQUxTRSkKCiMgZG93bmxvYWQgZGF0YSBpZiBub3QgYWxyZWFkeSBkb3dubG9hZGVkCmN1cnJlbnRfZGlyIDwtIGZpbGUucGF0aChnZXR3ZCgpKQpzdXBwX2ZpbGVfcGF0aCA8LSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGdlb19pZCwgc3VwcCRmbmFtZVsxXSkKaWYgKCFmaWxlLmV4aXN0cyhzdXBwX2ZpbGVfcGF0aCkpIHsKICBkYXRhX2ZpbGUgPC0gR0VPcXVlcnk6OmdldEdFT1N1cHBGaWxlcyhHRU8gPSBnZW9faWQpCn0KCiMgcmVhZCBkYXRhIGludG8gYSBkYXRhZnJhbWUKcmF3X2NvdW50cyA8LSByZWFkeGw6OnJlYWRfeGxzeChzdXBwX2ZpbGVfcGF0aCkKCiMgdGFrZSBhIHBlZWsKa25pdHI6OmthYmxlKHJhd19jb3VudHNbMTo1LCAxOjEwXSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICJjIikKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMgY291bnQgZ2VuZXMgYW5kIHNhbXBsZXMKY2F0KHBhc3RlKCJOdW1iZXIgb2YgZ2VuZXM6ICIsIG5yb3cocmF3X2NvdW50cyksCiAgICAgICAgICAiXG5OdW1iZXIgb2Ygc2FtcGxlczogIiwgbmNvbChyYXdfY291bnRzKS0xKSkKYGBgCgpTYW1wbGVzIGluIHRoZSByYXcgZGF0YSBhcmUgbmFtZWQgYWNjb3JkaW5nIHRvIHBhdGllbnQgaWRlbnRpdHkgYW5kIHRpbWUgcG9pbnQsIGJ1dCBkb24ndCBjb250YWluIGFueSBpbmZvcm1hdGlvbiBvbiB3aGV0aGVyIHRoZSBwYXRpZW50IHdhcyBhIHJlc3BvbmRlciBvciBhIG5vbi1yZXNwb25kZXIsIHNvIHdlJ2xsIG1hcCBzYW1wbGUgaWRlbnRpZmllcnMgdG8gYm90aCByZXNwb25zZSBhbmQgdGltZSBwb2ludC4KCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyByZXRyaWV2ZSBsaXN0IG9mIHNhbXBsZXMgaW4gdGhlIHNlcmllcywgYW5kIGNvbXBpbGUgY29uZGl0aW9uIGRhdGEgZm9yIGVhY2gKc2FtcGxlcyA8LSBnc2VAZ3NtcwpzYW1wbGVfc291cmNlcyA8LSBkby5jYWxsKHJiaW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoc2FtcGxlcywgRlVOPWZ1bmN0aW9uKHgpewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyh4QGhlYWRlciR0aXRsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeEBoZWFkZXIkc291cmNlX25hbWVfY2gxKX0pKQoKIyBVc2UgdGhpcyBkYXRhIHRvIGNyZWF0ZSBhIGRhdGFmcmFtZSBtYXBwaW5nIHNhbXBsZSB0aXRsZXMgdG8gcmVzcG9uZGVyIHN0YXR1cyBhbmQgdGltZSBwb2ludApzYW1wbGVfbWV0YWRhdGEgPC0gYXMuZGF0YS5mcmFtZShzYW1wbGVfc291cmNlcywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpjb2xuYW1lcyhzYW1wbGVfbWV0YWRhdGEpID0gYygic2FtcGxlIiwgInNvdXJjZSIpCnNhbXBsZV9tZXRhZGF0YSA8LSBzYW1wbGVfbWV0YWRhdGEgJT4lIAogIG1hZ3JpdHRyOjpzZXRfcm93bmFtZXMoLiRzYW1wbGUpICU+JSAKICBtdXRhdGUoCiAgICByZXNwb25zZSA9IGlmZWxzZShncmVwbCgiXlJlc3BvbmRlciIsIHNvdXJjZSksICJSIiwgIk5SIiksCiAgICB0aW1lX3BvaW50ID0gaWZlbHNlKGdyZXBsKCJUMSIsIHNvdXJjZSksICJUMSIsICJUMiIpLAogICkgJT4lIAogIGRwbHlyOjpzZWxlY3QocmVzcG9uc2UsIHRpbWVfcG9pbnQpCgojIHRha2UgYSBwZWVrCmtuaXRyOjprYWJsZShzYW1wbGVfbWV0YWRhdGFbMTo1LF0sIGZvcm1hdCA9ICJodG1sIiwgYWxpZ24gPSAiYyIpCmBgYAoKIyMgUXVhbGl0eSBhc3Nlc3NtZW50CgpOb3csIHdlJ2xsIGRldGVybWluZSB3aGV0aGVyIGRhdGEgcXVhbGl0eSB2YXJpZXMgYWNyb3NzIGNvbmRpdGlvbnMKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyBjYWxjdWxhdGluZyBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIGVhY2ggc2FtcGxlCnNhbXBsZV9zdW1tYXJpZXMgPC0gZGF0YS5mcmFtZShkby5jYWxsKGNiaW5kLCBsYXBwbHkocmF3X2NvdW50c1ssIDI6bmNvbChyYXdfY291bnRzKV0sIHN1bW1hcnkpKSkKcXVhbF9vdmVydmlldyA8LSBhcy5kYXRhLmZyYW1lKHQoc2FtcGxlX3N1bW1hcmllcykpCgojIEFkZGluZyBleHRyYSBzdGF0aXN0aWNzIGZvciB0b3RhbCByZWFkcywgbnVtYmVyIG9mIGdlbmVzIHdpdGggemVybyBleHByZXNzaW9uLCBudW1iZXIgb2YgZ2VuZXMgd2l0aCBsb3cgZXhwcmVzc2lvbgpxdWFsX292ZXJ2aWV3IDwtIHF1YWxfb3ZlcnZpZXcgJT4lIAogIGRwbHlyOjptdXRhdGUodG90YWxfcmVhZHMgPSBjb2xTdW1zKHJhd19jb3VudHNbMjpuY29sKHJhd19jb3VudHMpXSksCiAgICAgICAgICAgICAgICB6ZXJvX2V4cCA9IGNvbFN1bXMocmF3X2NvdW50c1syOm5jb2wocmF3X2NvdW50cyldID09IDApLAogICAgICAgICAgICAgICAgbG93X2V4cCA9IGNvbFN1bXMocmF3X2NvdW50c1syOm5jb2wocmF3X2NvdW50cyldPDEwKSwKICAgICAgICAgICAgICAgICkKCiMgYWRkaW5nIG1ldGFkYXRhIHRvIHNvcnQgYnkgY29uZGl0aW9ucwpxdWFsX292ZXJ2aWV3IDwtIG1lcmdlKHF1YWxfb3ZlcnZpZXcsIHNhbXBsZV9tZXRhZGF0YSwgYnkgPSAwKQoKIyBvdmVydmlldyBzdGF0cyBmb3Igc2FtcGxlcyBmcm9tIG5vbi1yZXNwb25kZXJzIGFuZCByZXNwb25kZXJzCnN0YXRzX2J5X3Jlc3BvbnNlIDwtIHF1YWxfb3ZlcnZpZXcgJT4lCiAgZHBseXI6Omdyb3VwX2J5KHJlc3BvbnNlLCkgJT4lCiAgc3VtbWFyaXplKAogICAgTnVtU2FtcGxlcyA9IG4oKSwKICAgIE1lYW5MaWJTaXplID0gbWVhbih0b3RhbF9yZWFkcyksCiAgICBTRExpYlNpemUgPSBzZCh0b3RhbF9yZWFkcyksCiAgICBQcm9wWmVyb0V4cCA9IG1lYW4oemVyb19leHApIC8gbnJvdyhyYXdfY291bnRzKSwKICAgIFByb3BMb3dFeHAgPSBtZWFuKGxvd19leHApIC8gbnJvdyhyYXdfY291bnRzKSwKICApCgojIG92ZXJ2aWV3IHN0YXRzIGZvciBzYW1wbGVzIGZyb20gdGltZSBwb2ludCAxIGFuZCB0aW1lIHBvaW50IDIKc3RhdHNfYnlfdGltZSA8LSBxdWFsX292ZXJ2aWV3ICU+JQogIGRwbHlyOjpncm91cF9ieSh0aW1lX3BvaW50LCkgJT4lCiAgc3VtbWFyaXplKAogICAgTnVtU2FtcGxlcyA9IG4oKSwKICAgIE1lYW5MaWJTaXplID0gbWVhbih0b3RhbF9yZWFkcyksCiAgICBTRExpYlNpemUgPSBzZCh0b3RhbF9yZWFkcyksCiAgICBQcm9wWmVyb0V4cCA9IG1lYW4oemVyb19leHApIC8gbnJvdyhyYXdfY291bnRzKSwKICAgIFByb3BMb3dFeHAgPSBtZWFuKGxvd19leHApIC8gbnJvdyhyYXdfY291bnRzKSwKICApCgojIG1lcmdpbmcgdGFibGVzIGFuZCBkaXNwbGF5aW5nCnN0YXRzX2J5X2NvbmRpdGlvbiA8LSBiaW5kX3Jvd3MoCiAgICBzdGF0c19ieV9yZXNwb25zZSAlPiUgCiAgICAgICAgZHBseXI6Om11dGF0ZShncm91cF90eXBlID0gInJlc3BvbnNlIikgJT4lCiAgICAgICAgZHBseXI6OnJlbmFtZShjb25kaXRpb24gPSByZXNwb25zZSksCiAgICBzdGF0c19ieV90aW1lICU+JSAKICAgICAgICBkcGx5cjo6bXV0YXRlKGdyb3VwX3R5cGUgPSAidGltZV9wb2ludCIpICU+JQogICAgICAgIGRwbHlyOjpyZW5hbWUoY29uZGl0aW9uID0gdGltZV9wb2ludCkKICAgICkKa25pdHI6OmthYmxlKHN0YXRzX2J5X2NvbmRpdGlvblssMTo2XSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICJjIikKYGBgCgpNZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24sIGFuZCBwcm9wb3J0aW9ucyBvZiB1bmV4cHJlc3NlZCBhbmQgbG93bHkgZXhwcmVzc2VkIGdlbmVzIGFyZSBzaW1pbGFyIGFjcm9zcyBwYXRpZW50IHJlc3BvbmRlciBzdGF0dXMgYW5kIHRpbWUsIHNvIHNwZWNpYWwgY29ycmVjdGlvbiBmb3IgZGF0YSBxdWFsaXR5IHdvbid0IGJlIG5lY2Vzc2FyeS4KCiMgSWRlbnRpZmllciBtYXBwaW5nIGFuZCBjbGVhbmluZwoKIyMgTWFwcGluZyB0byBIVUdPIHN5bWJvbHMKClRoZSBkYXRhIHVzZXMgRW5zZW1ibCBHZW5lIElEcyBiZWdpbm5pbmcgd2l0aCBFTlNHLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KIyBnZXQgZW5zZW1ibCB2ZXJzaW9uIDEwMCBhbmQgdGhlIGh1bWFuIGdlbmUgZGF0YXNldAplbnNlbWJsIDwtIGJpb21hUnQ6OnVzZUVuc2VtYmwoYmlvbWFydCA9ICJlbnNlbWJsIikKZW5zZW1ibCA8LSBiaW9tYVJ0Ojp1c2VEYXRhc2V0KCJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLCBtYXJ0ID0gZW5zZW1ibCkKYGBgCgpSYXRoZXIgdGhhbiBFbnNlbWJsIEdlbmUgSURzLCB3ZSB3YW50IHRvIHVzZSBIVUdPIEdlbmUgTm9tZW5jbGF0dXJlIENvbW1pdHRlZSAoSEdOQykgc3ltYm9scyB0byBpZGVudGlmeSB0aGUgZ2VuZXMgaW4gb3VyIGRhdGFzZXQuIFdlJ2xsIHVzZSB0aGUgRW5zZW1ibCBodW1hbiBkYXRhc2V0IHRvIG1hcCBhcyBtYW55IEVOU0cgSURzIGFzIHBvc3NpYmxlIHRvIEhHTkMgc3ltYm9scywgYW5kIGFkZCB0aG9zZSBtYXBwaW5ncyB0byBvdXIgcmVhZCBkYXRhLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQojIHN0b3JlIGVuc2VtYmwgSURzIGZyb20gdGhlIGRhdGEgYXMgYSB2ZWN0b3IKZW5zZW1ibF9pZHMgPC0gcmF3X2NvdW50cyRHZW5laWQKCiMgY2hlY2sgaWYgYW4gZW5zZW1ibCB0byBoZ25jIGNvbnZlcnNpb24gZmlsZSBleGlzdHMgYWxyZWFkeQpjb252ZXJzaW9uX3N0YXNoIDwtICJlbnNlbWJsX3RvX2hnbmMucmRzIgppZiAoZmlsZS5leGlzdHMoY29udmVyc2lvbl9zdGFzaCkpIHsKICAKICAjIGlmIHRoZSBmaWxlIGV4aXN0cywgcmVhZCBjb252ZXJzaW9uIGRhdGEgZnJvbSB0aGF0CiAgZW5zZW1ibF90b19oZ25jIDwtIHJlYWRSRFMoY29udmVyc2lvbl9zdGFzaCkKfSBlbHNlIHsKICAKICAjIGlmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0LCBnZXQgY29udmVyc2lvbiBkYXRhIGZyb20gYmlvbWFSdCBhbmQgY2FjaGUgaXQKICBlbnNlbWJsX3RvX2hnbmMgPC0gYmlvbWFSdDo6Z2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIsICJoZ25jX3N5bWJvbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVycyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gZW5zZW1ibF9pZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICBtYXJ0ID0gZW5zZW1ibCkKICBzYXZlUkRTKGVuc2VtYmxfdG9faGduYywgY29udmVyc2lvbl9zdGFzaCkKfQoKIyBtZXJnZSBjb252ZXJzaW9uIGRmIHdpdGggZGF0YSBhbmQgcmVhcnJhbmdlIHN1Y2ggdGhhdCBib3RoIGlkIGNvbHVtbnMgY29tZSBiZWZvcmUgc2FtcGxlcwpyYXdfY291bnRzX2Fubm90IDwtIGRwbHlyOjpsZWZ0X2pvaW4ocmF3X2NvdW50cywgZW5zZW1ibF90b19oZ25jLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiR2VuZWlkIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkKcmF3X2NvdW50c19jb2xzIDwtIGRwbHlyOjpzZXRkaWZmKG5hbWVzKHJhd19jb3VudHMpLCAiR2VuZWlkIikKY29sbmFtZXMocmF3X2NvdW50c19hbm5vdClbMV0gPSAiZW5zZW1ibF9nZW5lX2lkIgpyYXdfY291bnRzX2Fubm90IDwtIHJhd19jb3VudHNfYW5ub3RbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiaGduY19zeW1ib2wiLCByYXdfY291bnRzX2NvbHMpXQoKIyBwZWVrIGF0IGFubm90YXRlZCBjb3VudHMKa25pdHI6OmthYmxlKHJhd19jb3VudHNfYW5ub3RbMTo1LCAxOjEwXSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICJjIikKYGBgCgpOb3cgcm93cyBhcmUgaWRlbnRpZmllZCBieSBib3RoIEVOU0cgSUQgYW5kIEhHTkMgc3ltYm9sLgoKIyMgQ2xlYW5pbmcgb3V0IGxvdyBleHByZXNzaW9uIGFuZCB1bm1hcHBlZCByb3dzCgpBc3NheWluZyBmb3Igcm93cyB3aGVyZSBtYXBwaW5nIG9uZSBFTlNHIElEIHRvIG9uZSBIR05DIHN5bWJvbCBmYWlsZWQ6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMgc3Vic2V0IHJvd3Mgd2hlcmUgb25lIGVuc2VtYmwgaWQgbWFwcyB0byBtdWx0aXBsZSBoZ25jIHN5bWJvbHMKZW5zZW1ibF9kdXBzIDwtIHJhd19jb3VudHNfYW5ub3QkZW5zZW1ibF9nZW5lX2lkW2R1cGxpY2F0ZWQocmF3X2NvdW50c19hbm5vdCRlbnNlbWJsX2dlbmVfaWQpXQptdWx0aXBsZV9oZ25jIDwtIHJhd19jb3VudHNfYW5ub3QgJT4lIAogIGZpbHRlcihlbnNlbWJsX2dlbmVfaWQgJWluJSBlbnNlbWJsX2R1cHMpCgojIHN1YnNldCByb3dzIHdoZXJlIG11bHRpcGxlIGVuc2VtYmwgaWRzIG1hcCB0byBvbmUgaGduYyBzeW1ib2wKaGduY19kdXBzIDwtIHJhd19jb3VudHNfYW5ub3QkaGduY19zeW1ib2xbZHVwbGljYXRlZChyYXdfY291bnRzX2Fubm90JGhnbmNfc3ltYm9sKV0Kc2FtZV9oZ25jIDwtIHJhd19jb3VudHNfYW5ub3QgJT4lIAogIGZpbHRlcihoZ25jX3N5bWJvbCAlaW4lIGhnbmNfZHVwcyAmIGhnbmNfc3ltYm9sICE9ICIiKQoKIyBzdWJzZXQgcm93cyB3aGVyZSBlbnNlbWJsIGlkIGRvZXMgbm90IG1hcCB0byBhIGhnbmMgc3ltYm9sIAp1bm1hcHBlZCA8LSByYXdfY291bnRzX2Fubm90ICU+JSAKICBmaWx0ZXIoaXMubmEoaGduY19zeW1ib2wpIHwgaGduY19zeW1ib2wgPT0gIiIpCgpjYXQocGFzdGUobnJvdyh1bm1hcHBlZCksICJ1bm1hcHBlZCByb3dzXG4iLAogICAgICAgICAgbnJvdyhtdWx0aXBsZV9oZ25jKSwgCiAgICAgICAgICAicm93cyB3aGVyZSBvbmUgRU5TRyBJRCBtYXBzIHRvIG11bHRpcGxlIEhHTkMgc3ltYm9scyBcbiIsCiAgICAgICAgICBucm93KHNhbWVfaGduYyksIAogICAgICAgICAgInJvd3Mgd2hlcmUgbXVsdGlwbGUgRU5TRyBJRHMgbWFwIHRvIHRoZSBzYW1lIEhHTkMgc3ltYm9sIikpCmBgYAoKQSBoaWdoIHByb3BvcnRpb24gb2YgdGhlIGRhdGFzZXQncyByb3dzIGRvIG5vdCBtYXAgdG8gYW55IEhHTkMgc3ltYm9sLiBUaGVzZSBhcmUgbGlrZWx5IHRvIGNvcnJlc3BvbmQgdG8gb3V0ZGF0ZWQgYWxpYXNlcyBvZiBjdXJyZW50IHN5bWJvbHMsIG9yIGRlcHJlY2F0ZWQgT1JGcy4gQnkgZmlsdGVyaW5nIGxvdyBleHByZXNzaW9uIGdlbmVzIGZyb20gdGhlIGRhdGEgYW5kIGNvbXBhcmluZyB0aGUgcHJvcG9ydGlvbnMgb2YgbWFwcGVkIGFuZCB1bm1hcHBlZCBnZW5lcyB0aGF0IHJlbWFpbiwgd2UgY2FuIGFzc2VzcyB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSB1bm1hcHBlZCByb3dzLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KIyBzaXplIG9mIHNtYWxsZXN0IGNvbmRpdGlvbiBncm91cCBpbiB0aGUgZGF0YXNldDogbm9uLXJlc3BvbmRlcnMgYXQgdGltZSBwb2ludCAxLzIKc21hbGxlc3RfZ3JvdXBfc2l6ZSA8LSAxMQoKIyBrZWVwIG9ubHkgdW5tYXBwZWQgcm93cyB0aGF0IGhhdmUgYSBjb3VudCBvZiBhdCBsZWFzdCAxMCBpbiAxMSBzYW1wbGVzCnJvd3NfdG9fa2VlcCA8LSByb3dTdW1zKHVubWFwcGVkID49IDEwKSA+PSBzbWFsbGVzdF9ncm91cF9zaXplCmNsZWFuX3VubWFwcGVkIDwtIHVubWFwcGVkW3Jvd3NfdG9fa2VlcCxdCgojIHN1YnNldCBtYXBwZWQgY291bnRzIAptYXBwZWQgPC0gcmF3X2NvdW50c19hbm5vdCAlPiUgCiAgZmlsdGVyKCFpcy5uYShoZ25jX3N5bWJvbCkgJiBoZ25jX3N5bWJvbCAhPSAiIikKCiMgYXBwbHkgc2FtZSBleHByZXNzaW9uIGZpbHRlciB0byBtYXBwZWQgY291bnRzIApyb3dzX3RvX2tlZXAgPC0gcm93U3VtcyhtYXBwZWQgPj0gMTApID49IHNtYWxsZXN0X2dyb3VwX3NpemUKY2xlYW5fbWFwcGVkIDwtIG1hcHBlZFtyb3dzX3RvX2tlZXAsXQoKIyBjb2xsYXRlIGFuZCBkaXNwbGF5IHJlc3VsdHMgb2YgZmlsdGVyaW5nCmNsZWFuaW5nX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBUeXBlID0gYygibWFwcGVkIGdlbmVzIiwgInVubWFwcGVkIGdlbmVzIiksCiAgUHJlQ2xlYW5Db3VudCA9IGMobnJvdyhtYXBwZWQpLCBucm93KHVubWFwcGVkKSksCiAgUG9zdENsZWFuQ291bnQgPSBjKG5yb3coY2xlYW5fbWFwcGVkKSwgbnJvdyhjbGVhbl91bm1hcHBlZCkpLAogIFNpZ25pZmljYW50UHJvcG9ydGlvbiA9IGMobnJvdyhjbGVhbl9tYXBwZWQpL25yb3cobWFwcGVkKSwgCiAgICAgICAgICAgICAgICAgICAgIG5yb3coY2xlYW5fdW5tYXBwZWQpL25yb3codW5tYXBwZWQpKQopCmtuaXRyOjprYWJsZShjbGVhbmluZ19yZXN1bHRzLCBmb3JtYXQgPSAiaHRtbCIsIGFsaWduID0gImMiKQpgYGAKCkxlc3MgdGhhbiBhIHRlbnRoIG9mIHRoZSB1bm1hcHBlZCByb3dzIGhhZCBzdWZmaWNpZW50IGxldmVscyBvZiBleHByZXNzaW9uIHRvIG5vdCBiZSBmaWx0ZXJlZCBpbiBlYXJseSBkYXRhIGNsZWFuaW5nLCBjb21wYXJlZCB0byBtb3JlIHRoYW4gYSB0aGlyZCBvZiB0aGUgbWFwcGVkIHJvd3MuCgpTaW5jZSB1bm1hcHBlZCByb3dzIGFyZSBsYXJnZWx5IGxvd2x5IGV4cHJlc3NlZCwgd2UgY2FuIGRpc2NhcmQgdGhlbSB3aXRob3V0IGxvc2luZyBhIGdyZWF0IGFtb3VudCBvZiBpbmZvcm1hdGlvbi4gRU5TRyBJRHMgbWFwcGluZyB0byBtdWx0aXBsZSBIR05DIHN5bWJvbHMgbWF5IGJlIHRyYW5zY3JpcHRzIHRoYXQgaHlicmlkaXplIHRvIG1vcmUgdGhhbiBvbmUgZ2VuZSwgYW5kIHNpbmNlIHRoZXkgYXJlIGluIHN1Y2ggc21hbGwgcHJvcG9ydGlvbiBpbiB0aGUgZGF0YXNldCwgd2Ugd2lsbCB0cmVhdCB0aGVtIGFzIG11bHRpcGxlIGdlbmVzIHdpdGhvdXQgc2lnbmlmaWNhbnRseSBpbXBhY3RpbmcgYW5hbHlzaXMuIEhHTkMgc3ltYm9scyBtYXBwZWQgdG8gYnkgbXVsdGlwbGUgRU5TRyBJRHMgbWF5IGJlIGdlbmVzIHdpdGggbXVsdGlwbGUgc3BsaWNlIHZhcmlhbnRzLiBTaW5jZSB0aGV5IGFyZSBsaWtld2lzZSBpbiBtaW51c2N1bGUgcHJvcG9ydGlvbiBpbiB0aGUgZGF0YXNldCwgd2Ugd2lsbCBzdW0gdG9nZXRoZXIgcm93cyB0aGF0IG1hcCB0byB0aGUgc2FtZSBIVUdPIGdlbmUuCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyBjcmVhdGUgYSBuZXcgZGF0YWZyYW1lIHdoZXJlIHJvd3MgY29ycmVzcG9uZCB0byB1bmlxdWUgaGduYyBzeW1ib2xzCmNsZWFuX2NvdW50c19ieWhnbmMgPC0gY2xlYW5fbWFwcGVkICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoaGduY19zeW1ib2wpICU+JSAKICAjIHN1bSByb3dzIHRoYXQgbWFwIHRvIHRoZSBzYW1lIGhnbmMgc3ltYm9sCiAgZHBseXI6OnN1bW1hcmlzZShkcGx5cjo6YWNyb3NzKGRwbHlyOjp3aGVyZShpcy5udW1lcmljKSwgfiBzdW0oLngsIG5hLnJtID0gVFJVRSkpKQoKa25pdHI6OmthYmxlKGNsZWFuX2NvdW50c19ieWhnbmNbMTo1LCAxOjEwXSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICJjIikKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmNhdChwYXN0ZSgiTnVtYmVyIG9mIGdlbmVzOiAiLCBucm93KGNsZWFuX2NvdW50c19ieWhnbmMpLAogICAgICAgICAgIlxuTnVtYmVyIG9mIHNhbXBsZXM6ICIsIG5jb2woY2xlYW5fY291bnRzX2J5aGduYyktMSkpCmBgYAoKV2Ugbm93IGhhdmUgYSBkYXRhZnJhbWUgb2YgcmVhZCBjb3VudHMgZm9yIGdlbmVzIHdpdGggZXhwcmVzc2lvbiBsZXZlbHMgYWJvdmUgYSBiYXNlbGluZSwgaWRlbnRpZmllZCBieSB1bmlxdWUgSFVHTyBzeW1ib2xzLgoKIyBOb3JtYWxpemF0aW9uCgojIyBDb252ZXJ0aW5nIGRhdGEgZm9yIERFU2VxMgoKTGV0J3MgY3JlYXRlIGEgREVTZXFEYXRhU2V0IG9iamVjdCBmcm9tIG91ciBkYXRhLCBhbmQgY29udGludWUgb3VyIGFuYWx5c2lzIHdpdGggdGhlIERFU2VxMiBwYWNrYWdlLCBhZGFwdGluZyBtZXRob2RzIGZyb20gTG92ZSBldCBhbCdzIFJOQVNlcSB3b3JrZmxvdyBbQExvdmUyMDE1XS4KCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9CiMgZXh0cmFjdCBjb3VudHMgYXMgYSBtYXRyaXggYW5kIHNldCByb3cgYW5kIGNvbHVtbiBuYW1lcwpjbGVhbl9jb3VudF9tYXRyaXggPC0gYXMubWF0cml4KGNsZWFuX2NvdW50c19ieWhnbmNbLDI6bmNvbChjbGVhbl9jb3VudHNfYnloZ25jKV0pCnJvd25hbWVzKGNsZWFuX2NvdW50X21hdHJpeCkgPC0gY2xlYW5fY291bnRzX2J5aGduYyRoZ25jX3N5bWJvbApjb2xuYW1lcyhjbGVhbl9jb3VudF9tYXRyaXgpIDwtIGNvbG5hbWVzKGNsZWFuX2NvdW50c19ieWhnbmMpWzI6bmNvbChjbGVhbl9jb3VudHNfYnloZ25jKV0KCiNjcmVhdGUgYSB2YXJpYWJsZSBpbiB0aGUgbWV0YWRhdGEgZnJvbSB0aGUgaW50ZXJhY3Rpb24gb2YgcmVzcG9uc2UgYW5kIHRpbWVfcG9pbnQKc2FtcGxlX21ldGFkYXRhJGdyb3VwID0gaW50ZXJhY3Rpb24oc2FtcGxlX21ldGFkYXRhJHJlc3BvbnNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfbWV0YWRhdGEkdGltZV9wb2ludCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIl8iKQoKIyBjcmVhdGUgYSBERVNlcURhdGFTZXQgb2JqZWN0IGZyb20gdGhlIGNvdW50cyBtYXRyaXggYW5kIHRoZSBzYW1wbGUgbWV0YWRhdGEsIHVzaW5nIHRoZSBpbnRlcmFjdGlvbiBvZiByZXNwb25zZSBhbmQgdGltZSBwb2ludCBhcyB0aGUgZGVzaWduLiAKY291bnRzX2RkcyA8LSBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY2xlYW5fY291bnRfbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gc2FtcGxlX21ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+Z3JvdXApCmBgYAoKIyMgTm9ybWFsaXppbmcgY291bnRzCgpXZSdsbCBpbXBsZW1lbnQgcmVsYXRpdmUgbG9nIGV4cHJlc3Npb24gKFJMRSkgbm9ybWFsaXphdGlvbiBvbiB0aGUgY291bnRzIHVzaW5nIHRoZSBERVNlcTIgcGFja2FnZS4gUkxFIG5vcm1hbGl6YXRpb24gaXMgYmFzZWQgb24gdGhlIGh5cG90aGVzaXMgdGhhdCBtb3N0IGdlbmVzIGFyZSBub3QgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkLCB3aGljaCBpcyBzdWl0YWJsZSBmb3IgdGhpcyBkYXRhc2V0LCBhcyB0aGUgYXNzb2NpYXRlZCBwdWJsaWNhdGlvbiBpZGVudGlmaWVzIGEgbG93IHByb3BvcnRpb24gb2YgREUgZ2VuZXMuCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQoKIyBlc3RpbWF0ZSBub3JtYWxpemF0aW9uIGZhY3RvcnMgYW5kIGFwcGx5IHRoZW0gdG8gY291bnRzCmNvdW50c19kZHMgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGNvdW50c19kZHMpCm5vcm1fY291bnRzIDwtIERFU2VxMjo6Y291bnRzKGNvdW50c19kZHMsIG5vcm1hbGl6ZWQgPSBUUlVFKQpgYGAKCiMjIFBsb3R0aW5nIHNhbXBsZSBjbHVzdGVyaW5nCgpJbiBvcmRlciB0byB2aXN1YWxpemUgdGhlIGVmZmVjdHMgb2Ygbm9ybWFsaXphdGlvbiwgd2UnbGwgZ2VuZXJhdGUgTXVsdGktRGltZW5zaW9uYWwgU2NhbGluZyAoTURTKSBwbG90cyBmcm9tIHRoZSB1bi1ub3JtYWxpemVkIGFuZCBub3JtYWxpemVkIGRhdGEuCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMgY3JlYXRlIFN1bW1hcml6ZWRFeHBlcmltZW50IG9iamVjdHMgd2l0aCB1bi1ub3JtYWxpemVkIGFuZCBub3JtYWxpemVkIGNvdW50cwp1bm5vcm1fY291bnRzIDwtIERFU2VxMjo6Y291bnRzKGNvdW50c19kZHMsIG5vcm1hbGl6ZWQgPSBGQUxTRSkKdW5ub3JtX2NvdW50c19zZSA8LSBTdW1tYXJpemVkRXhwZXJpbWVudChhc3NheXMgPSBsaXN0KGNvdW50cyA9IHVubm9ybV9jb3VudHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBzYW1wbGVfbWV0YWRhdGEpCm5vcm1fY291bnRzX3NlIDwtIFN1bW1hcml6ZWRFeHBlcmltZW50KGFzc2F5cyA9IGxpc3QoY291bnRzID0gbm9ybV9jb3VudHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IHNhbXBsZV9tZXRhZGF0YSkKCiMgZ2VuZXJhdGUgTURTIGRhdGEgd2l0aCB1bi1ub3JtYWxpemVkIGNvdW50cwp1bm5vcm1fbWRzIDwtIGVkZ2VSOjpwbG90TURTLlN1bW1hcml6ZWRFeHBlcmltZW50KHVubm9ybV9jb3VudHNfc2UsIHBsb3QgPSBGQUxTRSkKdW5ub3JtX21kc19kZiA8LSBkYXRhLmZyYW1lKAogIERpbTEgPSB1bm5vcm1fbWRzJHgsCiAgRGltMiA9IHVubm9ybV9tZHMkeSwKICBHcm91cCA9IHVubm9ybV9jb3VudHNfc2UkZ3JvdXAsCiAgU2FtcGxlID0gY29sbmFtZXModW5ub3JtX2NvdW50c19zZSkKKQoKIyBnZW5lcmF0ZSBNRFMgZGF0YSB3aXRoIG5vcm1hbGl6ZWQgY291bnRzCm5vcm1fbWRzIDwtIGVkZ2VSOjpwbG90TURTLlN1bW1hcml6ZWRFeHBlcmltZW50KG5vcm1fY291bnRzX3NlLCBwbG90ID0gRkFMU0UpCm5vcm1fbWRzX2RmIDwtIGRhdGEuZnJhbWUoCiAgRGltMSA9IG5vcm1fbWRzJHgsCiAgRGltMiA9IG5vcm1fbWRzJHksCiAgR3JvdXAgPSBub3JtX2NvdW50c19zZSRncm91cCwKICBTYW1wbGUgPSBjb2xuYW1lcyhub3JtX2NvdW50c19zZSkKKQoKIyBwbG90IHVuLW5vcm1hbGl6ZWQgTURTICAKZ2dwbG90Mjo6Z2dwbG90KHVubm9ybV9tZHNfZGYsIGFlcyh4ID0gRGltMSwgeSA9IERpbTIsIGNvbG9yID0gR3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHggPSBwYXN0ZSgiRGltMSAoIiwgcm91bmQodW5ub3JtX21kcyR2YXIuZXhwbGFpbmVkWzFdKjEwMCwgMSksICIlKSIpLAogICAgeSA9IHBhc3RlKCJEaW0yICgiLCByb3VuZCh1bm5vcm1fbWRzJHZhci5leHBsYWluZWRbMl0qMTAwLCAxKSwgIiUpIiksCiAgICB0aXRsZSA9ICJNRFMgcGxvdDogdW4tbm9ybWFsaXplZCBjb3VudHMiCiAgKQpgYGAKCjxjZW50ZXI+CgoqKkZpZ3VyZSAxOioqIE1EUyBwbG90IGdlbmVyYXRlZCBmcm9tIGZpbHRlcmVkIFJOQSBzZXF1ZW5jaW5nIHJlYWQgY291bnRzIG9mIHdob2xlIGJsb29kIHNhbXBsZXMgZnJvbSBzZXB0aWMgc2hvY2sgcGF0aWVudHMgd2hvIHdlcmUgcmVzcG9uc2l2ZSAoUikgYW5kIG5vbi1yZXNwb25zaXZlIChOUikgdG8gaGVtb2R5bmFtaWMgdGhlcmFweSwgdGFrZW4gYXQgdGltZSBwb2ludHMgYmVmb3JlIGFuZCBhZnRlciB0cmVhdG1lbnQgKFQxIGFuZCBUMiksIHdpdGhvdXQgbm9ybWFsaXphdGlvbi4KCjwvY2VudGVyPgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQojIHBsb3Qgbm9ybWFsaXplZCBNRFMKZ2dwbG90Mjo6Z2dwbG90KG5vcm1fbWRzX2RmLCBhZXMoeCA9IERpbTEsIHkgPSBEaW0yLCBjb2xvciA9IEdyb3VwKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICB4ID0gcGFzdGUoIkRpbTEgKCIsIHJvdW5kKG5vcm1fbWRzJHZhci5leHBsYWluZWRbMV0qMTAwLCAxKSwgIiUpIiksCiAgICB5ID0gcGFzdGUoIkRpbTIgKCIsIHJvdW5kKG5vcm1fbWRzJHZhci5leHBsYWluZWRbMl0qMTAwLCAxKSwgIiUpIiksCiAgICB0aXRsZSA9ICJNRFMgcGxvdDogbm9ybWFsaXplZCBjb3VudHMiCiAgKQpgYGAKCjxjZW50ZXI+CgoqKkZpZ3VyZSAyOioqIE1EUyBwbG90IGdlbmVyYXRlZCBmcm9tIGZpbHRlcmVkIFJOQSBzZXF1ZW5jaW5nIHJlYWQgY291bnRzIG9mIHdob2xlIGJsb29kIHNhbXBsZXMgZnJvbSBzZXB0aWMgc2hvY2sgcGF0aWVudHMgd2hvIHdlcmUgcmVzcG9uc2l2ZSAoUikgYW5kIG5vbi1yZXNwb25zaXZlIChOUikgdG8gaGVtb2R5bmFtaWMgdGhlcmFweSwgdGFrZW4gYXQgdGltZSBwb2ludHMgYmVmb3JlIGFuZCBhZnRlciB0cmVhdG1lbnQgKFQxIGFuZCBUMiksIG5vcm1hbGl6ZWQgYnkgcmVsYXRpdmUgbG9nIGV4cHJlc3Npb24uCgo8L2NlbnRlcj4KClRoZSBNRFMgcGxvdHMgZ2VuZXJhdGVkIGZyb20gdGhlIGRhdGEgcHJlIGFuZCBwb3N0IG5vcm1hbGl6YXRpb24gYXJlIG5lYXJseSBpZGVudGljYWwuIFRoZSBsb3cgaW1wYWN0IG9mIG5vcm1hbGl6YXRpb24gaW5kaWNhdGVzIGxpdHRsZSB0ZWNobmljYWwgYmlhcyBpbiB0aGUgZGF0YXNldCwgYW5kIHN1Z2dlc3RzIHRoYXQgbXNvdCB2YXJpYXRpb24gaXMgYmlvbG9naWNhbCAKCiMgRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbgoKIyMgRXZhbHVhdGluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKRnJvbSBGaWcuIDEgYW5kIEZpZy4gMiwgc29tZSBncm91cGluZyBpcyB2aXNpYmxlIG9mIHNhbXBsZXMgd2l0aGluIHRoZSBzYW1lIHNldCBvZiBjb25kaXRpb25zLiBTYW1wbGVzIHRha2VuIGF0IHRoZSBzYW1lIHRpbWUgcG9pbnQgZnJvbSBwYXRpZW50cyB3aXRoIHRoZSBzYW1lIHJlc3BvbnNlIGJlaGF2aW91ciBsb29zZWx5IGNsdXN0ZXIgdG9nZXRoZXIuIEFzIHN1Y2gsIHdlJ2xsIHVzZSB0aGUgZm91ciBjb21iaW5hdGlvbnMgb2YgcmVzcG9uc2UgYW5kIHRpbWUgcG9pbnQgYXMgZmFjdG9ycyB0byBldmFsdWF0ZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KIyBldmFsdWF0ZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4gQXBwcm9wcmlhdGUgZGVzaWduIGFscmVhZHkgc3BlY2lmaWVkIGluIGNvdW50c19kZHMKY291bnRzX2RkcyA8LSBERVNlcTI6OkRFU2VxKGNvdW50c19kZHMpCmBgYApXZSdsbCBsb29rIGZvciBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmFzZWQgb24gcGF0aWVudCByZXNwb25zZSBhdCBlYWNoIG9mIHRoZSB0d28gdGltZSBwb2ludHMsIGFuZCBsb29rIGZvciBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgb3ZlciB0aW1lIHdpdGhpbiBlYWNoIG9mIHRoZSB0d28gcGF0aWVudCByZXNwb25zZSBncm91cHMuIApgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSAnaGlkZScsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQojIERFIGJldHdlZW4gUiBhbmQgTlIgYXQgVDEKcmVzcG9uc2VfVDEgPC0gREVTZXEyOjpyZXN1bHRzKGNvdW50c19kZHMsIGNvbnRyYXN0ID0gYygiZ3JvdXAiLCAiTlJfVDEiLCAiUl9UMSIpLCBhbHBoYSA9IDAuMDUpCnN1bW1hcnkocmVzcG9uc2VfVDEpCgojIERFIGJldHdlZW4gUiBhbmQgTlIgYXQgVDIgCnJlc3BvbnNlX1QyIDwtIERFU2VxMjo6cmVzdWx0cyhjb3VudHNfZGRzLCBjb250cmFzdCA9IGMoImdyb3VwIiwgIk5SX1QyIiwgIlJfVDIiKSwgYWxwaGEgPSAwLjA1KQpzdW1tYXJ5KHJlc3BvbnNlX1QyKQoKIyBERSBiZXR3ZWVuIFQxIGFuZCBUMiBmb3IgTlIgcGF0aWVudHMKdGltZV9OUiA8LSBERVNlcTI6OnJlc3VsdHMoY291bnRzX2RkcywgY29udHJhc3QgPSBjKCJncm91cCIsICJOUl9UMSIsICJOUl9UMiIpLCBhbHBoYSA9MC4wNSkKc3VtbWFyeSh0aW1lX05SKQoKIyBERSBiZXR3ZWVuIFQxIGFuZCBUMiBmb3IgUiBwYXRpZW50cwp0aW1lX1IgPC0gREVTZXEyOjpyZXN1bHRzKGNvdW50c19kZHMsIGNvbnRyYXN0ID0gYygiZ3JvdXAiLCAiUl9UMSIsICJSX1QyIiksIGFscGhhID0gMC4wNSkKc3VtbWFyeSh0aW1lX1IpCmBgYApgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CiMgZ2V0IGdlbmVzIHdpdGggYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMDUgZm9yIGVhY2ggdGVzdApzaWdfVDEgPC0gcmVzcG9uc2VfVDFbcmVzcG9uc2VfVDEkcGFkaiA8IDAuMDUsXQpzaWdfVDIgPC0gcmVzcG9uc2VfVDJbcmVzcG9uc2VfVDIkcGFkaiA8IDAuMDUsXQpzaWdfTlIgPC0gdGltZV9OUlt0aW1lX05SJHBhZGogPCAwLjA1LF0Kc2lnX1IgPC0gdGltZV9SW3RpbWVfUiRwYWRqIDwgMC4wNSxdCgpjYXQocGFzdGUobnJvdyhzaWdfVDEpLCAiREUgZ2VuZXMgYmV0d2VlbiBSIGFuZCBOUiBhdCBUMVxuIiwKICAgICAgICAgIG5yb3coc2lnX1QyKSwgIkRFIGdlbmVzIGJldHdlZW4gUiBhbmQgTlIgYXQgVDJcbiIsCiAgICAgICAgICBucm93KHNpZ19OUiksICJERSBnZW5lcyBmcm9tIFQxIHRvIFQyIGluIE5SXG4iLAogICAgICAgICAgbnJvdyhzaWdfUiksICJERSBnZW5lcyBmcm9tIFQxIHRvIFQyIGluIFIiKSkKYGBgCgoKREVTZXEyIGltcGxlbWVudHMgbXVsdGlwbGUgaHlwb3RoZXNpcyB0ZXN0aW5nIHZpYSBCZW5qYW1pbmktSG9jaGJlcmcgZmFsc2UgZGlzY292ZXJ5IHJhdGUgY29ycmVjdGlvbiBvbiBwLXZhbHVlcywgcHJvZHVjaW5nIGFkanVzdGVkIHAtdmFsdWVzIHRoYXQgbW9yZSBhY2N1cmF0ZWx5IHJlZmxlY3Qgc2lnbmlmaWNhbmNlIGluIGJ1bGsgUk5BLXNlcXVlbmNpbmcgZGF0YSB0aGFuIHRoZSBvcmlnaW5hbCBwLXZhbHVlcyBnaXZlbiBieSB0aGUgV2FsZCB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4gClRoZSB0aHJlc2hvbGQgd2UndmUgdXNlZCBmb3IgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGlzIGdlbmVzIHdpdGggYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMDUsIGEgY29tbW9ubHkgdXNlZCB0aHJlc2hvbGQgW2NpdGUgY2l0ZV0uIAoKSW4gdGhpcyBhbmFseXNpcywgd2UnbGwgd29yayB3aXRoIHRoZSBnZW5lcyB0aGF0IHdlcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gdGhlIFIgYW5kIE5SIGdyb3VwcyBhdCBUMi4gU2luY2Ugbm8gZ2VuZXMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gdGhlIFIgYW5kIE5SIGdyb3VwcyBhdCBUMSwgYW5hbHl6aW5nIHRoZSBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0aGUgZ3JvdXBzIGF0IFQyIHdpbGwgdGVsbCB1cyB3aGljaCBnZW5lcyB3ZXJlIHJlZ3VsYXRlZCBkaWZmZXJlbnRseSBiZXR3ZWVuIHJlc3BvbmRlciBhbmQgbm9uLXJlc3BvbmRlciBwYXRpZW50cyBhcyBhIHJlc3VsdCBvZiB0aGUgc2FtZSBjb25kaXRpb25zLCB5aWVsZGluZyBpbmZvcm1hdGlvbiBvbiB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvIHBhdGllbnQgZ3JvdXAncyBiaW9sb2dpY2FsIHJlc3BvbnNlcyB0byB0aGUgdGhlcmFweS4KCiMgVmlzdWFsaXppbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzCgpXZSdsbCBjcmVhdGUgYSB2b2xjYW5vIHBsb3Qgb2YgdGhlIGdlbmVzIHVzaW5nIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBzdGF0aXN0aWNzIGNhbGN1bGF0ZWQgYmV0d2VlbiB0aGUgUiBhbmQgTlIgZ3JvdXBzIGF0IFQyLgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQojIGNvbnZlcnQgREUgcmVzdWx0cyB0byBkYXRhIGZyYW1lCmRpZmV4cF9pbmZvIDwtIGFzLmRhdGEuZnJhbWUocmVzcG9uc2VfVDIpCgojIGFkZCBjb2x1bW4gaW5kaWNhdGluZyB3aGV0aGVyIGdlbmVzIGFyZSBzaWduaWZpY2FudGx5IHVwIG9yIGRvd25yZWd1bGF0ZWQKZGlmZXhwX2luZm8kREUgPC0gIm5vIgpkaWZleHBfaW5mbyRERVtkaWZleHBfaW5mbyRsb2cyRm9sZENoYW5nZSA+IDAgJiBkaWZleHBfaW5mbyRwYWRqIDwgMC4wNV0gPC0gInVwIgpkaWZleHBfaW5mbyRERVtkaWZleHBfaW5mbyRsb2cyRm9sZENoYW5nZSA8IDAgJiBkaWZleHBfaW5mbyRwYWRqIDwgMC4wNV0gPC0gImRvd24iCgojIGdlbmVyYXRlIHZvbGNhbm8gcGxvdCwgLWxvZzEwIG9mIGFkanVzdGVkIHAtdmFsIHZzIGxvZzIgb2YgRkMKZ2dwbG90Mjo6Z2dwbG90KGRhdGEgPSBkaWZleHBfaW5mbywgbWFwcGluZyA9IGFlcyh4ID0gbG9nMkZvbGRDaGFuZ2UsIHkgPSAtbG9nMTAocGFkaiksIGNvbCA9IERFKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgY29sID0gImJsYWNrIiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJncmV5IiwgInJlZCIpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJEb3ducmVndWxhdGVkIGluIFIgZ3JvdXAiLCAiTm90IERFIiwgIlVwcmVndWxhdGVkIGluIFIgZ3JvdXAiKSkgKwogIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIAogICAgICAgeCA9ICJsb2cgMiBmb2xkIGNoYW5nZSIsCiAgICAgICB5ID0gImxvZyAxMCBjb3JyZWN0ZWQgcC12YWx1ZSIsCiAgICAgICB0aXRsZSA9ICJFeHByZXNzaW9uIG9mIGdlbmVzIGluIFIgdnMuIE5SIHNhbXBsZXMgYXQgVDIiKQoKYGBgCjxjZW50ZXI+CgoqKkZpZ3VyZSAzOioqIEZEUi1jb3JyZWN0ZWQgcC12YWx1ZSAoLWxvZzEwKSB2cy4gZm9sZCBjaGFuZ2UgKGxvZzIpIGluIGV4cHJlc3Npb24gb2YgZ2VuZXMgaW4gd2hvbGUgYmxvb2Qgc2FtcGxlcyBmcm9tIHNlcHRpYyBzaG9jayBwYXRpZW50cyB3aG8gcmVzcG9uZGVkIHRvIGVhcmx5IHN1cHBvcnRpdmUgaGVtb2R5bmFtaWMgdGhlcmFweSAoUiBzYW1wbGVzKSBhbmQgcGF0aWVudHMgd2hvIGRpZCBub3QgcmVzcG9uZCAoTlIpLCB0YWtlbiA0OCBob3VycyBhZnRlciB0cmVhdG1lbnQuIFRocmVzaG9sZCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2FzIGNvcnJlY3RlZCBwLXZhbHVlIDwgMC4wNS4KCjwvY2VudGVyPgoKTmV4dCwgd2UnbGwgY3JlYXRlIGEgaGVhdG1hcCBvZiB0aGUgZ2VuZXMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gdGhlIFIgYW5kIE5SIGdyb3VwcyBhdCBUMiwgYW5kIHNlZSBob3cgdGhleSBjbHVzdGVyIGFjY29yZGluZyB0byBzYW1wbGUgY29uZGl0aW9ucy4KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KIyB1c2Ugbm9ybWFsaXplZCBjb3VudHMgZm9yIGhlYXRtYXAgbWF0cml4LCBmaWx0ZXIgZm9yIERFIGdlbmVzCm5vcm1jb3VudHNfaGVhdG1hcCA8LSBub3JtX2NvdW50c1tyb3duYW1lcyhub3JtX2NvdW50cykgJWluJSByb3duYW1lcyhzaWdfVDIpLF0KCiMgbm9ybWFsaXplIHJvd3MKbm9ybWNvdW50c19oZWF0bWFwIDwtIHQoc2NhbGUodChub3JtY291bnRzX2hlYXRtYXApKSkKCiMgc2V0IGNvbG91cnMgdG8gc2NhbGUgZnJvbSBibHVlIGF0IG1pbiB2YWx1ZXMgdG8gd2hpdGUgYXQgMCB0byByZWQgYXQgbWF4IHZhbHVlcwpoZWF0bWFwX2NvbCA9IGNpcmNsaXplOjpjb2xvclJhbXAyKGMobWluKG5vcm1jb3VudHNfaGVhdG1hcCksIDAsIG1heChub3JtY291bnRzX2hlYXRtYXApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQoKIyBzZXQgY29sb3VycyB0byBjb3JyZXNwb25kIHRvIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zCmdyb3VwX2NvbG91cnMgPC0gcmFpbmJvdyhuID0gNCkKbmFtZXMoZ3JvdXBfY29sb3VycykgPC0gdW5pcXVlKHNhbXBsZV9tZXRhZGF0YSRncm91cCkKCiMgYWRkIGFubm90YXRpb24gd2l0aCBleHBlcmltZW50YWwgY29uZGl0aW9ucyBhbmQgY29ycmVzcG9uZGluZyBjb2xvdXJzCmhhbm5vdCA8LSBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcEFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKAogIEdyb3VwID0gc2FtcGxlX21ldGFkYXRhJGdyb3VwKSwKICBjb2wgPSBsaXN0KAogICAgR3JvdXAgPSBncm91cF9jb2xvdXJzCiAgKSwKc2hvd19sZWdlbmQgPSBUUlVFKQoKIyBnZW5lcmF0ZSBoZWF0bWFwCkRFX2hlYXRtYXAgPC0gQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAobm9ybWNvdW50c19oZWF0bWFwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBoZWF0bWFwX2NvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBoYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICJHZW5lcyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgaW4gUiB2cy4gTlIgZ3JvdXBzIGF0IFQxIikKCkRFX2hlYXRtYXAKYGBgCjxjZW50ZXI+CgoqKkZpZ3VyZSA0OioqIEhlYXRtYXAgb2YgZ2VuZXMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIHNlcHRpYyBzaG9jayBwYXRpZW50cyB3aG8gcmVzcG9uZGVkIHRvIGhlbW9keW5hbWljIHRoZXJhcHkgYW5kIHBhdGllbnRzIHdobyBkaWQgbm90IHJlc3BvbmQgNDggaG91cnMgYWZ0ZXIgdHJlYXRtZW50IChncm91cHMgUl9UMiBhbmQgTlJfVDIsIHJlc3BlY3RpdmVseSkuIEJsdWUgZGVub3RlcyBsb3cgZ2VuZSBleHByZXNzaW9uIGFuZCByZWQgZGVub3RlcyBoaWdoIGdlbmUgZXhwcmVzc2lvbi4KCjwvY2VudGVyPgoKVGhlIFJfVDIgYW5kIE5SX1QyIHNhbXBsZXMgbGFyZ2VseSBjbHVzdGVyZWQgYXBhcnQgZnJvbSBlYWNoIG90aGVyLCB3aGlsZSB0aGUgUl9UMSBhbmQgTlJfVDEgc2FtcGxlcyBhcmUgbm90LiBUaGlzIGlzIGFzIGV4cGVjdGVkLCBzaW5jZSB0aGUgZ2VuZXMgYmVpbmcgcGxvdHRlZCBhcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gUiBhbmQgTlIgYXQgVDIsIHdoaWxlIG5vIGdlbmVzIGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiBSIGFuZCBOUiBhdCBUMS4gVGhlcmUgaXMgYWxzbyBzaWduaWZpY2FudCBzZXBhcmF0aW9uIGJldHdlZW4gdGhlIFQxIGFuZCBUMiBncm91cHMgZm9yIFIsIGJ1dCBub3QgZm9yIE5SLCBpbmRpY2F0aW5nIHRoYXQgbWFueSBvZiB0aGVzZSBnZW5lcyBjaGFuZ2UgaW4gZXhwcmVzc2lvbiBpbiByZXNwb25kZXJzIG92ZXIgdGhlIDQ4IGhvdXJzIGFmdGVyIGhlbW9keW5hbWljIHRoZXJhcHksIGJ1dCBub3QgaW4gbm9uLXJlc3BvbmRlcnMuCgojIEludGVycHJldGF0aW9uIGFuZCBkb2N1bWVudGF0aW9uCiogVGhpcyBkYXRhc2V0IHdhcyBvZiBpbnRlcmVzdCBiZWNhdXNlIHRoZSBkaXN0aW5jdCBjb25kaXRpb25zIHdpdGhpbiBpdCBhcmUgbm90IGEgcmVzdWx0IG9mIGRpZmZlcmVudGlhbCB0cmVhdG1lbnQgb3IgY2lyY3Vtc3RhbmNlcywgYnV0IG9mIGRpZmZlcmVudGlhbCBiaW9sb2dpY2FsIHJlc3BvbnNlIHRvIGEgdHJlYXRtZW50LCBhbmQgdGhlIGluY2x1c2lvbiBvZiB0d28gZGlmZmVyZW50IHRpbWUgcG9pbnRzIG1lYW5zIHRoYXQgdGhlIGRhdGFzZXQgY2FuIGJlIHVzZWQgdG8gYW5hbHl6ZSBob3cgcHJlLWV4aXN0aW5nIGJpb2xvZ2ljYWwgZGlmZmVyZW5jZXMgbGVhZCB0byBkaWZmZXJlbnQgZXBpZ2VuZXRpYyByZXNwb25zZXMuCgoqIEluIHRoaXMgZGF0YXNldCwgdGhlIGNvbnRyb2wgY29uZGl0aW9uIGlzIHBhdGllbnRzIHdobyB3ZXJlIG5vbi1yZXNwb25kZXJzIHRvIGVhcmx5IHN1cHBvcnRpdmUgaGVtb2R5bmFtaWMgdGhlcmFweSBhcyB0cmVhdG1lbnQgZm9yIHNlcHRpYyBzaG9jayBhbmQgdGhlIHRlc3QgY29uZGl0aW9uIGlzIHBhdGllbnRzIHdobyB3ZXJlIHJlc3BvbmRlcnMuIFNhbXBsZXMgY29sbGVjdGVkIGF0IElDVSBhZG1pc3Npb24gYWxzbyBzZXJ2ZSBhcyBhIGNvbnRyb2wgZm9yIHNhbXBsZXMgY29sbGVjdGVkIDQ4aCBsYXRlci4KCiogVGhlcmUgYXJlIDM0IHNhbXBsZXMgZnJvbSByZXNwb25kZXJzIGFuZCAyOCBzYW1wbGVzIGZyb20gbm9uIHJlc3BvbmRlcnMuIFRoZXJlIGFyZSAzMiBzYW1wbGVzIHRha2VuIGF0IHRpbWUgcG9pbnQgMSBhbmQgMzIgc2FtcGxlIHN0YWtlbiBhdCB0aW1lIHBvaW50IDIuCgoqIFRoZXJlIHdlcmUgZXhwcmVzc2lvbiB2YWx1ZXMgdGhhdCB3ZXJlIG5vdCB1bmlxdWUgZm9yIHNwZWNpZmljIGdlbmVzLCBidXQgdGhleSB3ZXJlIGEgdmVyeSBzbWFsbCBwcm9wb3J0aW9uIG9mIHRoZSBkYXRhLiBXaGVuIG11bHRpcGxlIGV4cHJlc3Npb24gdmFsdWVzIG1hcHBlZCB0byBvbmUgZ2VuZSwgd2UgdXNlZCB0aGVpciBzdW0gYXMgdGhlIGV4cHJlc3Npb24gdmFsdWUgZm9yIHRoYXQgZ2VuZS4gV2hlbiBhbiBleHByZXNzaW9uIHZhbHVlIG1hcHBlZCB0byBtdWx0aXBsZSBnZW5lcywgd2UgZHVwbGljYXRlZCBpdCBhbmQgdXNlZCBpdCBhcyB0aGUgZXhwcmVzc2lvbiB2YWx1ZSBmb3IgZWFjaCBnZW5lIGl0IG1hcHBlZCB0by4gU2luY2UgdGhlcmUgd2VyZSB2ZXJ5IGZldyBzdWNoIGNhc2VzLCB0aGUgaW1wYWN0IG9mIHRoaXMgdHJhbnNmb3JtYXRpb24gb24gbGlicmFyeSBzaXplIHdhcyBuZWdsaWdpYmxlLiAKCiogQSBsYXJnZSBwcm9wb3J0aW9uIG9mIHRoZSBleHByZXNzaW9uIHZhbHVlcyBjb3VsZCBub3QgYmUgbWFwcGVkIHRvIEhVR08gc3ltYm9scywgYnV0IG1vc3Qgb2YgdGhlIHVubWFwcGVkIHZhbHVlcyB3ZXJlIHZlcnkgbG93LCBhbmQgd2VyZSByZW1vdmVkIHdoZW4gZmlsdGVyaW5nIG91dCBsb3cgZXhwcmVzc2lvbiBnZW5lcy4gCgoqIFRoZXJlIHdlcmUgbm8gb3V0bGllcnMgaW4gdGhlIGRhdGFzZXQsIGFjY29yZGluZyB0byB0aGUgdGhyZXNob2xkIG9uIENvb2sncyBkaXN0YW5jZSBhcHBsaWVkIGJ5IERFU2VxMi4gCgoqIEJpb2xvZ2ljYWwgcmVwbGljYXRlcyB3ZXJlIGdyb3VwZWQgdG9nZXRoZXIgaW4gdGhlIGRlc2lnbiBtb2RlbCB1c2VkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcy4gVGhlcmUgd2VyZSBubyB0ZWNobmljYWwgcmVwbGljYXRlcy4KCiogVGhlIGRhdGFzZXQgY292ZXJzIDEzNjczIGdlbmVzIGFjcm9zcyA2MiBzYW1wbGVzLgoKIyBCaWJsaW9ncmFwaHkK