In this lecture we will introduce the main principles of working with
count data, and how to model these using generalized linear models
(GLMs). We focus on introducing the concept of generalized linear
models, and how they can be applied to genomics data analysis.
The Poisson
distribution
- The Poisson distribution is a typical count distribution that is
generally popular and fairly easy to work with. It is defined by a
single parameter: its mean \(\mu\). For
a Poisson distributed random variable \(Y_i\) with observations \(i \in \{1, \ldots, n\}\), its variance is
equal to its mean. That is, if
\[Y_i \sim Poi(\mu)\] , then
\[E(Y_i) = Var(Y_i) = \mu.\]
This immediately shows an important feature of count data: the
mean-variance relationship. Indeed, in count data, the
variance will always be a function of the mean.
This is quite intuitive. Consider the following example. You have
two bird cages, where in one bird cage there are \(10\) birds, while in the other there are
\(100\) birds. You let a sample of
people look to the number of birds in either one of the cages. It seems
unlikely that a person in front of the 10-bird cage would come up with
an estimate of \(3\), while it seems
likely that someone in front of the 100-bird cage would come up with an
estimate of \(80\). Even though the
difference from the true value is the same, the exact value has an
impact on the plausible deviation around it.
set.seed(11)
y1 <- rpois(n=500, lambda=10)
y2 <- rpois(n=500, lambda=100)
par(mfrow = c(1,2))
qplot(y1, main="Poisson(10)", geom = "histogram", binwidth=.5,center=0)
## Warning: `qplot()` was deprecated in ggplot2 3.4.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
qplot(y2, main="Poisson(100)", geom = "histogram", binwidth=.5,center=0)
The Poisson
distribution in RNA-seq
- In RNA-seq, technical replicates represent different aliquots of the
same sample being sequenced repeatedly. The underlying true expression
of a gene can hence safely be assumed to be equal across these technical
replicates.
- Marioni et
al. (2008) have shown that, for most genes, the distribution of
observed gene expression counts across technical replicates follow a
Poisson distribution. A small proportion of genes (\(\sim 0.5\%\)) do not follow this Poisson
model, however, and actually show evidence for ‘extra-Poisson
variation’.
Relative uncertainty
for Poisson distributed random variables
Take a minute to consider the following question:
- Suppose that we have a solid tumor sample from a cancer patient, as
well as a sample of surrounding healthy tissue. For each sample, we have
three technical replicates at our disposal. Let \(Y_{grt}\) denote the observed gene
expression values of gene \(g\) in
replicate \(r \in \{1,2,3\}\) from
tissue \(t \in \{0,1\}\), where \(t=0\) denotes healthy tissue and \(t=1\) denotes tumoral tissue.
- We then know that the random variables \(Y_{gr0}\) and \(Y_{gr1}\) follow a Poisson distribution,
and we would estimate its mean as \(\bar{Y}_{g0} = \frac{1}{3} \sum_{r=1}^3
Y_{gr0}\) and \(\bar{Y}_{g1} =
\frac{1}{3} \sum_{r=1}^3 Y_{gr1}\), respectively.
- Similar, for another gene \(k\), we
observe \(Y_{krt}\), and estimate \(\bar{Y}_{k0}\) and \(\bar{Y}_{k1}\) correspondingly.
- Now suppose that \(\beta_{k} =
\bar{Y}_{k1} / \bar{Y}_{k0} = 5\), but also \(\beta_g = \bar{Y}_{g1} / \bar{Y}_{g0} =
5\), i.e., the two genes have the same average expression ratio
(also often called a fold-change) across samples. However, they are
differently expressed as \(\bar{Y}_{k1} =
100\), and \(\bar{Y}_{g1} = 10\)
(making \(\bar{Y}_{k0} = 20\), and
\(\bar{Y}_{g0} = 2\)).
- For which of the two genes is the uncertainty on the expression
ratio the highest? In other words, do we trust \(\beta_k\) more or do we trust \(\beta_g\) more?
Let’s approximate the uncertainty in \(beta_g\) and \(\beta_k\) using simulation:
N <- 1e3
beta_g <- beta_k <- vector(length=N)
for(ii in 1:N){
ygr1 <- rpois(n=3, lambda=10)
ygr0 <- rpois(n=3, lambda=2)
ykr1 <- rpois(n=3, lambda=100)
ykr0 <- rpois(n=3, lambda=20)
beta_g[ii] <- mean(ygr1) / mean(ygr0)
beta_k[ii] <- mean(ykr1) / mean(ykr0)
}
par(mfrow=c(1,2), mar=c(4,2,3,1))
hist(beta_g, breaks=seq(0,50,by=1), xlim=c(0,50))
hist(beta_k, breaks=seq(0,50,by=1), xlim=c(0,50))
We clearly see that the uncertainty on \(\beta_k\) is much lower than on \(\beta_g\). Even though the variance on the
counts of gene \(k\) is higher, since
its mean is higher and it is distributed as a Poisson variable. How do
we explain this?
- We may explain this by considering the relative uncertainty on the
mean. Relative uncertainty may be defined as the coefficient of
variation \(CV = \frac{\sigma}{\mu}\)
(this is, the standard deviation divided by the mean). Indeed, the CV
describes the relative deviation of the distribution relative to its
mean, where a low CV indicates low dispersion with respect to the
mean.
- Calculating the CV shows that the relative uncertainty for
gene \(k\) than for gene \(g\), even though the variance on the raw
counts is higher for gene \(k\) than
for gene \(g\).
- This lower relative uncertainty on the mean then propagates further
to a lower uncertainty on the fold-change. This basic result will be
essential for understanding the results of a differential expression
analysis!
sqrt(100)/100 #CV for gene k
## [1] 0.1
sqrt(10)/10 #CV for gene g
## [1] 0.3162278
Modeling count data:
Generalized linear models
Just like we have modeled protein abundances in the proteomics module
of this course in order to assess differential protein abundance, we can
model gene expression counts to identify genes with differences in
average expression between groups of samples.
Why we can(’t) use
linear models to model count data
- If we are using a linear model to model a response \(Y_i\), with \(i
\in \{1, \ldots, n\}\) in function of a single covariate \(X_i\), the linear model can be defined as
follows:
\[
\left\{
\begin{array}{ccc}
Y_i & = & \beta_0 + \beta_1 x_i + \epsilon_i \\
Y_i | x_i & \sim & N(\beta_0 + \beta_1 x_i, \sigma^2 ).
\end{array}
\right.
\]
- Or, equivalently, we can write it in matrix form as \[
\left\{
\begin{array}{ccc}
Y & = & \mathbf{X}^T \boldsymbol{\beta} + \epsilon \\
Y | \mathbf{X} & \sim & N(\mathbf{X} \boldsymbol{\beta},
\sigma^2 \mathbf{I}),
\end{array}
\right.
\] where \(\mathbf{X}\) now
represents our \(n \times p\) design
matrix, with row \(i\) corresponding to
observation \(i\).
The variance-covariance matrix of \(\mathbf{Y}\) is assumed a diagonal matrix
with \(\sigma^2\) on the diagonal
elements and zero everywhere else. This means that the data points are
uncorrelated, and that every observation has the same variance \(\sigma^2\), also referred to as
homoscedasticity.
The latter does not hold for count data, due to the mean-variance
relationship. This makes linear models, in its basic form, unsuitable to
model count data.
In addition, count data are non-negative, while there are no such
constraints in the standard linear model to make sure that our estimates
will be non-negative. Indeed, \(\hat{Y}_i =
\hat\mu_i = \mathbf{X}^T_i \hat{\beta} \in ] -\infty,
\infty[\).
Generalized linear
models
- As the name suggests, generalized linear models (GLMs) extend linear
models. In GLMs, we extend two things with respect to the linear model:
- The conditional distribution of the response variable \(Y_i | X_i\) can be assumed to
follow any distribution that belongs to the exponential
family of distributions, which includes the Gaussian but also
other commonly known distributions, such as the Binomial, Gamma and
Poisson distribution.
- The linear model assumed a linear relationship between \(Y_i\) and \(X_i\), since we assumed that \(E(Y_i | X_i) = \mathbf{X}^T_i \beta\). In
GLMs, we will allow a link function \(g()\) that links the conditional mean to
the covariates. Hence, in GLMs we have that \(g(E(Y_i | X_i)) = \mathbf{X}^T_i \beta\).
Note that each family has got a canonical link function, which is the
identity link function \(g(\mu) = \mu\)
for Gaussian, the log link function \(g(\mu) =
\log \mu\) for Poisson, or the logit link function \(g(\mu) = \log(\frac{\mu}{1-\mu})\) for
Binomial.
A Poisson GLM
- We can define a Poisson GLM as follows \[
\left\{
\begin{array}{ccc}
Y_i & \sim & Poi(\mu_i) \\
\log \mu_i & = & \eta_i \\
\eta_i & = & \mathbf{X}^T_i \beta \\
\end{array}
\right.
\] where \(Y_i\) is the
response variable, with mean \(\mu_i\),
\(\eta_i\) is the linear predictor,
\(\mathbf{X}\) is the \(n \times p\) model matrix and \(\beta\) is the \(p \times 1\) matrix of regression
coefficients.
- It is insightful to compare this model to a linear model where \(Y_i\) is log-transformed. Indeed, in the
linear model case, we would be modeling \(E(\log Y_i )\), while in the GLM we are
modeling \(\log E(Y_i)\).
- This shows that in the GLM setting we are modeling a transformed
version of the expected value, and after retransforming we can interpret
the fit in terms of the mean of our response variable. In the
transformed linear model, however, we are working with the expected
value of a transformed version of our response variable, and we will not
be able to interpret the fit in terms of the mean (because \(E( \log Y_i) \ne \log E(Y_i)\). In this
specific case, we would have to resort to interpreting changes in terms
of a geometric mean.
- Also note that \(\mathbf{X}^T_i \beta \in
]-\infty, \infty[\), while \(Y_i\) must be non-negative \([0, \infty[\). The link function helps with
this, since the exponential function transforms any real number to a
non-negative number, i.e., \(\exp(\mathbf{X}^T_i \beta) \in [0,
\infty[\).
Sequencing Data
In this lecture we will use a subset of the real bulk RNA-seq dataset
from Haglund
et al. (2012).
Lets try to work out the experimental design using the following
paragraph from the Methods section of the paper.
Technical
repeats
There are technical repeats in the data!
data("parathyroidGenesSE", package="parathyroidSE")
se <- parathyroidGenesSE
rm(parathyroidGenesSE)
colData(se) %>% knitr::kable(.)
SRR479052 |
SRX140503 |
1 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308865 |
SRR479053 |
SRX140504 |
1 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308866 |
SRR479054 |
SRX140505 |
1 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308867 |
SRR479055 |
SRX140506 |
1 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308868 |
SRR479056 |
SRX140507 |
1 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308869 |
SRR479057 |
SRX140508 |
1 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308870 |
SRR479058 |
SRX140509 |
2 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308871 |
SRR479059 |
SRX140510 |
2 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308872 |
SRR479060 |
SRX140511 |
2 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308873 |
SRR479061 |
SRX140511 |
2 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308873 |
SRR479062 |
SRX140512 |
2 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308874 |
SRR479063 |
SRX140513 |
2 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308875 |
SRR479064 |
SRX140513 |
2 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308875 |
SRR479065 |
SRX140514 |
2 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308876 |
SRR479066 |
SRX140515 |
3 |
Control |
24h |
SRA051611 |
SRP012167 |
SRS308877 |
SRR479067 |
SRX140516 |
3 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308878 |
SRR479068 |
SRX140517 |
3 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308879 |
SRR479069 |
SRX140518 |
3 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308880 |
SRR479070 |
SRX140519 |
3 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308881 |
SRR479071 |
SRX140520 |
3 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308882 |
SRR479072 |
SRX140521 |
4 |
Control |
48h |
SRA051611 |
SRP012167 |
SRS308883 |
SRR479073 |
SRX140522 |
4 |
DPN |
24h |
SRA051611 |
SRP012167 |
SRS308884 |
SRR479074 |
SRX140523 |
4 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308885 |
SRR479075 |
SRX140523 |
4 |
DPN |
48h |
SRA051611 |
SRP012167 |
SRS308885 |
SRR479076 |
SRX140524 |
4 |
OHT |
24h |
SRA051611 |
SRP012167 |
SRS308886 |
SRR479077 |
SRX140525 |
4 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308887 |
SRR479078 |
SRX140525 |
4 |
OHT |
48h |
SRA051611 |
SRP012167 |
SRS308887 |
se %>%
colData %>%
as.data.frame %>%
pull(sample) %>%
nlevels
## [1] 23
## [1] 27
Extract sample names of duplicates!
dupl <- which(table(colData(se)$sample) > 1) %>% names
techreps <- assays(se)$counts[,colData(se)$sample==dupl[1]]
Explore the data of
two technical repeats
We expect the counts to be very similar. Indeed, they are based on
the same cell culture, stimulated with the same stimulus and incubated
for the same time.
qplot(techreps[,1],techreps[,2]) +
geom_abline(intercept = 0, slope = 1) +
xlab("Technical repeat 1") +
ylab("Technical repeat 2")
The plot shows a systematic difference between the counts of both
technical repeats!
However, plotting the data on the original count scale does not
give a good overview of the data. The plot is dominated by a few very
abundant genes, i.e. genes with very high counts.
Explore the data of
two technical repeats
qplot(techreps[,1],techreps[,2], log="xy") +
geom_abline(intercept = 0, slope = 1) +
xlab("Technical repeat 1") +
ylab("Technical repeat 2")
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning in scale_y_log10(): log-10 transformation introduced infinite values.
The plot clearly shows that the counts for all genes are very
different in the two technical repeats.
However, we have to look at the plot via the diagonal.
In omics we therefore often use MA plots. With M (log ratio) and
A (log average).
A <- techreps %>% log2 %>% rowMeans
M <- techreps %>% log2 %>% apply(.,1,diff)
w <- techreps[,1]==min(techreps[,1]) | techreps[,2]==min(techreps[,2])
if (any(w)) {
A[w] <- runif(sum(w), min = -1, max = .1)
M[w] <- log2(techreps[w,2] + 1) - log2(techreps[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)
The MA plot clearly shows that the counts of one technical repeat are
systematically higher than that of the other technical repeats.
## [1] 5251911 19332369
logFCdepth <- colSums(techreps) %>% log2 %>% diff
logFCdepth
## [1] 1.880104
## [1] 3.681016
The technical repeats differ with a factor 3.7 in sequencing
depth!
MAplot + geom_abline(intercept = logFCdepth, slope = 0, color="red")
- This log2 fold change in sequencing depth is also the baseline
around which the log2 fold changes between technical repeats of
individual genes are fluctuating!
Hence, we will have to correct for differences in sequencing
depth.
Count scaling using
GLM offsets
We have previously discussed count scaling transformations such
as CPM and TPM.
A more appropriate and natural way when working with GLMs is
through the use of offsets. The general use of an offset is to account
for the ‘effort’ performed in order to gather that observation of the
response variable.
\(\rightarrow\) i.e. sample being
sequenced deeper contains more information as compared to a sample being
sequenced relatively shallow. We have more confidence in a count from a
deeply sequenced sample than that from a shallowly sequenced sample. We
can therefore use the sequencing depth \(N_i=\sum_g Y_{gi}\) as offset in the
model.
Adding an offset to the model is different from adding a new
variable to the model. For each new variable we add, we will estimate
its average effect \(\beta\) on the
response variable. When adding an offset, however, we implicitly set
\(\beta=1\).
Offsets are typically added on the scale of the linear predictor.
Suppose we have a gene g and sample i specific offset \(O_{gi}\), then we can define our GLM
including the offset as
\[
\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.
\]
When we would like to correct for the overall sequencing depth \(O_{gi}=N_i\). However, better offsets
exist!
Note, that
\[
\mu_{ig}= \exp(\mathbf{X}^T_i \beta_g) \times O_{gi}
\] or \[
\log\left(\frac{\mu_{ig}}{O_{gi}}\right)= \mathbf{X}^T_i \beta_g
\]
Biological
repeats
We extract the four biological repeats from the study for the control
treatment at time 24h.
bioreps <- colData(se)$treatment=="Control" & colData(se)$time=="24h"
biorepCounts <- assays(se)$counts[,bioreps]
qplot(rowMeans(biorepCounts),rowVars(biorepCounts),log="xy") +
geom_abline(intercept = 0,slope = 1,col="red") +
geom_smooth(col="orange")
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning in scale_y_log10(): log-10 transformation introduced infinite values.
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning in scale_y_log10(): log-10 transformation introduced infinite values.
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
## Warning: Removed 37702 rows containing non-finite outside the scale range
## (`stat_smooth()`).
Having data on thousands of genes provides the opportunity to
empirically assess the mean-variance relationship.
It is clear that the data is overdispersed with respect to the
Poisson distribution (red y=x line). There also seems to be a quadratic
trend of the variance as a function of the mean.
Negative binomial
distribution
The observed quadratic mean variance trend has motivated the use of
the negative binomial distribution to model (bulk) RNA-seq gene
expression data.
\[
\left\{
\begin{array}{ccc}
Y_{gi} & \sim & NB(\mu_{gi},\phi_g) \\
\log \mu_{gi} & = & \eta_{gi} \\
\eta_{gi} & = & \mathbf{X}^T_i \beta_g + log(O_{gi}) \\
\end{array}
\right.
\]
with
\[
\text{var}[Y_{gi}] = \mu_{gi} + \phi_g \mu_{gi}^2
\]
total variability |
= |
technical variability |
+ |
biological variability |
\(\text{var}[Y_{gi}]\) |
= |
\(\mu_{gi}\) |
+ |
\(\phi_g \mu_{gi}^2\) |
total CV\(^2\) |
= |
\(\frac{1}{\mu_{gi}}\) |
+ |
\(\phi_g\) |
What about technical
repeats?
- Technical repeats are Poisson distributed.
- The sum of two Poisson distributed counts is again Poisson. So we
can summarize over technical repeats by taking the sum of the counts.
This enables us to collapse the technical repeats to the level of
biological repeats.
- We will illustrate that in the tutorial session.
Estimating the
overdispersion?
- Gene wise: for every single gene, very unstable due to the lack of
data
- Common dispersion for all genes
- Trended dispersion
- Tag-wise: EB shrinkage to a common (trended) dispersion: Borrow
strength across genes (McCarthy & Smyth, 2012, DOI:
10.1093/nar/gks042)
In the tutorials we will analyse the entire study and we will focus
on assessing the main research questions: i.e. comparing the early and
late effects of the stimuli, and if the effect of stimuli is changes
over time.
Here, we illustrate the estimation using the edgeR tool on a subset
of control treatment for patients 1, 2 and 3. For this subset only
biological repeats are sequenced and a measurement on time 24 and 48h
has been taken for cells of each patient.
So we can model the study using a simple block design with a time effect
and a block effect for patient.
- Setup the data
seSub <- se[,colData(se)$treatment=="Control"&colData(se)$patient%in%1:3]
colData(seSub)$patient <- colData(seSub)$patient %>%
as.double %>%
as.factor
y <- DGEList(counts = assays(seSub)$counts)
design <- model.matrix(~time+patient,colData(seSub))
- Typically lowly expressed genes are filtered.
keep <- filterByExpr(y,design)
y <- y[keep,]
- Normalisation to correct for differences in library size.
- Estimate the dispersions using empirical Bayes (EB)
y <- estimateDisp(y, design)
- Estimate gene-wise dispersions without shrinkage for comparison
purposes
yNoEB <- estimateDisp(y, design, prior.df = 0)
- Visualisation and comparison of tag-wise (EB) and genewise
dispersion
o <- order(y$AveLogCPM)
data.frame(
AveLogCPM=rep(yNoEB$AveLogCPM[o],2),
BCV=sqrt(
c(yNoEB$tagwise.dispersion[o],
y$tagwise.dispersion[o])
),
method=rep(c("genewise","tagwise"), each=nrow(y))) %>%
ggplot(aes(AveLogCPM,BCV,color=method)) +
geom_point(size = .2) +
geom_line(
data = data.frame(
AveLogCPM=y$AveLogCPM[o],
BCV = sqrt(y$trended.dispersion[o]),
method="trended")) +
scale_colour_manual(values =c('black','orange','blue'))+
ylab("Biological Coefficient of Variation") +
xlab("Average log CPM")
Note, that
- The gene-wise dispersion is very variable (black dots).
- There is a dispersion - mean trend (blue line)
- The tag-wise dispersions (orange dots) are the result of shrinking
the gene-wise dispersion (black dots) to the trend (blue line)
By default edgeR provides the following plot
In the methods paper of edgeR different dispersion estimators were
compared and the tag-wise dispersions seemed to provide the best
goodness of fit.
Statistical
Inference
Asymptotic statistical tests exist to test if (contrasts of the)
parameters of the GLM are different from zero.
Implemented in edgeR and DESeq2.
Again we have to correct for multiple testing !!! FDR correction
is done by default in the edgeR and DESeq2 output
- Fit the model
fit <- glmFit(y,design)
head(fit$coefficients)
## (Intercept) time48h patient2 patient3
## ENSG00000000003 -9.349871 0.13638138 -0.5613559 -0.7834884
## ENSG00000000419 -10.391095 -0.09800617 0.1057271 0.1356434
## ENSG00000000457 -10.928625 -0.08069712 0.4491010 -0.1289007
## ENSG00000000460 -10.041597 -0.81035512 0.5044914 -0.5433122
## ENSG00000000938 -14.614695 0.39307169 1.4719170 0.1349905
## ENSG00000000971 -13.512986 0.46252084 -0.2107229 0.5042261
Interpretation of model parameters?
- Statistical test to assess the time effect
lrt <- glmLRT(fit, coef = "time48h")
topTags(lrt)
## Coefficient: time48h
## logFC logCPM LR PValue FDR
## ENSG00000164089 4.284786 3.099739 213.7650 2.072422e-48 3.294944e-44
## ENSG00000148795 3.026969 3.686056 183.3434 9.025281e-42 7.174647e-38
## ENSG00000133110 1.293005 7.185439 164.0009 1.512056e-37 8.013393e-34
## ENSG00000211445 1.450374 8.966014 162.1696 3.798734e-37 1.509902e-33
## ENSG00000107796 1.398750 6.002617 146.0886 1.241600e-33 3.865574e-30
## ENSG00000169239 1.557744 7.377027 145.7683 1.458799e-33 3.865574e-30
## ENSG00000188404 -1.590059 9.851890 141.9293 1.007722e-32 2.288824e-29
## ENSG00000136235 1.375796 5.149565 139.4353 3.537613e-32 7.030564e-29
## ENSG00000163631 1.835300 4.898878 135.1416 3.074462e-31 5.431208e-28
## ENSG00000005189 -1.702284 5.615167 134.7941 3.662515e-31 5.823032e-28
LS0tCnRpdGxlOiAnSW50cm9kdWN0aW9uIHRvIFNlcXVlbmNpbmc6IFdvcmtpbmcgd2l0aCBSTkEtc2VxIGNvdW50IGRhdGEnCmF1dGhvcjogIktvZW4gVmFuIGRlbiBCZXJnZSAmIExpZXZlbiBDbGVtZW50IgpkYXRlOiAiTGFzdCBlZGl0ZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiA0Ci0tLQoKYGBge3IgZnVuY3Rpb25zLCBpbmNsdWRlPUZBTFNFfQojIEEgZnVuY3Rpb24gZm9yIGNhcHRpb25pbmcgYW5kIHJlZmVyZW5jaW5nIGltYWdlcwpmaWcgPC0gbG9jYWwoewogICAgaSA8LSAwCiAgICByZWYgPC0gbGlzdCgpCiAgICBsaXN0KAogICAgICAgIGNhcD1mdW5jdGlvbihyZWZOYW1lLCB0ZXh0KSB7CiAgICAgICAgICAgIGkgPDwtIGkgKyAxCiAgICAgICAgICAgIHJlZltbcmVmTmFtZV1dIDw8LSBpCiAgICAgICAgICAgIHBhc3RlKCJGaWd1cmUgIiwgaSwgIjogIiwgdGV4dCwgc2VwPSIiKQogICAgICAgIH0sCiAgICAgICAgcmVmPWZ1bmN0aW9uKHJlZk5hbWUpIHsKICAgICAgICAgICAgcmVmW1tyZWZOYW1lXV0KICAgICAgICB9KQp9KQpgYGAgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkoa25pdHIpCiAgbGlicmFyeShybWFya2Rvd24pCiAgbGlicmFyeShnZ3Bsb3QyKQogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoU3VtbWFyaXplZEV4cGVyaW1lbnQpCiAgbGlicmFyeShlZGdlUikKICBpZighInBhcmF0aHlyb2lkU0UiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKSBCaW9jTWFuYWdlcjo6aW5zdGFsbCgicGFyYXRoeXJvaWRTRSIpCn0pCmBgYAoKSW4gdGhpcyBsZWN0dXJlIHdlIHdpbGwgaW50cm9kdWNlIHRoZSBtYWluIHByaW5jaXBsZXMgb2Ygd29ya2luZyB3aXRoIGNvdW50IGRhdGEsIGFuZCBob3cgdG8gbW9kZWwgdGhlc2UgdXNpbmcgZ2VuZXJhbGl6ZWQgbGluZWFyIG1vZGVscyAoR0xNcykuIFdlIGZvY3VzIG9uIGludHJvZHVjaW5nIHRoZSBjb25jZXB0IG9mIGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMsIGFuZCBob3cgIHRoZXkgY2FuIGJlIGFwcGxpZWQgdG8gZ2Vub21pY3MgZGF0YSBhbmFseXNpcy4KCiMgVGhlIFBvaXNzb24gZGlzdHJpYnV0aW9uCgogLSBUaGUgUG9pc3NvbiBkaXN0cmlidXRpb24gaXMgYSB0eXBpY2FsIGNvdW50IGRpc3RyaWJ1dGlvbiB0aGF0IGlzIGdlbmVyYWxseSBwb3B1bGFyIGFuZCBmYWlybHkgZWFzeSB0byB3b3JrIHdpdGguIEl0IGlzIGRlZmluZWQgYnkgYSBzaW5nbGUgcGFyYW1ldGVyOiBpdHMgbWVhbiAkXG11JC4gRm9yIGEgUG9pc3NvbiBkaXN0cmlidXRlZCByYW5kb20gdmFyaWFibGUgJFlfaSQgd2l0aCBvYnNlcnZhdGlvbnMgJGkgXGluIFx7MSwgXGxkb3RzLCBuXH0kLCBpdHMgdmFyaWFuY2UgaXMgZXF1YWwgdG8gaXRzIG1lYW4uIFRoYXQgaXMsIGlmIAogCiAkJFlfaSBcc2ltIFBvaShcbXUpJCQKICwgdGhlbiAKIAogJCRFKFlfaSkgPSBWYXIoWV9pKSA9IFxtdS4kJAogCiAtIFRoaXMgaW1tZWRpYXRlbHkgc2hvd3MgYW4gaW1wb3J0YW50IGZlYXR1cmUgb2YgY291bnQgZGF0YTogdGhlICoqbWVhbi12YXJpYW5jZSByZWxhdGlvbnNoaXAqKi4gSW5kZWVkLCBpbiBjb3VudCBkYXRhLCB0aGUgdmFyaWFuY2Ugd2lsbCBhbHdheXMgYmUgYSBmdW5jdGlvbiBvZiB0aGUgbWVhbi4KIAogLSBUaGlzIGlzIHF1aXRlIGludHVpdGl2ZS4gQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBleGFtcGxlLiBZb3UgaGF2ZSB0d28gYmlyZCBjYWdlcywgd2hlcmUgaW4gb25lIGJpcmQgY2FnZSB0aGVyZSBhcmUgJDEwJCBiaXJkcywgd2hpbGUgaW4gdGhlIG90aGVyIHRoZXJlIGFyZSAkMTAwJCBiaXJkcy4gWW91IGxldCBhIHNhbXBsZSBvZiBwZW9wbGUgbG9vayB0byB0aGUgbnVtYmVyIG9mIGJpcmRzIGluIGVpdGhlciBvbmUgb2YgdGhlIGNhZ2VzLiBJdCBzZWVtcyB1bmxpa2VseSB0aGF0IGEgcGVyc29uIGluIGZyb250IG9mIHRoZSAxMC1iaXJkIGNhZ2Ugd291bGQgY29tZSB1cCB3aXRoIGFuIGVzdGltYXRlIG9mICQzJCwgd2hpbGUgaXQgc2VlbXMgbGlrZWx5IHRoYXQgc29tZW9uZSBpbiBmcm9udCBvZiB0aGUgMTAwLWJpcmQgY2FnZSB3b3VsZCBjb21lIHVwIHdpdGggYW4gZXN0aW1hdGUgb2YgJDgwJC4gRXZlbiB0aG91Z2ggdGhlIGRpZmZlcmVuY2UgZnJvbSB0aGUgdHJ1ZSB2YWx1ZSBpcyB0aGUgc2FtZSwgdGhlIGV4YWN0IHZhbHVlIGhhcyBhbiBpbXBhY3Qgb24gdGhlIHBsYXVzaWJsZSBkZXZpYXRpb24gYXJvdW5kIGl0LgogCmBgYHtyfQpzZXQuc2VlZCgxMSkKeTEgPC0gcnBvaXMobj01MDAsIGxhbWJkYT0xMCkKeTIgPC0gcnBvaXMobj01MDAsIGxhbWJkYT0xMDApCgpwYXIobWZyb3cgPSBjKDEsMikpCnFwbG90KHkxLCBtYWluPSJQb2lzc29uKDEwKSIsIGdlb20gPSAiaGlzdG9ncmFtIiwgYmlud2lkdGg9LjUsY2VudGVyPTApCnFwbG90KHkyLCBtYWluPSJQb2lzc29uKDEwMCkiLCBnZW9tID0gImhpc3RvZ3JhbSIsIGJpbndpZHRoPS41LGNlbnRlcj0wKQpgYGAKCiMjIFRoZSBQb2lzc29uIGRpc3RyaWJ1dGlvbiBpbiBSTkEtc2VxCgogLSBJbiBSTkEtc2VxLCB0ZWNobmljYWwgcmVwbGljYXRlcyByZXByZXNlbnQgZGlmZmVyZW50IGFsaXF1b3RzIG9mIHRoZSBzYW1lIHNhbXBsZSBiZWluZyBzZXF1ZW5jZWQgcmVwZWF0ZWRseS4gVGhlIHVuZGVybHlpbmcgdHJ1ZSBleHByZXNzaW9uIG9mIGEgZ2VuZSBjYW4gaGVuY2Ugc2FmZWx5IGJlIGFzc3VtZWQgdG8gYmUgZXF1YWwgYWNyb3NzIHRoZXNlIHRlY2huaWNhbCByZXBsaWNhdGVzLgogLSBbTWFyaW9uaSAqZXQgYWwuKiAoMjAwOCldKGh0dHBzOi8vZ2Vub21lLmNzaGxwLm9yZy9jb250ZW50LzE4LzkvMTUwOSkgaGF2ZSBzaG93biB0aGF0LCBmb3IgbW9zdCBnZW5lcywgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZlZCBnZW5lIGV4cHJlc3Npb24gY291bnRzIGFjcm9zcyB0ZWNobmljYWwgcmVwbGljYXRlcyBmb2xsb3cgYSBQb2lzc29uIGRpc3RyaWJ1dGlvbi4gQSBzbWFsbCBwcm9wb3J0aW9uIG9mIGdlbmVzICgkXHNpbSAwLjVcJSQpIGRvIG5vdCBmb2xsb3cgdGhpcyBQb2lzc29uIG1vZGVsLCBob3dldmVyLCBhbmQgYWN0dWFsbHkgc2hvdyBldmlkZW5jZSBmb3IgKidleHRyYS1Qb2lzc29uIHZhcmlhdGlvbicqLgogCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFRlY2huaWNhbCByZXBsaWNhdGlvbiBpbiBSTkEtc2VxLiBGaWd1cmVzIGZyb20gTWFyaW9uaSBldCBhbC4gKDIwMDgpLiIpfQojIEFsbCBkZWZhdWx0cwppbmNsdWRlX2dyYXBoaWNzKCIuL2ltYWdlc19zZXF1ZW5jaW5nL21hcmlvbmlGaWdzX2Nyb3BwZWQucG5nIikKYGBgCgojIyBSZWxhdGl2ZSB1bmNlcnRhaW50eSBmb3IgUG9pc3NvbiBkaXN0cmlidXRlZCByYW5kb20gdmFyaWFibGVzCgpUYWtlIGEgbWludXRlIHRvIGNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb246CgogLSBTdXBwb3NlIHRoYXQgd2UgaGF2ZSBhIHNvbGlkIHR1bW9yIHNhbXBsZSBmcm9tIGEgY2FuY2VyIHBhdGllbnQsIGFzIHdlbGwgYXMgYSBzYW1wbGUgb2Ygc3Vycm91bmRpbmcgaGVhbHRoeSB0aXNzdWUuIEZvciBlYWNoIHNhbXBsZSwgd2UgaGF2ZSB0aHJlZSB0ZWNobmljYWwgcmVwbGljYXRlcyBhdCBvdXIgZGlzcG9zYWwuIExldCAkWV97Z3J0fSQgZGVub3RlIHRoZSBvYnNlcnZlZCBnZW5lIGV4cHJlc3Npb24gdmFsdWVzIG9mIGdlbmUgJGckIGluIHJlcGxpY2F0ZSAkciBcaW4gXHsxLDIsM1x9JCBmcm9tIHRpc3N1ZSAkdCBcaW4gXHswLDFcfSQsIHdoZXJlICR0PTAkIGRlbm90ZXMgaGVhbHRoeSB0aXNzdWUgYW5kICR0PTEkIGRlbm90ZXMgdHVtb3JhbCB0aXNzdWUuIAogLSBXZSB0aGVuIGtub3cgdGhhdCB0aGUgcmFuZG9tIHZhcmlhYmxlcyAkWV97Z3IwfSQgYW5kICRZX3tncjF9JCBmb2xsb3cgYSBQb2lzc29uIGRpc3RyaWJ1dGlvbiwgYW5kIHdlIHdvdWxkIGVzdGltYXRlIGl0cyBtZWFuIGFzICRcYmFye1l9X3tnMH0gPSBcZnJhY3sxfXszfSBcc3VtX3tyPTF9XjMgWV97Z3IwfSQgYW5kICRcYmFye1l9X3tnMX0gPSBcZnJhY3sxfXszfSBcc3VtX3tyPTF9XjMgWV97Z3IxfSQsIHJlc3BlY3RpdmVseS4gCiAtIFNpbWlsYXIsIGZvciBhbm90aGVyIGdlbmUgJGskLCB3ZSBvYnNlcnZlICRZX3trcnR9JCwgYW5kIGVzdGltYXRlICRcYmFye1l9X3trMH0kIGFuZCAkXGJhcntZfV97azF9JCBjb3JyZXNwb25kaW5nbHkuCiAtIE5vdyBzdXBwb3NlIHRoYXQgJFxiZXRhX3trfSA9IFxiYXJ7WX1fe2sxfSAvIFxiYXJ7WX1fe2swfSA9IDUkLCBidXQgYWxzbyAkXGJldGFfZyA9IFxiYXJ7WX1fe2cxfSAvIFxiYXJ7WX1fe2cwfSA9IDUkLCBpLmUuLCB0aGUgdHdvIGdlbmVzIGhhdmUgdGhlIHNhbWUgYXZlcmFnZSBleHByZXNzaW9uIHJhdGlvIChhbHNvIG9mdGVuIGNhbGxlZCBhIGZvbGQtY2hhbmdlKSBhY3Jvc3Mgc2FtcGxlcy4gSG93ZXZlciwgdGhleSBhcmUgZGlmZmVyZW50bHkgZXhwcmVzc2VkIGFzICRcYmFye1l9X3trMX0gPSAxMDAkLCBhbmQgJFxiYXJ7WX1fe2cxfSA9IDEwJCAobWFraW5nICRcYmFye1l9X3trMH0gPSAyMCQsIGFuZCAkXGJhcntZfV97ZzB9ID0gMiQpLgogLSBGb3Igd2hpY2ggb2YgdGhlIHR3byBnZW5lcyBpcyB0aGUgdW5jZXJ0YWludHkgb24gdGhlIGV4cHJlc3Npb24gcmF0aW8gdGhlIGhpZ2hlc3Q/IEluIG90aGVyIHdvcmRzLCBkbyB3ZSB0cnVzdCAkXGJldGFfayQgbW9yZSBvciBkbyB3ZSB0cnVzdCAkXGJldGFfZyQgbW9yZT8KIAogLS0tCgpMZXQncyBhcHByb3hpbWF0ZSB0aGUgdW5jZXJ0YWludHkgaW4gJGJldGFfZyQgYW5kICRcYmV0YV9rJCB1c2luZyBzaW11bGF0aW9uOgogCmBgYHtyfQpOIDwtIDFlMwpiZXRhX2cgPC0gYmV0YV9rIDwtIHZlY3RvcihsZW5ndGg9TikKZm9yKGlpIGluIDE6Til7CiAgeWdyMSA8LSBycG9pcyhuPTMsIGxhbWJkYT0xMCkKICB5Z3IwIDwtIHJwb2lzKG49MywgbGFtYmRhPTIpCiAgeWtyMSA8LSBycG9pcyhuPTMsIGxhbWJkYT0xMDApCiAgeWtyMCA8LSBycG9pcyhuPTMsIGxhbWJkYT0yMCkKICBiZXRhX2dbaWldIDwtIG1lYW4oeWdyMSkgLyBtZWFuKHlncjApCiAgYmV0YV9rW2lpXSA8LSBtZWFuKHlrcjEpIC8gbWVhbih5a3IwKQp9CgpwYXIobWZyb3c9YygxLDIpLCBtYXI9Yyg0LDIsMywxKSkKaGlzdChiZXRhX2csIGJyZWFrcz1zZXEoMCw1MCxieT0xKSwgeGxpbT1jKDAsNTApKQpoaXN0KGJldGFfaywgYnJlYWtzPXNlcSgwLDUwLGJ5PTEpLCB4bGltPWMoMCw1MCkpCmBgYAogCiAtLS0gCiAKIFdlIGNsZWFybHkgc2VlIHRoYXQgdGhlIHVuY2VydGFpbnR5IG9uICRcYmV0YV9rJCBpcyBtdWNoIGxvd2VyIHRoYW4gb24gJFxiZXRhX2ckLiBFdmVuIHRob3VnaCB0aGUgdmFyaWFuY2Ugb24gdGhlIGNvdW50cyBvZiBnZW5lICRrJCBpcyBoaWdoZXIsIHNpbmNlIGl0cyBtZWFuIGlzIGhpZ2hlciBhbmQgaXQgaXMgZGlzdHJpYnV0ZWQgYXMgYSBQb2lzc29uIHZhcmlhYmxlLiBIb3cgZG8gd2UgZXhwbGFpbiB0aGlzPwogCiAtIFdlIG1heSBleHBsYWluIHRoaXMgYnkgY29uc2lkZXJpbmcgdGhlIHJlbGF0aXZlIHVuY2VydGFpbnR5IG9uIHRoZSBtZWFuLiBSZWxhdGl2ZSB1bmNlcnRhaW50eSBtYXkgYmUgZGVmaW5lZCBhcyB0aGUgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uICRDViA9IFxmcmFje1xzaWdtYX17XG11fSQgKHRoaXMgaXMsIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZGl2aWRlZCBieSB0aGUgbWVhbikuIEluZGVlZCwgdGhlIENWIGRlc2NyaWJlcyB0aGUgcmVsYXRpdmUgZGV2aWF0aW9uIG9mIHRoZSBkaXN0cmlidXRpb24gcmVsYXRpdmUgdG8gaXRzIG1lYW4sIHdoZXJlIGEgbG93IENWIGluZGljYXRlcyBsb3cgZGlzcGVyc2lvbiB3aXRoIHJlc3BlY3QgdG8gdGhlIG1lYW4uCiAtIENhbGN1bGF0aW5nIHRoZSBDViBzaG93cyB0aGF0ICoqdGhlIHJlbGF0aXZlIHVuY2VydGFpbnR5IGZvciBnZW5lICRrJCB0aGFuIGZvciBnZW5lICRnJCwgZXZlbiB0aG91Z2ggdGhlIHZhcmlhbmNlIG9uIHRoZSByYXcgY291bnRzIGlzIGhpZ2hlciBmb3IgZ2VuZSAkayQgdGhhbiBmb3IgZ2VuZSAkZyQqKi4gCiAtIFRoaXMgbG93ZXIgcmVsYXRpdmUgdW5jZXJ0YWludHkgb24gdGhlIG1lYW4gdGhlbiBwcm9wYWdhdGVzIGZ1cnRoZXIgdG8gYSBsb3dlciB1bmNlcnRhaW50eSBvbiB0aGUgZm9sZC1jaGFuZ2UuIFRoaXMgYmFzaWMgcmVzdWx0IHdpbGwgYmUgZXNzZW50aWFsIGZvciB1bmRlcnN0YW5kaW5nIHRoZSByZXN1bHRzIG9mIGEgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMhCiAKYGBge3J9CnNxcnQoMTAwKS8xMDAgI0NWIGZvciBnZW5lIGsKCnNxcnQoMTApLzEwICNDViBmb3IgZ2VuZSBnCmBgYAogCiMgTW9kZWxpbmcgY291bnQgZGF0YTogR2VuZXJhbGl6ZWQgbGluZWFyIG1vZGVscwoKSnVzdCBsaWtlIHdlIGhhdmUgbW9kZWxlZCBwcm90ZWluIGFidW5kYW5jZXMgaW4gdGhlIHByb3Rlb21pY3MgbW9kdWxlIG9mIHRoaXMgY291cnNlIGluIG9yZGVyIHRvIGFzc2VzcyBkaWZmZXJlbnRpYWwgcHJvdGVpbiBhYnVuZGFuY2UsIHdlIGNhbiBtb2RlbCBnZW5lIGV4cHJlc3Npb24gY291bnRzIHRvIGlkZW50aWZ5IGdlbmVzIHdpdGggZGlmZmVyZW5jZXMgaW4gYXZlcmFnZSBleHByZXNzaW9uIGJldHdlZW4gZ3JvdXBzIG9mIHNhbXBsZXMuCgojIyBXaHkgd2UgY2FuKCd0KSB1c2UgbGluZWFyIG1vZGVscyB0byBtb2RlbCBjb3VudCBkYXRhCgogLSBJZiB3ZSBhcmUgdXNpbmcgYSBsaW5lYXIgbW9kZWwgdG8gbW9kZWwgYSByZXNwb25zZSAkWV9pJCwgd2l0aCAkaSBcaW4gXHsxLCBcbGRvdHMsIG5cfSQgaW4gZnVuY3Rpb24gb2YgYSBzaW5nbGUgY292YXJpYXRlICRYX2kkLCB0aGUgbGluZWFyIG1vZGVsIGNhbiBiZSBkZWZpbmVkIGFzIGZvbGxvd3M6CgpcWwpcbGVmdFx7ClxiZWdpbnthcnJheX17Y2NjfQpZX2kgJiA9ICYgXGJldGFfMCArIFxiZXRhXzEgeF9pICsgXGVwc2lsb25faSBcXApZX2kgfCB4X2kgJiBcc2ltICYgTihcYmV0YV8wICsgXGJldGFfMSB4X2ksIFxzaWdtYV4yICkuClxlbmR7YXJyYXl9ClxyaWdodC4KXF0KCiAtIE9yLCBlcXVpdmFsZW50bHksIHdlIGNhbiB3cml0ZSBpdCBpbiBtYXRyaXggZm9ybSBhcwogICQkCiAgXGxlZnRcewogIFxiZWdpbnthcnJheX17Y2NjfQogIFkgJiA9ICYgXG1hdGhiZntYfV5UIFxib2xkc3ltYm9se1xiZXRhfSArIFxlcHNpbG9uIFxcCiAgWSB8IFxtYXRoYmZ7WH0gJiBcc2ltICYgTihcbWF0aGJme1h9IFxib2xkc3ltYm9se1xiZXRhfSwgXHNpZ21hXjIgXG1hdGhiZntJfSksCiAgXGVuZHthcnJheX0KICBccmlnaHQuCiAgJCQKd2hlcmUgJFxtYXRoYmZ7WH0kIG5vdyByZXByZXNlbnRzIG91ciAkbiBcdGltZXMgcCQgZGVzaWduIG1hdHJpeCwgd2l0aCByb3cgJGkkIGNvcnJlc3BvbmRpbmcgdG8gb2JzZXJ2YXRpb24gJGkkLgoKIC0tLQoKIC0gVGhlIHZhcmlhbmNlLWNvdmFyaWFuY2UgbWF0cml4IG9mICRcbWF0aGJme1l9JCBpcyBhc3N1bWVkIGEgZGlhZ29uYWwgbWF0cml4IHdpdGggJFxzaWdtYV4yJCBvbiB0aGUgZGlhZ29uYWwgZWxlbWVudHMgYW5kIHplcm8gZXZlcnl3aGVyZSBlbHNlLiBUaGlzIG1lYW5zIHRoYXQgdGhlIGRhdGEgcG9pbnRzIGFyZSB1bmNvcnJlbGF0ZWQsIGFuZCB0aGF0IGV2ZXJ5IG9ic2VydmF0aW9uIGhhcyB0aGUgc2FtZSB2YXJpYW5jZSAkXHNpZ21hXjIkLCBhbHNvIHJlZmVycmVkIHRvIGFzIGhvbW9zY2VkYXN0aWNpdHkuIAogCiAtIFRoZSBsYXR0ZXIgZG9lcyBub3QgaG9sZCBmb3IgY291bnQgZGF0YSwgZHVlIHRvIHRoZSBtZWFuLXZhcmlhbmNlIHJlbGF0aW9uc2hpcC4gVGhpcyBtYWtlcyBsaW5lYXIgbW9kZWxzLCBpbiBpdHMgYmFzaWMgZm9ybSwgdW5zdWl0YWJsZSB0byBtb2RlbCBjb3VudCBkYXRhLgogCiAtIEluIGFkZGl0aW9uLCBjb3VudCBkYXRhIGFyZSBub24tbmVnYXRpdmUsIHdoaWxlIHRoZXJlIGFyZSBubyBzdWNoIGNvbnN0cmFpbnRzIGluIHRoZSBzdGFuZGFyZCBsaW5lYXIgbW9kZWwgdG8gbWFrZSBzdXJlIHRoYXQgb3VyIGVzdGltYXRlcyB3aWxsIGJlIG5vbi1uZWdhdGl2ZS4gCiBJbmRlZWQsICRcaGF0e1l9X2kgPSBcaGF0XG11X2kgPSBcbWF0aGJme1h9XlRfaSBcaGF0e1xiZXRhfSBcaW4gXSAtXGluZnR5LCBcaW5mdHlbJC4KCiMjIEdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMKCiAtIEFzIHRoZSBuYW1lIHN1Z2dlc3RzLCBnZW5lcmFsaXplZCBsaW5lYXIgbW9kZWxzIChHTE1zKSBleHRlbmQgbGluZWFyIG1vZGVscy4gSW4gR0xNcywgd2UgZXh0ZW5kIHR3byB0aGluZ3Mgd2l0aCByZXNwZWN0IHRvIHRoZSBsaW5lYXIgbW9kZWw6CiAgICAtIFRoZSAqKmNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcmVzcG9uc2UgdmFyaWFibGUgJFlfaSB8IFhfaSQqKiBjYW4gYmUgYXNzdW1lZCB0byBmb2xsb3cgYW55IGRpc3RyaWJ1dGlvbiB0aGF0IGJlbG9uZ3MgdG8gdGhlICoqZXhwb25lbnRpYWwgZmFtaWx5Kiogb2YgZGlzdHJpYnV0aW9ucywgd2hpY2ggaW5jbHVkZXMgdGhlIEdhdXNzaWFuIGJ1dCBhbHNvIG90aGVyIGNvbW1vbmx5IGtub3duIGRpc3RyaWJ1dGlvbnMsIHN1Y2ggYXMgdGhlIEJpbm9taWFsLCBHYW1tYSBhbmQgUG9pc3NvbiBkaXN0cmlidXRpb24uCiAgICAtIFRoZSBsaW5lYXIgbW9kZWwgYXNzdW1lZCBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiAkWV9pJCBhbmQgJFhfaSQsIHNpbmNlIHdlIGFzc3VtZWQgdGhhdCAkRShZX2kgfCBYX2kpID0gXG1hdGhiZntYfV5UX2kgXGJldGEkLiBJbiBHTE1zLCB3ZSB3aWxsIGFsbG93IGEgKipsaW5rIGZ1bmN0aW9uKiogJGcoKSQgdGhhdCBsaW5rcyB0aGUgY29uZGl0aW9uYWwgbWVhbiB0byB0aGUgY292YXJpYXRlcy4gSGVuY2UsIGluIEdMTXMgd2UgaGF2ZSB0aGF0ICRnKEUoWV9pIHwgWF9pKSkgPSBcbWF0aGJme1h9XlRfaSBcYmV0YSQuIE5vdGUgdGhhdCBlYWNoIGZhbWlseSBoYXMgZ290IGEgY2Fub25pY2FsIGxpbmsgZnVuY3Rpb24sIHdoaWNoIGlzIHRoZSBpZGVudGl0eSBsaW5rIGZ1bmN0aW9uICRnKFxtdSkgPSBcbXUkIGZvciBHYXVzc2lhbiwgdGhlIGxvZyBsaW5rIGZ1bmN0aW9uICRnKFxtdSkgPSBcbG9nIFxtdSQgZm9yIFBvaXNzb24sIG9yIHRoZSBsb2dpdCBsaW5rIGZ1bmN0aW9uICRnKFxtdSkgPSBcbG9nKFxmcmFje1xtdX17MS1cbXV9KSQgZm9yIEJpbm9taWFsLgogICAgCiMjIyBBIFBvaXNzb24gR0xNCgogLSBXZSBjYW4gZGVmaW5lIGEgUG9pc3NvbiBHTE0gYXMgZm9sbG93cwogICQkCiAgXGxlZnRcewogIFxiZWdpbnthcnJheX17Y2NjfQogIFlfaSAmIFxzaW0gJiBQb2koXG11X2kpIFxcCiAgXGxvZyBcbXVfaSAmID0gJiBcZXRhX2kgXFwKICBcZXRhX2kgJiA9ICYgXG1hdGhiZntYfV5UX2kgXGJldGEgXFwKICBcZW5ke2FycmF5fQogIFxyaWdodC4KICAkJAp3aGVyZSAkWV9pJCBpcyB0aGUgcmVzcG9uc2UgdmFyaWFibGUsIHdpdGggbWVhbiAkXG11X2kkLCAkXGV0YV9pJCBpcyB0aGUgbGluZWFyIHByZWRpY3RvciwgJFxtYXRoYmZ7WH0kIGlzIHRoZSAkbiBcdGltZXMgcCQgbW9kZWwgbWF0cml4IGFuZCAkXGJldGEkIGlzIHRoZSAkcCBcdGltZXMgMSQgbWF0cml4IG9mIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLgogIC0gSXQgaXMgaW5zaWdodGZ1bCB0byBjb21wYXJlIHRoaXMgbW9kZWwgdG8gYSBsaW5lYXIgbW9kZWwgd2hlcmUgJFlfaSQgaXMgbG9nLXRyYW5zZm9ybWVkLiBJbmRlZWQsIGluIHRoZSBsaW5lYXIgbW9kZWwgY2FzZSwgd2Ugd291bGQgYmUgbW9kZWxpbmcgJEUoXGxvZyBZX2kgKSQsIHdoaWxlIGluIHRoZSBHTE0gd2UgYXJlIG1vZGVsaW5nICRcbG9nIEUoWV9pKSQuCiAgLSBUaGlzIHNob3dzIHRoYXQgaW4gdGhlIEdMTSBzZXR0aW5nIHdlIGFyZSBtb2RlbGluZyBhIHRyYW5zZm9ybWVkIHZlcnNpb24gb2YgdGhlIGV4cGVjdGVkIHZhbHVlLCBhbmQgYWZ0ZXIgcmV0cmFuc2Zvcm1pbmcgd2UgY2FuIGludGVycHJldCB0aGUgZml0IGluIHRlcm1zIG9mIHRoZSBtZWFuIG9mIG91ciByZXNwb25zZSB2YXJpYWJsZS4gSW4gdGhlIHRyYW5zZm9ybWVkIGxpbmVhciBtb2RlbCwgaG93ZXZlciwgd2UgYXJlIHdvcmtpbmcgd2l0aCB0aGUgZXhwZWN0ZWQgdmFsdWUgb2YgYSB0cmFuc2Zvcm1lZCB2ZXJzaW9uIG9mIG91ciByZXNwb25zZSB2YXJpYWJsZSwgYW5kIHdlIHdpbGwgbm90IGJlIGFibGUgdG8gaW50ZXJwcmV0IHRoZSBmaXQgaW4gdGVybXMgb2YgdGhlIG1lYW4gKGJlY2F1c2UgJEUoIFxsb2cgWV9pKSBcbmUgXGxvZyBFKFlfaSkkLiBJbiB0aGlzIHNwZWNpZmljIGNhc2UsIHdlIHdvdWxkIGhhdmUgdG8gcmVzb3J0IHRvIGludGVycHJldGluZyBjaGFuZ2VzIGluIHRlcm1zIG9mIGEgZ2VvbWV0cmljIG1lYW4uCiAgLSBBbHNvIG5vdGUgdGhhdCAkXG1hdGhiZntYfV5UX2kgXGJldGEgXGluIF0tXGluZnR5LCBcaW5mdHlbJCwgd2hpbGUgJFlfaSQgbXVzdCBiZSBub24tbmVnYXRpdmUgJFswLCBcaW5mdHlbJC4gVGhlIGxpbmsgZnVuY3Rpb24gaGVscHMgd2l0aCB0aGlzLCBzaW5jZSB0aGUgZXhwb25lbnRpYWwgZnVuY3Rpb24gdHJhbnNmb3JtcyBhbnkgcmVhbCBudW1iZXIgdG8gYSBub24tbmVnYXRpdmUgbnVtYmVyLCBpLmUuLCAkXGV4cChcbWF0aGJme1h9XlRfaSBcYmV0YSkgXGluIFswLCBcaW5mdHlbJC4gCgojIFNlcXVlbmNpbmcgRGF0YQoKSW4gdGhpcyBsZWN0dXJlIHdlIHdpbGwgdXNlIGEgc3Vic2V0IG9mIHRoZSByZWFsIGJ1bGsgUk5BLXNlcSBkYXRhc2V0IGZyb20gW0hhZ2x1bmQgKmV0IGFsLiogKDIwMTIpXShodHRwczovL2FjYWRlbWljLm91cC5jb20vamNlbS9hcnRpY2xlLzk3LzEyLzQ2MzEvMjUzNjU3MykuCgpMZXRzIHRyeSB0byB3b3JrIG91dCB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbiB1c2luZyB0aGUgZm9sbG93aW5nIHBhcmFncmFwaCBmcm9tIHRoZSBNZXRob2RzIHNlY3Rpb24gb2YgdGhlIHBhcGVyLgoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9cGFzdGUoIkZpZ3VyZTogQSBwYXJhZ3JhcGggZnJvbSB0aGUgTWV0aG9kcyBzZWN0aW9uLiIpfQojIEFsbCBkZWZhdWx0cwppbmNsdWRlX2dyYXBoaWNzKCIuL2ltYWdlc19zZXF1ZW5jaW5nL2V4cERlc2lnbl9wYXJhLnBuZyIpCmBgYAoKIyMgVGVjaG5pY2FsIHJlcGVhdHMgCgpUaGVyZSBhcmUgdGVjaG5pY2FsIHJlcGVhdHMgaW4gdGhlIGRhdGEhIAoKYGBge3J9CmRhdGEoInBhcmF0aHlyb2lkR2VuZXNTRSIsIHBhY2thZ2U9InBhcmF0aHlyb2lkU0UiKQpzZSA8LSBwYXJhdGh5cm9pZEdlbmVzU0UKcm0ocGFyYXRoeXJvaWRHZW5lc1NFKQpjb2xEYXRhKHNlKSAlPiUga25pdHI6OmthYmxlKC4pCmBgYAoKYGBge3J9CnNlICU+JSAKICBjb2xEYXRhICU+JQogIGFzLmRhdGEuZnJhbWUgJT4lCiAgcHVsbChzYW1wbGUpICU+JSAKICBubGV2ZWxzCgpzZSAlPiUgCiAgY29sRGF0YSAlPiUgCiAgbnJvdwpgYGAKCkV4dHJhY3Qgc2FtcGxlIG5hbWVzIG9mIGR1cGxpY2F0ZXMhIAoKYGBge3J9CmR1cGwgPC0gd2hpY2godGFibGUoY29sRGF0YShzZSkkc2FtcGxlKSA+IDEpICU+JSBuYW1lcwp0ZWNocmVwcyA8LSBhc3NheXMoc2UpJGNvdW50c1ssY29sRGF0YShzZSkkc2FtcGxlPT1kdXBsWzFdXQpgYGAKCiMjIyBFeHBsb3JlIHRoZSBkYXRhIG9mIHR3byB0ZWNobmljYWwgcmVwZWF0cwoKV2UgZXhwZWN0IHRoZSBjb3VudHMgdG8gYmUgdmVyeSBzaW1pbGFyLiBJbmRlZWQsIHRoZXkgYXJlIGJhc2VkIG9uIHRoZSBzYW1lIGNlbGwgY3VsdHVyZSwgc3RpbXVsYXRlZCB3aXRoIHRoZSBzYW1lIHN0aW11bHVzIGFuZCBpbmN1YmF0ZWQgZm9yIHRoZSBzYW1lIHRpbWUuIAoKYGBge3J9CnFwbG90KHRlY2hyZXBzWywxXSx0ZWNocmVwc1ssMl0pICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpICsgCiAgeGxhYigiVGVjaG5pY2FsIHJlcGVhdCAxIikgKwogIHlsYWIoIlRlY2huaWNhbCByZXBlYXQgMiIpCmBgYAoKLSBUaGUgcGxvdCBzaG93cyBhIHN5c3RlbWF0aWMgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjb3VudHMgb2YgYm90aCB0ZWNobmljYWwgcmVwZWF0cyEKCi0gSG93ZXZlciwgcGxvdHRpbmcgdGhlIGRhdGEgb24gdGhlIG9yaWdpbmFsIGNvdW50IHNjYWxlIGRvZXMgbm90IGdpdmUgYSBnb29kIG92ZXJ2aWV3IG9mIHRoZSBkYXRhLiBUaGUgcGxvdCBpcyBkb21pbmF0ZWQgYnkgYSBmZXcgdmVyeSBhYnVuZGFudCBnZW5lcywgaS5lLiBnZW5lcyB3aXRoIHZlcnkgaGlnaCBjb3VudHMuIAoKIyMjIEV4cGxvcmUgdGhlIGRhdGEgb2YgdHdvIHRlY2huaWNhbCByZXBlYXRzCgoKYGBge3J9CnFwbG90KHRlY2hyZXBzWywxXSx0ZWNocmVwc1ssMl0sIGxvZz0ieHkiKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSArIAogIHhsYWIoIlRlY2huaWNhbCByZXBlYXQgMSIpICsKICB5bGFiKCJUZWNobmljYWwgcmVwZWF0IDIiKQpgYGAKCi0gVGhlIHBsb3QgY2xlYXJseSBzaG93cyB0aGF0IHRoZSBjb3VudHMgZm9yIGFsbCBnZW5lcyBhcmUgdmVyeSBkaWZmZXJlbnQgaW4gdGhlIHR3byB0ZWNobmljYWwgcmVwZWF0cy4gCgotIEhvd2V2ZXIsIHdlIGhhdmUgdG8gbG9vayBhdCB0aGUgcGxvdCB2aWEgdGhlIGRpYWdvbmFsLiAKCi0gSW4gb21pY3Mgd2UgdGhlcmVmb3JlIG9mdGVuIHVzZSBNQSBwbG90cy4gV2l0aCBNIChsb2cgcmF0aW8pIGFuZCBBIChsb2cgYXZlcmFnZSkuIAoKYGBge3J9CkEgPC0gdGVjaHJlcHMgJT4lIGxvZzIgJT4lIHJvd01lYW5zCk0gPC0gdGVjaHJlcHMgJT4lIGxvZzIgJT4lIGFwcGx5KC4sMSxkaWZmKQp3IDwtIHRlY2hyZXBzWywxXT09bWluKHRlY2hyZXBzWywxXSkgfCB0ZWNocmVwc1ssMl09PW1pbih0ZWNocmVwc1ssMl0pCmlmIChhbnkodykpIHsKICAgICAgICAgICAgQVt3XSA8LSBydW5pZihzdW0odyksIG1pbiA9IC0xLCBtYXggPSAuMSkKICAgICAgICAgICAgTVt3XSA8LSBsb2cyKHRlY2hyZXBzW3csMl0gKyAxKSAtIGxvZzIodGVjaHJlcHNbdywxXSArIDEpCn0KCk1BcGxvdCA8LSBxcGxvdChBLCBNLCBjb2w9dykgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCJvcmFuZ2UiKSkgKwogIHhsYWIoIkE6IGxvZzIgQXZlcmFnZSIpICsKICB5bGFiKCJNOiBsb2cyIEZvbGQgQ2hhbmdlIikKCk1BcGxvdCArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsc2xvcGU9MCkKYGBgCgpUaGUgTUEgcGxvdCBjbGVhcmx5IHNob3dzIHRoYXQgdGhlIGNvdW50cyBvZiBvbmUgdGVjaG5pY2FsIHJlcGVhdCBhcmUgc3lzdGVtYXRpY2FsbHkgaGlnaGVyIHRoYW4gdGhhdCBvZiB0aGUgb3RoZXIgdGVjaG5pY2FsIHJlcGVhdHMuIAoKYGBge3J9CmNvbFN1bXModGVjaHJlcHMpCmxvZ0ZDZGVwdGggPC0gY29sU3Vtcyh0ZWNocmVwcykgJT4lIGxvZzIgJT4lIGRpZmYKbG9nRkNkZXB0aAoyXmxvZ0ZDZGVwdGgKYGBgCgpUaGUgdGVjaG5pY2FsIHJlcGVhdHMgZGlmZmVyIHdpdGggYSBmYWN0b3IgYHIgcm91bmQoMl5sb2dGQ2RlcHRoLDEpYCBpbiBzZXF1ZW5jaW5nIGRlcHRoISAKCgpgYGB7cn0KTUFwbG90ICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gbG9nRkNkZXB0aCwgc2xvcGUgPSAwLCBjb2xvcj0icmVkIikKYGBgCgotIFRoaXMgbG9nMiBmb2xkIGNoYW5nZSBpbiBzZXF1ZW5jaW5nIGRlcHRoIGlzIGFsc28gdGhlIGJhc2VsaW5lIGFyb3VuZCB3aGljaCB0aGUgbG9nMiBmb2xkIGNoYW5nZXMgYmV0d2VlbiB0ZWNobmljYWwgcmVwZWF0cyBvZiBpbmRpdmlkdWFsIGdlbmVzIGFyZSBmbHVjdHVhdGluZyEgCgpIZW5jZSwgd2Ugd2lsbCBoYXZlIHRvIGNvcnJlY3QgZm9yIGRpZmZlcmVuY2VzIGluIHNlcXVlbmNpbmcgZGVwdGguIAoKIyMgQ291bnQgc2NhbGluZyB1c2luZyBHTE0gb2Zmc2V0cyAKCi0gV2UgaGF2ZSBwcmV2aW91c2x5IGRpc2N1c3NlZCBjb3VudCBzY2FsaW5nIHRyYW5zZm9ybWF0aW9ucyBzdWNoIGFzIENQTSBhbmQgVFBNLgoKLSBBIG1vcmUgYXBwcm9wcmlhdGUgYW5kIG5hdHVyYWwgd2F5IHdoZW4gd29ya2luZyB3aXRoIEdMTXMgaXMgdGhyb3VnaCB0aGUgdXNlIG9mIG9mZnNldHMuIFRoZSBnZW5lcmFsIHVzZSBvZiBhbiBvZmZzZXQgaXMgdG8gYWNjb3VudCBmb3IgdGhlIOKAmGVmZm9ydOKAmSBwZXJmb3JtZWQgaW4gb3JkZXIgdG8gZ2F0aGVyIHRoYXQgb2JzZXJ2YXRpb24gb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlLgoKJFxyaWdodGFycm93JCBpLmUuIHNhbXBsZSBiZWluZyBzZXF1ZW5jZWQgZGVlcGVyIGNvbnRhaW5zIG1vcmUgaW5mb3JtYXRpb24gYXMgY29tcGFyZWQgdG8gYSBzYW1wbGUgYmVpbmcgc2VxdWVuY2VkIHJlbGF0aXZlbHkgc2hhbGxvdy4gV2UgaGF2ZSBtb3JlIGNvbmZpZGVuY2UgaW4gYSBjb3VudCBmcm9tIGEgZGVlcGx5IHNlcXVlbmNlZCBzYW1wbGUgdGhhbiB0aGF0IGZyb20gYSBzaGFsbG93bHkgc2VxdWVuY2VkIHNhbXBsZS4gV2UgY2FuIHRoZXJlZm9yZSB1c2UgdGhlIHNlcXVlbmNpbmcgZGVwdGggJE5faT1cc3VtX2cgWV97Z2l9JCBhcyBvZmZzZXQgaW4gdGhlIG1vZGVsLgoKCi0gQWRkaW5nIGFuIG9mZnNldCB0byB0aGUgbW9kZWwgaXMgZGlmZmVyZW50IGZyb20gYWRkaW5nIGEgbmV3IHZhcmlhYmxlIHRvIHRoZSBtb2RlbC4gRm9yIGVhY2ggbmV3IHZhcmlhYmxlIHdlIGFkZCwgd2Ugd2lsbCBlc3RpbWF0ZSBpdHMgYXZlcmFnZSBlZmZlY3QgJFxiZXRhJCBvbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIFdoZW4gYWRkaW5nIGFuIG9mZnNldCwgaG93ZXZlciwgd2UgaW1wbGljaXRseSBzZXQgJFxiZXRhPTEkLgoKLSBPZmZzZXRzIGFyZSB0eXBpY2FsbHkgYWRkZWQgb24gdGhlIHNjYWxlIG9mIHRoZSBsaW5lYXIgcHJlZGljdG9yLiBTdXBwb3NlIHdlIGhhdmUgYSBnZW5lIGcgYW5kIHNhbXBsZSBpIHNwZWNpZmljIG9mZnNldCAkT197Z2l9JCwgdGhlbiB3ZSBjYW4gZGVmaW5lIG91ciBHTE0gaW5jbHVkaW5nIHRoZSBvZmZzZXQgYXMKCiAgJCQKICBcbGVmdFx7CiAgXGJlZ2lue2FycmF5fXtjY2N9CiAgWV97Z2l9ICYgXHNpbSAmIFBvaShcbXVfe2dpfSkgXFwKICBcbG9nIFxtdV97Z2l9ICYgPSAmIFxldGFfe2dpfSBcXAogIFxldGFfe2dpfSAmID0gJiBcbWF0aGJme1h9XlRfaSBcYmV0YV9nICsgbG9nKE9fe2dpfSkgXFwKICBcZW5ke2FycmF5fQogIFxyaWdodC4KICAkJAoKV2hlbiB3ZSB3b3VsZCBsaWtlIHRvIGNvcnJlY3QgZm9yIHRoZSBvdmVyYWxsIHNlcXVlbmNpbmcgZGVwdGggJE9fe2dpfT1OX2kkLiBIb3dldmVyLCBiZXR0ZXIgb2Zmc2V0cyBleGlzdCEKCk5vdGUsIHRoYXQgCgokJApcbXVfe2lnfT0gXGV4cChcbWF0aGJme1h9XlRfaSBcYmV0YV9nKSBcdGltZXMgT197Z2l9CiQkCm9yIAokJApcbG9nXGxlZnQoXGZyYWN7XG11X3tpZ319e09fe2dpfX1ccmlnaHQpPSBcbWF0aGJme1h9XlRfaSBcYmV0YV9nCiQkCgojIyBCaW9sb2dpY2FsIHJlcGVhdHMKCldlIGV4dHJhY3QgdGhlIGZvdXIgYmlvbG9naWNhbCByZXBlYXRzIGZyb20gdGhlIHN0dWR5IGZvciB0aGUgY29udHJvbCB0cmVhdG1lbnQgYXQgdGltZSAyNGguIAoKYGBge3J9CmJpb3JlcHMgPC0gY29sRGF0YShzZSkkdHJlYXRtZW50PT0iQ29udHJvbCIgJiBjb2xEYXRhKHNlKSR0aW1lPT0iMjRoIgpiaW9yZXBDb3VudHMgPC0gYXNzYXlzKHNlKSRjb3VudHNbLGJpb3JlcHNdCnFwbG90KHJvd01lYW5zKGJpb3JlcENvdW50cykscm93VmFycyhiaW9yZXBDb3VudHMpLGxvZz0ieHkiKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCxzbG9wZSA9IDEsY29sPSJyZWQiKSArCiAgZ2VvbV9zbW9vdGgoY29sPSJvcmFuZ2UiKQpgYGAKCi0gSGF2aW5nIGRhdGEgb24gdGhvdXNhbmRzIG9mIGdlbmVzIHByb3ZpZGVzIHRoZSBvcHBvcnR1bml0eSB0byBlbXBpcmljYWxseSBhc3Nlc3MgdGhlIG1lYW4tdmFyaWFuY2UgcmVsYXRpb25zaGlwLgoKLSBJdCBpcyBjbGVhciB0aGF0IHRoZSBkYXRhIGlzIG92ZXJkaXNwZXJzZWQgd2l0aCByZXNwZWN0IHRvIHRoZSBQb2lzc29uIGRpc3RyaWJ1dGlvbiAocmVkIHk9eCBsaW5lKS4gVGhlcmUgYWxzbyBzZWVtcyB0byBiZSBhIHF1YWRyYXRpYyB0cmVuZCBvZiB0aGUgdmFyaWFuY2UgYXMgYSBmdW5jdGlvbiBvZiB0aGUgbWVhbi4gCgojIE5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbgoKVGhlIG9ic2VydmVkIHF1YWRyYXRpYyBtZWFuIHZhcmlhbmNlIHRyZW5kIGhhcyBtb3RpdmF0ZWQgdGhlIHVzZSBvZiB0aGUgbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uIHRvIG1vZGVsIChidWxrKSBSTkEtc2VxIGdlbmUgZXhwcmVzc2lvbiBkYXRhLgoKJCQKICBcbGVmdFx7CiAgXGJlZ2lue2FycmF5fXtjY2N9CiAgWV97Z2l9ICYgXHNpbSAmIE5CKFxtdV97Z2l9LFxwaGlfZykgXFwKICBcbG9nIFxtdV97Z2l9ICYgPSAmIFxldGFfe2dpfSBcXAogIFxldGFfe2dpfSAmID0gJiBcbWF0aGJme1h9XlRfaSBcYmV0YV9nICsgbG9nKE9fe2dpfSkgXFwKICBcZW5ke2FycmF5fQogIFxyaWdodC4KICAkJAoKd2l0aCAKCiQkIApcdGV4dHt2YXJ9W1lfe2dpfV0gPSBcbXVfe2dpfSArIFxwaGlfZyBcbXVfe2dpfV4yIAokJAoKfCAgIHwgJFxxdWFkJCB8IFNlcS4gdGVjaG5vbG9neSAgfCAkXHF1YWQkIHwgcmVhbCBleHByZXNzaW9uICB8IAp8LS0tfC0tLXwtLS18LS0tfC0tLXwKfCB0b3RhbCB2YXJpYWJpbGl0eSB8ID0gfCB0ZWNobmljYWwgdmFyaWFiaWxpdHkgfCArIHwgYmlvbG9naWNhbCB2YXJpYWJpbGl0eSAgIHwKfCAkXHRleHR7dmFyfVtZX3tnaX1dJCB8ID0gfCAkXG11X3tnaX0kICB8ICsgfCAkXHBoaV9nIFxtdV97Z2l9XjIkIHwgfCB0b3RhbCBDViReMiQgfCA9IHwgdGVjaG5pY2FsIENWJF4yJCB8ICsgfCBiaW9sb2dpY2FsIENWJF4yJCB8CnwgdG90YWwgQ1YkXjIkIHwgPSB8ICRcZnJhY3sxfXtcbXVfe2dpfX0kIHwgKyB8ICRccGhpX2ckICB8CgojIyAgV2hhdCBhYm91dCB0ZWNobmljYWwgcmVwZWF0cz8gCgotIFRlY2huaWNhbCByZXBlYXRzIGFyZSBQb2lzc29uIGRpc3RyaWJ1dGVkLgotIFRoZSBzdW0gb2YgdHdvIFBvaXNzb24gZGlzdHJpYnV0ZWQgY291bnRzIGlzIGFnYWluIFBvaXNzb24uIFNvIHdlIGNhbiBzdW1tYXJpemUgb3ZlciB0ZWNobmljYWwgcmVwZWF0cyBieSB0YWtpbmcgdGhlIHN1bSBvZiB0aGUgY291bnRzLiBUaGlzIGVuYWJsZXMgdXMgdG8gY29sbGFwc2UgdGhlIHRlY2huaWNhbCByZXBlYXRzIHRvIHRoZSBsZXZlbCBvZiBiaW9sb2dpY2FsIHJlcGVhdHMuIAotIFdlIHdpbGwgaWxsdXN0cmF0ZSB0aGF0IGluIHRoZSB0dXRvcmlhbCBzZXNzaW9uLgoKIyMgRXN0aW1hdGluZyB0aGUgb3ZlcmRpc3BlcnNpb24/CgotIEdlbmUgd2lzZTogZm9yIGV2ZXJ5IHNpbmdsZSBnZW5lLCB2ZXJ5IHVuc3RhYmxlIGR1ZSB0byB0aGUgbGFjayBvZiBkYXRhIAotIENvbW1vbiBkaXNwZXJzaW9uIGZvciBhbGwgZ2VuZXMgCi0gVHJlbmRlZCBkaXNwZXJzaW9uCi0gVGFnLXdpc2U6IEVCIHNocmlua2FnZSB0byBhIGNvbW1vbiAodHJlbmRlZCkgZGlzcGVyc2lvbjogQm9ycm93IHN0cmVuZ3RoIGFjcm9zcyBnZW5lcyAoTWNDYXJ0aHkgJiBTbXl0aCwgMjAxMiwgW0RPSTogMTAuMTA5My9uYXIvZ2tzMDQyXShodHRwczovL2RvaS5vcmcvMTAuMTA5My9uYXIvZ2tzMDQyKSkKCkluIHRoZSB0dXRvcmlhbHMgd2Ugd2lsbCBhbmFseXNlIHRoZSBlbnRpcmUgc3R1ZHkgYW5kIHdlIHdpbGwgZm9jdXMgb24gYXNzZXNzaW5nIHRoZSBtYWluIHJlc2VhcmNoIHF1ZXN0aW9uczogaS5lLiBjb21wYXJpbmcgdGhlIGVhcmx5IGFuZCBsYXRlIGVmZmVjdHMgb2YgdGhlIHN0aW11bGksIGFuZCBpZiB0aGUgZWZmZWN0IG9mIHN0aW11bGkgaXMgY2hhbmdlcyBvdmVyIHRpbWUuIAoKSGVyZSwgd2UgaWxsdXN0cmF0ZSB0aGUgZXN0aW1hdGlvbiB1c2luZyB0aGUgZWRnZVIgdG9vbCBvbiBhIHN1YnNldCBvZiBjb250cm9sIHRyZWF0bWVudCBmb3IgcGF0aWVudHMgMSwgMiBhbmQgMy4gRm9yIHRoaXMgc3Vic2V0IG9ubHkgYmlvbG9naWNhbCByZXBlYXRzIGFyZSBzZXF1ZW5jZWQgYW5kIGEgbWVhc3VyZW1lbnQgb24gdGltZSAyNCBhbmQgNDhoIGhhcyBiZWVuIHRha2VuIGZvciBjZWxscyBvZiBlYWNoIHBhdGllbnQuICAKU28gd2UgY2FuIG1vZGVsIHRoZSBzdHVkeSB1c2luZyBhIHNpbXBsZSBibG9jayBkZXNpZ24gd2l0aCBhIHRpbWUgZWZmZWN0IGFuZCBhIGJsb2NrIGVmZmVjdCBmb3IgcGF0aWVudC4KCjEuIFNldHVwIHRoZSBkYXRhCiAKCmBgYHtyfQpzZVN1YiA8LSBzZVssY29sRGF0YShzZSkkdHJlYXRtZW50PT0iQ29udHJvbCImY29sRGF0YShzZSkkcGF0aWVudCVpbiUxOjNdCmNvbERhdGEoc2VTdWIpJHBhdGllbnQgPC0gY29sRGF0YShzZVN1YikkcGF0aWVudCAlPiUgCiAgYXMuZG91YmxlICU+JSAKICBhcy5mYWN0b3IKeSA8LSBER0VMaXN0KGNvdW50cyA9IGFzc2F5cyhzZVN1YikkY291bnRzKQoKZGVzaWduIDwtIG1vZGVsLm1hdHJpeCh+dGltZStwYXRpZW50LGNvbERhdGEoc2VTdWIpKQpgYGAKCjIuIFR5cGljYWxseSBsb3dseSBleHByZXNzZWQgZ2VuZXMgYXJlIGZpbHRlcmVkLiAKCmBgYHtyfQprZWVwIDwtIGZpbHRlckJ5RXhwcih5LGRlc2lnbikKeSA8LSB5W2tlZXAsXQpgYGAKCjMuIE5vcm1hbGlzYXRpb24gdG8gY29ycmVjdCBmb3IgZGlmZmVyZW5jZXMgaW4gbGlicmFyeSBzaXplLgoKYGBge3J9CnkgPC0gY2FsY05vcm1GYWN0b3JzKHkpCmBgYAoKNC4gRXN0aW1hdGUgdGhlIGRpc3BlcnNpb25zIHVzaW5nIGVtcGlyaWNhbCBCYXllcyAoRUIpCgpgYGB7cn0KeSA8LSBlc3RpbWF0ZURpc3AoeSwgZGVzaWduKQpgYGAKCjUuIEVzdGltYXRlIGdlbmUtd2lzZSBkaXNwZXJzaW9ucyB3aXRob3V0IHNocmlua2FnZSBmb3IgY29tcGFyaXNvbiBwdXJwb3NlcyAKCmBgYHtyfQp5Tm9FQiA8LSBlc3RpbWF0ZURpc3AoeSwgZGVzaWduLCBwcmlvci5kZiA9IDApCmBgYAoKNi4gVmlzdWFsaXNhdGlvbiBhbmQgY29tcGFyaXNvbiBvZiB0YWctd2lzZSAoRUIpIGFuZCBnZW5ld2lzZSBkaXNwZXJzaW9uIAoKYGBge3J9Cm8gPC0gb3JkZXIoeSRBdmVMb2dDUE0pCmRhdGEuZnJhbWUoCiAgQXZlTG9nQ1BNPXJlcCh5Tm9FQiRBdmVMb2dDUE1bb10sMiksCiAgQkNWPXNxcnQoCiAgICBjKHlOb0VCJHRhZ3dpc2UuZGlzcGVyc2lvbltvXSwKICAgICAgeSR0YWd3aXNlLmRpc3BlcnNpb25bb10pCiAgICApLCAKICBtZXRob2Q9cmVwKGMoImdlbmV3aXNlIiwidGFnd2lzZSIpLCBlYWNoPW5yb3coeSkpKSAlPiUKICBnZ3Bsb3QoYWVzKEF2ZUxvZ0NQTSxCQ1YsY29sb3I9bWV0aG9kKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC4yKSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGRhdGEuZnJhbWUoCiAgICAgIEF2ZUxvZ0NQTT15JEF2ZUxvZ0NQTVtvXSwKICAgICAgQkNWID0gc3FydCh5JHRyZW5kZWQuZGlzcGVyc2lvbltvXSksCiAgICAgIG1ldGhvZD0idHJlbmRlZCIpKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9YygnYmxhY2snLCdvcmFuZ2UnLCdibHVlJykpKwogIHlsYWIoIkJpb2xvZ2ljYWwgQ29lZmZpY2llbnQgb2YgVmFyaWF0aW9uIikgKwogIHhsYWIoIkF2ZXJhZ2UgbG9nIENQTSIpCmBgYAoKTm90ZSwgdGhhdCAKCi0gVGhlIGdlbmUtd2lzZSBkaXNwZXJzaW9uIGlzIHZlcnkgdmFyaWFibGUgKGJsYWNrIGRvdHMpLgotIFRoZXJlIGlzIGEgZGlzcGVyc2lvbiAtIG1lYW4gdHJlbmQgKGJsdWUgbGluZSkKLSBUaGUgdGFnLXdpc2UgZGlzcGVyc2lvbnMgKG9yYW5nZSBkb3RzKSBhcmUgdGhlIHJlc3VsdCBvZiBzaHJpbmtpbmcgdGhlIGdlbmUtd2lzZSBkaXNwZXJzaW9uIChibGFjayBkb3RzKSB0byB0aGUgdHJlbmQgKGJsdWUgbGluZSkgCgpCeSBkZWZhdWx0IGVkZ2VSIHByb3ZpZGVzIHRoZSBmb2xsb3dpbmcgcGxvdCAKCmBgYHtyfQpwbG90QkNWKHkpCmBgYAoKSW4gdGhlIG1ldGhvZHMgcGFwZXIgb2YgZWRnZVIgZGlmZmVyZW50IGRpc3BlcnNpb24gZXN0aW1hdG9ycyB3ZXJlIGNvbXBhcmVkIGFuZCB0aGUgdGFnLXdpc2UgZGlzcGVyc2lvbnMgc2VlbWVkIHRvIHByb3ZpZGUgdGhlIGJlc3QgZ29vZG5lc3Mgb2YgZml0LiAKCmBgYHtyIHJlZkdlbm9tZSwgZWNobz1GQUxTRSwgZmlnLmNhcD0iUVEtcGxvdHMgb2YgZ29vZG5lc3Mgb2YgZml0IHN0YXRpc3RpY3MgdXNpbmcgY29tbW9uLCB0cmVuZGVkIG9yIGVtcGlyaWNhbCBCYXllcy4gSW1hZ2UgZnJvbSBNY0NhcnRoeSBhbmQgU215dGgsIDIwMTIsIE5BUiwgRE9JOiAxMC4xMDkzL25hci9na3MwNDIifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9OQVJEaXNwZXJzaW9uLnBuZyIpCmBgYAoKIyBTdGF0aXN0aWNhbCBJbmZlcmVuY2UgCgotIEFzeW1wdG90aWMgc3RhdGlzdGljYWwgdGVzdHMgZXhpc3QgdG8gdGVzdCBpZiAoY29udHJhc3RzIG9mIHRoZSkgcGFyYW1ldGVycyBvZiB0aGUgR0xNIGFyZSBkaWZmZXJlbnQgZnJvbSB6ZXJvLgoKLSBJbXBsZW1lbnRlZCBpbiBlZGdlUiBhbmQgREVTZXEyLgoKLSBBZ2FpbiB3ZSBoYXZlIHRvIGNvcnJlY3QgZm9yIG11bHRpcGxlIHRlc3RpbmcgISEhIEZEUiBjb3JyZWN0aW9uIGlzIGRvbmUgYnkgIGRlZmF1bHQgaW4gdGhlIGVkZ2VSIGFuZCBERVNlcTIgb3V0cHV0IAoKMS4gRml0IHRoZSBtb2RlbAoKYGBge3J9CmZpdCA8LSBnbG1GaXQoeSxkZXNpZ24pCmhlYWQoZml0JGNvZWZmaWNpZW50cykKYGBgCgpJbnRlcnByZXRhdGlvbiBvZiBtb2RlbCBwYXJhbWV0ZXJzPyAKCgoyLiBTdGF0aXN0aWNhbCB0ZXN0IHRvIGFzc2VzcyB0aGUgdGltZSBlZmZlY3QgCgpgYGB7cn0KbHJ0IDwtIGdsbUxSVChmaXQsIGNvZWYgPSAidGltZTQ4aCIpCnRvcFRhZ3MobHJ0KQpgYGAKCg==