Independent
Filtering
Independent filtering is a strategy to remove features (in this case,
genes) prior to the analysis. Removal of these features may lower the
multiple testing correction for other genes that pass the filter. We try
to remove genes that have a low power to be found statistically
significant, and/or that are biologically less relevant. A common
filtering strategy is to remove genes with a generally low expression,
as low counts have lower relative uncertainty (hence lower statistical
power), and may be considered biologically less relevant.
Implementation in edgeR.
## No documentation for 'filterByExpr' in specified packages and libraries
suppressPackageStartupMessages({
library(limma)
library(edgeR)
library(DESeq2)
})
dds <- makeExampleDESeqDataSet()
simCounts <-counts(dds)
group <- dds$condition
dge <- edgeR::DGEList(simCounts)
design <- model.matrix(~group)
keep <- filterByExpr(dge, design)
table(keep)
lib.size <- dge$samples$lib.size * dge$samples$norm.factors
cpmMinCount <- 10/median(lib.size)*1e6
summary(group)
## A B
## 6 6
minSampSize <- min(summary(group))
minSampSize
## [1] 6
keep <- rowSums(cpm(dge) > cpmMinCount) >= minSampSize
table(keep)
leverage <- design%*% solve(t(design)%*%design)%*%t(design) %>%diag()
1/leverage
## 1 2 3 4 5 6 7 8 9 10 11 12
## 6 6 6 6 6 6 6 6 6 6 6 6
## [1] 6
Independent filtering has been formalized by Bourgon et al.
(2010).
The concept of independent filtering can be summarized as
follows:
- For each feature we calculate two statistics, \(S_F\) and \(S_T\), respectively used for two stages:
filtering and testing (e.g., differential expression).
- In order for a feature to be deemed significant, both of its
statistics must be greater than some cut-off.
- We want to control the type I error rate of the second stage
(testing). But note that the second stage is conditional on the
first stage, as we only test features passing the filter, and
basically ignore the fact that filtering was performed. Indeed, one
criticism is that computing and correcting the \(p\)-values as if filtering had not been
performed may lead to overoptimistic adjusted \(p\)-values.
- Bourgon et
al. (2010) show that filtering is only appropriate (i.e., does
not inflate type I error rate) if the conditional null distribution of
test statistics for features passing the filter is the same as the
unconditional null distribution. Therefore, filtering is
appropriate if the statistic used for filtering is independent of the
statistic used for testing under the null hypothesis.
Let’s try a couple of examples to get some intuition using simulated
data.
suppressPackageStartupMessages(library(DESeq2))
set.seed(24)
dds <- DESeq2::makeExampleDESeqDataSet()
simCounts <- counts(dds)
group <- dds$condition
A Dependent Test
Statistic
filterStatEffectSize <- abs(rowMeans(simCounts[,group == "A"]) - rowMeans(simCounts[,group == "B"]))
testStat <- genefilter::rowttests(simCounts, group)
## unconditional distribution
plot(density(testStat$statistic, na.rm=TRUE),
xlab = "Test statistic",
main = "Unconditional distribution")
## conditional distribution: very different!
mean(filterStatEffectSize > 1)
## [1] 0.792
hist(filterStatEffectSize, breaks=40)
abline(v=1, col="red")
keepEffectSize <- filterStatEffectSize > 1
plot(density(testStat$statistic[keepEffectSize], na.rm=TRUE),
xlab = "Test statistic",
main = "Conditional distribution")
An Independent Test
Statistic
filterStatGlobalMean <- rowMeans(simCounts)
mean(filterStatGlobalMean > 5) # we remove a similar fraction
## [1] 0.771
keepGlobalMean <- filterStatGlobalMean > 5
## unconditional distribution
plot(density(testStat$statistic, na.rm=TRUE),
xlab = "Test statistic",
main = "Unconditional distribution")
## conditional distribution: the same.
plot(density(testStat$statistic[keepGlobalMean], na.rm=TRUE),
xlab = "Test statistic",
main = "Conditional distribution")
Normalization
Normalization is necessary to correct for several sources of
technical variation:
- Differences in sequencing depth between samples.
Some samples get sequenced deeper in the sense that they consist of more
(mapped) reads and therefore can be considered to contain a higher
amount of information, which we should be taking into account. In
addition, if a sample is sequenced deeper, it is natural that the counts
for each gene will be higher, jeopardizing a direct comparison of the
expression counts.
- Differences in RNA population composition between
samples. As an extreme example, suppose that two samples have been
sequenced to the exact same depth. One sample is contaminated and has a
very high concentration of the contaminant cDNA being sequenced, but
otherwise the two samples are identical. Since the contaminant will be
taking up a significant proportion of the reads being sequenced, the
counts will not be directly comparable between the samples. Hence, we
may also want to correct for differences in the composition of the RNA
population of the samples.
- Other technical variation such as sample-specific
GC-content or transcript length effects may also be accounted for.
data("parathyroidGenesSE", package="parathyroidSE")
se1 <- parathyroidGenesSE
rm(parathyroidGenesSE)
colData(se1) %>%
as.data.frame() %>%
filter(duplicated(experiment))
SRR479061 |
SRX140511 |
2 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308873 |
SRR479064 |
SRX140513 |
2 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308875 |
SRR479075 |
SRX140523 |
4 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308885 |
SRR479078 |
SRX140525 |
4 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308887 |
There are technical repeats in the data.
We mentioned previous lectures that we can sum over technical
repeats, because techical repeats are Poisson and the sum of two Poisson
variables is again Poisson.
dupExps <- colData(se1) %>%
as.data.frame() %>%
filter(duplicated(experiment)) %>%
pull(experiment)
counts <- assays(se1)$counts
newCounts <- counts
cd <- colData(se1)
for(ss in 1:length(dupExps)){
# check which samples are duplicates
relevantId <- which(colData(se1)$experiment == dupExps[ss])
# sum counts
newCounts[,relevantId[1]] <- rowSums(counts[,relevantId])
# keep which columns / rows to remove.
if(ss == 1){
toRemove <- relevantId[2]
} else {
toRemove <- c(toRemove, relevantId[2])
}
}
# remove after summing counts (otherwise IDs get mixed up)
newCounts <- newCounts[,-toRemove]
newCD <- cd[-toRemove,]
# Create new SummarizedExperiment
se <- SummarizedExperiment(assays = list("counts" = newCounts),
colData = newCD,
metadata = metadata(se1))
treatment <- colData(se)$treatment
table(treatment)
qplot(colSums(assays(se)$counts)/1e6, geom="histogram", bins=10,col="black") +
theme(legend.position = "none") +
xlab("libsize (million reads)")
qplot(
colData(se)$treatment:colData(se)$time,
colSums(assays(se)$counts)/1e6,geom="boxplot"
) +
xlab("treatment")+
ylab("libsize (million reads)")
qplot(
colData(se)$patient,
colSums(assays(se)$counts)/1e6,geom="boxplot"
) +
xlab("Patient")+
ylab("libsize (million reads)")
ma2Samp <- function(countMx,libSize=NULL) {
stopifnot("`countMx` is not a matrix with two columns" = ncol(countMx) == 2)
A <- countMx %>% log2 %>% rowMeans
if(is.null(libSize))
M <- countMx %>% log2 %>% apply(.,1,diff)
else
M <- countMx %>% log2 %>% apply(.,1,diff) - libSize %>% log2 %>% diff
w <- countMx[,1]==min(countMx[,1]) | countMx[,2]==min(countMx[,2])
if (any(w)) {
A[w] <- runif(sum(w), min = -1, max = .1)
M[w] <- log2(countMx[w,2] + 1) - log2(countMx[w,1] + 1)
}
MAplot <- qplot(A, M, col=w) +
theme(legend.position = "none") +
scale_color_manual(values = c("black","orange")) +
xlab("A: log2 Average") +
ylab("M: log2 Fold Change")
MAplot +
geom_abline(intercept=0,slope=0,col="blue") +
geom_abline(intercept=median(M[!w],na.rm=TRUE),slope=0,col="red")
}
Let’s take a look at how comparable different replicates are in the
Control condition at 48h in our dataset. We will investigate this using
MD-plots (mean-difference plots as introduced by Dudoit et al. (2002)),
also sometimes referred to as MA-plots.
ids <- which(colData(se)$treatment =="Control" & colData(se)$time == "48h")
ids
## [1] 2 8 14 19
colSums(assays(se)$counts[,ids]) / 1e6
## [1] 10.827109 6.844144 8.064268 7.701432
pairComb <- combn(
ids,
m=2)
plots <- apply(pairComb,2,function(x) ma2Samp(assay(se)[,x]) + ggtitle(paste("samples",x[2],"vs", x[1])))
do.call("grid.arrange",c(plots,ncol=3))
We see clear bias for some pairwise comparisons. For example, in the
first plot comparing sample 8 versus sample 2, the log fold-changes are
biased downwards. This means that, on average, a gene is lower expressed
in sample 8 versus sample 2. Looking at the library sizes, we can indeed
see that the library size for sample 2 is about \(11×10^6\) while it is only about \(7×10^6\) for sample 8! This is a clear
library size effect that we should take into account.
We can solve these issues by introducing offsets in our model.
\[
\left\{
\begin{array}{ccc}
Y_{gi} & \sim & Poi(\mu_{gi}) \\
\log \mu_{gi} & = & \eta_{gi} \\
\eta_{gi} & = & \mathbf{X}^T_i \beta_g + log(O_{gi}) \\
\end{array}
\right.
\]
libSize <- colSums(assay(se))
plots2 <- apply(pairComb,2,function(x) ma2Samp(assay(se)[,x],libSize = libSize[x]) + ggtitle(paste("samples",x[2],"vs", x[1])))
do.call("grid.arrange",c(plots2,ncol=3))
TMM method (default
of edgeR
)
Robinson
and Oshlack (2010). Genome Biology
knitr::include_graphics("./figs/edgeRNormIntro.png")
- On the plot we see a clear effect on all genes
- Correcting for library size tends to over correct.
- Some DE genes are highly abundant and determine the library size to
a large extend
The trimmed mean of M-values (TMM) method introduced by Robinson
& Oshlack (2010) is a normalization procedure that calculates a
single normalization factor for each sample. As the name suggests, it is
based on a trimmed mean of fold-changes (\(M\)-values) as the scaling factor. A
trimmed mean is an average after removing a set of ``extreme’’ values.
Specifically, TMM calculates a normalization factor \(F_i^{(r)}\) across genes \(g\) for each sample \(i\) as compared to a reference sample \(r\), \[
\log_2(F_i^{(r)}) = \frac{\sum_{g \in {\cal G}^*} w_{gi}^r
M_{gi}^r}{\sum_{g \in {\cal G}^*} w_{gi}^r},
\] where \(M_{gi}^r\) represents
the \(\log_2\)-fold-change of the gene
expression fraction as compared to a reference sample \(r\), i.e., \[
M_{gi}^r = \log_2\left( \frac{Y_{gi} / N_i}{ Y_{gr} / N_r} \right),
\] and \(w_{gi}^r\) represents a
precision weight calculated as \[
w_{gi}^r = \frac{N_i - Y_{gi}}{N_i Y_{gi}} + \frac{N_r - Y_{gr}}{N_r
Y_{gr}},
\] and \({\cal G}^*\) represents
the set of genes after trimming those with the most extreme average
expression. The weights serve to account for the fact that fold-changes
for genes with lower read counts are more variable.
The procedure only takes genes into account where both \(Y_{gi}>0\) and \(Y_{gr}>0\). By default, TMM trims genes
with the \(30\%\) most extreme \(M\)-values and \(5\%\) most extreme average gene expression,
and chooses as reference \(r\) the
sample whose upper-quartile is closest to the across-sample average
upper-quartile. The normalized counts are then given by \(\tilde{Y}_{gi} = Y_{gi} / N_i^s\), where
\[N_i^s = \frac{N_i F_i^{(r)}}{\sum_{i=1}^n
N_i F_i^{(r)}/n}.\]
TMM normalization may be performed from the
calcNormFactors
function implemented in
edgeR
:
dge <- edgeR::calcNormFactors(se)
dge$samples #normalization factors added to colData
Sample1 |
1 |
9102683 |
0.9782830 |
SRR479052 |
SRX140503 |
1 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308865 |
Sample2 |
1 |
10827109 |
0.9728700 |
SRR479053 |
SRX140504 |
1 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308866 |
Sample3 |
1 |
5217761 |
0.9898593 |
SRR479054 |
SRX140505 |
1 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308867 |
Sample4 |
1 |
9706035 |
0.9930169 |
SRR479055 |
SRX140506 |
1 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308868 |
Sample5 |
1 |
5700022 |
0.9850867 |
SRR479056 |
SRX140507 |
1 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308869 |
Sample6 |
1 |
7854568 |
0.9897270 |
SRR479057 |
SRX140508 |
1 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308870 |
Sample7 |
1 |
8610014 |
0.9266581 |
SRR479058 |
SRX140509 |
2 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308871 |
Sample8 |
1 |
6844144 |
0.9544240 |
SRR479059 |
SRX140510 |
2 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308872 |
Sample9 |
1 |
24584280 |
0.9188545 |
SRR479060 |
SRX140511 |
2 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308873 |
Sample10 |
1 |
8267977 |
0.9398000 |
SRR479062 |
SRX140512 |
2 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308874 |
Sample11 |
1 |
23590411 |
0.9096695 |
SRR479063 |
SRX140513 |
2 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308875 |
Sample12 |
1 |
8247122 |
0.9369050 |
SRR479065 |
SRX140514 |
2 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308876 |
Sample13 |
1 |
7341000 |
1.0668032 |
SRR479066 |
SRX140515 |
3 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308877 |
Sample14 |
1 |
8064268 |
1.0552688 |
SRR479067 |
SRX140516 |
3 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308878 |
Sample15 |
1 |
12481958 |
1.0461698 |
SRR479068 |
SRX140517 |
3 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308879 |
Sample16 |
1 |
16310090 |
1.0260056 |
SRR479069 |
SRX140518 |
3 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308880 |
Sample17 |
1 |
23697329 |
1.0268459 |
SRR479070 |
SRX140519 |
3 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308881 |
Sample18 |
1 |
7642648 |
1.0409451 |
SRR479071 |
SRX140520 |
3 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308882 |
Sample19 |
1 |
7701432 |
1.0559132 |
SRR479072 |
SRX140521 |
4 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308883 |
Sample20 |
1 |
7135899 |
1.0675040 |
SRR479073 |
SRX140522 |
4 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308884 |
Sample21 |
1 |
13818393 |
1.0327004 |
SRR479074 |
SRX140523 |
4 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308885 |
Sample22 |
1 |
6099942 |
1.0890994 |
SRR479076 |
SRX140524 |
4 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308886 |
Sample23 |
1 |
15825211 |
1.0286470 |
SRR479077 |
SRX140525 |
4 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308887 |
Let’s check how our MD-plots look like after normalization. Note
that, we can rewrite the GLM as \[ \log\left(
\frac{\mu_{gi}}{N_i^s} \right) = \mathbf{X}_i^T \beta_g \] and so
\(\frac{\mu_{gi}}{N_i^s}\) can be
considered as an ‘offset-corrected count’.
We see that all MD-plots are now nicely centered around a
log-fold-change of zero!
## normalize
effLibSize <- dge$samples$lib.size * dge$samples$norm.factors
#normCountTMM <- sweep(assays(se)$counts, 2, FUN="/", effLibSize)
plotsNorm <- apply(pairComb,2,function(x)
ma2Samp(assays(se)$counts[,x], effLibSize[x]) + ggtitle(paste("samples",x[2],"vs", x[1])))
do.call("grid.arrange",c(plotsNorm,ncol=3))
Aliasing
Suppose we are working with the following experimental design on
colon cancer. Studying the effect of a drug on gene expression,
researchers gather RNA-seq data from four colon cancer patients and four
healthy individuals. For each individual, they obtain RNA-seq data from
a blood sample before as well as two weeks after taking a daily dose of
the drug. The research question relates to differential expression after
vs. before taking the drug, in particular whether this is different for
the diseased versus healthy group (i.e., the interaction between time
(before/after taking the drug) and disease status (healthy/colon
cancer)).
In terms of the model matrix, we could imagine a design such as
~ patient + disease*time
, where
disease
is a binary indicator referring to colon cancer
versus control sample.
time
defines if the sample is taken before or after
taking the drug.
patient
defines the individual donor the sample comes
from.
The research question could then amount to testing the
disease * time
interaction.
Let’s try this, by simulating random data for one gene.
set.seed(2)
# 2 samples per patient for 8 patients
patient <- factor(rep(letters[1:8], each=2))
# first four are healthy, next four are diseased
disease <- factor(c(rep("healthy",8), rep("cancer",8)), levels=c("healthy", "cancer"))
# one before and one after sample for each
time <- factor(rep(c("before", "after"), 8), levels=c("before", "after"))
table(patient, disease, time)
a |
cancer |
after |
0 |
|
|
before |
0 |
|
healthy |
after |
1 |
|
|
before |
1 |
b |
cancer |
after |
0 |
|
|
before |
0 |
|
healthy |
after |
1 |
|
|
before |
1 |
c |
cancer |
after |
0 |
|
|
before |
0 |
|
healthy |
after |
1 |
|
|
before |
1 |
d |
cancer |
after |
0 |
|
|
before |
0 |
|
healthy |
after |
1 |
|
|
before |
1 |
e |
cancer |
after |
1 |
|
|
before |
1 |
|
healthy |
after |
0 |
|
|
before |
0 |
f |
cancer |
after |
1 |
|
|
before |
1 |
|
healthy |
after |
0 |
|
|
before |
0 |
g |
cancer |
after |
1 |
|
|
before |
1 |
|
healthy |
after |
0 |
|
|
before |
0 |
h |
cancer |
after |
1 |
|
|
before |
1 |
|
healthy |
after |
0 |
|
|
before |
0 |
## simulate data for one gene
n <- 16
y <- rpois(n = n, lambda = 50)
## fit a Poisson model
m <- glm(y ~ patient + disease*time,
family = "poisson")
summary(m)
##
## Call:
## glm(formula = y ~ patient + disease * time, family = "poisson")
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.76900 0.11916 31.631 <2e-16 ***
## patientb 0.06744 0.14999 0.450 0.6530
## patientc 0.06744 0.14999 0.450 0.6530
## patientd 0.27304 0.14310 1.908 0.0564 .
## patiente 0.16449 0.16224 1.014 0.3107
## patientf 0.02565 0.16644 0.154 0.8775
## patientg -0.01784 0.16785 -0.106 0.9154
## patienth 0.05706 0.16544 0.345 0.7302
## diseasecancer NA NA NA NA
## timeafter -0.01567 0.10220 -0.153 0.8782
## diseasecancer:timeafter 0.12374 0.14407 0.859 0.3904
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 16.1200 on 15 degrees of freedom
## Residual deviance: 8.8417 on 6 degrees of freedom
## AIC: 120.16
##
## Number of Fisher Scoring iterations: 4
We find that one of the coefficients is NA
! This is
obviously not because we’re dealing with NA
values in the
data as we’ve just simulated the response variable ourselves. What’s
going on?
One of the parameters, in this case the parameter distinguishing
cancer from healthy patients cannot be estimated as it is a
linear combination of other parameters. In our case, estimating
the diseased effect would use information that is already used to
estimate the patient-level intercepts. In other words, once you
know the patient, you immediately also know the disease status,
so estimating the diseased vs healthy effect on top of the patient
effect provides no additional information if we have already estimated
the patient-level effects. This concept is called aliasing, and is a
common technical issue in ’omics experiments with complex experimental
designs.
While to understand the origin of the aliasing it is crucial to
understand the relationship between the variables in the experimental
design, we can also investigate it in detail using the
alias
function, to give us an idea.
## Model :
## y ~ patient + disease * time
##
## Complete :
## (Intercept) patientb patientc patientd patiente patientf patientg
## diseasecancer 0 0 0 0 1 1 1
## patienth timeafter diseasecancer:timeafter
## diseasecancer 1 0 0
We see that the effect diseasecancer
is a linear
combination of the patient-specific effects of the cancer patients. This
makes sense!
For clarity, let’s reproduce this using our design matrix.
X <- model.matrix(~ patient + disease*time) # this is the design used in glm()
## these are indeed identical.
X[,"diseasecancer"]
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
## 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
X[,"patiente"] + X[,"patientf"] + X[,"patientg"] + X[,"patienth"]
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
## 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
Since one of our parameters is a linear combination of other
parameters, it cannot be estimated simultaneously with the other
parameters. In this case, we can actually drop the disease
main effect from the model, since we know that it is already included in
the patient
effect.
We will have to carefully construct our design matrix in order to
account for all important sources of variation while still allowing us
to answer the research question of interest. The aliasing exploration
above has made it clear we may drop the disease
main
effect, so let’s start by constructing this design matrix.
X <- model.matrix(~ patient + time + disease:time)
m2 <- glm(y ~ -1 + X,
family = "poisson")
summary(m2)
##
## Call:
## glm(formula = y ~ -1 + X, family = "poisson")
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error z value Pr(>|z|)
## X(Intercept) 3.76900 0.11916 31.631 <2e-16 ***
## Xpatientb 0.06744 0.14999 0.450 0.6530
## Xpatientc 0.06744 0.14999 0.450 0.6530
## Xpatientd 0.27304 0.14310 1.908 0.0564 .
## Xpatiente 0.28823 0.16077 1.793 0.0730 .
## Xpatientf 0.14939 0.16500 0.905 0.3653
## Xpatientg 0.10590 0.16643 0.636 0.5246
## Xpatienth 0.18081 0.16400 1.102 0.2703
## Xtimeafter -0.01567 0.10220 -0.153 0.8782
## Xtimebefore:diseasecancer -0.12374 0.14407 -0.859 0.3904
## Xtimeafter:diseasecancer NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 4489.2752 on 16 degrees of freedom
## Residual deviance: 8.8417 on 6 degrees of freedom
## AIC: 120.16
##
## Number of Fisher Scoring iterations: 4
## Model :
## y ~ -1 + X
##
## Complete :
## X(Intercept) Xpatientb Xpatientc Xpatientd Xpatiente
## Xtimeafter:diseasecancer 0 0 0 0 1
## Xpatientf Xpatientg Xpatienth Xtimeafter
## Xtimeafter:diseasecancer 1 1 1 0
## Xtimebefore:diseasecancer
## Xtimeafter:diseasecancer -1
We are still confronted with aliasing as the model matrix contains an
interaction effect timebefore:diseasecancer
as well as
timeafter:diseasecancer
, while only the latter is relevant.
Indeed, we know that we can derive the
timebefore:diseasecancer
effect by averaging the patient
effects of the cancer patients.
X <- X[,!colnames(X) %in% "timebefore:diseasecancer"]
## fit a Poisson model
m2 <- glm(y ~ -1 + X,
family = "poisson")
summary(m2)
##
## Call:
## glm(formula = y ~ -1 + X, family = "poisson")
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## X(Intercept) 3.76900 0.11916 31.631 <2e-16 ***
## Xpatientb 0.06744 0.14999 0.450 0.6530
## Xpatientc 0.06744 0.14999 0.450 0.6530
## Xpatientd 0.27304 0.14310 1.908 0.0564 .
## Xpatiente 0.16449 0.16224 1.014 0.3107
## Xpatientf 0.02565 0.16644 0.154 0.8775
## Xpatientg -0.01784 0.16785 -0.106 0.9154
## Xpatienth 0.05706 0.16544 0.345 0.7302
## Xtimeafter -0.01567 0.10220 -0.153 0.8782
## Xtimeafter:diseasecancer 0.12374 0.14407 0.859 0.3904
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 4489.2752 on 16 degrees of freedom
## Residual deviance: 8.8417 on 6 degrees of freedom
## AIC: 120.16
##
## Number of Fisher Scoring iterations: 4
We see that all coefficients can now be estimated. The
timeafter
effect may be interpreted as the time effect for
healthy patients, while the timeafter:diseasecancer
effect
may be interpreted as the difference in the time effect for cancer
patients as compared to healthy patients, i.e., it is the relevant
interaction effect we are interested in.
LS0tCnRpdGxlOiAnU2VxdWVuY2luZzogU2VsZWN0ZWQgdGVjaG5pY2FsIHRvcGljcycKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQgJiBLb2VuIFZhbiBkZW4gQmVyZ2UiCmRhdGU6ICJMYXN0IGVkaXRlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4CmFsd2F5c19hbGxvd19odG1sOiB0cnVlCmxpbmtjb2xvcjogYmx1ZQp1cmxjb2xvcjogYmx1ZSAKY2l0ZWNvbG9yOiBibHVlCmxpbmstY2l0YXRpb25zOiB5ZXMKCi0tLQoKYGBge3IgZnVuY3Rpb25zLCBpbmNsdWRlPUZBTFNFfQojIEEgZnVuY3Rpb24gZm9yIGNhcHRpb25pbmcgYW5kIHJlZmVyZW5jaW5nIGltYWdlcwpmaWcgPC0gbG9jYWwoewogICAgaSA8LSAwCiAgICByZWYgPC0gbGlzdCgpCiAgICBsaXN0KAogICAgICAgIGNhcD1mdW5jdGlvbihyZWZOYW1lLCB0ZXh0KSB7CiAgICAgICAgICAgIGkgPDwtIGkgKyAxCiAgICAgICAgICAgIHJlZltbcmVmTmFtZV1dIDw8LSBpCiAgICAgICAgICAgIHBhc3RlKCJGaWd1cmUgIiwgaSwgIjogIiwgdGV4dCwgc2VwPSIiKQogICAgICAgIH0sCiAgICAgICAgcmVmPWZ1bmN0aW9uKHJlZk5hbWUpIHsKICAgICAgICAgICAgcmVmW1tyZWZOYW1lXV0KICAgICAgICB9KQp9KQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBldmFsPVRSVUV9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeShrbml0cikKICBsaWJyYXJ5KHJtYXJrZG93bikKICBsaWJyYXJ5KGdncGxvdDIpCiAgbGlicmFyeShwcmludHIpCiAgbGlicmFyeShncmlkRXh0cmEpCiAgbGlicmFyeSh0aWR5dmVyc2UpCiAgbGlicmFyeShwbG90bHkpCn0pCmBgYAoKIyBQYXJhbWV0ZXIgRXN0aW1hdGlvbiBhbmQgSW5mZXJlbmNlIGluIEdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMgCgojIyBTaW11bGF0ZSBQb2lzc29uIERhdGEKCi0gV2Ugc2ltdWxhdGUgZGF0YSBmb3IgMTAwIG9ic2VydmF0aW9ucy4KLSBDb3ZhcmlhdGVzIHggYXJlIHNpbXVsYXRlZCBmcm9tIG5vcm1hbCBkaXN0cmlidXRpb24KLSBUaGUgJFxiZXRhJCBhcmUgY2hvc2VuIGF0ICRcYmV0YV8wPTIkLCAkXGJldGFfMT0wLjgkLCAkXGJldGFfMj0xLjIkCgpgYGB7cn0Kc2V0LnNlZWQoMzAwKQp4aGxwPC1jYmluZCgxLHJub3JtKDEwMCkscm5vcm0oMTAwKSkKYmV0YXNUcnVlPC1jKDIsMC44LDEuMikKZXRhVHJ1ZTwteGhscCUqJWJldGFzVHJ1ZQp5PC1ycG9pcygxMDAsZXhwKGV0YVRydWUpKQpkYXRhLmZyYW1lKGNvZWYgPTA6MixiZXRhc1RydWU9YmV0YXNUcnVlKSAlPiUgCiAgZ2dwbG90KGFlcyh4PWNvZWYseT1iZXRhc1RydWUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKCkgKwogIHlsYWIoInBhcmFtZXRlciB2YWx1ZSIpICsKICB4bGFiKCJiZXRhIikgKwogIHlsaW0oMCw0KSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDAsMSwyKSkKCgpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CngxIDwtIHhobHBbLDJdCngyIDwtIHhobHBbLDNdCnAxIDwtIHBsb3RfbHkoCiAgICB4ID0gfngxLAogICAgeSA9IH54MiwKICAgIHo9IH55LAogICAgbW9kZT0ibWFya2VycyIsCiAgICBzaXplPS41KSAlPiUKICBhZGRfbWFya2Vycyh0eXBlPSJzY2F0dGVyM2QiKSAlPiUKICBsYXlvdXQoCiAgICBzY2VuZSA9IGxpc3QoCiAgICAgIGFzcGVjdG1vZGU9ImN1YmUiLAogICAgICB4YXhpcyA9IGxpc3QocmFuZ2U9cmFuZ2UoeGhscFssMl0pKSksIHlheGlzID0gbGlzdChyYW5nZT1yYW5nZSh4aGxwWywzXSkpLCB6YXhpcyA9IGxpc3QocmFuZ2U9cmFuZ2UoeSkpCiAgICAgICkKcDEKYGBgCgpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp4MSA8LSB4aGxwWywyXQp4MiA8LSB4aGxwWywzXQpwMSA8LSBwbG90X2x5KAogICAgeCA9IH54MSwKICAgIHkgPSB+eDIsCiAgICB6PSB+IGxvZzIoeSsuNSksCiAgICBtb2RlPSJtYXJrZXJzIiwKICAgIHNpemU9LjUpICU+JQogIGFkZF9tYXJrZXJzKHR5cGU9InNjYXR0ZXIzZCIpICU+JQogIGxheW91dCgKICAgIHNjZW5lID0gbGlzdCgKICAgICAgYXNwZWN0bW9kZT0iY3ViZSIsCiAgICAgIHhheGlzID0gbGlzdChyYW5nZT1yYW5nZSh4aGxwWywyXSkpKSwgeWF4aXMgPSBsaXN0KHJhbmdlPXJhbmdlKHhobHBbLDNdKSksIHpheGlzID0gbGlzdChyYW5nZT1yYW5nZSh5KSkKICAgICAgKQpwMQpgYGAKCgojIyBFeHBvbmVudGlhbCBGYW1pbHkKCiQkCmYoeV9pXHZlcnQgXHRoZXRhX2ksXHBoaSk9XGV4cFxsZWZ0XHsgXGZyYWN7eV9pXHRoZXRhX2ktIGIoXHRoZXRhX2kpfXthKFxwaGkpfStjKHlfaSxccGhpKVxyaWdodFx9CiQkCgp3aXRoCgotICRcdGhldGFfaSQ6IGNhbm9uaWNhbCBwYXJhbWV0ZXJzCi0gJFxwaGkkOiBkaXNwZXJzaW9uIHBhcmFtZXRlcgotICRhKC4pJCwgJGIoLikkLCAkYyguKSQ6IHNwZWNpZmljIGZ1bmN0aW9ucyB0aGF0IGRlcGVuZCBvbiB0aGUgZGlzdHJpYnV0aW9uLCAKCmUuZy4gZm9yIG5vcm1hbCBkaXN0cmlidXRpb24gCgotICRccGhpPVxzaWdtYV4yJCwgCi0gJFx0aGV0YT1cbXUkLCAKLSAkYShccGhpKT1ccGhpPVxzaWdtYV4yJCwgCi0gJGIoXHRoZXRhX2kpPVx0aGV0YV9pXjIvMiQsIAotICRjKHlfaSxccGhpKT0tXGZyYWN7MX17Mn1beV4yL1xwaGkrXGxvZygyXHBpXHBoaSldJAoKIyMjIFBvaXNzb24gRGlzdHJpYnV0aW9uCgokJAp5X2kgXHNpbSBcZnJhY3tcbXVfaV57eV9pfWVeey1cbXVfaX19e3lfaSF9CiQkCgpJbiBmb3JtYXQgb2YgZXhwb25lbnRpYWwgZmFtaWx5OiAKCiQkCnlfaSBcc2ltIFxleHBcbGVmdFx7eV9pXGxvZyhcbXVfaSkgLSBcbXVfaSAtIFxsb2coeV9pISlccmlnaHRcfQokJAoKIyMgQ29tcG9uZW50cyBvZiBHZW5lcmFsaXplZCBMaW5lYXIgTW9kZWwKCiQkClxsZWZ0XHtcYmVnaW57YXJyYXl9e2NjY30KeV9pXHZlcnQgeF9pJlxzaW0mZih5X2lcdmVydHtcdGhldGF9X2ksXHBoaSlcXFxcClx0ZXh0e0V9XGxlZnRbIHlfaVx2ZXJ0IFxtYXRoYmZ7eH1faVxyaWdodF0mPSZcbXVfaVxcXFwKZyhcbXVfaSkmPSZcZXRhKFxtYXRoYmZ7eH1faSlcXFxcClxldGEoXG1hdGhiZnt4fV9pKSY9JlxtYXRoYmZ7eH1faV5UXGJvbGRzeW1ib2x7XGJldGF9ClxlbmR7YXJyYXl9XHJpZ2h0LiwKJCQKd2l0aCAkZyguKSQgdGhlIGxpbmsgZnVuY3Rpb24sIGUuZy4gCgotICRnKC4pPS4kIDogaWRlbnRpdHkgbGluayBmb3IgTm9ybWFsIGRpc3RyaWJ1dGlvbgotICRnKC4pPVxsb2coLikkIDogY2Fub25pY2FsIGxpbmsgZm9yIFBvaXNzb24gZGlzdHJpYnV0aW9uCi0gJGcoLik9XHRleHR7bG9naXR9KC4pPVxsb2dcbGVmdFtcZnJhY3soLil9eygxLS4pfVxyaWdodF0kIDogY2Fub25pY2FsIGxpbmsgZm9yIEJlcm5vdWlsbGkgZGlzdHJpYnV0aW9uLgoKIyMjIFBvaXNzb24gR0xNCgokJFxsZWZ0XHtcYmVnaW57YXJyYXl9e2xjcn0KeV9pICZcc2ltJiBQb2lzc29uKFxtdV9pKVxcCkVbeV9pXSY9JlxtdV9pXFwKXGxvZyhcbXVfaSkmPSZcZXRhX2lcXApcZXRhX2kmPSZcbWF0aGJme3h9X2lcYm9sZHN5bWJvbHtcYmV0YX0KXGVuZHthcnJheX1ccmlnaHQuJCQKCiMjIExpa2VsaWhvb2QKCldlIHN0YXJ0IGZyb20gYSBzYW1wbGUsIGFuZCBjb25zaWRlciBpdCBhcyBmaXhlZCBhbmQga25vd24uIAoKLSBJbiBwYXJ0aWN1bGFyIHdlIGRvIE5PVCBjb25zaWRlciB0aGUgc2FtcGxlIG9ic2VydmF0aW9ucyBhcyByYW5kb20gdmFyaWFibGVzLiAKCi0gVGhlcmVmb3JlIHdlIHdyaXRlIHRoZSBvYnNlcnZlZCBzYW1wbGUgYXMgJHlfaSwgLiAuIC4gLCB5X24kCgotIFRoZSB0aGVvcnkgaXMgYmFzZWQgb24gdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24sIHdoaWNoICBjYW4gYmUgaW50ZXJwcmV0ZWQgYXMgYSBtZWFzdXJlIGZvciB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgZ2l2ZW4gc2FtcGxlIGlzIG9ic2VydmVkIGFzIGEgcmVhbGlzYXRpb24gb2YgYSBzZXF1ZW5jZSBvZiByYW5kb20gdmFyaWFibGVzICRZXzEsIFxsZG90cyBZX24kIAoKLSBUaGUgcmFuZG9tIHZhcmlhYmxlcyAkWV9pJCBhcmUgY2hhcmFjdGVyaXplZCBieSBhIGRpc3RyaWJ1dGlvbiBvciBkZW5zaXR5IGZ1bmN0aW9uIHdoaWNoIGhhcyB0eXBpY2FsbHkgdW5rbm93biBwYXJhbWV0ZXJzLCBlLmcuIGEgUG9pc3NvbiBkaXN0cmlidXRpb24gJGYoWV9pKVxzaW0gXHRleHR7UG9pc3Nvbn0oXHRoZXRhX2kpJC4KCi0gV2hlbiB0aGUgc3ViamVjdHMgYXJlIG11dHVhbGx5IGluZGVwZW5kZW50IHRoZSBqb2ludCBsaWtlbGlob29kIHRvIG9ic2VydmUgJHlfMSwgXGxkb3RzLCB5X24kIGVxdWFscyAKJCRccHJvZFxsaW1pdHNfe2k9MX1ebiBmKHlfaSxcdGhldGFfaSxccGhpKSQkCi0gVGhlIGRlbnNpdGllcyBhcmUgYWN0dWFsbHkgYWxzbyBhIGZ1bmN0aW9uIG9mIHRoZSBwYXJhbWV0ZXJzICRcdGhldGFfaSwgXHBoaSQuIFRvIHN0cmVzcyB0aGlzLCB3ZSBpbmRpY2F0ZWQgdGhhdCBpbiB0aGUgZGVuc2l0eSBmb3JtdWxhdGlvbi4KCi0gVGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gaXMgYSBmdW5jdGlvbiBvZiBhbGwgcGFyYW1ldGVycyAKCiQkCkwoXGJvbGRzeW1ib2x7XHRoZXRhfSxccGhpXHZlcnQgXGJvbGRzeW1ib2x7eX0pPVxwcm9kXGxpbWl0c197aT0xfV5uIGYoeV9pLFx0aGV0YV9pLFxwaGkpCiQkCgotIFRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyBvZnRlbiB1c2VkLCB3aGljaCBpcyBkZWZpbmVkIGFzCiQkCmwoXGJvbGRzeW1ib2x7XHRoZXRhfSxccGhpXHZlcnQgXGJvbGRzeW1ib2x7eX0pID0gXGxvZyBMKFxib2xkc3ltYm9se1x0aGV0YX0sXHBoaVx2ZXJ0IFxib2xkc3ltYm9se3l9KSA9ICBcc3VtXGxpbWl0c197aT0xfV5uIFxsb2cgIGYoeV9pLFx0aGV0YV9pLFxwaGkpCiQkCiAKIyMjIFBvaXNzb24gRXhhbXBsZSAKClRoZSBsb2ctbGlrZWxpaG9vZCBmb3Igb3VyIHNpbXVsYXRlZCBkYXRhc2V0IGdpdmVuIHRoZSByZWFsIG1vZGVsIHBhcmFtZXRlcnMgaXM6IAoKRm9yIG9uZSBvYnNlcnZhdGlvbjoKJCRsKFxtdV9pIFx2ZXJ0IHlfaSkgPSB5X2kgXGxvZyBcbXVfaSAtIFxtdV9pIC0gXGxvZyB5X2khJCQKCi0gVmVyaWZ5IGluIFIuCgpgYGB7cn0KbXVUcnVlIDwtIGV4cChldGFUcnVlKQpsb2dsaWtQb2lzIDwtIGRwb2lzKHksbXVUcnVlLGxvZyA9IFRSVUUpCmxvZ0xpa1NlbGYgPC0geSpsb2cobXVUcnVlKSAtIG11VHJ1ZSAtIGxmYWN0b3JpYWwoeSkKcXBsb3QobG9nbGlrUG9pcyxsb2dMaWtTZWxmKSArIHRoZW1lX2J3KCkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZT0xKQpgYGAKClRoZSBsb2ctbGlrZWxpaG9vZCBjYW4gYWxzbyBiZSB3cml0dGVuIGluIHRlcm1zIG9mIHRoZSBjYW5vbmljYWwgbW9kZWwgcGFyYW1ldGVycyAkXHRoZXRhJAoKJCRsKFxtdV9pIFx2ZXJ0IHlfaSkgPSB5X2kgXHRoZXRhX2kgLSBlXntcdGhldGFfaX0gLSBcbG9nIHlfaSEkJAoKLSBOb3RlIHRoYXQgJFx0aGV0YV9pID0gXGV0YV9pJC4gVGhlIGNhbm9uaWNhbCBwYXJhbWV0ZXIgZm9yIHRoZSBwb2lzc29uIGVxdWFscyB0aGUgbGluZWFyIHByZWRpY3RvciEKICAkJFx0aGV0YV9pPVxldGFfaT1cbWF0aGJme3h9X2ledFxib2xkc3ltYm9se1xiZXRhfSQkCgpMb2ctbGlrZWxpaG9vZCBmb3IgYWxsIG9ic2VydmF0aW9ucywgZ2l2ZW4gdGhhdCB0aGV5IGFyZSBpbmRlcGVuZGVudDoKJCRsKFxib2xkc3ltYm9se1xtdX0gXHZlcnQgXG1hdGhiZnt5fSkgPSBcc3VtXGxpbWl0c197aT0xfV5uIFxsZWZ0XHsgeV9pIFx0aGV0YV9pIC0gZV57XHRoZXRhX2l9IC0gXGxvZyB5X2khXHJpZ2h0XH0kJAoKLSBDYWxjdWxhdGUgaW4gUjogCgpgYGB7cn0KZHBvaXMoeSxsYW1iZGEgPSBtdVRydWUsIGxvZyA9IFRSVUUpICU+JSAKICBzdW0oKQpgYGAKCiMjIyBQcm9wZXJ0aWVzIG9mIHRoZSBMb2ctTGlrZWxpaG9vZAoKJCQKbChcdGhldGFfaSxccGhpXHZlcnQgeV9pKT1cbGVmdFx7IFxmcmFje3lfaVx0aGV0YV9pLSBiKFx0aGV0YV9pKX17YShccGhpKX0rYyh5X2ksXHBoaSlccmlnaHRcfQokJAoKLSAkRVt5X2ldPVxtdV9pPWJeXHByaW1lKFx0aGV0YV9pKSQKLSAkXHRleHR7dmFyfVt5X2ldPWJee1xwcmltZVxwcmltZX0oXHRoZXRhX2kpIGEoXHBoaSkkCgpOb3RlIHRoYXQsIAoKLSBWYXJpYW5jZSAkXHRleHR7dmFyfVt5X2ldJCBkZXBlbmRzIG9uIG1lYW4hIAotIE9mdGVuIHRoZXJlIGlzIG5vIGRpc3BlcnNpb24gcGFyYW1ldGVyIGUuZy4gQmVybm91aWxsaTogJFx0ZXh0e3Zhcn1beV9pXT1cbXVfaSgxLVxtdV9pKSQsIAoKIyMjIFBvaXNzb24gRXhhbXBsZSAKCi0gQ2Fub25pY2FsIG1vZGVsIHBhcmFtZXRlciAkXHRoZXRhX2k9XGxvZ3tcbXVfaX0kLgotICRiKFx0aGV0YV9pKSA9IFxleHAoXHRoZXRhX2kpJAotICRjKHlfaSxccGhpKSA9IC0gXGxvZyh5X2khKSQKLSAkXHBoaSA9IDEkCi0gJGEoXHBoaSk9IDEkCi0gJFxtdV9pID1cZnJhY3tccGFydGlhbCBiKFx0aGV0YV9pKX17XHBhcnRpYWwgXHRoZXRhX2l9PSAgXGZyYWN7XHBhcnRpYWwgXGV4cChcdGhldGFfaSl9e1xwYXJ0aWFsIFx0aGV0YV9pfT1cZXhwKFx0aGV0YV9pKSQKLSAkXHRleHR7VmFyfVxsZWZ0W3lfaSBccmlnaHRdPSBhKFxwaGkpXGZyYWN7XHBhcnRpYWxeMiBiKFx0aGV0YV9pKX17KFxwYXJ0aWFsIFx0aGV0YV9pKV4yfT0gIFxmcmFje1xwYXJ0aWFsXjIgXGV4cChcdGhldGFfaSl9e1xwYXJ0aWFsIFx0aGV0YV9pXjJ9PVxleHAoXHRoZXRhX2kpJC4KLSBNZWFuIGlzIGVxdWFsIHRvIHZhcmlhbmNlIGZvciBQb2lzc29uIQoKIyMgUGFyYW1ldGVyIEVzdGltYXRpb246IE1heGltdW0gTGlrZWxpaG9vZAoKQ2hvb3NlIHRoZSBwYXJhbWV0ZXJzICRcYm9sZHN5bWJvbHtcYmV0YX0kIHNvIHRoYXQgdGhlIGxpa2VsaWhvb2QgdG8gb2JzZXJ2ZSB0aGUgc2FtcGxlIHVuZGVyIHRoZSBzdGF0aXN0aWNhbCBtb2RlbCBpcyBtYXhpbWl6ZWQuCgpJdCBpcyBlYXNpZXIgYW5kIGVxdWl2YWxlbnQgdG8gbWF4aW1pemUgdGhlIGxvZy1saWtpaG9vZAoKJCRcdGV4dHthcmdtYXh9X3tcYm9sZHN5bWJvbHtcYmV0YX19IGwoXGJvbGRzeW1ib2x7XG11fSBcdmVydCBcbWF0aGJme3l9KSQkCgokJApcZnJhY3tccGFydGlhbCAgbChcYm9sZHN5bWJvbHtcbXV9IFx2ZXJ0IFxtYXRoYmZ7eX0pfXsKXHBhcnRpYWx7XGJvbGRzeW1ib2x7XGJldGF9fX09MAokJAoKJFxmcmFje1xwYXJ0aWFsICBsKFxib2xkc3ltYm9se1xtdX0gXHZlcnQgXG1hdGhiZnt5fSl9ewpccGFydGlhbHtcYm9sZHN5bWJvbHtcYmV0YX19fSQgaXMgYWxzbyByZWZlcnJlZCB0byBhcyB0aGUgc2NvcmUgZnVuY3Rpb24uCgojIyMgU2NvcmUgZnVuY3Rpb24KCiQkClNfaShcdGhldGFfaSk9IFxmcmFje1xwYXJ0aWFsIGwoXHRoZXRhX2ksXHBoaVx2ZXJ0IHlfaSl9e1xwYXJ0aWFsIFx0aGV0YV9pfQokJAoKJCQKU19pKFx0aGV0YV9pKT0gXGZyYWN7XHBhcnRpYWwgbChcdGhldGFfaSxccGhpXHZlcnQgeV9pKX17XHBhcnRpYWwgXHRoZXRhX2l9PVxmcmFje3lfaSAtIFxtdV9pfXthKFxwaGkpfQokJAoKd2hlbiBjYW5vbmljYWwgbGluayBmdW5jdGlvbiBpcyB1c2VkOgoKLSAkXG11X2k9Yl5ccHJpbWUoXHRoZXRhX2kpJCAKCgpSZWdyZXNzaW9uIChjaGFpbiBydWxlIGFuZCAkaT0xLFxsZG90cyxuJCBpLmkuZCBvYnNlcnZhdGlvbnMpCgpcYmVnaW57ZXFuYXJyYXkqfQpTKFxib2xkc3ltYm9se1xiZXRhfSkmPSZcZnJhY3tccGFydGlhbCAgXHN1bVxsaW1pdHNfe2k9MX1ebiBcbGVmdFx7IFxmcmFje3lfaSBcdGhldGFfaSAtIGIoXHRoZXRhX2kpfXthKFxwaGkpfStjKHlfaSxccGhpKVxyaWdodFx9fXtccGFydGlhbCBcYmV0YX1cXAomPSZcc3VtXGxpbWl0c197aT0xfV5uXGZyYWN7XHBhcnRpYWwgIFxsZWZ0XHsgXGZyYWN7eV9pIFx0aGV0YV9pIC0gYihcdGhldGFfaSl9e2EoXHBoaSl9K2MoeV9pLFxwaGkpXHJpZ2h0XH19e1xwYXJ0aWFsIFx0aGV0YX1cZnJhY3tccGFydGlhbCBcdGhldGF9e1xwYXJ0aWFsXG11fVxmcmFje1xwYXJ0aWFsXG11fXtccGFydGlhbFxldGF9XGZyYWN7XHBhcnRpYWxcZXRhfXtccGFydGlhbFxiZXRhfVxcCiY9JlxzdW1cbGltaXRzX3tpPTF9Xm5cZnJhY3t5X2ktXG11X2l9e2EoXHBoaSl9XGZyYWN7MX17Yl57XHByaW1lXHByaW1lfShcdGhldGEpfVxmcmFje1xwYXJ0aWFsXG11fXtccGFydGlhbFxldGF9XG1hdGhiZnt4fV50XFwKJj0mXG1hdGhiZntYfV5UXG1hdGhiZntBfVxsZWZ0KFxtYXRoYmZ7eX0tXGJvbGRzeW1ib2x7XG11fVxyaWdodCkKXGVuZHtlcW5hcnJheSp9CgoKLSAkXGJvbGRzeW1ib2x7QX0kIGlzIGEgZGlhZ29uYWwgbWF0cml4OiAkYV97aWl9PVxsZWZ0KFx0ZXh0e3Zhcn1beV9pXVxmcmFje1xwYXJ0aWFsIFxldGFfaX17XHBhcnRpYWwgXG11X2l9XHJpZ2h0KV57LTF9JCwgJFxib2xkc3ltYm9se3l9PVt5XzEsXGxkb3RzLCB5X25dXlQkLCAkXGJvbGRzeW1ib2x7XG11fT1bXG11XzEsXGxkb3RzLFxtdV9uXV5UJCAKCiMjIyMgUG9pc3NvbiBFeGFtcGxlIAoKCkZvciBwb2lzc29uIGRhdGE6ICRhKFxwaGkpYl57XHByaW1lXHByaW1lfShcdGhldGEpPVxtdSQgYW5kICRcZnJhY3tccGFydGlhbCBcbXV9e1xwYXJ0aWFsIFxldGF9PVxtdSQuIFNvICRcbWF0aGJme0F9PVxtYXRoYmZ7SX0kIGFuZAoKJCQgUyhcYmV0YSk9XG1hdGhiZntYfV5UIFxsZWZ0XHtcbWF0aGJme1l9LVxib2xkc3ltYm9se1xtdX1ccmlnaHRcfSQkCgojIyMgU29sdmUgU2NvcmUgRXF1YXRpb25zCgpGaW5kICBwYXJhbWV0ZXIgZXN0aW1hdG9yICAkXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19JCBzbyB0aGF0CiQkIFMoXGJvbGRzeW1ib2x7XGJldGF9KSA9IFxtYXRoYmZ7MH0kJAokJFxtYXRoYmZ7WH1eVFxtYXRoYmZ7QX1cbGVmdChcbWF0aGJme3l9LVxib2xkc3ltYm9se1xtdX1ccmlnaHQpID1cbWF0aGJmezB9JCQKUHJvYmxlbSEgTm9uIGxpbmVhciBpbiAkXGJldGEkIGR1ZSB0byAKCi0gbGluayBmdW5jdGlvbjogJFxib2xkc3ltYm9se1xtdX09aF57LTF9KFxldGEpJCAKLSAkYV97aWl9PVxsZWZ0KFx0ZXh0e3Zhcn1beV9pXVxmcmFje1xwYXJ0aWFsIFxldGFfaX17XHBhcnRpYWwgXG11X2l9XHJpZ2h0KV57LTF9JAoKJFxyaWdodGFycm93JCBGaW5kIHJvb3RzIG9mIHNjb3JlIGVxdWF0aW9uIGJ5IHVzaW5nIE5ld3Rvbi1SYXBoc29uIG1ldGhvZC4KCiMjIyBOZXd0b24tUmFwaHNvbgoKYGBge3IgZWNobz1GQUxTRSwgZmlnLmNhcD0gIk5ld3Rvbi1SYXBoc29uIGFsZ29yaXRobTogVGhlIGFsZ29yaXRobSBzdGFydHMgYXQgYW4gaW5pdGlhbCBndWVzcyBiayBmb3IgdGhlIHJvb3Qgb2YgdGhlIHNjb3JlIGZ1bmN0aW9uIFMuIEl0IHdhbGtzIGFsb25nIHRoZSB0YW5nZW50IGxpbmUgb2YgdGhlIHNjb3JlIGZ1bmN0aW9uIGluIFMoYmspICB0byBtb3ZlIGludG8gdGhlIGRpcmVjdGlvbiB3aGVyZSB0aGUgc2NvcmUgZnVuY3Rpb24gYmVjb21lcyB6ZXJvIChhbmQgd2hlcmUgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIGlzIG1heGltYWwpLiBUaGUgbmV3IGVzdGltYXRlIG9mIHRoZSByb290IGlzIHRha2VuIGF0IGJrKzEgd2hlcmUgdGhlIHRhbmdlbnQgbGluZSBiZWNvbWVzIHplcm8uIEl0IHRoZW4gY2FsY3VsYXRlcyB0aGUgc2NvcmUgZm9yIHRoZSB1cGRhdGVkIHBhcmFtZXRlciBlc3RpbWF0b3IgYW5kIHRoZSB3aG9sZSBwcm9jZXNzIGlzIHJlcGVhdGVkIHVudGlsIHRoZSByb290IGlzIGZvdW5kLiJ9ClMgPC0gZnVuY3Rpb24oYmV0YSkgKGJldGEgLSAzKV4yIApkUyA8LSBmdW5jdGlvbihiZXRhKSAyKihiZXRhLTMpCmRTbGluZSA8LSBmdW5jdGlvbihiZXRhLCBiZXRhaykgZFMoYmV0YWspICpiZXRhICsgUyhiZXRhaykgLSBkUyhiZXRhaykgKiBiZXRhawoKYmV0YSA8LSBzZXEoLTIxLDE1LGxlbmd0aD0xMDApCmJldGFrIDwtIC0yMApiZXRhazEgPC0gYmV0YWsgLSAxL2RTKGJldGFrKSpTKGJldGFrKQpiZXRhU2VxRGsgPC0gc2VxKGJldGFrLGJldGFrMSxsZW5ndGg9MTAwKQpwTlIgPC0gcXBsb3QoYmV0YSwgUyhiZXRhKSwgZ2VvbT0ibGluZSIpICsKICBhbm5vdGF0ZSgibGluZSIseD1iZXRhU2VxRGsseT1kU2xpbmUoYmV0YVNlcURrLGJldGFrKSxsaW5ldHlwZSA9ICJkYXNoZWQiLGNvbD0icmVkIikgKwogICAgYW5ub3RhdGUoImxpbmUiLHg9cmVwKGJldGFrMSwyKSx5PWMoMCxTKGJldGFrMSkpLGxpbmV0eXBlID0gImRhc2hlZCIsY29sPSJyZWQiKSArCiAgICBhbm5vdGF0ZSgicG9pbnQiLHg9YmV0YWsseT1TKGJldGFrKSxjb2w9InJlZCIpICsKICB0aGVtZV9idygpCmJldGFOcyA8LSBiZXRhazEKZm9yIChpIGluIDE6NSkKewpiZXRhayA8LSBiZXRhazEKYmV0YWsxIDwtIGJldGFrIC0gMS9kUyhiZXRhaykqUyhiZXRhaykKYmV0YU5zIDwtIGMoYmV0YU5zLGJldGFrMSkKYmV0YVNlcURrIDwtIHNlcShiZXRhayxiZXRhazEsbGVuZ3RoPTEwMCkKcE5SIDwtIHBOUiArCiAgICBhbm5vdGF0ZSgibGluZSIseD1iZXRhU2VxRGsseT1kU2xpbmUoYmV0YVNlcURrLGJldGFrKSxsaW5ldHlwZSA9ICJkYXNoZWQiLGNvbD0icmVkIikgKwogICAgYW5ub3RhdGUoImxpbmUiLHg9cmVwKGJldGFrMSwyKSx5PWMoMCxTKGJldGFrMSkpLGxpbmV0eXBlID0gImRhc2hlZCIsY29sPSJyZWQiKSAKfQpwTlIgKyAKICBhbm5vdGF0ZSgidGV4dCIseD0tMjAseT1TKC0yMCkrNDAsbGFiZWw9cGFzdGUwKCJTKGJldGFba10pIiksY29sPSJyZWQiLHBhcnNlPVRSVUUpICsKICBhbm5vdGF0ZSgidGV4dCIseD1iZXRhTnNbMToyXSx5PVMoYmV0YU5zWzE6Ml0pKzQwLGxhYmVsPXBhc3RlMCgiUyhiZXRhW2srIiwxOjIsIl0pIiksY29sPSJyZWQiLHBhcnNlPVRSVUUpICAgKwogIGFubm90YXRlKCJ0ZXh0Iix4PWJldGFOc1sxOjNdLHk9cmVwKC00MCwzKSxsYWJlbD1wYXN0ZTAoImJldGFbaysiLDE6MywiXSIpLGNvbD0icmVkIixwYXJzZT1UUlVFKSArCiAgYW5ub3RhdGUoInBvaW50Iix4PWJldGFOcyx5PVMoYmV0YU5zKSxjb2w9InJlZCIpICsKICBhbm5vdGF0ZSgidGV4dCIseD0tMjAseT00MDAsIGxhYmVsPSJmcmFjKHBhcnRpYWxkaWZmKlMsIHBhcnRpYWxkaWZmKmJldGEpKicgfCcqYmV0YVtrXSIsIGNvbD0icmVkIixwYXJzZT1UUlVFKSArCiAgeGxhYihleHByZXNzaW9uKGJldGEpKSArCiAgeWxhYihleHByZXNzaW9uKFMoYmV0YSkpKQpgYGAKCk5ld3RvbiBSYXBoc29uIGFsZ29yaXRobSB0byBmaW5kIHRoZSByb290IG9mIHRoZSBzY29yZSBmdW5jdGlvbi4gCgoxLiBDaG9vc2UgaW5pdGlhbCBwYXJhbWV0ZXIgZXN0aW1hdGUgJFxib2xkc3ltYm9se1xiZXRhfV5rPVxib2xkc3ltYm9se1xiZXRhfV4wJAoyLiBDYWxjdWxhdGUgc2NvcmUgJFMoXGJvbGRzeW1ib2x7XGJldGF9KVx2ZXJ0X3tcYm9sZHN5bWJvbHtcYmV0YX09XGJvbGRzeW1ib2x7XGJldGF9Xmt9JAozLiBDYWxjdWxhdGUgZGVyaXZhdGl2ZSBvZiB0aGUgZnVuY3Rpb24gZm9yIHdoaWNoIHlvdSB3YW50IHRvIGNhbGN1bGF0ZSB0aGUgcm9vdHMKNC4gV2FsayBhbG9uZyBmaXJzdCBkZXJpdmF0aXZlIHVudGlsIGxpbmUgKHBsYW5lKSBvZiB0aGUgZGVyaXZhdGl2ZSBjcm9zc2VzIHplcm8KNS4gVXBkYXRlIHRoZSBiZXRhcyAkXGJvbGRzeW1ib2x7XGJldGF9XntrKzF9JAo2LiBJdGVyYXRlIGZyb20gc3RlcCAyIC0gNSB1bnRpbCBjb252ZXJnZW5jZS4KCgojIyMjIERlcml2YXRpdmUgb2YgU2NvcmUgCgpXZSBoYXZlIHRvIGltcGxlbWVudCBhbiBpbnRlcmF0aXZlIGFsZ29yaXRobSBmb3Igb3B0aW1pc2F0aW9uLiBUbyBtYWtlIHRoaW5ncyB0cmFjdGFibGUgd2Ugd2lsbCBhY3QgYXMgaWYgJFxtYXRoYmZ7QX0kIGlzIGtub3duIGFuZCBmaXggaXQgdXNpbmcgdGhlIGN1cnJlbnQgdmFsdWVzIG9mICRcYm9sZHN5bWJvbHtcYmV0YX1eayQuIE5vdGUsIHRoYXQgZm9yIFBvaXNzb24gcmVncmVzc2lvbiAkXG1hdGhiZntBfT1cbWF0aGJme0l9JC4KClxiZWdpbntlcW5hcnJheSp9ClxmcmFje1xwYXJ0aWFsIFMoXGJvbGRzeW1ib2x7XGJldGF9KX17XHBhcnRpYWwgXGJvbGRzeW1ib2x7XGJldGF9fSAmPSYgXGZyYWN7IFxtYXRoYmZ7WH1eVFxtYXRoYmZ7QX0gXGxlZnRce1xtYXRoYmZ7WX0tXGJvbGRzeW1ib2x7XG11fVxyaWdodFx9fXtccGFydGlhbCBcYm9sZHN5bWJvbHtcYmV0YX19XFwKJj0mIC0gXG1hdGhiZntYfV5UIFxtYXRoYmZ7QX1cbGVmdFsKXGJlZ2lue2FycmF5fXtjY2NjfSBcZnJhY3tccGFydGlhbCBcbXVfMX17XHBhcnRpYWwgXGV0YV8xfSAmMCZcbGRvdHMmMFxcCiAwJlxmcmFje1xwYXJ0aWFsIFxtdV8yfXtccGFydGlhbCBcZXRhXzJ9ICZcbGRvdHMmMFxcClx2ZG90cyZcdmRvdHMmXHZkb3RzJlx2ZG90c1xcCjAmMCZcbGRvdHMmIFxmcmFje1xwYXJ0aWFsIFxtdV9ufXtccGFydGlhbCBcZXRhX259XFwKXGVuZHthcnJheX1ccmlnaHRdIFxmcmFje1xwYXJ0aWFsIFxib2xkc3ltYm9se1xldGF9fXtccGFydGlhbCBcYm9sZHN5bWJvbHtcYmV0YX19XFwKJj0mLVxtYXRoYmZ7WH1eVFxtYXRoYmZ7V1h9ClxlbmR7ZXFuYXJyYXkqfQoKIyMjIyBEZWZpbmUgZXF1YXRpb24gb2YgVGFuZ2VudCBMaW5lIChQbGFuZSkKCi0gV2Uga25vdyB0d28gcG9pbnRzIG9mIHRoZSB0YW5nZW50IHBsYW5lICQoXGJvbGRzeW1ib2x7XGJldGF9XmssUyhcYm9sZHN5bWJvbHtcYmV0YX1eaykpJCBhbmQgJChcYm9sZHN5bWJvbHtcYmV0YX1ee2srMX0sMCkkCi0gV2Uga25vdyB0aGUgZGlyZWN0aW9uIG9mIHRoZSBwbGFuZSAkU15ccHJpbWUoXGJvbGRzeW1ib2x7XGJldGF9KT1cZnJhY3tccGFydGlhbCBTKFxib2xkc3ltYm9se1xiZXRhfSl9e1xwYXJ0aWFsIFxib2xkc3ltYm9se1xiZXRhfX0kCi0gRXF1YXRpb24gb2YgUGxhbmU6CiQkUyhcYm9sZHN5bWJvbHtcYmV0YX0pPXtcYWxwaGF9XzArU15ccHJpbWVcdmVydF97XGJvbGRzeW1ib2x7XGJldGF9Xmt9IFxib2xkc3ltYm9se1xiZXRhfSQkCgotIEdldCAkXGJvbGRzeW1ib2x7XGJldGF9X3trKzF9JApcYmVnaW57ZXFuYXJyYXkqfQpcbWF0aGJmezB9Jj0me1xhbHBoYX1fMCtTXlxwcmltZVx2ZXJ0X3tcYm9sZHN5bWJvbHtcYmV0YX1ee2t9fSBcYm9sZHN5bWJvbHtcYmV0YX1ee2srMX1cXApcYm9sZHN5bWJvbHtcYmV0YX1ee2srMX0mPSYtXGxlZnQoU157XHByaW1lfVx2ZXJ0X3tcYm9sZHN5bWJvbHtcYmV0YX1ee2t9fVxyaWdodCleey0xfXtcYWxwaGF9XzBcXApcZW5ke2VxbmFycmF5Kn0KCi0gR2V0ICR7XGFscGhhfV8wJApcYmVnaW57ZXFuYXJyYXkqfQpTKFxib2xkc3ltYm9se1xiZXRhfV5rKSY9Jlxib2xkc3ltYm9se1xhbHBoYX1fMCtTXlxwcmltZVx2ZXJ0X3tcYm9sZHN5bWJvbHtcYmV0YX1ea30gXGJvbGRzeW1ib2x7XGJldGF9XmtcXAp7XGFscGhhfV8wJj0mLVNeXHByaW1lXHZlcnRfe1xib2xkc3ltYm9se1xiZXRhfV5rfSBcYm9sZHN5bWJvbHtcYmV0YX1eayArIFMoXGJvbGRzeW1ib2x7XGJldGF9XmspXFwKXGVuZHtlcW5hcnJheSp9CgotIEdldCAkXGJvbGRzeW1ib2x7XGJldGF9X3trKzF9JAoKXGJlZ2lue2VxbmFycmF5Kn0KXGJvbGRzeW1ib2x7XGJldGF9XntrKzF9Jj0mXGJvbGRzeW1ib2x7XGJldGF9XmstXGxlZnQoU157XHByaW1lfVx2ZXJ0X3tcYm9sZHN5bWJvbHtcYmV0YX1ee2t9fVxyaWdodCleey0xfVMoXGJvbGRzeW1ib2x7XGJldGF9XmspXFwKXGJvbGRzeW1ib2x7XGJldGF9XntrKzF9Jj0mXGJvbGRzeW1ib2x7XGJldGF9XmsrIFxsZWZ0KFxtYXRoYmZ7WH1eVFxtYXRoYmZ7V1h9XHJpZ2h0KV57LTF9IFMoXGJvbGRzeW1ib2x7XGJldGF9XmspClxlbmR7ZXFuYXJyYXkqfQoKV2l0aCAkSihcYm9sZHN5bWJvbHtcYmV0YX0pPUkoXGJvbGRzeW1ib2x7XGJldGF9KT1cbWF0aGJme1h9XlRcbWF0aGJme1dYfSQgIHRoZSBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4LgoKIyMjIEZpc2hlciBTY29yaW5nCgpCZWNhdXNlIHdlIHVzZSB0aGUgY2Fub25pY2FsIG1vZGVsIHBhcmFtZXRlcnMgdGhlIG9ic2VydmVkICBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4IGVxdWFscyB0aGUgZXhwZWN0ZWQgIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggJEooXGJvbGRzeW1ib2x7XGJldGF9KT1JKFxib2xkc3ltYm9se1xiZXRhfSkkLgpJbmRlZWQsIHRoZSBvYnNlcnZlZCBGaXNoZXIgaW5mb3JtYXRpb24gbWF0cml4IGlzIG5vdCBkZXBlbmRpbmcgb24gdGhlIG9ic2VydmF0aW9ucywgYnV0IG9ubHkgb24gdGhlIGRlc2lnbiBhbmQgdGhlIHZhcmlhbmNlIG9mIHRoZSBkYXRhICh2aWEgdGhlIHdlaWdodHMpLgoKSGVuY2UsIE5ld3Rvbi1SYXBoc29uIGlzIGVxdWl2YWxlbnQgdG8gRmlzaGVyIHNjb3Jpbmcgd2hlbiB0aGUgY2Fub25pY2FsIGxpbmsgZnVuY3Rpb24gaXMgdXNlZC4KCk5vdGUsIHRoYXQgdGhlIEZpc2hlciBtYXRyaXgsIG1pbnVzIHNlY29uZCBkZXJpdmF0aXZlIChvciBoZXNzaWFuKSBvZiB0aGUgbGlrZWxpaG9vZCB0byB0aGUgbW9kZWwgcGFyYW1ldGVycywgaXMgYWxzbyB0aGUgaW52ZXJzZSBvZiB0aGUgdmFyaWFuY2UgY292YXJpYW5jZSBtYXRyaXggb2YgdGhlIG1vZGVsIHBhcmFtZXRlcnMuIEl0IGlzIHRodXMgcmVsYXRlZCB0byB0aGUgcHJlY2lzaW9uLgoKCiMjIyBJdGVyYXRpdmVseSBSZXdlaWdodGVkIExlYXN0IFNxdWFyZXMgKElSTFMpLgoKV2UgY2FuIHJld3JpdGUgTmV3dG9uIFJhcGhzb24gb3IgRmlzaGVyIHNjb3JpbmcgYXMgSVJMUy4KClxiZWdpbntlcW5hcnJheSp9Clxib2xkc3ltYm9se1xiZXRhfV57aysxfSY9Jlxib2xkc3ltYm9se1xiZXRhfV5rKyBcbGVmdChcbWF0aGJme1h9XlRcbWF0aGJme1dYfVxyaWdodCleey0xfSBTKFxib2xkc3ltYm9se1xiZXRhfV5rKVxcClxib2xkc3ltYm9se1xiZXRhfV57aysxfSY9Jlxib2xkc3ltYm9se1xiZXRhfV5rKyBcbGVmdChcbWF0aGJme1h9XlRcbWF0aGJme1dYfVxyaWdodCleey0xfSBcbWF0aGJme1h9XlRcbWF0aGJme0F9IFxsZWZ0KFxtYXRoYmZ7WX0tXGJvbGRzeW1ib2x7XG11fVxyaWdodClcXApcYm9sZHN5bWJvbHtcYmV0YX1ee2srMX0mPSYgXGxlZnQoXG1hdGhiZntYfV5UXG1hdGhiZntXWH1ccmlnaHQpXnstMX1cbWF0aGJme1h9XlRcbWF0aGJme1dYfVxib2xkc3ltYm9se1xiZXRhfV5rKyBcbGVmdChcYm9sZHN5bWJvbHtYfV5UXG1hdGhiZntXWH1ccmlnaHQpXnstMX0gXG1hdGhiZntYfV5UIFxtYXRoYmZ7V31cZnJhY3tccGFydGlhbCBcZXRhfXtccGFydGlhbCBcbXV9ICBcbGVmdChcbWF0aGJme1l9LVxib2xkc3ltYm9se1xtdX1ccmlnaHQpXFwKXGJvbGRzeW1ib2x7XGJldGF9XntrKzF9Jj0mIFxsZWZ0KFxtYXRoYmZ7WH1eVFxtYXRoYmZ7V1h9XHJpZ2h0KV57LTF9XG1hdGhiZntYfV5UXG1hdGhiZntXfSBcbGVmdFtcbWF0aGJme1h9XGJvbGRzeW1ib2x7XGJldGF9XmsgKyBcZnJhY3tccGFydGlhbCBcZXRhfXtccGFydGlhbCBcbXV9ICBcbGVmdChcbWF0aGJme1l9LVxib2xkc3ltYm9se1xtdX1ccmlnaHQpClxyaWdodF1cXApcYm9sZHN5bWJvbHtcYmV0YX1ee2srMX0mPSYgXGxlZnQoXG1hdGhiZntYfV5UXG1hdGhiZntXWH1ccmlnaHQpXnstMX1cbWF0aGJme1h9XlRcbWF0aGJme1d6fQpcZW5ke2VxbmFycmF5Kn0KCndpdGggJFxtYXRoYmZ7en09XGxlZnRbXG1hdGhiZntYfVxib2xkc3ltYm9se1xiZXRhfV5rICsgXGZyYWN7XHBhcnRpYWwgXGV0YX17XHBhcnRpYWwgXG11fSAgXGxlZnQoXG1hdGhiZntZfS1cYm9sZHN5bWJvbHtcbXV9XHJpZ2h0KVxyaWdodF0kCgpTbyB3ZSBjYW4gZml0IHRoZSBtb2RlbCBieSBwZXJmb3JtaW5nIGl0ZXJhdGl2ZSByZWdyZXNzaW9ucyBvZiB0aGUgcHNldWRvIGRhdGEgJFxtYXRoYmZ7en0kIG9uICRcbWF0aGJme1h9JC4KSW4gZWFjaCBpdGVyYXRpb24gd2Ugd2lsbCB1cGRhdGUgJFxtYXRoYmZ7en0kLCB0aGUgd2VpZ2h0cyAkXG1hdGhiZntXfSQgYW5kIHRoZSBtb2RlbCBwYXJhbWV0ZXJzLgoKRm9yIFBvaXNzb24gZGF0YSAKCi0gJFxmcmFje1xwYXJ0aWFsIFxldGF9e1xwYXJ0aWFsIFxtdX09XGZyYWN7XHBhcnRpYWxcbG9nIFxtdX17XHBhcnRpYWxcbXV9PVxmcmFjezF9e1xtdX09XGV4cCgtXGV0YSkkICAKLSAkXG1hdGhiZntXfT1cbWF0aGJme0F9XGZyYWN7XHBhcnRpYWx7XG11fX17e1xwYXJ0aWFsIFxldGF9fSQgaXMgYSBkaWFnb25hbCBtYXRyaXggd2l0aCAkW1xmcmFje1xwYXJ0aWFse1xtdV9pfX17e1xwYXJ0aWFsIFxldGFfaX19XV97aWl9PVtcbXVfaV1fe2lpfT1bXGV4cChcZXRhX2kpXV97aWl9JCBvbiBpdHMgZGlhZ29uYWwgZWxlbWVudHMuCgoKIyMjIFZhcmlhbmNlLUNvdmFyaWFuY2UgTWF0cml4IG9mIE1lYW4gTW9kZWwgUGFyYW1ldGVycz8KCkluIHRoZSBJUldMUyBhbGdvcml0aG0sIHRoZSBkYXRhIGlzIHdlaWdodGVkIGFjY29yZGluZyB0byB0aGUgdmFyaWFuY2Ugb2YgJFxtYXRoYmZ7WX0kLiBXZSBjb3JyZWN0IGZvciB0aGUgZmFjdCB0aGF0IHRoZSBkYXRhIGFyZSBoZXRlcm9zY2VkYXN0aWMuCgpDb3VudCBkYXRhIGhhdmUgYSBtZWFuIHZhcmlhbmNlIHJlbGF0aW9uIChlLmcuIGluIFBvaXNzb24gY2FzZSAkXHRleHR7RX1cbGVmdFtZIFxyaWdodF09XHRleHR7dmFyfVxsZWZ0W1kgXHJpZ2h0XT1cbXUkKS4KVGhlIElSV0xTIGFsc28gY29ycmVjdHMgZm9yIHRoZSBzY2FsZSBwYXJhbWV0ZXIgJFxwaGkkIGluICRcbWF0aGJme1d9JC4gKE5vdGUgdGhhdCB0aGUgc2NhbGUgcGFyYW1ldGVyIGZvciBQb2lzc29uIGlzICRccGhpPTEkKS4KClNvIElSV0xTIHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeCBmb3IgdGhlIG1vZGVsIHBhcmFtZXRlciBlcXVhbHMKJCRcbWF0aGJme1xTaWdtYX1fe1xoYXRcYmV0YX09XGxlZnQoXG1hdGhiZntYfV5UXG1hdGhiZntXWH1ccmlnaHQpXnstMX0uJCQKCk5vdGUsIHRoYXQgdGhlIEZpc2hlciBJbmZvcm1hdGlvbiBNYXRyaXggZXF1YWxzIHRoZSBpbnZlcnNlIG9mIHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeCBvZiB0aGUgZXhwZXJpbWVudC4KVGhlIGxhcmdlciB0aGUgRmlzaGVyIEluZm9ybWF0aW9uIE1hdHJpeCB0aGUgbW9yZSBpbmZvcm1hdGlvbiB3ZSBoYXZlIG9uIHRoZSBleHBlcmltZW50IHRvIGVzdGltYXRlIHRoZSBtb2RlbCBwYXJhbWV0ZXJzLgpGSU0gJFx1cGFycm93JCwgcHJlY2lzaW9uICRcdXBhcnJvdyQsICRcdGV4dHtTRX1cZG93bmFycm93JAoKIyMgUG9pc3NvbiBFeGFtcGxlIAoKCiMjIyBJbml0aWFsIEVzdGltYXRlCgpUaGlzIGlzIGEgdmVyeSBwb29yIGluaXRpYWwgZXN0aW1hdGUgdXNlZCB0byBpbGx1c3RyYXRlIHRoZSBhbGdvcml0aG0uCk90aGVyd2lzZSBjb252ZXJnZW5jZSBmb3IgdGhpcyBzaW1wbGUgZXhhbXBsZSBpcyB3YXkgdG9vIHF1aWNrCgpgYGB7cn0KaXRlcmF0aW9uPTAKYmV0YXM8LWMobG9nKG1lYW4oeSkpLDAsMCkKcGxvdChiZXRhc1RydWUsCiAgICAgeWxhYj1leHByZXNzaW9uKGJldGEpLAogICAgIHlsaW09YygwLDQpLAogICAgIHBjaD0xOSwKICAgICB0eXBlPSJiIiwgCiAgICAgbWFpbj1wYXN0ZTAoImxpa2VsaWhvb2QgcmVhbCBiZXRhPSIsCiAgICAgICAgICAgICAgICAgcm91bmQoc3VtKGRwb2lzKHksZXhwKGV0YVRydWUpLGxvZz1UUlVFKSksMSksIlxubGlrZWxpaG9vZCBmaXQ9Iiwgcm91bmQoc3VtKGRwb2lzKHksZXhwKHhobHAlKiViZXRhcyksbG9nPVRSVUUpKSwxKSkKKQpsaW5lcyhiZXRhcyx0eXBlPSJiIixsdHk9MiApCmBgYAoKIyMjIEl0ZXJhdGl2ZWx5IFJld2VpZ2h0ZWQgTGVhc3QgU3F1YXJlcwoKIyMjIyBQc2V1ZG8gRGF0YQoKJCR6X2k9IFxldGFfaSArIFxmcmFje1xwYXJ0aWFsIFxldGFfaX17XHBhcnRpYWwgXG11X2l9KHlfaSAtXG11X2kpJCQKJCR6X2k9IFxldGFfaSArIGVeey1cZXRhX2l9IHlfaSAtMSQkCgojIyMjIFdlaWdodCBNYXRyaXg/CgokJFt3X3tpaX1dPSB2YXJfe3lfaX1eey0xfSBcbGVmdChcZnJhY3tccGFydGlhbCBcbXV9e1xwYXJ0aWFsIFxldGF9XHJpZ2h0KV4yJCQKJCRbd197aWl9XT0gZV57XGV0YV9pfSQkCgojIyMjIFJ1biBVcGRhdGUgU3RlcCBNdWx0aXBsZSBUaW1lcwoKRmlyc3QgMyB0aW1lcyAoY29sb3JzIGFyZSBibGFjayAwLCByZWQgaXRlcmF0aW9uIDEsIGdyZWVuIGl0ZXJhdGlvbiAyLCBibHVlIGl0ZXJhdGlvbiAzKQoKYGBge3J9CnBsb3QoYmV0YXNUcnVlLHlsYWI9ZXhwcmVzc2lvbihiZXRhKSx5bGltPWMoMCw0KSxwY2g9MTksdHlwZT0iYiIpCmxpbmVzKGJldGFzLHR5cGU9ImIiLGx0eT0yKQoKY2F0KCJcbmxpa2VsaWhvb2QgVFJVRT0iLCByb3VuZChzdW0oZHBvaXMoeSxleHAoeGhscCUqJWJldGFzVHJ1ZSksbG9nPVRSVUUpKSwxKSkKY2F0KCJcbmxpa2VsaWhvb2QgaW5pdGlhbCBmaXQ9Iiwgcm91bmQoc3VtKGRwb2lzKHksZXhwKHhobHAlKiViZXRhcyksbG9nPVRSVUUpKSwxKSkKCiNDYWxjdWxhdGUgY3VycmVudCBldGEKZXRhPC14aGxwJSolYmV0YXMKCml0ZXJhdGlvbj0wCmZvciAoaSBpbiAxOjMpCnsKI3N0YXJ0IElSTFMgVVBEQVRFIFNURVAKaXRlcmF0aW9uPWl0ZXJhdGlvbisxCiNjYWxjdWxhdGUgcHNldWRvIGRhdGEgYmFzZWQgb24gY3VycmVudCBiZXRhcwp6PWV0YStleHAoLWV0YSkqKHktZXhwKGV0YSkpCiNjYWxjdWxhdGUgbmV3IHdlaWdodHM6IGRpYWdvbmFsIGVsZW1lbnRzCnc8LWMoZXhwKGV0YSkpCgojdXBkYXRlIGJldGFzCmxtVXBkYXRlPC1sbSh6fi0xK3hobHAsd2VpZ2h0PXcpCiNldGE8LXhobHAlKiViZXRhcwpldGE8LWxtVXBkYXRlJGZpdHRlZApiZXRhczwtbG1VcGRhdGUkY29lZgpsaW5lcyhiZXRhcyx0eXBlPSJiIixjb2w9aXRlcmF0aW9uKzEscGNoPWl0ZXJhdGlvbixsdHk9MikKY2F0KCJcbmxpa2VsaWhvb2QgY3VycmVudCBmaXQ9Iiwgcm91bmQoc3VtKGRwb2lzKHksZXhwKHhobHAlKiViZXRhcyksbG9nPVRSVUUpKSwxKSkKfQpgYGAKCgojIyBDb21wYXJpc29uIHdpdGggR0xNIEZ1bmN0aW9uCgojIyMgU21hcnRlciBJbml0aWFsaXNhdGlvbgpgYGB7cn0KejwtbG9nKHkrLjUpCmJldGFzPC1sbSh6fi0xK3hobHApJGNvZWYKcGxvdChiZXRhc1RydWUseWxhYj1leHByZXNzaW9uKGJldGEpLHlsaW09YygwLDQpLHBjaD0xOSx0eXBlPSJiIikKbGluZXMoYmV0YXMsY29sPTIsdHlwZT0iYiIsbHR5PTIpCiNjYWxjdWxhdGUgY3VycmVudCBldGEKZXRhPC14aGxwJSolYmV0YXMKCmNhdCgiXG5saWtlbGlob29kIFRSVUU9Iiwgcm91bmQoc3VtKGRwb2lzKHksZXhwKHhobHAlKiViZXRhc1RydWUpLGxvZz1UUlVFKSksMSkpCmNhdCgiXG5saWtlbGlob29kIGluaXRpYWwgZml0PSIsIHJvdW5kKHN1bShkcG9pcyh5LGV4cCh4aGxwJSolYmV0YXMpLGxvZz1UUlVFKSksMSkpCmBgYAoKIyMjIEV2YWx1YXRpb24gU3RvcHBpbmcgQ3JpdGVyaW9uCgotIFJlc2lkdWFsIGRldmlhbmNlOiBJcyAyIGxvZyBvZiBMUiBiZXR3ZWVuIGJlc3QgcG9zc2libGUgZml0IGFuZCBjdXJyZW50IGZpdAokJExSPVxmcmFje0xfXHRleHR7YmVzdH19e0xfXHRleHR7Y3VycmVudH19JCQKJCREPTIgKFxsb2cgTF9cdGV4dHtiZXN0fS0gXGxvZyBMX1x0ZXh0e2N1cnJlbnR9KSQkCiQkRD0yIChsX1x0ZXh0e2Jlc3R9LWxfXHRleHR7Y3VycmVudH0pJCQKLSBCZXN0IGZpdDogJFxtdT15JAotIE9wdGltYWwgcG9pc3NvbjoKJCQgbF9cdGV4dHtiZXN0fT1cc3VtXGxlZnRbeV9pIFxsb2coeV9pKSAtIHlfaSAtIFxsb2dcbGVmdCh5X2khXHJpZ2h0KVxyaWdodF0kJAotIEN1cnJlbnQgZml0CiQkIGxfXHRleHR7Y3VycmVudH09XHN1bSBcbGVmdFt5X2kgXGV0YV9pIC1lXntcZXRhX2l9IC0gbG9nXGxlZnQoeV9pIVxyaWdodClccmlnaHRdJCQKLSBEZXZpYW5jZSBEOgokJEQgPSAyIFxzdW0gXGxlZnRbIHlfaSBsb2coeV9pKSAtIHlfaSBcZXRhX2kgLSAoeV9pIC1lXntcZXRhX2l9KVxyaWdodF0kJAotIFByb2JsZW0gdG8gY2FsY3VsYXRlIGl0IGlmIHk9MCBidXQgYnkgYXBwbHkgbCdIb3BpdGFsJ3MgcnVsZSB3ZSBrbm93CiQkXGxpbV97eV9pIFx0byAwfSB5X2kgXGxvZyh5X2kpID0wJCQKCmBgYHtyfQp5bG9neTwtZnVuY3Rpb24oeSkKewpyZXR1cm4oaWZlbHNlKHk9PTAscmVwKDAsbGVuZ3RoKHkpKSx5KmxvZyh5KSkpCn0KCmRldmlhbmNlPC0yKnN1bSh5bG9neSh5KS15KmV0YS0oeS1leHAoZXRhKSkpCgpkZXZpYW5jZU9sZDwtMWUzMApgYGAKCgojIyMgUnVuIFVwZGF0ZSBTdGVwIHVudGlsIENvbnZlcmdlbmNlCgpgYGB7cn0KcGxvdChiZXRhc1RydWUseWxhYj1leHByZXNzaW9uKGJldGEpLHlsaW09YygwLDQpLHBjaD0xOSx0eXBlPSJiIikKbGluZXMoYmV0YXMsdHlwZT0iYiIsbHR5PTIpCgp0b2w8LTFlLTYKaXRlcmF0aW9uPTAKd2hpbGUoKChkZXZpYW5jZU9sZC1kZXZpYW5jZSkvZGV2aWFuY2VPbGQpPnRvbCkKewojc3RhcnQgSVJMUyBVUERBVEUgU1RFUAppdGVyYXRpb249aXRlcmF0aW9uKzEKI2NhbGN1bGF0ZSBwc2V1ZG8gZGF0YSBiYXNlZCBvbiBjdXJyZW50IGJldGFzCno9ZXRhK2V4cCgtZXRhKSooeS1leHAoZXRhKSkKI2NhbGN1bGF0ZSBuZXcgd2VpZ2h0czogZGlhZ29uYWwgZWxlbWVudHMKdzwtYyhleHAoZXRhKSkKCiN1cGRhdGUgYmV0YXMKbG1VcGRhdGU8LWxtKHp+LTEreGhscCx3ZWlnaHQ9dykKI2V0YTwteGhscCUqJWJldGFzCmV0YTwtbG1VcGRhdGUkZml0dGVkCmJldGFzPC1sbVVwZGF0ZSRjb2VmCmxpbmVzKGJldGFzLHR5cGU9ImIiLGNvbD1pdGVyYXRpb24rMSxwY2g9aXRlcmF0aW9uLGx0eT0yKQoKI2NyaXRlcmlvbiBmb3IgY29udmVyZ2VuY2UKZGV2aWFuY2VPbGQ8LWRldmlhbmNlCmRldmlhbmNlPC0yKnN1bSh5bG9neSh5KS15KmV0YS0oeS1leHAoZXRhKSkpCmNhdCgiaXRlcmF0aW9uIixpdGVyYXRpb24sIkRldmlhbmNlIE9sZCIsZGV2aWFuY2VPbGQsIkRldmlhbmNlIiwgZGV2aWFuY2UsIlxuIikKfQpgYGAKCiMjIyBWYXJpYW5jZSAkXGJldGEkPwoKJCRcU2lnbWFfe1xiZXRhfT1cbGVmdChcbWF0aGJme1h9XlRcbWF0aGJme1d9IFxtYXRoYmZ7WH1ccmlnaHQpXnstMX0kJAoKYGBge3J9CnZhckJldGE9c29sdmUodCh4aGxwKSUqJWRpYWcodyklKiV4aGxwKQpgYGAKCiMjIyBDb21wYXJpc29uIHdpdGggR0xNIGZpdAoKVXNlIC0xIGJlY2F1c2UgaW50ZXJjZXB0IGlzIGFscmVhZHkgaW4geGhscApgYGB7cn0KZ2xtZml0PWdsbSh5fi0xK3hobHAsZmFtaWx5PXBvaXNzb24pCmNvbXA9ZGF0YS5mcmFtZShnbG1maXQ9YyhnbG1maXQkZGV2aWFuY2UsZ2xtZml0JGNvZWYsc3VtbWFyeShnbG1maXQpJGNvZWZbLDJdKSxvdXJGaXQ9YyhkZXZpYW5jZSxiZXRhcyxzcXJ0KGRpYWcodmFyQmV0YSkpKSkKcm93Lm5hbWVzKGNvbXApPWMoImRldmlhbmNlIixwYXN0ZSgiYmV0YSIsMTozLHNlcD0iIikscGFzdGUoInNlIiwxOjMsc2VwPSIiKSkKY29tcApgYGAKCgojIyBIeXBvdGhlc2lzIHRlc3Rpbmc6IExhcmdlIHNhbXBsZSB0aGVvcnkKCiMjIyBXYWxkIHRlc3QKCi0gRm9sbG93cyBpbW1lZGlhdGVseSBmcm9tIHRoZSBpbmZvcm1hdGlvbiBtYXRyaXggZm9yIGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMKIFxbSShcYm9sZHN5bWJvbHtcYmV0YX0pID0gXG1hdGhiZntYfV5UXG1hdGhiZntXWH1cXSAKIAogc28gbGFyZ2Ugc2FtcGxlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRvciAkXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19JCBpcyBtdWx0aXZhcmlhdGUgbm9ybWFsClxbClxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fSBcc2ltIE1WTlxsZWZ0W1xib2xkc3ltYm9se1xiZXRhfSxcbGVmdChcbWF0aGJme1h9XlRcbWF0aGJme1dYfVxyaWdodCleey0xfVxyaWdodF0KXF0KCldlIGNhbiBwZXJmb3JtIGEgV2FsZCBUZXN0IGZvciBhIHNpbmdsZSBtb2RlbCBwYXJhbWV0ZXIgCgokJApXID0gXGZyYWN7XGhhdFxiZXRhX219e1xoYXR7XHRleHR7c2V9fV97XGhhdFxiZXRhX219fSBcYXBwcm94IE4oMCwxKVx2ZXJ0IEhfMAokJAp0byB0ZXN0IGZvciAKCiQkCkhfMDogXGJldGFfcD0wIFxsZWZ0cmlnaHRhcnJvdyBIXzE6XGJldGFfcFxuZXEwCiQkCgoKQWdhaW4sIHdlIGNhbiBhbHNvIGFzc2VzcyBjb250cmFzdHMhIEluZGVlZCwgbGluZWFyIGNvbWJpbmF0aW9ucyBvZiBtb2RlbCBwYXJhbWV0ZXIgZXN0aW1hdG9ycyBhbHNvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uIAoKJCQKXG1hdGhiZntMfV5UXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19IFxzaW0gTlxsZWZ0W1xtYXRoYmZ7TH1eVFxib2xkc3ltYm9se1xiZXRhfSxcbWF0aGJme0x9XlRcaGF0e1xib2xkc3ltYm9se1xTaWdtYX19X3tcaGF0e1xib2xkc3ltYm9se1xiZXRhfX19XG1hdGhiZntMfVxyaWdodF0KJCQKCldpdGggJFxtYXRoYmZ7TH0kIGEgdmVjdG9yIGZvciBhIHNpbmdsZSBjb250cmFzdC4gCgokJApXID0gXGZyYWN7XG1hdGhiZntMfV5UXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19fXtcaGF0e1x0ZXh0e3NlfX1fe1xtYXRoYmZ7TH1eVFxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fX19IFxhcHByb3ggTigwLDEpXHZlcnQgSF8wCiQkCnRlc3RpbmcgZm9yIAokJApIXzA6IFxtYXRoYmZ7TH1eVFxib2xkc3ltYm9se1xiZXRhfT0wIFxsZWZ0cmlnaHRhcnJvdyBIXzE6XG1hdGhiZntMfV5UXGJvbGRzeW1ib2x7XGJldGF9XG5lcTAKJCQKCldlIGNhbiBhbHNvIHRlc3QgZm9yIG11bHRpcGxlIGNvbnRyYXN0cyBzaW11bHRhbmVvdXNseSwgZS5nLiBieSBhc3N1bWluZyB0aGF0IG11bHRpcGxlIG1vZGVsIHBhcmFtZXRlcnMgYXJlIHplcm8uIFN1cHBvc2UgdGhhdCAkXG1hdGhiZntMfSQgaXMgdGhlIGNvbnRyYXN0IG1hdHJpeCB0aGF0IGNvcnJlc3BvbmRzIHRlc3RpbmcgZm9yICRjJCBtb2RlbCBwYXJhbWV0ZXJzLCBzaW11bHRhbmVvdXNseS4gIFRoZW4gCgokJApcbWF0aGJme0x9XlRcaGF0e1xib2xkc3ltYm9se1xiZXRhfX0gXHNpbSBNVk5cbGVmdFtcbWF0aGJme0x9XlRcYm9sZHN5bWJvbHtcYmV0YX0sXG1hdGhiZntMfV5UXGhhdHtcYm9sZHN5bWJvbHtcU2lnbWF9fV97XGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19fVxtYXRoYmZ7TH1ccmlnaHRdCiQkCgphbmQgCgokJCAKVyA9IFxtYXRoYmZ7TH1eVFxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fVxsZWZ0KFxtYXRoYmZ7TH1eVFxoYXR7XGJvbGRzeW1ib2x7XFNpZ21hfX1fe1xoYXR7XGJvbGRzeW1ib2x7XGJldGF9fX1cbWF0aGJme0x9XHJpZ2h0KV57LTF9XGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19XG1hdGhiZntMfSBcc2ltIFxjaGleMl9jXHZlcnQgSF8wCiQkCnRvIHRlc3QgZm9yIAoKJCQKSF8wOiBcbWF0aGJme0x9XlRcYm9sZHN5bWJvbHtcYmV0YX09XG1hdGhiZnswfSBcbGVmdHJpZ2h0YXJyb3cgSF8xOlxtYXRoYmZ7TH1eVFxib2xkc3ltYm9se1xiZXRhfT1cbWF0aGJmezB9XG5lcTAKJCQKCkluIGdlbmVyYWwsIHdoZW4gd2UgdGVzdCBmb3IgJGNcZ2VxMSQgY29udHJhc3RzLCB0aGVuIHRoZSB0ZXN0IHN0YXRpc3RpYyAkV+KIvFxjaGleMl9yfEhfMCQsIHdpdGggJHIkIHRoZSByYW5rIG9mIHRoZSBjb250cmFzdCBtYXRyaXguCgoKIyMjICBMaWtlbGlob29kIHJhdGlvIHRlc3QKClRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3QgKExSVCkgbWVhc3VyZXMgdGhlIGRpc2NyZXBhbmN5IGluIGxvZy1saWtlbGlob29kIGJldHdlZW4gb3VyIGN1cnJlbnQgbW9kZWwgKHNvbWV0aW1lcyBhbHNvIHJlZmVycmVkIHRvIGFzIGZ1bGwgbW9kZWwpIGFuZCBhIHJlZHVjZWQgbW9kZWwgKHNvbWV0aW1lcyBhbHNvIHJlZmVycmVkIHRvIGFzIG51bGwgb3IgYWx0ZXJuYXRpdmUgbW9kZWwpLiAKClRoZSByZWR1Y2VkIG1vZGVsIG11c3QgYmUgbmVzdGVkIGluIChhbmQgdGhlcmVmb3JlIG9mIGxvd2VyIGRpbWVuc2lvbiBhcyBjb21wYXJlZCB0bykgdGhlIGZ1bGwgbW9kZWwuIAoKV2hpbGUgYWRkaW5nIG1vcmUgY292YXJpYXRlcyB3aWxsIGFsd2F5cyBleHBsYWluIG1vcmUgdmFyaWFiaWxpdHkgaW4gb3VyIHJlc3BvbnNlIHZhcmlhYmxlLCB0aGUgTFJUIHRlc3RzIHdoZXRoZXIgdGhpcyBpcyBhY3R1YWxseSBzaWduaWZpY2FudC4gCgpGb3IgZXhhbXBsZSwgaW4gdGhlIGV4YW1wbGUgb2YgZ2VuZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIGhlYWx0aHkgdmVyc3VzIHR1bW9yYWwgdGlzc3VlLCB0aGUgZnVsbCBtb2RlbCBjb3VsZCBiZSBhIEdMTSB3aGVyZSB0aGUgbWVhbiBpcyBtb2RlbGVkIGFjY29yZGluZyB0byBhbiBpbnRlcmNlcHQgYW5kIGEgdGlzc3VlIGluZGljYXRvciB2YXJpYWJsZSAoaGVhbHRoeSAvIHR1bW9yKSwgd2hpbGUgdGhlIGFsdGVybmF0aXZlIG1vZGVsIGNvdWxkIGJlIGEgR0xNIHdpdGgganVzdCBhbiBpbnRlcmNlcHQuIEluZGVlZCwgaWYgdGhlIGdlbmUgaXMgc2ltaWxhcmx5IGV4cHJlc3NlZCBiZXR3ZWVuIGhlYWx0aHkgYW5kIHR1bW9yIHRpc3N1ZSwgdGhlIGxvZy1saWtlbGlob29kIG9mIHRoZSBhbHRlcm5hdGl2ZSBtb2RlbCB3aWxsIGRlY3JlYXNlIG9ubHkgYSBsaXR0bGUgYXMgY29tcGFyZWQgdG8gdGhlIGZ1bGwgbW9kZWwuIAoKQXMgdGhlIG5hbWUgc3VnZ2VzdHMsIHRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3QgYXNzZXNzZXMgd2hldGhlciB0aGUgcmF0aW8gb2YgdGhlIGxvZy1saWtlbGlob29kcyBwcm92aWRlcyBzdWZmaWNpZW50IGV2aWRlbmNlIGZvciBhIHdvcnNlIGZpdCBvZiB0aGUgYWx0ZXJuYXRpdmUgdmVyc3VzIGZ1bGwgbW9kZWwKCiAkJAogXGxhbWJkYT0yXGxlZnRbbChcaGF0e1xib2xkc3ltYm9se1xiZXRhfX1fXHRleHR7ZnVsbH0pLTJsKFxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fV9cdGV4dHswfSlccmlnaHRdCiAkJCAKIAogICAgQXN5bXB0b3RpY2FsbHksIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgaXQgY2FuIGJlIHNob3duIHRoYXQKICAgJCQgTCBcc2ltIFxjaGlfY14yIHwgSF8wLCAkJAogICB3aXRoICRjJCB0aGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgZHJvcHBlZCBpbiB0aGUgYWx0ZXJuYXRpdmUgbW9kZWwgdmVyc3VzIHRoZSBmdWxsIG1vZGVsLiAKICAgCkxldCAkXG1hdGhiZntDfSQgZGVub3RlIHRoZSAkYyBcdGltZXMgcCQgY29udHJhc3QgbWF0cml4IGRlbm90aW5nIHRoZSBjb250cmFzdCBmb3IgdGhlIHBhcmFtZXRlcnMgYmVpbmcgZHJvcHBlZCwgdGhlIG51bGwgYW5kIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgYXJlIGFzIGluIHRoZSBXYWxkIHRlc3Qgc2V0dGluZzoKICAgJCQgSF8wOiBcbWF0aGJme0N9IFxiZXRhID0gMCQkCiAgICQkIEhfMTogXG1hdGhiZntDfSBcYmV0YSBcbmUgMCQkCiAgIAoKIC0gSXQgaXMgaW1wb3J0YW50IHRvIGtlZXAgaW4gbWluZCB0aGF0IHN0YW5kYXJkIHN0YXRpc3RpY2FsIGluZmVyZW5jZSB0aGVvcnkgaW4gR0xNcyB3b3JrcyAqKmFzeW1wdG90aWNhbGx5IGluIHRlcm1zIG9mIHRoZSBzYW1wbGUgc2l6ZSoqLgoKVGh1cyB3ZSBuZWVkIG1hbnkgZGF0YSBwb2ludHMgaW4gb3JkZXIgZm9yIHRoZSB0aGVvcnkgdG8gaG9sZCBpbiBwcmFjdGljZS4gSW4gb3JkZXIgZm9yIHRoZSAkcCQtdmFsdWVzIHRvIGJlIGNvcnJlY3QsIG91ciBwYXJhbWV0cmljIChkaXN0cmlidXRpb25hbCkgYXNzdW1wdGlvbnMgYXMgd2VsbCBhcyB0aGUgaW5kZXBlbmRlbmNlIGFzc3VtcHRpb24sIG11c3QgYWxzbyBob2xkLgoKIC0gSW4gYnVsayBSTkEtc2VxLCB3ZSBhcmUgb2Z0ZW4gd29ya2luZyB3aXRoIGEgbGltaXRlZCBudW1iZXIgb2Ygc2FtcGxlcyBhbmQgc28gd2UgdHlwaWNhbGx5IGRvIG5vdCBleHBlY3QgYXN5bXB0b3RpYyB0aGVvcnkgdG8gaG9sZCB5ZXQuIEluIHNpbmdsZS1jZWxsIFJOQS1zZXEsIHdlIG9mdGVuIHBlcmZvcm0gc2V2ZXJhbCBwcmVwcm9jZXNzaW5nIHN0ZXBzIGJlZm9yZSBjYWxjdWxhdGluZyAkcCQtdmFsdWVzIGZvciBlYWNoIGdlbmUgYW5kIHNvIHdlIG1heSBiZSAndXNpbmcgdGhlIGRhdGEgbXVsdGlwbGUgdGltZXMnLiBSYXRoZXIgdGhhbiBhdHRhY2hpbmcgc3Ryb25nIHByb2JhYmlsaXN0aWMgaW50ZXJwcmV0YXRpb25zIHRvIHRoZSAkcCQtdmFsdWVzLCB3ZSB0aGVyZWZvcmUgYWR2aWNlIHRvIHZpZXcgdGhlICRwJC12YWx1ZXMgc2ltcGx5IGFzIHVzZWZ1bCBudW1lcmljYWwgc3VtbWFyaWVzIGZvciByYW5raW5nIHRoZSBnZW5lcyBmb3IgZnVydGhlciBpbnNwZWN0aW9uIGluIGdlbm9taWNzIGFwcGxpY2F0aW9ucy4KIApgYGB7ciBlY2hvPUZBTFNFLCBmaWcud2lkdGg9MC41LCBmaWcuY2FwdGlvbj0iRGlmZmVyZW5jZSBiZXR3ZWVuIFdhbGQgYW5kIExSVCB0ZXN0IixmaWcuYWxpZ249J2NlbnRlcid9CmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcvbGlrVGVzdHMucG5nIikKYGBgCiAKCiMgRWRnZVIKCltNY0NhcnRoeSBhbmQgU215dGgsIDIwMTJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzMzNzg4ODIvKQoKYGBge3IgZmlnLndpZHRoPS45OSwgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi4vZmlncy9NY0NhcnRoeVNteXRoMjAxMi5wbmciKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9Ljk5LCBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9maWdzL01jQ2FydGh5U215dGgyMDEyX3Rlc3RpbmcucG5nIikKYGBgCgojIEVkZ2VSIC0gUXVhc2ktTGlrZWxpaG9vZAoKW0x1bmQgZXQgYWwuIDIwMTJdKGh0dHBzOi8vcHVibGljYXRpb25zLndlaGkuZWR1LmF1L2RvY3VtZW50YXNwZGYvMjU2LnBkZikKCkZvciBxdWFzaS1saWtlbGlob29kIHdlIGRvIG5vdCBzcGVjaWZ5IHRoZSBmdWxsIGRpc3RyaWJ1dGlvbiwgb25seSB0aGUgZmlyc3QgdHdvIG1vbWVudHM6IHRoZSBtZWFuIGFuZCB2YXJpYW5jZS4KCiQkClxsZWZ0XHsKXGJlZ2lue2FycmF5fXtsY2x9CkVbeV97aWd9XHZlcnQgXG1hdGhiZnt4fV97aWd9XSY9JlxtdV97aWd9XFwKbG9nKFxtdV97aWd9KSY9JlxldGFfe2lnfVxcClxldGFfe2lnfSY9JiBcbWF0aGJme3h9X3tpfV5UXGJvbGRzeW1ib2x7XGJldGF9KyBcbG9nIE5faVxcClx0ZXh0e1Zhcn1beV97aWd9XHZlcnQgXG1hdGhiZnt4fV97aWd9XSY9JlxzaWdtYV4yX2dcbGVmdChcbXVfe2lnfStccGhpXG11X3tpZ31eMlxyaWdodCkKXGVuZHthcnJheX1ccmlnaHQuCiQkCgpXZSB3aWxsIGxvb2stdXAgdGhlIGRldGFpbHMgaW4gdGhlIHBhcGVyLiAKCgoKCiMgTGltbWEgLSBWb29tCgpbTGF3IGV0IGFsLiAoMjAxMykuIEdlbm9tZSBCaW9sb2d5XShodHRwczovL2dlbm9tZWJpb2xvZ3kuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni9nYi0yMDE0LTE1LTItcjI5KQoKLSBDb3VudCBtb2RlbHMgdnMgdHJhbnNmb3JtYXRpb246IFBvaXNzb24gY291bnRzLCAkXHNxcnQoeSkkICBzdGFiaWxpc2VzIHRoZSB2YXJpYW5jZSwgaW5zdWZmaWNpZW50IGZvciBuZWdhdGl2ZSBiaW5vbWlhbC4gCkxvZyB0cmFuc2Zvcm1hdGlvbjogdGhlIHRyYW5zZm9ybWVkIGRhdGEgYXJlIHN0aWxsIGhldGVyb3NjZWRhc3RpYy4kXHJpZ2h0YXJyb3ckIGxpbW1hLXZvb20KLSBVc2Ugbm9ybWFsaXplZCBsb2ctY3BtIExpbW1hIHBpcGVsaW5lIGZvciBzZXF1ZW5jaW5nCgpQcm9ibGVtOiBjb3VudHMgaGF2ZSBhIG1lYW4gdmFyaWFuY2UgcmVsYXRpb25zaGlwOiBoZXRlcm9zY2VkYXN0aWMKCkhvdyBkbyB3ZSBkZWFsIHdpdGggaGV0ZXJvc2NlZGFzdGljaXR5IGluIHRyYWRpdGlvbmFsIGxpbmVhciBtb2RlbHM/CgpUd28gc3RhZ2UgYXBwcm9hY2g6CgoxLiBTdGFnZSBJCgogIC0gT0xTCiAgLSBFc3RpbWF0ZSB2YXJpYW5jZXMgYXQgZWFjaCBkYXRhIHBvaW50CiAgLSBVc2UgdmFyaWFuY2VzIGFzIHdlaWdodHM6ICRXPVx0ZXh0e2RpYWd9WzEvXGhhdFxzaWdtYV9pXjJdJAoKMi4gU3RhZ2UgSUkgV0xTICRcdGV4dHthcmdtaW59X3tcYm9sZHN5bWJvbHtcYmV0YX19IFx7IChcbWF0aGJme3l9LVxtYXRoYmZ7WH1cYm9sZHN5bWJvbHtcYmV0YX0pXlRcbWF0aGJme1d9IChcbWF0aGJme3l9LVxtYXRoYmZ7WH1cYm9sZHN5bWJvbHtcYmV0YX0pXH0kCgoKUG9ydCB0aGlzIGlkZWEgdG8gUk5BLXNlcSBwaXBlbGluZQoKYGBge3IgZmlnLndpZHRoPS45OSwgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi4vZmlncy9saW1tYVZvb21QYXBlckNodW5rMS5wbmciKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0uOTksIGVjaG89RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIuL2ZpZ3MvbGltbWFWb29tUGFwZXJDaHVuazIucG5nIikKYGBgCgpgYGB7ciBmaWcud2lkdGg9Ljk5LCBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9maWdzL2xpbW1hVm9vbVBhcGVyRmlnMi5wbmciKQpgYGAKCgoKIyBJbmRlcGVuZGVudCBGaWx0ZXJpbmcKCkluZGVwZW5kZW50IGZpbHRlcmluZyBpcyBhIHN0cmF0ZWd5IHRvIHJlbW92ZSBmZWF0dXJlcyAoaW4gdGhpcyBjYXNlLCBnZW5lcykgcHJpb3IgdG8gdGhlIGFuYWx5c2lzLiBSZW1vdmFsIG9mIHRoZXNlIGZlYXR1cmVzIG1heSBsb3dlciB0aGUgbXVsdGlwbGUgdGVzdGluZyBjb3JyZWN0aW9uIGZvciBvdGhlciBnZW5lcyB0aGF0IHBhc3MgdGhlIGZpbHRlci4gV2UgdHJ5IHRvIHJlbW92ZSBnZW5lcyB0aGF0IGhhdmUgYSBsb3cgcG93ZXIgdG8gYmUgZm91bmQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgYW5kL29yIHRoYXQgYXJlIGJpb2xvZ2ljYWxseSBsZXNzIHJlbGV2YW50LiAKQSBjb21tb24gZmlsdGVyaW5nIHN0cmF0ZWd5IGlzIHRvIHJlbW92ZSBnZW5lcyB3aXRoIGEgZ2VuZXJhbGx5IGxvdyBleHByZXNzaW9uLCBhcyBsb3cgY291bnRzIGhhdmUgbG93ZXIgcmVsYXRpdmUgdW5jZXJ0YWludHkgKGhlbmNlIGxvd2VyIHN0YXRpc3RpY2FsIHBvd2VyKSwgYW5kIG1heSBiZSBjb25zaWRlcmVkIGJpb2xvZ2ljYWxseSBsZXNzIHJlbGV2YW50LgoKSW1wbGVtZW50YXRpb24gaW4gZWRnZVIuIAoKYGBge3J9Cj9maWx0ZXJCeUV4cHIKYGBgCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KGxpbW1hKQogIGxpYnJhcnkoZWRnZVIpCiAgbGlicmFyeShERVNlcTIpCn0pCgpkZHMgPC0gbWFrZUV4YW1wbGVERVNlcURhdGFTZXQoKQpzaW1Db3VudHMgPC1jb3VudHMoZGRzKQpncm91cCA8LSBkZHMkY29uZGl0aW9uCmRnZSA8LSBlZGdlUjo6REdFTGlzdChzaW1Db3VudHMpCmRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofmdyb3VwKQprZWVwIDwtIGZpbHRlckJ5RXhwcihkZ2UsIGRlc2lnbikKdGFibGUoa2VlcCkKYGBgCgpgYGB7cn0KbGliLnNpemUgPC0gZGdlJHNhbXBsZXMkbGliLnNpemUgKiBkZ2Ukc2FtcGxlcyRub3JtLmZhY3RvcnMKY3BtTWluQ291bnQgPC0gMTAvbWVkaWFuKGxpYi5zaXplKSoxZTYKc3VtbWFyeShncm91cCkKbWluU2FtcFNpemUgPC0gbWluKHN1bW1hcnkoZ3JvdXApKQptaW5TYW1wU2l6ZQprZWVwIDwtIHJvd1N1bXMoY3BtKGRnZSkgPiBjcG1NaW5Db3VudCkgPj0gbWluU2FtcFNpemUKdGFibGUoa2VlcCkKYGBgCgpgYGB7cn0KbGV2ZXJhZ2UgPC0gZGVzaWduJSolIHNvbHZlKHQoZGVzaWduKSUqJWRlc2lnbiklKiV0KGRlc2lnbikgJT4lZGlhZygpCjEvbGV2ZXJhZ2UKbWluKDEvbGV2ZXJhZ2UpCmBgYAoKSW5kZXBlbmRlbnQgZmlsdGVyaW5nIGhhcyBiZWVuIGZvcm1hbGl6ZWQgYnkgW0JvdXJnb24gKmV0IGFsLiogKDIwMTApXShodHRwczovL3d3dy5wbmFzLm9yZy9jb250ZW50LzEwNy8yMS85NTQ2KS4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmUgMSBmcm9tIEJvdXJnb24gKmV0IGFsLiogKDIwMTApLiIpLCBmaWcud2lkdGg9MC45OX0KIyBBbGwgZGVmYXVsdHMKaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9pbmRlcGVuZGVudEZpbHRlcmluZy5wbmciKQpgYGAKCiAtLS0KClRoZSBjb25jZXB0IG9mIGluZGVwZW5kZW50IGZpbHRlcmluZyBjYW4gYmUgc3VtbWFyaXplZCBhcyBmb2xsb3dzOgoKIC0gRm9yIGVhY2ggZmVhdHVyZSB3ZSBjYWxjdWxhdGUgdHdvIHN0YXRpc3RpY3MsICRTX0YkIGFuZCAkU19UJCwgcmVzcGVjdGl2ZWx5IHVzZWQgZm9yIHR3byBzdGFnZXM6IGZpbHRlcmluZyBhbmQgdGVzdGluZyAoZS5nLiwgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24pLgogLSBJbiBvcmRlciBmb3IgYSBmZWF0dXJlIHRvIGJlIGRlZW1lZCBzaWduaWZpY2FudCwgYm90aCBvZiBpdHMgc3RhdGlzdGljcyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBzb21lIGN1dC1vZmYuCiAtIFdlIHdhbnQgdG8gY29udHJvbCB0aGUgdHlwZSBJIGVycm9yIHJhdGUgb2YgdGhlIHNlY29uZCBzdGFnZSAodGVzdGluZykuIEJ1dCBub3RlIHRoYXQgKip0aGUgc2Vjb25kIHN0YWdlIGlzIGNvbmRpdGlvbmFsIG9uIHRoZSBmaXJzdCBzdGFnZSoqLCBhcyB3ZSBvbmx5IHRlc3QgZmVhdHVyZXMgcGFzc2luZyB0aGUgZmlsdGVyLCBhbmQgYmFzaWNhbGx5IGlnbm9yZSB0aGUgZmFjdCB0aGF0IGZpbHRlcmluZyB3YXMgcGVyZm9ybWVkLiBJbmRlZWQsIG9uZSBjcml0aWNpc20gaXMgdGhhdCBjb21wdXRpbmcgYW5kIGNvcnJlY3RpbmcgdGhlICRwJC12YWx1ZXMgYXMgaWYgZmlsdGVyaW5nIGhhZCBub3QgYmVlbiBwZXJmb3JtZWQgbWF5IGxlYWQgdG8gb3Zlcm9wdGltaXN0aWMgYWRqdXN0ZWQgJHAkLXZhbHVlcy4KIC0gW0JvdXJnb24gKmV0IGFsLiogKDIwMTApXShodHRwczovL3d3dy5wbmFzLm9yZy9jb250ZW50LzEwNy8yMS85NTQ2KSBzaG93IHRoYXQgZmlsdGVyaW5nIGlzIG9ubHkgYXBwcm9wcmlhdGUgKGkuZS4sIGRvZXMgbm90IGluZmxhdGUgdHlwZSBJIGVycm9yIHJhdGUpIGlmIHRoZSBjb25kaXRpb25hbCBudWxsIGRpc3RyaWJ1dGlvbiBvZiB0ZXN0IHN0YXRpc3RpY3MgZm9yIGZlYXR1cmVzIHBhc3NpbmcgdGhlIGZpbHRlciBpcyB0aGUgc2FtZSBhcyB0aGUgdW5jb25kaXRpb25hbCBudWxsIGRpc3RyaWJ1dGlvbi4gVGhlcmVmb3JlLCAqKmZpbHRlcmluZyBpcyBhcHByb3ByaWF0ZSBpZiB0aGUgc3RhdGlzdGljIHVzZWQgZm9yIGZpbHRlcmluZyBpcyBpbmRlcGVuZGVudCBvZiB0aGUgc3RhdGlzdGljIHVzZWQgZm9yIHRlc3RpbmcgdW5kZXIgdGhlIG51bGwgaHlwb3RoZXNpcyoqLgogCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmUgMiBmcm9tIEJvdXJnb24gKmV0IGFsLiogKDIwMTApLiIpLCBmaWcud2lkdGg9MC45OSxmaWcuYWxpZ249J2NlbnRlcid9CiMgQWxsIGRlZmF1bHRzCmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcvaW5kZXBlbmRlbnRGaWx0ZXJpbmcyLnBuZyIpCmBgYAogIC0tLQogIApMZXQncyB0cnkgYSBjb3VwbGUgb2YgZXhhbXBsZXMgdG8gZ2V0IHNvbWUgaW50dWl0aW9uIHVzaW5nIHNpbXVsYXRlZCBkYXRhLgoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KERFU2VxMikpCnNldC5zZWVkKDI0KQpkZHMgPC0gREVTZXEyOjptYWtlRXhhbXBsZURFU2VxRGF0YVNldCgpCnNpbUNvdW50cyA8LSBjb3VudHMoZGRzKQpncm91cCA8LSBkZHMkY29uZGl0aW9uCmBgYAoKIyMgQSBEZXBlbmRlbnQgVGVzdCBTdGF0aXN0aWMKCmBgYHtyfQpmaWx0ZXJTdGF0RWZmZWN0U2l6ZSA8LSBhYnMocm93TWVhbnMoc2ltQ291bnRzWyxncm91cCA9PSAiQSJdKSAtIHJvd01lYW5zKHNpbUNvdW50c1ssZ3JvdXAgPT0gIkIiXSkpCnRlc3RTdGF0IDwtIGdlbmVmaWx0ZXI6OnJvd3R0ZXN0cyhzaW1Db3VudHMsIGdyb3VwKQoKIyMgdW5jb25kaXRpb25hbCBkaXN0cmlidXRpb24KcGxvdChkZW5zaXR5KHRlc3RTdGF0JHN0YXRpc3RpYywgbmEucm09VFJVRSksCiAgICAgeGxhYiA9ICJUZXN0IHN0YXRpc3RpYyIsCiAgICAgbWFpbiA9ICJVbmNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbiIpCgojIyBjb25kaXRpb25hbCBkaXN0cmlidXRpb246IHZlcnkgZGlmZmVyZW50IQptZWFuKGZpbHRlclN0YXRFZmZlY3RTaXplID4gMSkKaGlzdChmaWx0ZXJTdGF0RWZmZWN0U2l6ZSwgYnJlYWtzPTQwKQphYmxpbmUodj0xLCBjb2w9InJlZCIpCmtlZXBFZmZlY3RTaXplIDwtIGZpbHRlclN0YXRFZmZlY3RTaXplID4gMQpwbG90KGRlbnNpdHkodGVzdFN0YXQkc3RhdGlzdGljW2tlZXBFZmZlY3RTaXplXSwgbmEucm09VFJVRSksCiAgICAgeGxhYiA9ICJUZXN0IHN0YXRpc3RpYyIsCiAgICAgbWFpbiA9ICJDb25kaXRpb25hbCBkaXN0cmlidXRpb24iKQpgYGAKCgojIyBBbiBJbmRlcGVuZGVudCBUZXN0IFN0YXRpc3RpYwoKYGBge3J9CmZpbHRlclN0YXRHbG9iYWxNZWFuIDwtIHJvd01lYW5zKHNpbUNvdW50cykKbWVhbihmaWx0ZXJTdGF0R2xvYmFsTWVhbiA+IDUpICMgd2UgcmVtb3ZlIGEgc2ltaWxhciBmcmFjdGlvbgprZWVwR2xvYmFsTWVhbiA8LSBmaWx0ZXJTdGF0R2xvYmFsTWVhbiA+IDUKCiMjIHVuY29uZGl0aW9uYWwgZGlzdHJpYnV0aW9uCnBsb3QoZGVuc2l0eSh0ZXN0U3RhdCRzdGF0aXN0aWMsIG5hLnJtPVRSVUUpLAogICAgIHhsYWIgPSAiVGVzdCBzdGF0aXN0aWMiLAogICAgIG1haW4gPSAiVW5jb25kaXRpb25hbCBkaXN0cmlidXRpb24iKQoKIyMgY29uZGl0aW9uYWwgZGlzdHJpYnV0aW9uOiB0aGUgc2FtZS4KcGxvdChkZW5zaXR5KHRlc3RTdGF0JHN0YXRpc3RpY1trZWVwR2xvYmFsTWVhbl0sIG5hLnJtPVRSVUUpLAogICAgIHhsYWIgPSAiVGVzdCBzdGF0aXN0aWMiLAogICAgIG1haW4gPSAiQ29uZGl0aW9uYWwgZGlzdHJpYnV0aW9uIikKYGBgCgoKIyBOb3JtYWxpemF0aW9uCgpOb3JtYWxpemF0aW9uIGlzIG5lY2Vzc2FyeSB0byBjb3JyZWN0IGZvciBzZXZlcmFsIHNvdXJjZXMgb2YgdGVjaG5pY2FsIHZhcmlhdGlvbjoKCiAtICoqRGlmZmVyZW5jZXMgaW4gc2VxdWVuY2luZyBkZXB0aCoqIGJldHdlZW4gc2FtcGxlcy4gU29tZSBzYW1wbGVzIGdldCBzZXF1ZW5jZWQgZGVlcGVyIGluIHRoZSBzZW5zZSB0aGF0IHRoZXkgY29uc2lzdCBvZiBtb3JlIChtYXBwZWQpIHJlYWRzIGFuZCB0aGVyZWZvcmUgY2FuIGJlIGNvbnNpZGVyZWQgdG8gY29udGFpbiBhIGhpZ2hlciBhbW91bnQgb2YgaW5mb3JtYXRpb24sIHdoaWNoIHdlIHNob3VsZCBiZSB0YWtpbmcgaW50byBhY2NvdW50LiBJbiBhZGRpdGlvbiwgaWYgYSBzYW1wbGUgaXMgc2VxdWVuY2VkIGRlZXBlciwgaXQgaXMgbmF0dXJhbCB0aGF0IHRoZSBjb3VudHMgZm9yIGVhY2ggZ2VuZSB3aWxsIGJlIGhpZ2hlciwgamVvcGFyZGl6aW5nIGEgZGlyZWN0IGNvbXBhcmlzb24gb2YgdGhlIGV4cHJlc3Npb24gY291bnRzLgogLSAqKkRpZmZlcmVuY2VzIGluIFJOQSBwb3B1bGF0aW9uIGNvbXBvc2l0aW9uKiogYmV0d2VlbiBzYW1wbGVzLiBBcyBhbiBleHRyZW1lIGV4YW1wbGUsIHN1cHBvc2UgdGhhdCB0d28gc2FtcGxlcyBoYXZlIGJlZW4gc2VxdWVuY2VkIHRvIHRoZSBleGFjdCBzYW1lIGRlcHRoLiBPbmUgc2FtcGxlIGlzIGNvbnRhbWluYXRlZCBhbmQgaGFzIGEgdmVyeSBoaWdoIGNvbmNlbnRyYXRpb24gb2YgdGhlIGNvbnRhbWluYW50IGNETkEgYmVpbmcgc2VxdWVuY2VkLCBidXQgb3RoZXJ3aXNlIHRoZSB0d28gc2FtcGxlcyBhcmUgaWRlbnRpY2FsLiBTaW5jZSB0aGUgY29udGFtaW5hbnQgd2lsbCBiZSB0YWtpbmcgdXAgYSBzaWduaWZpY2FudCBwcm9wb3J0aW9uIG9mIHRoZSByZWFkcyBiZWluZyBzZXF1ZW5jZWQsIHRoZSBjb3VudHMgd2lsbCBub3QgYmUgZGlyZWN0bHkgY29tcGFyYWJsZSBiZXR3ZWVuIHRoZSBzYW1wbGVzLiBIZW5jZSwgd2UgbWF5IGFsc28gd2FudCB0byBjb3JyZWN0IGZvciBkaWZmZXJlbmNlcyBpbiB0aGUgY29tcG9zaXRpb24gb2YgdGhlIFJOQSBwb3B1bGF0aW9uIG9mIHRoZSBzYW1wbGVzLgogLSAqKk90aGVyIHRlY2huaWNhbCB2YXJpYXRpb24qKiBzdWNoIGFzIHNhbXBsZS1zcGVjaWZpYyBHQy1jb250ZW50IG9yIHRyYW5zY3JpcHQgbGVuZ3RoIGVmZmVjdHMgbWF5IGFsc28gYmUgYWNjb3VudGVkIGZvci4KIAogCmBgYHtyfQpkYXRhKCJwYXJhdGh5cm9pZEdlbmVzU0UiLCBwYWNrYWdlPSJwYXJhdGh5cm9pZFNFIikKc2UxIDwtIHBhcmF0aHlyb2lkR2VuZXNTRQpybShwYXJhdGh5cm9pZEdlbmVzU0UpCgpjb2xEYXRhKHNlMSkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZmlsdGVyKGR1cGxpY2F0ZWQoZXhwZXJpbWVudCkpIApgYGAKClRoZXJlIGFyZSB0ZWNobmljYWwgcmVwZWF0cyBpbiB0aGUgZGF0YS4gCgpXZSBtZW50aW9uZWQgcHJldmlvdXMgbGVjdHVyZXMgdGhhdCB3ZSBjYW4gc3VtIG92ZXIgdGVjaG5pY2FsIHJlcGVhdHMsIGJlY2F1c2UgdGVjaGljYWwgcmVwZWF0cyBhcmUgUG9pc3NvbiBhbmQgdGhlIHN1bSBvZiB0d28gUG9pc3NvbiB2YXJpYWJsZXMgaXMgYWdhaW4gUG9pc3Nvbi4gCgpgYGB7cn0KZHVwRXhwcyA8LSBjb2xEYXRhKHNlMSkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZmlsdGVyKGR1cGxpY2F0ZWQoZXhwZXJpbWVudCkpICAlPiUgCiAgcHVsbChleHBlcmltZW50KQoKY291bnRzIDwtIGFzc2F5cyhzZTEpJGNvdW50cwpuZXdDb3VudHMgPC0gY291bnRzCmNkIDwtIGNvbERhdGEoc2UxKQpmb3Ioc3MgaW4gMTpsZW5ndGgoZHVwRXhwcykpewogICMgY2hlY2sgd2hpY2ggc2FtcGxlcyBhcmUgZHVwbGljYXRlcwogIHJlbGV2YW50SWQgPC0gd2hpY2goY29sRGF0YShzZTEpJGV4cGVyaW1lbnQgPT0gZHVwRXhwc1tzc10pCiAgIyBzdW0gY291bnRzCiAgbmV3Q291bnRzWyxyZWxldmFudElkWzFdXSA8LSByb3dTdW1zKGNvdW50c1sscmVsZXZhbnRJZF0pCiAgIyBrZWVwIHdoaWNoIGNvbHVtbnMgLyByb3dzIHRvIHJlbW92ZS4KICBpZihzcyA9PSAxKXsKICAgIHRvUmVtb3ZlIDwtIHJlbGV2YW50SWRbMl0KICB9IGVsc2UgewogICAgdG9SZW1vdmUgPC0gYyh0b1JlbW92ZSwgcmVsZXZhbnRJZFsyXSkKICB9Cn0KCiMgcmVtb3ZlIGFmdGVyIHN1bW1pbmcgY291bnRzIChvdGhlcndpc2UgSURzIGdldCBtaXhlZCB1cCkKbmV3Q291bnRzIDwtIG5ld0NvdW50c1ssLXRvUmVtb3ZlXQpuZXdDRCA8LSBjZFstdG9SZW1vdmUsXQoKIyBDcmVhdGUgbmV3IFN1bW1hcml6ZWRFeHBlcmltZW50CnNlIDwtIFN1bW1hcml6ZWRFeHBlcmltZW50KGFzc2F5cyA9IGxpc3QoImNvdW50cyIgPSBuZXdDb3VudHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IG5ld0NELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YShzZTEpKQoKdHJlYXRtZW50IDwtIGNvbERhdGEoc2UpJHRyZWF0bWVudAp0YWJsZSh0cmVhdG1lbnQpCmBgYAoKYGBge3J9CnFwbG90KGNvbFN1bXMoYXNzYXlzKHNlKSRjb3VudHMpLzFlNiwgZ2VvbT0iaGlzdG9ncmFtIiwgYmlucz0xMCxjb2w9ImJsYWNrIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHhsYWIoImxpYnNpemUgKG1pbGxpb24gcmVhZHMpIikKCnFwbG90KAogIGNvbERhdGEoc2UpJHRyZWF0bWVudDpjb2xEYXRhKHNlKSR0aW1lLAogIGNvbFN1bXMoYXNzYXlzKHNlKSRjb3VudHMpLzFlNixnZW9tPSJib3hwbG90IgogICkgKwogIHhsYWIoInRyZWF0bWVudCIpKwogIHlsYWIoImxpYnNpemUgKG1pbGxpb24gcmVhZHMpIikKCnFwbG90KAogIGNvbERhdGEoc2UpJHBhdGllbnQsCiAgY29sU3Vtcyhhc3NheXMoc2UpJGNvdW50cykvMWU2LGdlb209ImJveHBsb3QiCiAgKSArCiAgeGxhYigiUGF0aWVudCIpKwogIHlsYWIoImxpYnNpemUgKG1pbGxpb24gcmVhZHMpIikKYGBgCgpgYGB7cn0KbWEyU2FtcCA8LSBmdW5jdGlvbihjb3VudE14LGxpYlNpemU9TlVMTCkgewpzdG9waWZub3QoImBjb3VudE14YCBpcyBub3QgYSBtYXRyaXggd2l0aCB0d28gY29sdW1ucyIgPSBuY29sKGNvdW50TXgpID09IDIpCkEgPC0gY291bnRNeCAlPiUgbG9nMiAlPiUgcm93TWVhbnMKaWYoaXMubnVsbChsaWJTaXplKSkgCiAgTSA8LSBjb3VudE14ICU+JSBsb2cyICU+JSBhcHBseSguLDEsZGlmZikgCmVsc2UgCiAgTSA8LSBjb3VudE14ICU+JSBsb2cyICU+JSBhcHBseSguLDEsZGlmZikgLSBsaWJTaXplICU+JSBsb2cyICU+JSBkaWZmCncgPC0gY291bnRNeFssMV09PW1pbihjb3VudE14WywxXSkgfCBjb3VudE14WywyXT09bWluKGNvdW50TXhbLDJdKQppZiAoYW55KHcpKSB7CiAgICAgICAgICAgIEFbd10gPC0gcnVuaWYoc3VtKHcpLCBtaW4gPSAtMSwgbWF4ID0gLjEpCiAgICAgICAgICAgIE1bd10gPC0gbG9nMihjb3VudE14W3csMl0gKyAxKSAtIGxvZzIoY291bnRNeFt3LDFdICsgMSkKfQpNQXBsb3QgPC0gcXBsb3QoQSwgTSwgY29sPXcpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwib3JhbmdlIikpICsKICB4bGFiKCJBOiBsb2cyIEF2ZXJhZ2UiKSArCiAgeWxhYigiTTogbG9nMiBGb2xkIENoYW5nZSIpCgpNQXBsb3QgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdD0wLHNsb3BlPTAsY29sPSJibHVlIikgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdD1tZWRpYW4oTVshd10sbmEucm09VFJVRSksc2xvcGU9MCxjb2w9InJlZCIpCn0KYGBgCgpMZXTigJlzIHRha2UgYSBsb29rIGF0IGhvdyBjb21wYXJhYmxlIGRpZmZlcmVudCByZXBsaWNhdGVzIGFyZSBpbiB0aGUgQ29udHJvbCBjb25kaXRpb24gYXQgNDhoIGluIG91ciBkYXRhc2V0LiBXZSB3aWxsIGludmVzdGlnYXRlIHRoaXMgdXNpbmcgTUQtcGxvdHMgKG1lYW4tZGlmZmVyZW5jZSBwbG90cyBhcyBpbnRyb2R1Y2VkIGJ5IER1ZG9pdCBldCBhbC4gKDIwMDIpKSwgYWxzbyBzb21ldGltZXMgcmVmZXJyZWQgdG8gYXMgTUEtcGxvdHMuCgpgYGB7cn0KaWRzIDwtIHdoaWNoKGNvbERhdGEoc2UpJHRyZWF0bWVudCA9PSJDb250cm9sIiAmIGNvbERhdGEoc2UpJHRpbWUgPT0gIjQ4aCIpCmlkcwpjb2xTdW1zKGFzc2F5cyhzZSkkY291bnRzWyxpZHNdKSAvIDFlNgpgYGAKCmBgYHtyfQpwYWlyQ29tYiA8LSBjb21ibigKICBpZHMsIAogIG09MikKcGxvdHMgPC0gYXBwbHkocGFpckNvbWIsMixmdW5jdGlvbih4KSBtYTJTYW1wKGFzc2F5KHNlKVsseF0pICsgZ2d0aXRsZShwYXN0ZSgic2FtcGxlcyIseFsyXSwidnMiLCB4WzFdKSkpCmRvLmNhbGwoImdyaWQuYXJyYW5nZSIsYyhwbG90cyxuY29sPTMpKQpgYGAKCldlIHNlZSBjbGVhciBiaWFzIGZvciBzb21lIHBhaXJ3aXNlIGNvbXBhcmlzb25zLiBGb3IgZXhhbXBsZSwgaW4gdGhlIGZpcnN0IHBsb3QgY29tcGFyaW5nIHNhbXBsZSA4IHZlcnN1cyBzYW1wbGUgMiwgdGhlIGxvZyBmb2xkLWNoYW5nZXMgYXJlIGJpYXNlZCBkb3dud2FyZHMuIFRoaXMgbWVhbnMgdGhhdCwgb24gYXZlcmFnZSwgYSBnZW5lIGlzIGxvd2VyIGV4cHJlc3NlZCBpbiBzYW1wbGUgOCB2ZXJzdXMgc2FtcGxlIDIuIExvb2tpbmcgYXQgdGhlIGxpYnJhcnkgc2l6ZXMsIHdlIGNhbiBpbmRlZWQgc2VlIHRoYXQgdGhlIGxpYnJhcnkgc2l6ZSBmb3Igc2FtcGxlIDIgaXMgYWJvdXQgJDExw5cxMF42JCB3aGlsZSBpdCBpcyBvbmx5IGFib3V0ICQ3w5cxMF42JCBmb3Igc2FtcGxlIDghIFRoaXMgaXMgYSBjbGVhciBsaWJyYXJ5IHNpemUgZWZmZWN0IHRoYXQgd2Ugc2hvdWxkIHRha2UgaW50byBhY2NvdW50LgoKCldlIGNhbiBzb2x2ZSB0aGVzZSBpc3N1ZXMgYnkgaW50cm9kdWNpbmcgb2Zmc2V0cyBpbiBvdXIgbW9kZWwuCgokJAogIFxsZWZ0XHsKICBcYmVnaW57YXJyYXl9e2NjY30KICBZX3tnaX0gJiBcc2ltICYgUG9pKFxtdV97Z2l9KSBcXAogIFxsb2cgXG11X3tnaX0gJiA9ICYgXGV0YV97Z2l9IFxcCiAgXGV0YV97Z2l9ICYgPSAmIFxtYXRoYmZ7WH1eVF9pIFxiZXRhX2cgKyBsb2coT197Z2l9KSBcXAogIFxlbmR7YXJyYXl9CiAgXHJpZ2h0LgogICQkCiAgCgpgYGB7cn0KbGliU2l6ZSA8LSBjb2xTdW1zKGFzc2F5KHNlKSkKcGxvdHMyIDwtIGFwcGx5KHBhaXJDb21iLDIsZnVuY3Rpb24oeCkgbWEyU2FtcChhc3NheShzZSlbLHhdLGxpYlNpemUgPSBsaWJTaXplW3hdKSArIGdndGl0bGUocGFzdGUoInNhbXBsZXMiLHhbMl0sInZzIiwgeFsxXSkpKQpkby5jYWxsKCJncmlkLmFycmFuZ2UiLGMocGxvdHMyLG5jb2w9MykpCmBgYAoKIyMgVE1NIG1ldGhvZCAoZGVmYXVsdCBvZiBgZWRnZVJgKQoKW1JvYmluc29uIGFuZCBPc2hsYWNrICgyMDEwKS4gR2Vub21lIEJpb2xvZ3ldKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L2diLTIwMTAtMTEtMy1yMjUpCgpgYGB7ciBmaWcud2lkdGg9MC41LCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9PSIgUm9iaW5zb24gYW5kIE9zaGxhY2sgKDIwMTApLiBHZW5vbWUgQmlvbG9neS4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9maWdzL2VkZ2VSTm9ybUludHJvLnBuZyIpCmBgYAoKLSBPbiB0aGUgcGxvdCB3ZSBzZWUgYSBjbGVhciBlZmZlY3Qgb24gYWxsIGdlbmVzCi0gQ29ycmVjdGluZyBmb3IgbGlicmFyeSBzaXplIHRlbmRzIHRvIG92ZXIgY29ycmVjdC4gCi0gU29tZSBERSBnZW5lcyBhcmUgaGlnaGx5IGFidW5kYW50IGFuZCBkZXRlcm1pbmUgdGhlIGxpYnJhcnkgc2l6ZSB0byBhIGxhcmdlIGV4dGVuZAoKVGhlIHRyaW1tZWQgbWVhbiBvZiBNLXZhbHVlcyAoVE1NKSBtZXRob2QgaW50cm9kdWNlZCBieSBbUm9iaW5zb24gJiBPc2hsYWNrICgyMDEwKV0oaHR0cHM6Ly9nZW5vbWViaW9sb2d5LmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvZ2ItMjAxMC0xMS0zLXIyNSkgaXMgYSBub3JtYWxpemF0aW9uIHByb2NlZHVyZSB0aGF0IGNhbGN1bGF0ZXMgYSBzaW5nbGUgbm9ybWFsaXphdGlvbiBmYWN0b3IgZm9yIGVhY2ggc2FtcGxlLiBBcyB0aGUgbmFtZSBzdWdnZXN0cywgaXQgaXMgYmFzZWQgb24gYSB0cmltbWVkIG1lYW4gb2YgZm9sZC1jaGFuZ2VzICgkTSQtdmFsdWVzKSBhcyB0aGUgc2NhbGluZyBmYWN0b3IuIEEgdHJpbW1lZCBtZWFuIGlzIGFuIGF2ZXJhZ2UgYWZ0ZXIgcmVtb3ZpbmcgYSBzZXQgb2YgYGBleHRyZW1lJycgdmFsdWVzLiAKU3BlY2lmaWNhbGx5LCBUTU0gY2FsY3VsYXRlcyBhIG5vcm1hbGl6YXRpb24gZmFjdG9yICRGX2leeyhyKX0kIGFjcm9zcyBnZW5lcyAkZyQgZm9yIGVhY2ggc2FtcGxlICRpJCBhcyBjb21wYXJlZCB0byBhIHJlZmVyZW5jZSBzYW1wbGUgJHIkLAokJApcbG9nXzIoRl9pXnsocil9KSA9IFxmcmFje1xzdW1fe2cgXGluIHtcY2FsIEd9Xip9IHdfe2dpfV5yIE1fe2dpfV5yfXtcc3VtX3tnIFxpbiB7XGNhbCBHfV4qfSB3X3tnaX1ecn0sCiQkCndoZXJlICRNX3tnaX1eciQgcmVwcmVzZW50cyB0aGUgJFxsb2dfMiQtZm9sZC1jaGFuZ2Ugb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBmcmFjdGlvbiBhcyBjb21wYXJlZCB0byBhIHJlZmVyZW5jZSBzYW1wbGUgJHIkLCBpLmUuLAokJCBNX3tnaX1eciA9IFxsb2dfMlxsZWZ0KCBcZnJhY3tZX3tnaX0gLyBOX2l9eyBZX3tncn0gLyBOX3J9IFxyaWdodCksICQkCmFuZCAkd197Z2l9XnIkIHJlcHJlc2VudHMgYSBwcmVjaXNpb24gd2VpZ2h0IGNhbGN1bGF0ZWQgYXMKJCQKIHdfe2dpfV5yID0gXGZyYWN7Tl9pIC0gWV97Z2l9fXtOX2kgWV97Z2l9fSArIFxmcmFje05fciAtIFlfe2dyfX17Tl9yIFlfe2dyfX0sCiQkCmFuZCAke1xjYWwgR31eKiQgcmVwcmVzZW50cyB0aGUgc2V0IG9mIGdlbmVzIGFmdGVyIHRyaW1taW5nIHRob3NlIHdpdGggdGhlIG1vc3QgZXh0cmVtZSBhdmVyYWdlIGV4cHJlc3Npb24uIFRoZSB3ZWlnaHRzIHNlcnZlIHRvIGFjY291bnQgZm9yIHRoZSBmYWN0IHRoYXQgZm9sZC1jaGFuZ2VzIGZvciBnZW5lcyB3aXRoIGxvd2VyIHJlYWQgY291bnRzIGFyZSBtb3JlIHZhcmlhYmxlLgoKVGhlIHByb2NlZHVyZSBvbmx5IHRha2VzIGdlbmVzIGludG8gYWNjb3VudCB3aGVyZSBib3RoICRZX3tnaX0+MCQgYW5kICRZX3tncn0+MCQuIEJ5IGRlZmF1bHQsIFRNTSB0cmltcyBnZW5lcyB3aXRoIHRoZSAkMzBcJSQgbW9zdCBleHRyZW1lICRNJC12YWx1ZXMgYW5kICQ1XCUkIG1vc3QgZXh0cmVtZSBhdmVyYWdlIGdlbmUgZXhwcmVzc2lvbiwgYW5kIGNob29zZXMgYXMgcmVmZXJlbmNlICRyJCB0aGUgc2FtcGxlIHdob3NlIHVwcGVyLXF1YXJ0aWxlIGlzIGNsb3Nlc3QgdG8gdGhlIGFjcm9zcy1zYW1wbGUgYXZlcmFnZSB1cHBlci1xdWFydGlsZS4gVGhlIG5vcm1hbGl6ZWQgY291bnRzIGFyZSB0aGVuIGdpdmVuIGJ5ICRcdGlsZGV7WX1fe2dpfSA9IFlfe2dpfSAvIE5faV5zJCwgd2hlcmUgCiQkTl9pXnMgPSBcZnJhY3tOX2kgRl9pXnsocil9fXtcc3VtX3tpPTF9Xm4gTl9pIEZfaV57KHIpfS9ufS4kJAoKVE1NIG5vcm1hbGl6YXRpb24gbWF5IGJlIHBlcmZvcm1lZCBmcm9tIHRoZSBgY2FsY05vcm1GYWN0b3JzYCBmdW5jdGlvbiBpbXBsZW1lbnRlZCBpbiBgZWRnZVJgOgoKYGBge3J9CmRnZSA8LSBlZGdlUjo6Y2FsY05vcm1GYWN0b3JzKHNlKQpkZ2Ukc2FtcGxlcyAjbm9ybWFsaXphdGlvbiBmYWN0b3JzIGFkZGVkIHRvIGNvbERhdGEKYGBgCgpMZXQncyBjaGVjayBob3cgb3VyIE1ELXBsb3RzIGxvb2sgbGlrZSBhZnRlciBub3JtYWxpemF0aW9uLiBOb3RlIHRoYXQsIHdlIGNhbiByZXdyaXRlIHRoZSBHTE0gYXMKJCQgXGxvZ1xsZWZ0KCBcZnJhY3tcbXVfe2dpfX17Tl9pXnN9IFxyaWdodCkgPSBcbWF0aGJme1h9X2leVCBcYmV0YV9nICQkCmFuZCBzbyAkXGZyYWN7XG11X3tnaX19e05faV5zfSQgY2FuIGJlIGNvbnNpZGVyZWQgYXMgYW4gJ29mZnNldC1jb3JyZWN0ZWQgY291bnQnLgoKV2Ugc2VlIHRoYXQgYWxsIE1ELXBsb3RzIGFyZSBub3cgbmljZWx5IGNlbnRlcmVkIGFyb3VuZCBhIGxvZy1mb2xkLWNoYW5nZSBvZiB6ZXJvIQoKYGBge3J9CiMjIG5vcm1hbGl6ZQplZmZMaWJTaXplIDwtIGRnZSRzYW1wbGVzJGxpYi5zaXplICogZGdlJHNhbXBsZXMkbm9ybS5mYWN0b3JzCiNub3JtQ291bnRUTU0gPC0gc3dlZXAoYXNzYXlzKHNlKSRjb3VudHMsIDIsIEZVTj0iLyIsIGVmZkxpYlNpemUpCgpwbG90c05vcm0gPC0gYXBwbHkocGFpckNvbWIsMixmdW5jdGlvbih4KSAKICBtYTJTYW1wKGFzc2F5cyhzZSkkY291bnRzWyx4XSwgZWZmTGliU2l6ZVt4XSkgKyBnZ3RpdGxlKHBhc3RlKCJzYW1wbGVzIix4WzJdLCJ2cyIsIHhbMV0pKSkKZG8uY2FsbCgiZ3JpZC5hcnJhbmdlIixjKHBsb3RzTm9ybSxuY29sPTMpKQpgYGAKCgojIyBNZWRpYW4tb2YtUmF0aW9zIE1ldGhvZCAoZGVmYXVsdCBvZiBgREVTZXEyYCkKClRoZSBtZWRpYW4tb2YtcmF0aW9zIG1ldGhvZCBpcyB1c2VkIGluIGBERVNlcTJgIGFzIGRlc2NyaWJlZCBpbiBbTG92ZSAqZXQgYWwuKiAoMjAxNCldKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTQtMDU1MC04KS4KSXQgYXNzdW1lcyB0aGF0IHRoZSBleHBlY3RlZCB2YWx1ZSAkXG11X3tnaX0gPSBFKFlfe2dpfSkkIGlzIHByb3BvcnRpb25hbCB0byB0aGUgdHJ1ZSBleHByZXNzaW9uIG9mIHRoZSBnZW5lLCAkcV97Z2l9JCwgc2NhbGVkIGJ5IGEgbm9ybWFsaXphdGlvbiBmYWN0b3IgJHNfe2l9JCBmb3IgZWFjaCBzYW1wbGUsCiQkIFxtdV97Z2l9ID0gc197aX1xX3tnaX0uICQkCgpUaGUgbm9ybWFsaXphdGlvbiBmYWN0b3IgJHNfe2l9JCBpcyB0aGVuIGVzdGltYXRlZCB1c2luZyB0aGUgbWVkaWFuLW9mLXJhdGlvcyBtZXRob2QgY29tcGFyZWQgdG8gYSBzeW50aGV0aWMgcmVmZXJlbmNlIHNhbXBsZSAkciQgZGVmaW5lZCBiYXNlZCBvbiBnZW9tZXRyaWMgbWVhbnMgb2YgY291bnRzIGFjcm9zcyBzYW1wbGVzCiQkCnNfaSA9IFx0ZXh0e21lZGlhbn1fe1x7e2c6WV57Kn1fe2dyfSBcbmUgMH1cfX0gXGZyYWN7WV97Z2l9fXtZXnsqfV97Z3J9fSwKJCQKd2l0aCAKJCQgWV57Kn1fe2dyfSA9IFxsZWZ0KCBccHJvZF97aT0xfV5uIFlfe2dpfSBccmlnaHQpXnsxL259LiAkJAoKV2UgY2FuIHRoZW4gdXNlIHRoZSBzaXplIGZhY3RvcnMgJHNfaSQgYXMgb2Zmc2V0cyB0byB0aGUgR0xNLgoKTWVkaWFuLW9mLXJhdGlvcyBub3JtYWxpemF0aW9uIGlzIGltcGxlbWVudGVkIGluIHRoZSBgREVTZXEyYCBwYWNrYWdlOgoKYGBge3J9CmRkcyA8LSBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gYXNzYXlzKHNlKSRjb3VudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbERhdGEoc2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gMSkgI2p1c3QgYWRkIGludGVyY2VwdCB0byBzaG93Y2FzZSBub3JtYWxpemF0aW9uCmRkcyA8LSBERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzKQpzaXplRmFjdG9ycyhkZHMpCmBgYAoKWW91IG1heSBhbHNvIHdhbnQgdG8gY2hlY2sgb3V0IHRoZSBbU3RhdFF1ZXN0IHZpZGVvIG9uIERFU2VxMiBub3JtYWxpemF0aW9uXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PVVGQjk5M3h1ZlVVKS4KCiMjIyBDb21wYXJpbmcgVE1NIHdpdGggREVTZXEyIE5vcm1hbGl6YXRpb24KCldlIGNhbiBjb21wYXJlIHRoZSBzaXplIGZhY3RvcnMgZm9yIGJvdGggbm9ybWFsaXphdGlvbnMgdG8gdmVyaWZ5IGlmIHRoZXkgYWdyZWUgb24gdGhlIG5vcm1hbGl6YXRpb24gZmFjdG9ycy4gTm90ZSB3ZSBuZWVkIHRvIHNjYWxlIHRoZSBlZmZlY3RpdmUgbGlicmFyeSBzaXplcyBmcm9tIGBlZGdlUmAgdG8gZW5mb3JjZSBhIHNpbWlsYXIgc2NhbGUgYXMgdGhlIHNpemUgZmFjdG9ycyBmcm9tIGBERVNlcTJgLiBXaGlsZSBiZWxvdyB3ZSBhcmUgdXNpbmcgYW4gYXJpdGhtZXRpYyBtZWFuLCBhIGdlb21ldHJpYyBtZWFuIG1heSBiZSB1c2VkIGFzIHdlbGwsIHdoaWNoIHdpbGwgYmUgbW9yZSByb2J1c3QgdG8gb3V0bHlpbmcgZWZmZWN0aXZlIGxpYnJhcnkgc2l6ZXMuCgpgYGB7cn0KcGxvdChlZmZMaWJTaXplIC8gbWVhbihlZmZMaWJTaXplKSwgc2l6ZUZhY3RvcnMoZGRzKSwKICAgICB4bGFiID0gImVkZ2VSIHNpemUgZmFjdG9yIiwKICAgICB5bGFiID0gIkRFU2VxMiBzaXplIGZhY3RvciIpCmBgYAoKIyBBbGlhc2luZwoKU3VwcG9zZSB3ZSBhcmUgd29ya2luZyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudGFsIGRlc2lnbiBvbiBjb2xvbiBjYW5jZXIuIFN0dWR5aW5nIHRoZSBlZmZlY3Qgb2YgYSBkcnVnIG9uIGdlbmUgZXhwcmVzc2lvbiwgcmVzZWFyY2hlcnMgZ2F0aGVyIFJOQS1zZXEgZGF0YSBmcm9tIGZvdXIgY29sb24gY2FuY2VyIHBhdGllbnRzIGFuZCBmb3VyIGhlYWx0aHkgaW5kaXZpZHVhbHMuIEZvciBlYWNoIGluZGl2aWR1YWwsIHRoZXkgb2J0YWluIFJOQS1zZXEgZGF0YSBmcm9tIGEgYmxvb2Qgc2FtcGxlIGJlZm9yZSBhcyB3ZWxsIGFzIHR3byB3ZWVrcyBhZnRlciB0YWtpbmcgYSBkYWlseSBkb3NlIG9mIHRoZSBkcnVnLiBUaGUgcmVzZWFyY2ggcXVlc3Rpb24gcmVsYXRlcyB0byBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhZnRlciB2cy4gYmVmb3JlIHRha2luZyB0aGUgZHJ1ZywgaW4gcGFydGljdWxhciB3aGV0aGVyIHRoaXMgaXMgZGlmZmVyZW50IGZvciB0aGUgZGlzZWFzZWQgdmVyc3VzIGhlYWx0aHkgZ3JvdXAgKGkuZS4sIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRpbWUgKGJlZm9yZS9hZnRlciB0YWtpbmcgdGhlIGRydWcpIGFuZCBkaXNlYXNlIHN0YXR1cyAoaGVhbHRoeS9jb2xvbiBjYW5jZXIpKS4KCkluIHRlcm1zIG9mIHRoZSBtb2RlbCBtYXRyaXgsIHdlIGNvdWxkIGltYWdpbmUgYSBkZXNpZ24gc3VjaCBhcyBgIH4gcGF0aWVudCArIGRpc2Vhc2UqdGltZWAsIHdoZXJlIAoKIC0gYGRpc2Vhc2VgIGlzIGEgYmluYXJ5IGluZGljYXRvciByZWZlcnJpbmcgdG8gY29sb24gY2FuY2VyIHZlcnN1cyBjb250cm9sIHNhbXBsZS4KIC0gYHRpbWVgIGRlZmluZXMgaWYgdGhlIHNhbXBsZSBpcyB0YWtlbiBiZWZvcmUgb3IgYWZ0ZXIgdGFraW5nIHRoZSBkcnVnLgogLSBgcGF0aWVudGAgZGVmaW5lcyB0aGUgaW5kaXZpZHVhbCBkb25vciB0aGUgc2FtcGxlIGNvbWVzIGZyb20uCgpUaGUgcmVzZWFyY2ggcXVlc3Rpb24gY291bGQgdGhlbiBhbW91bnQgdG8gdGVzdGluZyB0aGUgYGRpc2Vhc2UgKiB0aW1lYCBpbnRlcmFjdGlvbi4KCkxldCdzIHRyeSB0aGlzLCBieSBzaW11bGF0aW5nIHJhbmRvbSBkYXRhIGZvciBvbmUgZ2VuZS4KCmBgYHtyfQpzZXQuc2VlZCgyKQojIDIgc2FtcGxlcyBwZXIgcGF0aWVudCBmb3IgOCBwYXRpZW50cwpwYXRpZW50IDwtIGZhY3RvcihyZXAobGV0dGVyc1sxOjhdLCBlYWNoPTIpKSAKIyBmaXJzdCBmb3VyIGFyZSBoZWFsdGh5LCBuZXh0IGZvdXIgYXJlIGRpc2Vhc2VkCmRpc2Vhc2UgPC0gZmFjdG9yKGMocmVwKCJoZWFsdGh5Iiw4KSwgcmVwKCJjYW5jZXIiLDgpKSwgbGV2ZWxzPWMoImhlYWx0aHkiLCAiY2FuY2VyIikpIAojIG9uZSBiZWZvcmUgYW5kIG9uZSBhZnRlciBzYW1wbGUgZm9yIGVhY2gKdGltZSA8LSBmYWN0b3IocmVwKGMoImJlZm9yZSIsICJhZnRlciIpLCA4KSwgbGV2ZWxzPWMoImJlZm9yZSIsICJhZnRlciIpKSAKCnRhYmxlKHBhdGllbnQsIGRpc2Vhc2UsIHRpbWUpCgojIyBzaW11bGF0ZSBkYXRhIGZvciBvbmUgZ2VuZQpuIDwtIDE2CnkgPC0gcnBvaXMobiA9IG4sIGxhbWJkYSA9IDUwKQoKIyMgZml0IGEgUG9pc3NvbiBtb2RlbAptIDwtIGdsbSh5IH4gcGF0aWVudCArIGRpc2Vhc2UqdGltZSwKICAgICAgICAgZmFtaWx5ID0gInBvaXNzb24iKQpzdW1tYXJ5KG0pCmBgYAoKIC0tLQogCldlIGZpbmQgdGhhdCBvbmUgb2YgdGhlIGNvZWZmaWNpZW50cyBpcyBgTkFgISBUaGlzIGlzIG9idmlvdXNseSBub3QgYmVjYXVzZSB3ZSdyZSBkZWFsaW5nIHdpdGggYE5BYCB2YWx1ZXMgaW4gdGhlIGRhdGEgYXMgd2UndmUganVzdCBzaW11bGF0ZWQgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIG91cnNlbHZlcy4gV2hhdCdzIGdvaW5nIG9uPwoKT25lIG9mIHRoZSBwYXJhbWV0ZXJzLCBpbiB0aGlzIGNhc2UgdGhlIHBhcmFtZXRlciBkaXN0aW5ndWlzaGluZyBjYW5jZXIgZnJvbSBoZWFsdGh5IHBhdGllbnRzICoqY2Fubm90IGJlIGVzdGltYXRlZCBhcyBpdCBpcyBhIGxpbmVhciBjb21iaW5hdGlvbiBvZiBvdGhlciBwYXJhbWV0ZXJzKiouIEluIG91ciBjYXNlLCBlc3RpbWF0aW5nIHRoZSBkaXNlYXNlZCBlZmZlY3Qgd291bGQgdXNlIGluZm9ybWF0aW9uIHRoYXQgaXMgYWxyZWFkeSB1c2VkIHRvIGVzdGltYXRlIHRoZSBwYXRpZW50LWxldmVsIGludGVyY2VwdHMuIEluIG90aGVyIHdvcmRzLCAqKm9uY2UgeW91IGtub3cgdGhlIHBhdGllbnQsIHlvdSBpbW1lZGlhdGVseSBhbHNvIGtub3cgdGhlIGRpc2Vhc2Ugc3RhdHVzKiosIHNvIGVzdGltYXRpbmcgdGhlIGRpc2Vhc2VkIHZzIGhlYWx0aHkgZWZmZWN0IG9uIHRvcCBvZiB0aGUgcGF0aWVudCBlZmZlY3QgcHJvdmlkZXMgbm8gYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBpZiB3ZSBoYXZlIGFscmVhZHkgZXN0aW1hdGVkIHRoZSBwYXRpZW50LWxldmVsIGVmZmVjdHMuIFRoaXMgY29uY2VwdCBpcyBjYWxsZWQgYWxpYXNpbmcsIGFuZCBpcyBhIGNvbW1vbiB0ZWNobmljYWwgaXNzdWUgaW4gJ29taWNzIGV4cGVyaW1lbnRzIHdpdGggY29tcGxleCBleHBlcmltZW50YWwgZGVzaWducy4gCgogLS0tCgpXaGlsZSB0byB1bmRlcnN0YW5kIHRoZSBvcmlnaW4gb2YgdGhlIGFsaWFzaW5nIGl0IGlzIGNydWNpYWwgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcyBpbiB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbiwgd2UgY2FuIGFsc28gaW52ZXN0aWdhdGUgaXQgaW4gZGV0YWlsIHVzaW5nIHRoZSBgYWxpYXNgIGZ1bmN0aW9uLCB0byBnaXZlIHVzIGFuIGlkZWEuCgpgYGB7cn0KYWxpYXMobSkKYGBgCgpXZSBzZWUgdGhhdCB0aGUgZWZmZWN0IGBkaXNlYXNlY2FuY2VyYCBpcyBhIGxpbmVhciBjb21iaW5hdGlvbiBvZiB0aGUgcGF0aWVudC1zcGVjaWZpYyBlZmZlY3RzIG9mIHRoZSBjYW5jZXIgcGF0aWVudHMuIFRoaXMgbWFrZXMgc2Vuc2UhCgogLS0tIAoKRm9yIGNsYXJpdHksIGxldCdzIHJlcHJvZHVjZSB0aGlzIHVzaW5nIG91ciBkZXNpZ24gbWF0cml4LgoKYGBge3J9ClggPC0gbW9kZWwubWF0cml4KH4gcGF0aWVudCArIGRpc2Vhc2UqdGltZSkgIyB0aGlzIGlzIHRoZSBkZXNpZ24gdXNlZCBpbiBnbG0oKQoKIyMgdGhlc2UgYXJlIGluZGVlZCBpZGVudGljYWwuClhbLCJkaXNlYXNlY2FuY2VyIl0KWFssInBhdGllbnRlIl0gKyBYWywicGF0aWVudGYiXSArIFhbLCJwYXRpZW50ZyJdICsgWFssInBhdGllbnRoIl0KYGBgCgpTaW5jZSBvbmUgb2Ygb3VyIHBhcmFtZXRlcnMgaXMgYSBsaW5lYXIgY29tYmluYXRpb24gb2Ygb3RoZXIgcGFyYW1ldGVycywgaXQgY2Fubm90IGJlIGVzdGltYXRlZCBzaW11bHRhbmVvdXNseSB3aXRoIHRoZSBvdGhlciBwYXJhbWV0ZXJzLiBJbiB0aGlzIGNhc2UsIHdlIGNhbiBhY3R1YWxseSBkcm9wIHRoZSBgZGlzZWFzZWAgbWFpbiBlZmZlY3QgZnJvbSB0aGUgbW9kZWwsIHNpbmNlIHdlIGtub3cgdGhhdCBpdCBpcyBhbHJlYWR5IGluY2x1ZGVkIGluIHRoZSBgcGF0aWVudGAgZWZmZWN0LgoKIC0tLQoKV2Ugd2lsbCBoYXZlIHRvIGNhcmVmdWxseSBjb25zdHJ1Y3Qgb3VyIGRlc2lnbiBtYXRyaXggaW4gb3JkZXIgdG8gYWNjb3VudCBmb3IgYWxsIGltcG9ydGFudCBzb3VyY2VzIG9mIHZhcmlhdGlvbiB3aGlsZSBzdGlsbCBhbGxvd2luZyB1cyB0byBhbnN3ZXIgdGhlIHJlc2VhcmNoIHF1ZXN0aW9uIG9mIGludGVyZXN0LiBUaGUgYWxpYXNpbmcgZXhwbG9yYXRpb24gYWJvdmUgaGFzIG1hZGUgaXQgY2xlYXIgd2UgbWF5IGRyb3AgdGhlIGBkaXNlYXNlYCBtYWluIGVmZmVjdCwgc28gbGV0J3Mgc3RhcnQgYnkgY29uc3RydWN0aW5nIHRoaXMgZGVzaWduIG1hdHJpeC4KCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeCh+IHBhdGllbnQgKyB0aW1lICsgZGlzZWFzZTp0aW1lKQoKbTIgPC0gZ2xtKHkgfiAtMSArIFgsCiAgICAgICAgIGZhbWlseSA9ICJwb2lzc29uIikKc3VtbWFyeShtMikKYWxpYXMobTIpCmBgYAoKV2UgYXJlIHN0aWxsIGNvbmZyb250ZWQgd2l0aCBhbGlhc2luZyBhcyB0aGUgbW9kZWwgbWF0cml4IGNvbnRhaW5zIGFuIGludGVyYWN0aW9uIGVmZmVjdCBgdGltZWJlZm9yZTpkaXNlYXNlY2FuY2VyYCBhcyB3ZWxsIGFzIGB0aW1lYWZ0ZXI6ZGlzZWFzZWNhbmNlcmAsIHdoaWxlIG9ubHkgdGhlIGxhdHRlciBpcyByZWxldmFudC4gSW5kZWVkLCB3ZSBrbm93IHRoYXQgd2UgY2FuIGRlcml2ZSB0aGUgYHRpbWViZWZvcmU6ZGlzZWFzZWNhbmNlcmAgZWZmZWN0IGJ5IGF2ZXJhZ2luZyB0aGUgcGF0aWVudCBlZmZlY3RzIG9mIHRoZSBjYW5jZXIgcGF0aWVudHMuCgogLS0tCgpgYGB7cn0KWCA8LSBYWywhY29sbmFtZXMoWCkgJWluJSAidGltZWJlZm9yZTpkaXNlYXNlY2FuY2VyIl0KCgojIyBmaXQgYSBQb2lzc29uIG1vZGVsCm0yIDwtIGdsbSh5IH4gLTEgKyBYLAogICAgICAgICBmYW1pbHkgPSAicG9pc3NvbiIpCnN1bW1hcnkobTIpCmBgYAoKV2Ugc2VlIHRoYXQgYWxsIGNvZWZmaWNpZW50cyBjYW4gbm93IGJlIGVzdGltYXRlZC4gVGhlIGB0aW1lYWZ0ZXJgIGVmZmVjdCBtYXkgYmUgaW50ZXJwcmV0ZWQgYXMgdGhlIHRpbWUgZWZmZWN0IGZvciBoZWFsdGh5IHBhdGllbnRzLCB3aGlsZSB0aGUgYHRpbWVhZnRlcjpkaXNlYXNlY2FuY2VyYCBlZmZlY3QgbWF5IGJlIGludGVycHJldGVkIGFzIHRoZSBkaWZmZXJlbmNlIGluIHRoZSB0aW1lIGVmZmVjdCBmb3IgY2FuY2VyIHBhdGllbnRzIGFzIGNvbXBhcmVkIHRvIGhlYWx0aHkgcGF0aWVudHMsIGkuZS4sIGl0IGlzIHRoZSByZWxldmFudCBpbnRlcmFjdGlvbiBlZmZlY3Qgd2UgYXJlIGludGVyZXN0ZWQgaW4uIAoK