Review Bayesian
Rule
Bayesian inference is a probabilistic framework for updating beliefs
(in the form of probability distributions) about unknown parameters
\(\boldsymbol{\theta}\) after observing
data \(\mathbf{X} = (X_1, X_2, \cdots,
X_n)\). It combines prior knowledge (the prior) with
observed evidence (the likelihood) to form an updated belief
(the posterior).
The core mechanism is Bayes’ Theorem:
\[
P(\boldsymbol{\theta} \mid \mathbf{X}) = \frac{P(\mathbf{X} \mid
\boldsymbol{\theta}) \, P(\boldsymbol{\theta})}{P(\mathbf{X})} \propto
P(\mathbf{X} \mid \boldsymbol{\theta}) \, P(\boldsymbol{\theta}) =
P\left[(X_1, X_2, \cdots, X_n) \mid \boldsymbol{\theta}\right] \,
P(\boldsymbol{\theta})
\]
Where:
\(P(\boldsymbol{\theta} \mid
\mathbf{X})\): Posterior distribution – belief
about \(\boldsymbol{\theta}\) after
seeing data.
\(P(\mathbf{X} \mid
\boldsymbol{\theta})\): Likelihood – probability
of data given \(\boldsymbol{\theta}\).
This a joint probability distribution of
\((X_1, X_2, \cdots, X_n) \mid
\theta\). Later, we will
make a naïve assumption of conditional independence,
which leads to a classification model called naïve
Bayes.
\(P(\boldsymbol{\theta})\):
Prior distribution – belief about \(\boldsymbol{\theta}\) before seeing data.
This implies that we can make use of prior auxiliary information in
Bayes inference.
\(P(\mathbf{X})\):
Marginal likelihood / Evidence – This is the
probability of the data under all possible \(\boldsymbol{\theta}\) (i.e., the
normalizing constant). Because \(P(\mathbf{X})\) is constant with respect to
\(\boldsymbol{\theta}\), its derivative
will be zero in the optimization for parameter estimation. This is also
why \(P(\boldsymbol{\theta} \mid \mathbf{X})
\propto P(\mathbf{X} \mid \boldsymbol{\theta}) \,
P(\boldsymbol{\theta})\).
\(P(\mathbf{X}
\mid \boldsymbol{\theta}) \, P(\boldsymbol{\theta})\) is called
the kernel of \(P(\boldsymbol{\theta} \mid
\mathbf{X})\)
Conjugate Bayesian
Inference
A conjugate prior is chosen such that the posterior
distribution belongs to the same probability family as the prior. This
simplifies computation dramatically because the posterior can be derived
analytically. If:
\[
\text{Prior}: \theta \sim \text{Dist}_1(\alpha)
\]
\[
\text{Likelihood}: \mathbf{X} \mid \theta \sim \text{Dist}_2(\theta)
\]
Then for conjugacy:
\[
\text{Posterior: } \theta \mid \mathbf{X} \sim
\text{Dist}_1(\alpha')
\]
where \(\alpha'\) are updated
hyperparameters.
Bayesian Estimation
Binomial Distribution
This section use Bayesian estimation of the success probability of
binomial distribution as an example to illustrate the process of
conjugate Bayesian inference.
Beta Distribution:
Basics and Properties
The Beta distribution is a continuous probability distribution
defined on the interval {[0, 1], making it particularly
useful for modeling probabilities, proportions, or
percentages. It is the conjugate prior for the
Bernoulli, binomial, and geometric distributions in Bayesian
inference.
For parameters \(\alpha > 0\) and
\(\beta > 0\), the PDF is:
\[
f(x; \alpha, \beta) = \frac{x^{\alpha-1}(1-x)^{\beta-1}}{B(\alpha,
\beta)}, \quad x \in [0, 1]
\] where:
- \(\alpha, \beta\) are shape
parameters that control the distribution’s form
- \(B(\alpha, \beta)\) is the
Beta function:
\[
B(\alpha, \beta) = \int_0^1 t^{\alpha-1}(1-t)^{\beta-1} dt =
\frac{\Gamma(\alpha)\Gamma(\beta)}{\Gamma(\alpha + \beta)}
\]
- \(\Gamma(\cdot)\) is the **Gamma
function}: \(\Gamma(n) = (n-1)!\) for
positive integers
The Beta function ensures the PDF integrates to 1 over \([0, 1]\):
\[
\int_0^1 f(x; \alpha, \beta) \, dx = 1
\]
Mean (Expected Value)
\[
\mathbb{E}[X] = \frac{\alpha}{\alpha + \beta}
\]
Interpretation: The mean represents a weighted
average where \(\alpha\) and \(\beta\) act like
pseudo-counts of successes and failures.
Variance
\[
\text{Var}(X) = \frac{\alpha\beta}{(\alpha + \beta)^2(\alpha + \beta +
1)}
\]
Interpretation:
Bayesian Estimation
of Binomial Success Probability
We conduct \(n\) independent
Bernoulli trials with success probability \(\theta \in [0,1]\). We observe \(k\) successes. We want to estimate \(\theta\) using Bayesian inference with a
conjugate Beta prior.
Likelihood
Function
The data \(X = \{x_1, x_2, \dots,
x_n\}\), where \(x_i \in
\{0,1\}\).
\[
P(X \mid \theta) = \prod_{i=1}^n \theta^{x_i}(1-\theta)^{1-x_i}
\]
Let \(k = \sum_{i=1}^n x_i\) be the
total number of successes.
\[
P(X \mid \theta) = \theta^k (1-\theta)^{n-k}
\]
This is the binomial likelihood (up to the binomial
coefficient \(\binom{n}{k}\), which is
constant with respect to \(\theta\)):
\[
P(k \mid \theta, n) = \binom{n}{k} \theta^k (1-\theta)^{n-k}
\]
For Bayesian updating, we can use the proportional
form:
\[
P(k \mid \theta, n) \propto \theta^k (1-\theta)^{n-k}
\]
Prior
Distribution
We choose a Beta distribution as conjugate
prior:
\[
P(\theta \mid \alpha, \beta) =
\frac{\theta^{\alpha-1}(1-\theta)^{\beta-1}}{B(\alpha, \beta)}
\]
Where:
- \(\alpha > 0\), \(\beta > 0\) are hyperparameters
- \(B(\alpha, \beta) =
\frac{\Gamma(\alpha)\Gamma(\beta)}{\Gamma(\alpha+\beta)}\) is the
Beta function
The proportional form (dropping the normalizing
constant):
\[
P(\theta) \propto \theta^{\alpha-1}(1-\theta)^{\beta-1}
\]
Bayes’ Theorem
Application
\[
P(\theta \mid k, n) = \frac{P(k \mid \theta, n) P(\theta)}{P(k \mid n)}
\]
Where \(P(k \mid n) = \int_0^1 P(k \mid
\theta, n) P(\theta) d\theta\) is the marginal likelihood.
The number of Bernoulli trials \(n\) is a predetermined constant. It is not
an unknown parameter of the binomial distribution.
Posterior
Derivation
We ignore all constants and work only with the kernels of related
distributions to derive the kernel of posterior distribution and add the
normalizing in the end to make the complete the posterior
distribution.
Kernel of Posterior Distribution
We first find the kernel of the posterior distribution based on the
above Bayes rule in the following
\[
P(\theta \mid k, n) \propto P(k \mid \theta, n) \cdot P(\theta)
\]
\[
\propto \left[\theta^k (1-\theta)^{n-k}\right] \cdot
\left[\theta^{\alpha-1}(1-\theta)^{\beta-1}\right]
\]
\[
= \theta^{k + \alpha - 1} (1-\theta)^{n - k + \beta - 1}
\]
\[
= \theta^{\alpha' - 1} (1-\theta)^{\beta' - 1}
\]
Where:
\[
\alpha' = \alpha + k, \quad \beta' = \beta + (n - k)
\]
Complete Posterior Distribution
We next find the normalizing coefficient to make the above kernel in
a valid distribution.
\[
P(\theta \mid k, n) =
\frac{\theta^{\alpha'-1}(1-\theta)^{\beta'-1}}{B(\alpha',
\beta')}
\]
\[
\theta \mid k, n \sim \text{Beta}(\alpha', \beta')
\]
Where:
\[
\alpha' = \alpha + k, \quad \beta' = \beta + n - k
\]
The hyperparameters \(\alpha\) and
\(\beta\) act as
pseudo-counts:
\(\alpha-1\) = prior number of
successes
\(\beta-1\) = prior number of
failures
\(\alpha + \beta - 2\) = total
prior observations
The posterior simply adds the observed counts to the
prior pseudo-counts.
Posterior
Statistics
Key statistics used in Bayesian inference
Mean:
\[
\mathbb{E}[\theta \mid k, n] = \frac{\alpha'}{\alpha' +
\beta'} = \boxed{\frac{\alpha + k}{\alpha + \beta + n} }
\]
The above expression in the above box can be re-written in the
following to make the connection between the MLE of \(\theta\), denoted by \(\hat{p}_{MLE}\).
\[
=
\frac{\frac{\alpha}{n}+\frac{k}{p}}{\frac{\alpha}{n}+\frac{\beta}{n}+1}
=
\frac{\frac{\alpha}{n}+\hat{p}_{MLE}}{\frac{\alpha}{n}+\frac{\beta}{n}+1} \xrightarrow{\text{as
n gets bigger}} \hat{p}_{MLE}
\]
where \(\hat{p}_{MLE} = k/n\). As
\(n \to \infty\), \(\alpha/n \to 0\) and \(\beta/n \to 0\).
Variance:
\[
\text{Var}[\theta \mid k, n] =
\frac{\alpha'\beta'}{(\alpha'+\beta')^2(\alpha'+\beta'+1)}
=
\boxed{\frac{(\alpha+k)(\beta+n-k)}{(\alpha+\beta+n)^2(\alpha+\beta+n+1)}}
\]
The posterior variance in the above box can also be re-written in the
following to make the connection with the MLE of variance. We divide
both numerator and denominator by \(n^3\)
\[
\frac{(\alpha+k)(\beta+n-k)}{(\alpha+\beta+n)^2(\alpha+\beta+n+1)} =
\frac{\frac{1}{n}(\frac{\alpha}{n}+\frac{k}{n})(\frac{\beta}{n}+1-\frac{k}{n})}{(\frac{\alpha}{n}+\frac{\beta}{n}+1)^2(\frac{\alpha}{n}+\frac{\beta}{n}+1+\frac{1}{n})}
\approx \frac{\hat{p}_{MLE}(1-\hat{p}_{MLE})}{n}, \ \ \text{ as n gets
bigger}.
\]
Numerical
Example
Consider an experiments of 20 Bernoulli trials (\(n = 20\)) with 14 successes (\(k = 14\)). We want to find the Bayes
estimate of the success probability \(\hat{p}_{\text{Bayes}}\) with the prior
distribution of the true success probability \(\theta\), i.e., \(\theta \sim \text{Beta}(3, 3)\) which is
symmetric, centered at 0.5.
Bayesian
Estimation
The objective is to construct a 95% Bayesian credible interval based
on the information in the experiment (i.e., sample data).
Setup
- Prior: \(\theta \sim
\text{Beta}(3, 3)\) (symmetric, centered at 0.5)
- Data: \(n = 20\)
trials, \(k = 14\) successes
- MLE: \(\hat{\theta}_{\text{MLE}} = 14/20 =
0.7\)
Posterior Calculation
Based on the derivation of the above subsection, the Prior
parameters are given by
- Prior Parameters: \(\alpha = 3\), \(\beta = 3\)
- Prior mean: \(3/(3+3) =
0.5\)
- Prior strength: \(\alpha
+ \beta = 6\) (equivalent to 4 pseudo-observations)
Posterior parameters:
\[
\alpha' = 3 + 14 = 17, \quad \beta' = 3 + (20 - 14) = 3 + 6 = 9
\]
Posterior distribution:
\[
\theta \mid k, n \sim \text{Beta}(17, 9)
\]
Posterior statistics:
\[
\mathbb{E}[\theta \mid k, n] = \frac{17}{17 + 9} = \frac{17}{26} \approx
0.654
\]
\[
\text{Var}[\theta \mid k, n] = \frac{17 \times 9}{(26)^2(27)} =
\frac{153}{18252} \approx 0.00838
\]
\[
\text{SD}[\theta \mid k, n] \approx \sqrt{0.00838} \approx 0.0916
\]
95% Credible Interval
The \(100(1-\alpha)\%\) credible
interval \([L, U]\) satisfies:
\[
P(L \leq \theta \leq U \mid k, n) = 0.95
\]
For Beta(17,9), we use R to find 2.5th and 97.5th percentiles to the
obtain the lower and upper credible limits in the following
\(L = \text{Beta}^{-1}(0.025; 17, 9)
\approx 0.478\)
\(U = \text{Beta}^{-1}(0.975; 17, 9)
\approx 0.813\)
Therefore, \(\theta \in [0.478,
0.813]\) with 95% posterior probability.
Bayesian Prediction
(Optional)
Based on the Bayesian estimates of the parameter obtained previously,
we want to predict the outcome of the next \(m\) trials. The general formula for the
probability of success in next \(m\)
trials with \(y\) successes:
\[
P(y \mid k, n, m) = \int_0^1 P(y \mid \theta, m) P(\theta \mid k, n)
d\theta
\]
\[
= \int_0^1 \binom{m}{y} \theta^y (1-\theta)^{m-y} \cdot
\frac{\theta^{\alpha'-1}(1-\theta)^{\beta'-1}}{B(\alpha',
\beta')} d\theta
\]
\[
= \binom{m}{y} \frac{B(\alpha' + y, \beta' + m -
y)}{B(\alpha', \beta')}
\]
This is again a Beta-binomial distribution. Next, we
look at prediction with special \(m\).
In the following special cases, \(n =
20\) and \(k = 14\):
- For 1 next trial (\(m=1\), i.e.,
Bernoulli trial) with the outcome of a success:
\[
P(\text{success} \mid k, n) = \mathbb{E}[\theta \mid k, n] =
\frac{\alpha'}{\alpha' + \beta'} \approx 0.654
\]
- For 5 next trials (\(m=5\)) with
\(y = 3\) successes:
\[
P(y=3 \mid k, n, m=5) = \binom{5}{3} \frac{B(17+3, 9+2)}{B(17, 9)} = 10
\cdot \frac{B(20, 11)}{B(17, 9)} \approx 0.344
\]
Common Conjugate
Families
The primary purpose of using a conjugate prior in Bayesian inference
is to ensure mathematical tractability by guaranteeing that the
posterior distribution belongs to the same probability family as the
prior, which allows for closed-form analytical updates rather than
computationally intensive numerical approximations. This conjugacy
enables straightforward sequential learning, where posterior parameters
are simply updated through addition of observed data statistics to prior
hyperparameters, making it ideal for real-time or streaming data
applications. While modern computational methods have reduced the
necessity of strict conjugacy, it remains a powerful tool for
pedagogical clarity, rapid prototyping, and applications where
computational efficiency and transparency are prioritized over full
prior flexibility.
The following is a list of some commonly used conjugate priors
associated with a few population distributions.
Bernoulli/Binomial \(\leftrightarrow\) Beta
Poisson \(\leftrightarrow\)
Gamma
Normal (with known variance) \(\leftrightarrow\) Normal (for
mean)
Normal (with known mean) \(\leftrightarrow\) Inverse-Gamma (for
variance)
Multinomial \(\leftrightarrow\)
Dirichlet
Practical
Applications
A/B testing: Update success rate posteriors for
two webpage variants.
Quality control: Estimate defect rates with
historical prior.
Pharmacokinetics: Update drug effect size
distribution from trials.
Naïve Bayes
Classifier
Recall the Bayes Rule with multiple feature
variables \(\mathbf{X} = (X_1, X_2, \cdots,
X_k)\) and a categorical variable \(\mathbf{C}=(C_1, C_2. \cdots, C_d)\) with
\(d\) categories.
The core mechanism is Bayes’ Theorem:
\[
P(C_j \mid \mathbf{X}) = \frac{P(\mathbf{X} \mid C_j) \,
P(C_j)}{P(\mathbf{X})} \propto P(\mathbf{X} \mid C_j) \, P(C_j) =
P\left[(X_1, X_2, \cdots, X_k) \mid C_j\right] \, P(C_j)
\]
A probabilistic classifier based on Bayes theorem with a strong
(naive) assumption: features are conditionally
independent given the class label.
\[
P\left[(X_1, X_2, \cdots, X_d) \mid C_j\right] = \prod_{i=1}^k P(X_i\mid
C_j), \ \ \text{ where } \ \ 1 \le j \le d.
\]
That is, under the framework of Naive Bayes, the
category probability (or proportional to the probability) is calculated
by
\[
P(C_j \mid \mathbf{X}) \propto P(C_j) \prod_{i=1}^{d} P(x_j \mid C_j)
\]
\(P(C_k)\):
Prior probability of class \(k\).
\(P(x_j \mid
C_k)\): Likelihood of feature \(j\) given class \(k\).
Decision rule for classification: Choose class
with highest posterior \(P(C_k \mid
\mathbf{x})\).
Gaussian Naïve
Bayes
When features are continuous, assume \(P(x_j \mid C_k)\) is Gaussian:
\[
P(x_j \mid C_k) = \frac{1}{\sqrt{2\pi\sigma_{jk}^2}}
\exp\left(-\frac{(x_j - \mu_{jk})^2}{2\sigma_{jk}^2}\right)
\]
Parameters \(\mu_{jk},
\sigma_{jk}^2\) estimated via MLE from training data for each
class \(k\) and feature \(j\).
An Numerical Example - Classify Fruits Based on Weight and
Sweetness: We want to predict whether a fruit is an
Apple or Orange based on:
- Weight (in grams)
- Sweetness (scale 1-10, where 10 is very sweet)
The training Data is given by
| 1 |
150 |
6 |
Apple |
| 2 |
130 |
8 |
Orange |
| 3 |
160 |
5 |
Apple |
| 4 |
140 |
7 |
Orange |
| 5 |
170 |
4 |
Apple |
The following are the steps for making prediction.
Step 1: Calculate Class Probabilities
- Total fruits: 5
- Apples: 3 \(\rightarrow P(\text{Apple}) =
\frac{3}{5} = 0.6\)
- Oranges: 2 \(\rightarrow P(\text{Orange})
= \frac{2}{5} = 0.4\)
Step 2: Calculate Gaussian Parameters for Each Feature per
Class
\[\begin{align}
\mu_{\text{weight,Apple}} &= \frac{150 + 160 + 170}{3} = 160 \\
\sigma^2_{\text{weight,Apple}} &= \frac{(150-160)^2 +
(160-160)^2 + (170-160)^2}{3} \\
&= \frac{100 + 0 + 100}{3} = 66.67 \\
\sigma_{\text{weight,Apple}} &= \sqrt{66.67} \approx 8.16
\end{align}\]
\[\begin{align}
\mu_{\text{sweet,Apple}} &= \frac{6 + 5 + 4}{3} = 5 \\
\sigma^2_{\text{sweet,Apple}} &= \frac{(6-5)^2 + (5-5)^2 +
(4-5)^2}{3} \\
&= \frac{1 + 0 + 1}{3} = 0.67 \\
\sigma_{\text{sweet,Apple}} &= \sqrt{0.67} \approx 0.82
\end{align}\]
\[\begin{align}
\mu_{\text{weight,Orange}} &= \frac{130 + 140}{2} = 135 \\
\sigma^2_{\text{weight,Orange}} &= \frac{(130-135)^2 +
(140-135)^2}{2} \\
&= \frac{25 + 25}{2} = 25 \\
\sigma_{\text{weight,Orange}} &= \sqrt{25} = 5
\end{align}\]
\[\begin{align}
\mu_{\text{sweet,Orange}} &= \frac{8 + 7}{2} = 7.5 \\
\sigma^2_{\text{sweet,Orange}} &= \frac{(8-7.5)^2 +
(7-7.5)^2}{2} \\
&= \frac{0.25 + 0.25}{2} = 0.25 \\
\sigma_{\text{sweet,Orange}} &= \sqrt{0.25} = 0.5
\end{align}\]
Step 3: Make a Prediction for a New Fruit: Given a
New fruit with Weight = 145g and Sweetness = 6.5. The
objective is to use Naive Bayes to predict whether this
fruit is Apple or Orange. To proceed,
we calculate category probabilities based on the given information of
the new fruit in the following:
- Calculate Likelihoods using Gaussian PDF
\[
P(x \mid \text{class}) = \frac{1}{\sqrt{2\pi\sigma^2}}
\exp\left(-\frac{(x - \mu)^2}{2\sigma^2}\right)
\]
\[\begin{align}
P(\text{Weight}=145 \mid \text{Apple}) &= \mathcal{N}(145;
\mu=160, \sigma^2=66.67) \approx 0.035 \\
P(\text{Sweetness}=6.5 \mid \text{Apple}) &= \mathcal{N}(6.5;
\mu=5, \sigma^2=0.67) \approx 0.139 \\
\text{Likelihood}(\text{Apple}) &= 0.035 \times 0.139 = 0.004865
\end{align}\]
\[\begin{align}
P(\text{Weight}=145 \mid \text{Orange}) &= \mathcal{N}(145;
\mu=135, \sigma^2=25) \approx 0.0108 \\
P(\text{Sweetness}=6.5 \mid \text{Orange}) &= \mathcal{N}(6.5;
\mu=7.5, \sigma^2=0.25) \approx 0.484 \\
\text{Likelihood}(\text{Orange}) &= 0.0108 \times 0.484 =
0.005227
\end{align}\]
Step 4: Apply Bayes’ Theorem
- Posterior Probabilities (Ignoring
Denominator):
\[\begin{align}
P(\text{Apple} \mid \text{data}) &\propto P(\text{Apple}) \times
\text{Likelihood}(\text{Apple}) \\
&= 0.6 \times 0.004865 = \mathbf{0.002919} \\[6pt]
P(\text{Orange} \mid \text{data}) &\propto P(\text{Orange})
\times \text{Likelihood}(\text{Orange}) \\
&= 0.4 \times 0.005227 = \mathbf{0.002091}
\end{align}\]
\[\begin{align}
\text{Total} &= 0.002919 + 0.002091 = 0.00501 \\[6pt]
P(\text{Apple} \mid \text{data}) &= \frac{0.002919}{0.00501}
\approx \mathbf{58.3\%} \\[6pt]
P(\text{Orange} \mid \text{data}) &= \frac{0.002091}{0.00501}
\approx \mathbf{41.7\%}
\end{align}\]
Prediction:
Apple (higher
probability)
Semiparametric Naive
Bayes
When feature variables include both categorical and numerical
features, naive Bayes is a natural semiparametric
model. The following is a numerical example.
Example - Email Spam Detection with Naive Bayes:
Classify emails as or using:
Sender Domain (categorical): \(\{\text{gmail}, \text{work},
\text{unknown}\}\)
Email Length (continuous): Number of characters
in email body
Next few steps illustrate the process of training the Naive
Bayes model and use the trained naive Bayes to
make prediction.
Step 1. Training Dataset
| 1 |
gmail |
250 |
0 (Not Spam) |
| 2 |
work |
120 |
0 |
| 3 |
unknown |
500 |
1 (Spam) |
| 4 |
gmail |
300 |
0 |
| 5 |
unknown |
450 |
1 |
| 6 |
work |
180 |
0 |
| 7 |
unknown |
400 |
1 |
| 8 |
gmail |
280 |
0 |
Step 2. Priors Calculation
\[
P(Y=0) = \frac{5}{8} = 0.625
\]
\[
P(Y=1) = \frac{3}{8} = 0.375
\]
Step 3. Categorical Feature Likelihoods (Sender
Domain)
\[\begin{align*}
P(X_1=\text{gmail} | Y=0) &= 2/5 = 0.4 \\
P(X_1=\text{work} | Y=0) &= 2/5 = 0.4 \\
P(X_1=\text{unknown} | Y=0) &= 1/5 = 0.2
\end{align*}\]
\[\begin{align*}
P(X_1=\text{gmail} | Y=1) &= 0/3 = 0 \\
P(X_1=\text{work} | Y=1) &= 0/3 = 0 \\
P(X_1=\text{unknown} | Y=1) &= 3/3 = 1
\end{align*}\]
- With Laplace Smoothing (\(\alpha=1\)): To avoid zero
probability of empty subcategories, we add a small constant.
\[
P(X_1=k|Y=c) = \frac{\text{count}(k,c) + \alpha}{\text{count}(c) +
\alpha \times \text{num\_categories}}
\]
3 categories: \(\{\text{gmail},
\text{work}, \text{unknown}\}\)
\[\begin{align*}
P(X_1=\text{gmail}|Y=0) &= (2+1)/(5+3) = 3/8 = 0.375 \\
P(X_1=\text{work}|Y=0) &= (2+1)/(5+3) = 3/8 = 0.375 \\
P(X_1=\text{unknown}|Y=0) &= (1+1)/(5+3) = 2/8 = 0.25
\end{align*}\]
\[\begin{align*}
P(X_1=\text{gmail}|Y=1) &= (0+1)/(3+3) = 1/6 \approx 0.167 \\
P(X_1=\text{work}|Y=1) &= (0+1)/(3+3) = 1/6 \approx 0.167 \\
P(X_1=\text{unknown}|Y=1) &= (3+1)/(3+3) = 4/6 \approx 0.667
\end{align*}\]
Step 4. Continuous Feature (Gaussian) - Email
Length
\[\begin{align*}
\mu_0 &= \frac{250+120+300+180+280}{5} = \frac{1130}{5} = 226 \\
\sigma_0^2 &=
\frac{(250-226)^2+(120-226)^2+(300-226)^2+(180-226)^2+(280-226)^2}{4} \\
&= \frac{24420}{4} = 6105 \\
\sigma_0 &= \sqrt{6105} \approx 78.13
\end{align*}\]
\[\begin{align*}
\mu_1 &= \frac{500+450+400}{3} = \frac{1350}{3} = 450 \\
\sigma_1^2 &= \frac{(500-450)^2+(450-450)^2+(400-450)^2}{2} =
\frac{5000}{2} = 2500 \\
\sigma_1 &= \sqrt{2500} = 50
\end{align*}\]
Step 5. Gaussian Probability Density Function
\[
P(X_2=x|Y=c) = \frac{1}{\sqrt{2\pi\sigma_c^2}}
\exp\left(-\frac{(x-\mu_c)^2}{2\sigma_c^2}\right)
\]
Step 6. Classification Example
Now, we have an incoming New email with features:
Sender = “unknown”, Length = 480 characters. We want to use
naive Bayes to classify it into either
Spam or Not Spam.
The calculation is divided in the following steps as described
earlier:
- Step 1: Likelihood for categorical feature
\[\begin{align*}
P(X_1=\text{unknown}|Y=0) &= 0.25 \\
P(X_1=\text{unknown}|Y=1) &= 0.667
\end{align*}\]
- Step 2: Likelihood for continuous feature (using Gaussian
PDF)
\[\begin{align*}
P(X_2=480|Y=0) &= \frac{1}{\sqrt{2\pi \times 6105}}
\exp\left(-\frac{(480-226)^2}{2 \times 6105}\right) \\
&= \frac{1}{195.77} \exp\left(-\frac{64516}{12210}\right) \\
&= 0.00511 \times \exp(-5.285) \\
&= 0.00511 \times 0.00507 \approx 2.59 \times 10^{-5}
\end{align*}\]
\[\begin{align*}
P(X_2=480|Y=1) &= \frac{1}{\sqrt{2\pi \times 2500}}
\exp\left(-\frac{(480-450)^2}{2 \times 2500}\right) \\
&= \frac{1}{125.66} \exp\left(-\frac{900}{5000}\right) \\
&= 0.00796 \times \exp(-0.18) \\
&= 0.00796 \times 0.835 \approx 0.00665
\end{align*}\]
- Step 3: Posterior probabilities (ignoring
denominator)
\[\begin{align*}
P(Y=0|X) &\propto P(Y=0) \times P(X_1|Y=0) \times P(X_2|Y=0) \\
&= 0.625 \times 0.25 \times 2.59 \times 10^{-5} \approx 4.05 \times
10^{-6} \\[0.5em]
P(Y=1|X) &\propto P(Y=1) \times P(X_1|Y=1) \times P(X_2|Y=1) \\
&= 0.375 \times 0.667 \times 0.00665 \approx 0.00166
\end{align*}\]
\[\begin{align*}
\text{Sum} &= 4.05 \times 10^{-6} + 0.00166 \approx 0.001664
\\[0.5em]
P(Y=0|X) &= \frac{4.05 \times 10^{-6}}{0.001664} \approx 0.0024
\\[0.5em]
P(Y=1|X) &= \frac{0.00166}{0.001664} \approx 0.9976
\end{align*}\]
Prediction:
Spam (\(Y=1\)) with
99.76% confidence
Key Naive Bayes Assumptions
- Feature Independence: Assumes sender domain and
email length are independent given the class
- Gaussian: Email length follows normal distribution
within each class
- Categorical: Sender domain probabilities estimated
with smoothing
- Naive: Joint probability = product of individual
feature probabilities
LS0tDQp0aXRsZTogIkNvbmp1Z2F0ZSBCYXllcyBJbmZlcmVuY2UgYW5kIE5haXZlIEJheWVzIFByZWRpY3Rpb24iDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIldlc3QgQ2hlc3RlciBVbml2ZXJzaXR5Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICBsaWJyYXJ5KHBzeWNoKQ0KfQ0KaWYgKCFyZXF1aXJlKCJSQ29sb3JCcmV3ZXIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQ0KICBsaWJyYXJ5KFJDb2xvckJyZXdlcikNCn0NCg0KaWYgKCFyZXF1aXJlKCJib290IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogIGxpYnJhcnkoYm9vdCkNCn0NCmlmICghcmVxdWlyZSgiZWZmc2l6ZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImVmZnNpemUiKQ0KICBsaWJyYXJ5KGVmZnNpemUpDQp9DQojIyBsaWJyYXJ5KGVmZnNpemUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQpcDQoNCiMgUmV2aWV3IEJheWVzaWFuIFJ1bGUNCg0KQmF5ZXNpYW4gaW5mZXJlbmNlIGlzIGEgcHJvYmFiaWxpc3RpYyBmcmFtZXdvcmsgZm9yIHVwZGF0aW5nIGJlbGllZnMgKGluIHRoZSBmb3JtIG9mIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMpIGFib3V0IHVua25vd24gcGFyYW1ldGVycyAkXGJvbGRzeW1ib2x7XHRoZXRhfSQgYWZ0ZXIgb2JzZXJ2aW5nIGRhdGEgJFxtYXRoYmZ7WH0gPSAoWF8xLCBYXzIsIFxjZG90cywgWF9uKSQuIEl0IGNvbWJpbmVzIHByaW9yIGtub3dsZWRnZSAodGhlICpwcmlvciopIHdpdGggb2JzZXJ2ZWQgZXZpZGVuY2UgKHRoZSAqbGlrZWxpaG9vZCopIHRvIGZvcm0gYW4gdXBkYXRlZCBiZWxpZWYgKHRoZSAqcG9zdGVyaW9yKikuDQoNClRoZSBjb3JlIG1lY2hhbmlzbSBpcyAqKkJheWVzJyBUaGVvcmVtKio6DQoNCg0KJCQNClAoXGJvbGRzeW1ib2x7XHRoZXRhfSBcbWlkIFxtYXRoYmZ7WH0pID0gXGZyYWN7UChcbWF0aGJme1h9IFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfSkgXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KX17UChcbWF0aGJme1h9KX0gXHByb3B0byBQKFxtYXRoYmZ7WH0gXG1pZCBcYm9sZHN5bWJvbHtcdGhldGF9KSBcLCBQKFxib2xkc3ltYm9se1x0aGV0YX0pID0gUFxsZWZ0WyhYXzEsIFhfMiwgXGNkb3RzLCBYX24pIFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfVxyaWdodF0gXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KQ0KJCQNCg0KDQpXaGVyZToNCg0KKiAkUChcYm9sZHN5bWJvbHtcdGhldGF9IFxtaWQgXG1hdGhiZntYfSkkOiAqKlBvc3RlcmlvciBkaXN0cmlidXRpb24qKiAtLSBiZWxpZWYgYWJvdXQgJFxib2xkc3ltYm9se1x0aGV0YX0kIGFmdGVyIHNlZWluZyBkYXRhLg0KDQoqICRQKFxtYXRoYmZ7WH0gXG1pZCBcYm9sZHN5bWJvbHtcdGhldGF9KSQ6ICoqTGlrZWxpaG9vZCoqIC0tIHByb2JhYmlsaXR5IG9mIGRhdGEgZ2l2ZW4gJFxib2xkc3ltYm9se1x0aGV0YX0kLiA8Zm9udCBjb2xvciA9ICJyZWQiPioqVGhpcyBhIGpvaW50IHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBvZiAkKFhfMSwgWF8yLCBcY2RvdHMsIFhfbikgXG1pZCBcdGhldGEkLioqPC9mb250PiA8Zm9udCBjb2xvciA9ICJibHVlIj5MYXRlciwgd2Ugd2lsbCBtYWtlIGEgKipuYcOvdmUqKiBhc3N1bXB0aW9uIG9mIGNvbmRpdGlvbmFsIGluZGVwZW5kZW5jZSwgd2hpY2ggbGVhZHMgdG8gYSBjbGFzc2lmaWNhdGlvbiBtb2RlbCBjYWxsZWQgKipuYcOvdmUgQmF5ZXMqKi48L2ZvbnQ+DQoNCiogJFAoXGJvbGRzeW1ib2x7XHRoZXRhfSkkOiAqKlByaW9yIGRpc3RyaWJ1dGlvbioqIC0tIGJlbGllZiBhYm91dCAkXGJvbGRzeW1ib2x7XHRoZXRhfSQgYmVmb3JlIHNlZWluZyBkYXRhLiBUaGlzIGltcGxpZXMgdGhhdCB3ZSBjYW4gbWFrZSB1c2Ugb2YgcHJpb3IgYXV4aWxpYXJ5IGluZm9ybWF0aW9uIGluIEJheWVzIGluZmVyZW5jZS4NCg0KKiAkUChcbWF0aGJme1h9KSQ6ICoqTWFyZ2luYWwgbGlrZWxpaG9vZCAvIEV2aWRlbmNlKiogLS0gVGhpcyBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIGRhdGEgdW5kZXIgYWxsIHBvc3NpYmxlICRcYm9sZHN5bWJvbHtcdGhldGF9JCAoaS5lLiwgdGhlIG5vcm1hbGl6aW5nIGNvbnN0YW50KS4gQmVjYXVzZSAkUChcbWF0aGJme1h9KSQgaXMgY29uc3RhbnQgd2l0aCByZXNwZWN0IHRvICRcYm9sZHN5bWJvbHtcdGhldGF9JCwgaXRzIGRlcml2YXRpdmUgd2lsbCBiZSB6ZXJvIGluIHRoZSBvcHRpbWl6YXRpb24gZm9yIHBhcmFtZXRlciBlc3RpbWF0aW9uLiBUaGlzIGlzIGFsc28gd2h5ICRQKFxib2xkc3ltYm9se1x0aGV0YX0gXG1pZCBcbWF0aGJme1h9KSBccHJvcHRvIFAoXG1hdGhiZntYfSBcbWlkIFxib2xkc3ltYm9se1x0aGV0YX0pIFwsIFAoXGJvbGRzeW1ib2x7XHRoZXRhfSkkLg0KDQoNCjxmb250IGNvbG9yID0gInJlZCI+KiokUChcbWF0aGJme1h9IFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfSkgXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KSQgaXMgY2FsbGVkIHRoZSBrZXJuZWwgb2YgJFAoXGJvbGRzeW1ib2x7XHRoZXRhfSBcbWlkIFxtYXRoYmZ7WH0pJCoqPC9mb250Pg0KDQoNClwNCg0KIyBDb25qdWdhdGUgQmF5ZXNpYW4gSW5mZXJlbmNlDQoNCkEgKipjb25qdWdhdGUgcHJpb3IqKiBpcyBjaG9zZW4gc3VjaCB0aGF0IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGJlbG9uZ3MgdG8gdGhlIHNhbWUgcHJvYmFiaWxpdHkgZmFtaWx5IGFzIHRoZSBwcmlvci4gVGhpcyBzaW1wbGlmaWVzIGNvbXB1dGF0aW9uIGRyYW1hdGljYWxseSBiZWNhdXNlIHRoZSBwb3N0ZXJpb3IgY2FuIGJlIGRlcml2ZWQgYW5hbHl0aWNhbGx5LiBJZjoNCg0KJCQNClx0ZXh0e1ByaW9yfTogIFx0aGV0YSBcc2ltIFx0ZXh0e0Rpc3R9XzEoXGFscGhhKQ0KJCQNCg0KJCQNClx0ZXh0e0xpa2VsaWhvb2R9OiAgXG1hdGhiZntYfSBcbWlkIFx0aGV0YSBcc2ltIFx0ZXh0e0Rpc3R9XzIoXHRoZXRhKQ0KJCQNCg0KVGhlbiBmb3IgY29uanVnYWN5Og0KDQokJA0KXHRleHR7UG9zdGVyaW9yOiB9IFx0aGV0YSBcbWlkIFxtYXRoYmZ7WH0gXHNpbSBcdGV4dHtEaXN0fV8xKFxhbHBoYScpDQokJA0KDQp3aGVyZSAkXGFscGhhJyQgYXJlIHVwZGF0ZWQgaHlwZXJwYXJhbWV0ZXJzLg0KDQoNCg0KIyMgQmF5ZXNpYW4gRXN0aW1hdGlvbiBCaW5vbWlhbCBEaXN0cmlidXRpb24NCg0KVGhpcyBzZWN0aW9uIHVzZSBCYXllc2lhbiBlc3RpbWF0aW9uIG9mIHRoZSBzdWNjZXNzIHByb2JhYmlsaXR5IG9mIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBhcyBhbiBleGFtcGxlIHRvIGlsbHVzdHJhdGUgdGhlIHByb2Nlc3Mgb2YgY29uanVnYXRlIEJheWVzaWFuIGluZmVyZW5jZS4NCg0KIyMjIEJldGEgRGlzdHJpYnV0aW9uOiBCYXNpY3MgYW5kIFByb3BlcnRpZXMNCg0KVGhlIEJldGEgZGlzdHJpYnV0aW9uIGlzIGEgY29udGludW91cyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gZGVmaW5lZCBvbiB0aGUgaW50ZXJ2YWwgKip7WzAsIDFdKiosIG1ha2luZyBpdCBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBtb2RlbGluZyAqKnByb2JhYmlsaXRpZXMsIHByb3BvcnRpb25zLCBvciBwZXJjZW50YWdlcyoqLiBJdCBpcyB0aGUgKipjb25qdWdhdGUgcHJpb3IqKiBmb3IgdGhlIEJlcm5vdWxsaSwgYmlub21pYWwsIGFuZCBnZW9tZXRyaWMgZGlzdHJpYnV0aW9ucyBpbiBCYXllc2lhbiBpbmZlcmVuY2UuDQoNCkZvciBwYXJhbWV0ZXJzICRcYWxwaGEgPiAwJCBhbmQgJFxiZXRhID4gMCQsIHRoZSBQREYgaXM6DQoNCiQkDQpmKHg7IFxhbHBoYSwgXGJldGEpID0gXGZyYWN7eF57XGFscGhhLTF9KDEteClee1xiZXRhLTF9fXtCKFxhbHBoYSwgXGJldGEpfSwgXHF1YWQgeCBcaW4gWzAsIDFdDQokJA0Kd2hlcmU6DQoNCiogJFxhbHBoYSwgXGJldGEkIGFyZSAqKnNoYXBlIHBhcmFtZXRlcnMqKiB0aGF0IGNvbnRyb2wgdGhlIGRpc3RyaWJ1dGlvbidzIGZvcm0NCiogJEIoXGFscGhhLCBcYmV0YSkkIGlzIHRoZSAqKkJldGEgZnVuY3Rpb24qKjoNCg0KJCQNCiAgICBCKFxhbHBoYSwgXGJldGEpID0gXGludF8wXjEgdF57XGFscGhhLTF9KDEtdClee1xiZXRhLTF9IGR0ID0gXGZyYWN7XEdhbW1hKFxhbHBoYSlcR2FtbWEoXGJldGEpfXtcR2FtbWEoXGFscGhhICsgXGJldGEpfQ0KJCQNCg0KKiAkXEdhbW1hKFxjZG90KSQgaXMgdGhlICoqR2FtbWEgZnVuY3Rpb259OiAkXEdhbW1hKG4pID0gKG4tMSkhJCBmb3IgcG9zaXRpdmUgaW50ZWdlcnMNCg0KVGhlIEJldGEgZnVuY3Rpb24gZW5zdXJlcyB0aGUgUERGIGludGVncmF0ZXMgdG8gMSBvdmVyICRbMCwgMV0kOg0KDQokJA0KXGludF8wXjEgZih4OyBcYWxwaGEsIFxiZXRhKSBcLCBkeCA9IDENCiQkDQoNCioqTWVhbiAoRXhwZWN0ZWQgVmFsdWUpKioNCg0KJCQNClxtYXRoYmJ7RX1bWF0gPSBcZnJhY3tcYWxwaGF9e1xhbHBoYSArIFxiZXRhfQ0KJCQNCg0KKipJbnRlcnByZXRhdGlvbioqOiBUaGUgbWVhbiByZXByZXNlbnRzIGEgd2VpZ2h0ZWQgYXZlcmFnZSB3aGVyZSAkXGFscGhhJCBhbmQgJFxiZXRhJCBhY3QgbGlrZSAqKnBzZXVkby1jb3VudHMqKiBvZiBzdWNjZXNzZXMgYW5kIGZhaWx1cmVzLg0KIA0KKipWYXJpYW5jZSoqDQoNCiQkDQpcdGV4dHtWYXJ9KFgpID0gXGZyYWN7XGFscGhhXGJldGF9eyhcYWxwaGEgKyBcYmV0YSleMihcYWxwaGEgKyBcYmV0YSArIDEpfQ0KJCQNCg0KKipJbnRlcnByZXRhdGlvbioqOg0KDQoqIFZhcmlhbmNlICoqZGVjcmVhc2VzKiogYXMgJFxhbHBoYSArIFxiZXRhJCBpbmNyZWFzZXMgKG1vcmUgKipwc2V1ZG8tb2JzZXJ2YXRpb25zKiogJFxSaWdodGFycm93JCBtb3JlIGNlcnRhaW50eSkNCg0KKiBWYXJpYW5jZSBpcyAqKm1heGltaXplZCoqIHdoZW4gJFxhbHBoYSA9IFxiZXRhID0gMSQgKHVuaWZvcm0gZGlzdHJpYnV0aW9uKQ0KDQoNCg0KIyMgQmF5ZXNpYW4gRXN0aW1hdGlvbiBvZiBCaW5vbWlhbCBTdWNjZXNzIFByb2JhYmlsaXR5DQoNCldlIGNvbmR1Y3QgJG4kIGluZGVwZW5kZW50IEJlcm5vdWxsaSB0cmlhbHMgd2l0aCBzdWNjZXNzIHByb2JhYmlsaXR5ICRcdGhldGEgXGluIFswLDFdJC4gV2Ugb2JzZXJ2ZSAkayQgc3VjY2Vzc2VzLiBXZSB3YW50IHRvIGVzdGltYXRlICRcdGhldGEkIHVzaW5nIEJheWVzaWFuIGluZmVyZW5jZSB3aXRoIGEgY29uanVnYXRlIEJldGEgcHJpb3IuIA0KDQojIyMgTGlrZWxpaG9vZCBGdW5jdGlvbg0KDQpUaGUgZGF0YSAkWCA9IFx7eF8xLCB4XzIsIFxkb3RzLCB4X25cfSQsIHdoZXJlICR4X2kgXGluIFx7MCwxXH0kLg0KDQokJA0KUChYIFxtaWQgXHRoZXRhKSA9IFxwcm9kX3tpPTF9Xm4gXHRoZXRhXnt4X2l9KDEtXHRoZXRhKV57MS14X2l9DQokJA0KDQpMZXQgJGsgPSBcc3VtX3tpPTF9Xm4geF9pJCBiZSB0aGUgdG90YWwgbnVtYmVyIG9mIHN1Y2Nlc3Nlcy4NCg0KJCQNClAoWCBcbWlkIFx0aGV0YSkgPSBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQpUaGlzIGlzIHRoZSAqKmJpbm9taWFsIGxpa2VsaWhvb2QqKiAodXAgdG8gdGhlIGJpbm9taWFsIGNvZWZmaWNpZW50ICRcYmlub217bn17a30kLCB3aGljaCBpcyBjb25zdGFudCB3aXRoIHJlc3BlY3QgdG8gJFx0aGV0YSQpOg0KDQokJA0KUChrIFxtaWQgXHRoZXRhLCBuKSA9IFxiaW5vbXtufXtrfSBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQpGb3IgQmF5ZXNpYW4gdXBkYXRpbmcsIHdlIGNhbiB1c2UgdGhlICoqcHJvcG9ydGlvbmFsIGZvcm0qKjoNCg0KJCQNClAoayBcbWlkIFx0aGV0YSwgbikgXHByb3B0byBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQojIyMgUHJpb3IgRGlzdHJpYnV0aW9uDQoNCldlIGNob29zZSBhICoqQmV0YSBkaXN0cmlidXRpb24qKiBhcyBjb25qdWdhdGUgcHJpb3I6DQoNCiQkDQpQKFx0aGV0YSBcbWlkIFxhbHBoYSwgXGJldGEpID0gXGZyYWN7XHRoZXRhXntcYWxwaGEtMX0oMS1cdGhldGEpXntcYmV0YS0xfX17QihcYWxwaGEsIFxiZXRhKX0NCiQkDQoNCldoZXJlOg0KDQoqICRcYWxwaGEgPiAwJCwgJFxiZXRhID4gMCQgYXJlIGh5cGVycGFyYW1ldGVycw0KKiAkQihcYWxwaGEsIFxiZXRhKSA9IFxmcmFje1xHYW1tYShcYWxwaGEpXEdhbW1hKFxiZXRhKX17XEdhbW1hKFxhbHBoYStcYmV0YSl9JCBpcyB0aGUgQmV0YSBmdW5jdGlvbg0KDQoNClRoZSAqKnByb3BvcnRpb25hbCBmb3JtKiogKGRyb3BwaW5nIHRoZSBub3JtYWxpemluZyBjb25zdGFudCk6DQoNCiQkDQpQKFx0aGV0YSkgXHByb3B0byBcdGhldGFee1xhbHBoYS0xfSgxLVx0aGV0YSlee1xiZXRhLTF9DQokJA0KDQojIyMgQmF5ZXMnIFRoZW9yZW0gQXBwbGljYXRpb24NCg0KJCQNClAoXHRoZXRhIFxtaWQgaywgbikgPSBcZnJhY3tQKGsgXG1pZCBcdGhldGEsIG4pIFAoXHRoZXRhKX17UChrIFxtaWQgbil9DQokJA0KDQpXaGVyZSAkUChrIFxtaWQgbikgPSBcaW50XzBeMSBQKGsgXG1pZCBcdGhldGEsIG4pIFAoXHRoZXRhKSBkXHRoZXRhJCBpcyB0aGUgbWFyZ2luYWwgbGlrZWxpaG9vZC4gPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipUaGUgbnVtYmVyIG9mIEJlcm5vdWxsaSB0cmlhbHMgJG4kIGlzIGEgcHJlZGV0ZXJtaW5lZCBjb25zdGFudC4gSXQgaXMgbm90IGFuIHVua25vd24gcGFyYW1ldGVyIG9mIHRoZSBiaW5vbWlhbCBkaXN0cmlidXRpb24uKio8L2ZvbnQ+DQoNCiMjIyBQb3N0ZXJpb3IgRGVyaXZhdGlvbg0KDQpXZSBpZ25vcmUgYWxsIGNvbnN0YW50cyBhbmQgd29yayBvbmx5IHdpdGggdGhlIGtlcm5lbHMgb2YgcmVsYXRlZCBkaXN0cmlidXRpb25zIHRvIGRlcml2ZSB0aGUga2VybmVsIG9mIHBvc3RlcmlvciBkaXN0cmlidXRpb24gYW5kIGFkZCB0aGUgbm9ybWFsaXppbmcgaW4gdGhlIGVuZCB0byBtYWtlIHRoZSBjb21wbGV0ZSB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbi4NCg0KKipLZXJuZWwgb2YgUG9zdGVyaW9yIERpc3RyaWJ1dGlvbioqDQoNCldlIGZpcnN0IGZpbmQgdGhlIGtlcm5lbCBvZiB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiB0aGUgYWJvdmUgQmF5ZXMgcnVsZSBpbiB0aGUgZm9sbG93aW5nDQoNCiQkDQpQKFx0aGV0YSBcbWlkIGssIG4pIFxwcm9wdG8gUChrIFxtaWQgXHRoZXRhLCBuKSBcY2RvdCBQKFx0aGV0YSkNCiQkDQoNCiQkDQpccHJvcHRvIFxsZWZ0W1x0aGV0YV5rICgxLVx0aGV0YSlee24ta31ccmlnaHRdIFxjZG90IFxsZWZ0W1x0aGV0YV57XGFscGhhLTF9KDEtXHRoZXRhKV57XGJldGEtMX1ccmlnaHRdDQokJA0KDQokJA0KPSBcdGhldGFee2sgKyBcYWxwaGEgLSAxfSAoMS1cdGhldGEpXntuIC0gayArIFxiZXRhIC0gMX0NCiQkDQoNCiQkDQo9IFx0aGV0YV57XGFscGhhJyAtIDF9ICgxLVx0aGV0YSlee1xiZXRhJyAtIDF9DQokJA0KDQpXaGVyZToNCg0KJCQNClxhbHBoYScgPSBcYWxwaGEgKyBrLCBccXVhZCBcYmV0YScgPSBcYmV0YSArIChuIC0gaykNCiQkDQoNCioqQ29tcGxldGUgUG9zdGVyaW9yIERpc3RyaWJ1dGlvbioqDQoNCldlIG5leHQgZmluZCB0aGUgbm9ybWFsaXppbmcgY29lZmZpY2llbnQgdG8gbWFrZSB0aGUgYWJvdmUga2VybmVsIGluIGEgdmFsaWQgZGlzdHJpYnV0aW9uLg0KDQokJA0KUChcdGhldGEgXG1pZCBrLCBuKSA9IFxmcmFje1x0aGV0YV57XGFscGhhJy0xfSgxLVx0aGV0YSlee1xiZXRhJy0xfX17QihcYWxwaGEnLCBcYmV0YScpfQ0KJCQNCg0KJCQNClx0aGV0YSBcbWlkIGssIG4gXHNpbSBcdGV4dHtCZXRhfShcYWxwaGEnLCBcYmV0YScpDQokJA0KDQpXaGVyZToNCg0KJCQNClxhbHBoYScgPSBcYWxwaGEgKyBrLCBccXVhZCBcYmV0YScgPSBcYmV0YSArIG4gLSBrDQokJA0KDQoNClRoZSBoeXBlcnBhcmFtZXRlcnMgJFxhbHBoYSQgYW5kICRcYmV0YSQgYWN0IGFzICoqcHNldWRvLWNvdW50cyoqOg0KDQoqICRcYWxwaGEtMSQgPSBwcmlvciBudW1iZXIgb2Ygc3VjY2Vzc2VzDQoNCiogJFxiZXRhLTEkID0gcHJpb3IgbnVtYmVyIG9mIGZhaWx1cmVzDQoNCiogJFxhbHBoYSArIFxiZXRhIC0gMiQgPSB0b3RhbCBwcmlvciBvYnNlcnZhdGlvbnMNCg0KVGhlIHBvc3RlcmlvciBzaW1wbHkgYWRkcyB0aGUgKipvYnNlcnZlZCBjb3VudHMqKiB0byB0aGUgcHJpb3IgcHNldWRvLWNvdW50cy4NCg0KDQojIyMgUG9zdGVyaW9yIFN0YXRpc3RpY3MNCg0KS2V5IHN0YXRpc3RpY3MgdXNlZCBpbiBCYXllc2lhbiBpbmZlcmVuY2UNCg0KKipNZWFuKio6DQoNCiQkDQpcbWF0aGJie0V9W1x0aGV0YSBcbWlkIGssIG5dID0gXGZyYWN7XGFscGhhJ317XGFscGhhJyArIFxiZXRhJ30gPSBcYm94ZWR7XGZyYWN7XGFscGhhICsga317XGFscGhhICsgXGJldGEgKyBufSB9DQokJA0KDQpUaGUgYWJvdmUgZXhwcmVzc2lvbiBpbiB0aGUgYWJvdmUgYm94IGNhbiBiZSByZS13cml0dGVuIGluIHRoZSBmb2xsb3dpbmcgdG8gbWFrZSB0aGUgY29ubmVjdGlvbiBiZXR3ZWVuIHRoZSBNTEUgb2YgJFx0aGV0YSQsIGRlbm90ZWQgYnkgJFxoYXR7cH1fe01MRX0kLg0KDQoNCiQkDQo9IFxmcmFje1xmcmFje1xhbHBoYX17bn0rXGZyYWN7a317cH19e1xmcmFje1xhbHBoYX17bn0rXGZyYWN7XGJldGF9e259KzF9ID0gXGZyYWN7XGZyYWN7XGFscGhhfXtufStcaGF0e3B9X3tNTEV9fXtcZnJhY3tcYWxwaGF9e259K1xmcmFje1xiZXRhfXtufSsxfSAgXHhyaWdodGFycm93e1x0ZXh0e2FzIG4gZ2V0cyBiaWdnZXJ9fSBcaGF0e3B9X3tNTEV9DQokJA0KDQp3aGVyZSAkXGhhdHtwfV97TUxFfSA9IGsvbiQuIEFzICRuIFx0byBcaW5mdHkkLCAkXGFscGhhL24gXHRvIDAkIGFuZCAkXGJldGEvbiBcdG8gMCQuDQoNCg0KKipWYXJpYW5jZSoqOg0KDQokJA0KXHRleHR7VmFyfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFje1xhbHBoYSdcYmV0YSd9eyhcYWxwaGEnK1xiZXRhJyleMihcYWxwaGEnK1xiZXRhJysxKX0gPSBcYm94ZWR7XGZyYWN7KFxhbHBoYStrKShcYmV0YStuLWspfXsoXGFscGhhK1xiZXRhK24pXjIoXGFscGhhK1xiZXRhK24rMSl9fQ0KJCQNCg0KVGhlIHBvc3RlcmlvciB2YXJpYW5jZSBpbiB0aGUgYWJvdmUgYm94IGNhbiBhbHNvIGJlIHJlLXdyaXR0ZW4gaW4gdGhlIGZvbGxvd2luZyB0byBtYWtlIHRoZSBjb25uZWN0aW9uIHdpdGggdGhlIE1MRSBvZiB2YXJpYW5jZS4gV2UgZGl2aWRlIGJvdGggbnVtZXJhdG9yIGFuZCBkZW5vbWluYXRvciBieSAkbl4zJA0KDQoNCiQkDQpcZnJhY3soXGFscGhhK2spKFxiZXRhK24tayl9eyhcYWxwaGErXGJldGErbileMihcYWxwaGErXGJldGErbisxKX0gPSBcZnJhY3tcZnJhY3sxfXtufShcZnJhY3tcYWxwaGF9e259K1xmcmFje2t9e259KShcZnJhY3tcYmV0YX17bn0rMS1cZnJhY3trfXtufSl9eyhcZnJhY3tcYWxwaGF9e259K1xmcmFje1xiZXRhfXtufSsxKV4yKFxmcmFje1xhbHBoYX17bn0rXGZyYWN7XGJldGF9e259KzErXGZyYWN7MX17bn0pfSBcYXBwcm94IFxmcmFje1xoYXR7cH1fe01MRX0oMS1caGF0e3B9X3tNTEV9KX17bn0sIFwgXCBcdGV4dHsgYXMgbiBnZXRzIGJpZ2dlcn0uDQokJA0KDQoNCg0KIyMgTnVtZXJpY2FsIEV4YW1wbGUNCg0KQ29uc2lkZXIgYW4gZXhwZXJpbWVudHMgb2YgMjAgQmVybm91bGxpIHRyaWFscyAoJG4gPSAyMCQpIHdpdGggMTQgc3VjY2Vzc2VzICgkayA9IDE0JCkuIFdlIHdhbnQgdG8gZmluZCB0aGUgQmF5ZXMgZXN0aW1hdGUgb2YgdGhlIHN1Y2Nlc3MgcHJvYmFiaWxpdHkgJFxoYXR7cH1fe1x0ZXh0e0JheWVzfX0kIHdpdGggdGhlIHByaW9yIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdHJ1ZSBzdWNjZXNzIHByb2JhYmlsaXR5ICRcdGhldGEkLCBpLmUuLCAkXHRoZXRhIFxzaW0gXHRleHR7QmV0YX0oMywgMykkIHdoaWNoIGlzIHN5bW1ldHJpYywgY2VudGVyZWQgYXQgMC41Lg0KDQoNCiMjIyBCYXllc2lhbiBFc3RpbWF0aW9uDQoNClRoZSBvYmplY3RpdmUgaXMgdG8gY29uc3RydWN0IGEgOTVcJSBCYXllc2lhbiBjcmVkaWJsZSBpbnRlcnZhbCBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gaW4gdGhlIGV4cGVyaW1lbnQgKGkuZS4sIHNhbXBsZSBkYXRhKS4NCg0KKipTZXR1cCoqDQoNCiogKipQcmlvcioqOiAkXHRoZXRhIFxzaW0gXHRleHR7QmV0YX0oMywgMykkIChzeW1tZXRyaWMsIGNlbnRlcmVkIGF0IDAuNSkNCiogKipEYXRhKio6ICRuID0gMjAkIHRyaWFscywgJGsgPSAxNCQgc3VjY2Vzc2VzDQoqICoqTUxFKio6ICRcaGF0e1x0aGV0YX1fe1x0ZXh0e01MRX19ID0gMTQvMjAgPSAwLjckDQoNCg0KKipQb3N0ZXJpb3IgQ2FsY3VsYXRpb24qKg0KDQpCYXNlZCBvbiB0aGUgZGVyaXZhdGlvbiBvZiB0aGUgYWJvdmUgc3Vic2VjdGlvbiwgdGhlICoqUHJpb3IgcGFyYW1ldGVycyoqIGFyZSBnaXZlbiBieQ0KDQoqICoqUHJpb3IgUGFyYW1ldGVycyoqOiAkXGFscGhhID0gMyQsICRcYmV0YSA9IDMkDQoqICoqUHJpb3IgbWVhbioqOiAkMy8oMyszKSA9IDAuNSQNCiogKipQcmlvciBzdHJlbmd0aCoqOiAkXGFscGhhICsgXGJldGEgPSA2JCAoZXF1aXZhbGVudCB0byA0IHBzZXVkby1vYnNlcnZhdGlvbnMpDQoNCg0KKipQb3N0ZXJpb3IgcGFyYW1ldGVycyoqOg0KDQokJA0KXGFscGhhJyA9IDMgKyAxNCA9IDE3LCBccXVhZCBcYmV0YScgPSAzICsgKDIwIC0gMTQpID0gMyArIDYgPSA5DQokJA0KDQoNCioqUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbioqOg0KDQokJA0KXHRoZXRhIFxtaWQgaywgbiBcc2ltIFx0ZXh0e0JldGF9KDE3LCA5KQ0KJCQNCg0KKipQb3N0ZXJpb3Igc3RhdGlzdGljcyoqOg0KDQokJA0KXG1hdGhiYntFfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFjezE3fXsxNyArIDl9ID0gXGZyYWN7MTd9ezI2fSBcYXBwcm94IDAuNjU0DQokJA0KDQokJA0KXHRleHR7VmFyfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFjezE3IFx0aW1lcyA5fXsoMjYpXjIoMjcpfSA9IFxmcmFjezE1M317MTgyNTJ9IFxhcHByb3ggMC4wMDgzOA0KJCQNCg0KJCQNClx0ZXh0e1NEfVtcdGhldGEgXG1pZCBrLCBuXSBcYXBwcm94IFxzcXJ0ezAuMDA4Mzh9IFxhcHByb3ggMC4wOTE2DQokJA0KDQoqKjk1XCUgQ3JlZGlibGUgSW50ZXJ2YWwqKg0KDQpUaGUgJDEwMCgxLVxhbHBoYSlcJSQgY3JlZGlibGUgaW50ZXJ2YWwgJFtMLCBVXSQgc2F0aXNmaWVzOg0KDQokJA0KUChMIFxsZXEgXHRoZXRhIFxsZXEgVSBcbWlkIGssIG4pID0gMC45NQ0KJCQNCg0KRm9yIEJldGEoMTcsOSksIHdlIHVzZSBSIHRvIGZpbmQgMi41dGggYW5kIDk3LjV0aCBwZXJjZW50aWxlcyB0byB0aGUgb2J0YWluIHRoZSBsb3dlciBhbmQgdXBwZXIgY3JlZGlibGUgbGltaXRzIGluIHRoZSBmb2xsb3dpbmcNCg0KKiAkTCA9IFx0ZXh0e0JldGF9XnstMX0oMC4wMjU7IDE3LCA5KSBcYXBwcm94IDAuNDc4JA0KDQoqICRVID0gXHRleHR7QmV0YX1eey0xfSgwLjk3NTsgMTcsIDkpIFxhcHByb3ggMC44MTMkDQoNClRoZXJlZm9yZSwgJFx0aGV0YSBcaW4gWzAuNDc4LCAwLjgxM10kIHdpdGggOTVcJSBwb3N0ZXJpb3IgcHJvYmFiaWxpdHkuDQoNCg0KIyMjIEJheWVzaWFuIFByZWRpY3Rpb24gPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KE9wdGlvbmFsKTwvZm9udD4NCg0KQmFzZWQgb24gdGhlIEJheWVzaWFuIGVzdGltYXRlcyBvZiB0aGUgcGFyYW1ldGVyIG9idGFpbmVkIHByZXZpb3VzbHksIHdlIHdhbnQgdG8gcHJlZGljdCB0aGUgb3V0Y29tZSBvZiB0aGUgbmV4dCAkbSQgdHJpYWxzLiBUaGUgZ2VuZXJhbCBmb3JtdWxhIGZvciB0aGUgcHJvYmFiaWxpdHkgb2Ygc3VjY2VzcyBpbiBuZXh0ICRtJCB0cmlhbHMgd2l0aCAkeSQgc3VjY2Vzc2VzOg0KDQokJA0KUCh5IFxtaWQgaywgbiwgbSkgPSBcaW50XzBeMSBQKHkgXG1pZCBcdGhldGEsIG0pIFAoXHRoZXRhIFxtaWQgaywgbikgZFx0aGV0YQ0KJCQNCg0KJCQNCj0gXGludF8wXjEgXGJpbm9te219e3l9IFx0aGV0YV55ICgxLVx0aGV0YSlee20teX0gXGNkb3QgXGZyYWN7XHRoZXRhXntcYWxwaGEnLTF9KDEtXHRoZXRhKV57XGJldGEnLTF9fXtCKFxhbHBoYScsIFxiZXRhJyl9IGRcdGhldGENCiQkDQoNCiQkDQo9IFxiaW5vbXttfXt5fSBcZnJhY3tCKFxhbHBoYScgKyB5LCBcYmV0YScgKyBtIC0geSl9e0IoXGFscGhhJywgXGJldGEnKX0NCiQkDQoNClRoaXMgaXMgYWdhaW4gYSAqKkJldGEtYmlub21pYWwgZGlzdHJpYnV0aW9uKiouIE5leHQsIHdlIGxvb2sgYXQgcHJlZGljdGlvbiB3aXRoIHNwZWNpYWwgJG0kLiBJbiB0aGUgZm9sbG93aW5nIHNwZWNpYWwgY2FzZXMsICRuID0gMjAkIGFuZCAkayA9IDE0JDoNCg0KKiBGb3IgMSBuZXh0IHRyaWFsICgkbT0xJCwgaS5lLiwgQmVybm91bGxpIHRyaWFsKSB3aXRoIHRoZSBvdXRjb21lIG9mIGEgc3VjY2VzczoNCg0KJCQNClAoXHRleHR7c3VjY2Vzc30gXG1pZCBrLCBuKSA9IFxtYXRoYmJ7RX1bXHRoZXRhIFxtaWQgaywgbl0gPSBcZnJhY3tcYWxwaGEnfXtcYWxwaGEnICsgXGJldGEnfSBcYXBwcm94IDAuNjU0DQokJA0KDQoqIEZvciA1IG5leHQgdHJpYWxzICgkbT01JCkgd2l0aCAkeSA9IDMkIHN1Y2Nlc3NlczoNCg0KJCQNClAoeT0zIFxtaWQgaywgbiwgbT01KSA9IFxiaW5vbXs1fXszfSBcZnJhY3tCKDE3KzMsIDkrMil9e0IoMTcsIDkpfSA9IDEwIFxjZG90IFxmcmFje0IoMjAsIDExKX17QigxNywgOSl9IFxhcHByb3ggMC4zNDQNCiQkDQoNCg0KIyMgQ29tbW9uIENvbmp1Z2F0ZSBGYW1pbGllcw0KDQpUaGUgcHJpbWFyeSBwdXJwb3NlIG9mIHVzaW5nIGEgY29uanVnYXRlIHByaW9yIGluIEJheWVzaWFuIGluZmVyZW5jZSBpcyB0byBlbnN1cmUgbWF0aGVtYXRpY2FsIHRyYWN0YWJpbGl0eSBieSBndWFyYW50ZWVpbmcgdGhhdCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBiZWxvbmdzIHRvIHRoZSBzYW1lIHByb2JhYmlsaXR5IGZhbWlseSBhcyB0aGUgcHJpb3IsIHdoaWNoIGFsbG93cyBmb3IgY2xvc2VkLWZvcm0gYW5hbHl0aWNhbCB1cGRhdGVzIHJhdGhlciB0aGFuIGNvbXB1dGF0aW9uYWxseSBpbnRlbnNpdmUgbnVtZXJpY2FsIGFwcHJveGltYXRpb25zLiBUaGlzIGNvbmp1Z2FjeSBlbmFibGVzIHN0cmFpZ2h0Zm9yd2FyZCBzZXF1ZW50aWFsIGxlYXJuaW5nLCB3aGVyZSBwb3N0ZXJpb3IgcGFyYW1ldGVycyBhcmUgc2ltcGx5IHVwZGF0ZWQgdGhyb3VnaCBhZGRpdGlvbiBvZiBvYnNlcnZlZCBkYXRhIHN0YXRpc3RpY3MgdG8gcHJpb3IgaHlwZXJwYXJhbWV0ZXJzLCBtYWtpbmcgaXQgaWRlYWwgZm9yIHJlYWwtdGltZSBvciBzdHJlYW1pbmcgZGF0YSBhcHBsaWNhdGlvbnMuIFdoaWxlIG1vZGVybiBjb21wdXRhdGlvbmFsIG1ldGhvZHMgaGF2ZSByZWR1Y2VkIHRoZSBuZWNlc3NpdHkgb2Ygc3RyaWN0IGNvbmp1Z2FjeSwgaXQgcmVtYWlucyBhIHBvd2VyZnVsIHRvb2wgZm9yIHBlZGFnb2dpY2FsIGNsYXJpdHksIHJhcGlkIHByb3RvdHlwaW5nLCBhbmQgYXBwbGljYXRpb25zIHdoZXJlIGNvbXB1dGF0aW9uYWwgZWZmaWNpZW5jeSBhbmQgdHJhbnNwYXJlbmN5IGFyZSBwcmlvcml0aXplZCBvdmVyIGZ1bGwgcHJpb3IgZmxleGliaWxpdHkuDQoNClRoZSBmb2xsb3dpbmcgaXMgYSBsaXN0IG9mIHNvbWUgY29tbW9ubHkgdXNlZCBjb25qdWdhdGUgcHJpb3JzIGFzc29jaWF0ZWQgd2l0aCBhIGZldyBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbnMuDQoNCiogQmVybm91bGxpL0Jpbm9taWFsICRcbGVmdHJpZ2h0YXJyb3ckIEJldGENCg0KKiBQb2lzc29uICRcbGVmdHJpZ2h0YXJyb3ckIEdhbW1hDQoNCiogTm9ybWFsICh3aXRoIGtub3duIHZhcmlhbmNlKSAkXGxlZnRyaWdodGFycm93JCBOb3JtYWwgKGZvciBtZWFuKQ0KDQoqIE5vcm1hbCAod2l0aCBrbm93biBtZWFuKSAkXGxlZnRyaWdodGFycm93JCBJbnZlcnNlLUdhbW1hIChmb3IgdmFyaWFuY2UpDQoNCiogTXVsdGlub21pYWwgJFxsZWZ0cmlnaHRhcnJvdyQgRGlyaWNobGV0DQoNCg0KDQojIyAgUHJhY3RpY2FsIEFwcGxpY2F0aW9ucw0KDQoqICoqQS9CIHRlc3RpbmcqKjogVXBkYXRlIHN1Y2Nlc3MgcmF0ZSBwb3N0ZXJpb3JzIGZvciB0d28gd2VicGFnZSB2YXJpYW50cy4NCg0KKiAqKlF1YWxpdHkgY29udHJvbCoqOiBFc3RpbWF0ZSBkZWZlY3QgcmF0ZXMgd2l0aCBoaXN0b3JpY2FsIHByaW9yLg0KDQoqICoqUGhhcm1hY29raW5ldGljcyoqOiBVcGRhdGUgZHJ1ZyBlZmZlY3Qgc2l6ZSBkaXN0cmlidXRpb24gZnJvbSB0cmlhbHMuDQoNCg0KDQojIE5hw692ZSBCYXllcyBDbGFzc2lmaWVyDQoNCg0KUmVjYWxsIHRoZSAqKkJheWVzIFJ1bGUqKiB3aXRoIG11bHRpcGxlIGZlYXR1cmUgdmFyaWFibGVzICRcbWF0aGJme1h9ID0gKFhfMSwgWF8yLCBcY2RvdHMsIFhfaykkIGFuZCBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlICRcbWF0aGJme0N9PShDXzEsIENfMi4gXGNkb3RzLCBDX2QpJCB3aXRoICRkJCBjYXRlZ29yaWVzLiANCg0KDQpUaGUgY29yZSBtZWNoYW5pc20gaXMgKipCYXllcycgVGhlb3JlbSoqOg0KDQoNCiQkDQpQKENfaiBcbWlkIFxtYXRoYmZ7WH0pID0gXGZyYWN7UChcbWF0aGJme1h9IFxtaWQgQ19qKSBcLCBQKENfail9e1AoXG1hdGhiZntYfSl9IFxwcm9wdG8gUChcbWF0aGJme1h9IFxtaWQgQ19qKSBcLCBQKENfaikgPSBQXGxlZnRbKFhfMSwgWF8yLCBcY2RvdHMsIFhfaykgXG1pZCBDX2pccmlnaHRdIFwsIFAoQ19qKQ0KJCQNCg0KQSBwcm9iYWJpbGlzdGljIGNsYXNzaWZpZXIgYmFzZWQgb24gQmF5ZXMgdGhlb3JlbSB3aXRoIGEgc3Ryb25nICgqKm5haXZlKiopIGFzc3VtcHRpb246ICoqZmVhdHVyZXMgYXJlIGNvbmRpdGlvbmFsbHkgaW5kZXBlbmRlbnQgZ2l2ZW4gdGhlIGNsYXNzIGxhYmVsKiouDQoNCiQkDQpQXGxlZnRbKFhfMSwgWF8yLCBcY2RvdHMsIFhfZCkgXG1pZCBDX2pccmlnaHRdID0gXHByb2Rfe2k9MX1eayBQKFhfaVxtaWQgQ19qKSwgXCBcIFx0ZXh0eyB3aGVyZSB9IFwgXCAxIFxsZSBqIFxsZSBkLg0KJCQNCg0KVGhhdCBpcywgdW5kZXIgdGhlIGZyYW1ld29yayBvZiAqKk5haXZlIEJheWVzKiosIHRoZSBjYXRlZ29yeSBwcm9iYWJpbGl0eSAob3IgcHJvcG9ydGlvbmFsIHRvIHRoZSBwcm9iYWJpbGl0eSkgaXMgY2FsY3VsYXRlZCBieQ0KDQoNCiQkDQpQKENfaiBcbWlkIFxtYXRoYmZ7WH0pIFxwcm9wdG8gUChDX2opIFxwcm9kX3tpPTF9XntkfSBQKHhfaiBcbWlkIENfaikNCiQkDQoNCiogKiokUChDX2spJCoqOiBQcmlvciBwcm9iYWJpbGl0eSBvZiBjbGFzcyAkayQuDQoNCiogKiokUCh4X2ogXG1pZCBDX2spJCoqOiBMaWtlbGlob29kIG9mIGZlYXR1cmUgJGokIGdpdmVuIGNsYXNzICRrJC4NCg0KKiAqKkRlY2lzaW9uIHJ1bGUgZm9yIGNsYXNzaWZpY2F0aW9uKio6IENob29zZSBjbGFzcyB3aXRoIGhpZ2hlc3QgcG9zdGVyaW9yICRQKENfayBcbWlkIFxtYXRoYmZ7eH0pJC4NCg0KDQojIyBHYXVzc2lhbiBOYcOvdmUgQmF5ZXMNCg0KV2hlbiBmZWF0dXJlcyBhcmUgY29udGludW91cywgYXNzdW1lICRQKHhfaiBcbWlkIENfaykkIGlzIEdhdXNzaWFuOg0KDQokJA0KUCh4X2ogXG1pZCBDX2spID0gXGZyYWN7MX17XHNxcnR7MlxwaVxzaWdtYV97amt9XjJ9fSBcZXhwXGxlZnQoLVxmcmFjeyh4X2ogLSBcbXVfe2prfSleMn17MlxzaWdtYV97amt9XjJ9XHJpZ2h0KQ0KJCQNCg0KUGFyYW1ldGVycyAkXG11X3tqa30sIFxzaWdtYV97amt9XjIkIGVzdGltYXRlZCB2aWEgTUxFIGZyb20gdHJhaW5pbmcgZGF0YSBmb3IgZWFjaCBjbGFzcyAkayQgYW5kIGZlYXR1cmUgJGokLg0KDQoNCioqQW4gTnVtZXJpY2FsIEV4YW1wbGUgLSBDbGFzc2lmeSBGcnVpdHMgQmFzZWQgb24gV2VpZ2h0IGFuZCBTd2VldG5lc3MqKjogV2Ugd2FudCB0byBwcmVkaWN0IHdoZXRoZXIgYSBmcnVpdCBpcyBhbiAqKkFwcGxlKiogb3IgKipPcmFuZ2UqKiBiYXNlZCBvbjoNCg0KKiAqKldlaWdodCoqIChpbiBncmFtcykNCiogKipTd2VldG5lc3MqKiAoc2NhbGUgMS0xMCwgd2hlcmUgMTAgaXMgdmVyeSBzd2VldCkNCg0KVGhlIHRyYWluaW5nIERhdGEgaXMgZ2l2ZW4gYnkNCg0KfCBGcnVpdCB8IFdlaWdodCAoZykgfCBTd2VldG5lc3MgfCBDbGFzcyB8DQp8Oi0tLS0tfDotLS0tLS18Oi0tLS0tLS0tLS0tfDotLS0tLS0tLS0tfA0KfCAgMSB8ICAgMTUwIHwgICA2IHwgICBBcHBsZSB8ICANCnwgIDIgfCAgIDEzMCB8ICAgOCB8ICAgT3JhbmdlIHwgIA0KfCAgMyB8ICAgMTYwIHwgICA1IHwgICBBcHBsZSB8ICANCnwgIDQgfCAgIDE0MCB8ICAgNyB8ICAgT3JhbmdlfCAgDQp8ICA1IHwgICAxNzAgfCAgIDQgfCAgIEFwcGxlIHwgIA0KDQpUaGUgZm9sbG93aW5nIGFyZSB0aGUgc3RlcHMgZm9yIG1ha2luZyBwcmVkaWN0aW9uLg0KDQoqKlN0ZXAgMTogQ2FsY3VsYXRlIENsYXNzIFByb2JhYmlsaXRpZXMqKg0KDQoqIFRvdGFsIGZydWl0czogNQ0KKiBBcHBsZXM6IDMgJFxyaWdodGFycm93IFAoXHRleHR7QXBwbGV9KSA9IFxmcmFjezN9ezV9ID0gMC42JA0KKiBPcmFuZ2VzOiAyICRccmlnaHRhcnJvdyBQKFx0ZXh0e09yYW5nZX0pID0gXGZyYWN7Mn17NX0gPSAwLjQkDQoNCg0KKipTdGVwIDI6IENhbGN1bGF0ZSBHYXVzc2lhbiBQYXJhbWV0ZXJzIGZvciBFYWNoIEZlYXR1cmUgcGVyIENsYXNzKioNCg0KKiAqKkZvciBBcHBsZXMgKyBXZWlnaHQqKg0KIA0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHt3ZWlnaHQsQXBwbGV9fSAmPSBcZnJhY3sxNTAgKyAxNjAgKyAxNzB9ezN9ID0gMTYwIFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3dlaWdodCxBcHBsZX19ICY9IFxmcmFjeygxNTAtMTYwKV4yICsgKDE2MC0xNjApXjIgKyAoMTcwLTE2MCleMn17M30gXFwNCiAgICAmPSBcZnJhY3sxMDAgKyAwICsgMTAwfXszfSA9IDY2LjY3IFxcDQogICAgXHNpZ21hX3tcdGV4dHt3ZWlnaHQsQXBwbGV9fSAmPSBcc3FydHs2Ni42N30gXGFwcHJveCA4LjE2DQpcZW5ke2FsaWdufQ0KDQoNCiogKipGb3IgQXBwbGVzICsgU3dlZXQqKiANCg0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHtzd2VldCxBcHBsZX19ICY9IFxmcmFjezYgKyA1ICsgNH17M30gPSA1IFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3N3ZWV0LEFwcGxlfX0gJj0gXGZyYWN7KDYtNSleMiArICg1LTUpXjIgKyAoNC01KV4yfXszfSBcXA0KICAgICY9IFxmcmFjezEgKyAwICsgMX17M30gPSAwLjY3IFxcDQogICAgXHNpZ21hX3tcdGV4dHtzd2VldCxBcHBsZX19ICY9IFxzcXJ0ezAuNjd9IFxhcHByb3ggMC44Mg0KXGVuZHthbGlnbn0NCg0KDQoNCiogKipGb3IgT3JhbmdlcyArIFdlaWdodDoqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBcbXVfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcZnJhY3sxMzAgKyAxNDB9ezJ9ID0gMTM1IFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcZnJhY3soMTMwLTEzNSleMiArICgxNDAtMTM1KV4yfXsyfSBcXA0KICAgICY9IFxmcmFjezI1ICsgMjV9ezJ9ID0gMjUgXFwNCiAgICBcc2lnbWFfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcc3FydHsyNX0gPSA1DQogICAgXGVuZHthbGlnbn0NCg0KDQoqICoqRm9yIE9yYW5nZXMgKyBTd2VldG5lc3M6KioNCg0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHtzd2VldCxPcmFuZ2V9fSAmPSBcZnJhY3s4ICsgN317Mn0gPSA3LjUgXFwNCiAgICBcc2lnbWFeMl97XHRleHR7c3dlZXQsT3JhbmdlfX0gJj0gXGZyYWN7KDgtNy41KV4yICsgKDctNy41KV4yfXsyfSBcXA0KICAgICY9IFxmcmFjezAuMjUgKyAwLjI1fXsyfSA9IDAuMjUgXFwNCiAgICBcc2lnbWFfe1x0ZXh0e3N3ZWV0LE9yYW5nZX19ICY9IFxzcXJ0ezAuMjV9ID0gMC41DQpcZW5ke2FsaWdufQ0KDQoNCioqU3RlcCAzOiBNYWtlIGEgUHJlZGljdGlvbiBmb3IgYSBOZXcgRnJ1aXQqKjogR2l2ZW4gYSAqKk5ldyBmcnVpdCoqIHdpdGggV2VpZ2h0ID0gMTQ1ZyBhbmQgU3dlZXRuZXNzID0gNi41LiBUaGUgb2JqZWN0aXZlIGlzIHRvIHVzZSAqKk5haXZlIEJheWVzKiogdG8gcHJlZGljdCB3aGV0aGVyIHRoaXMgZnJ1aXQgaXMgKipBcHBsZSoqIG9yICoqT3JhbmdlKiouIFRvIHByb2NlZWQsIHdlIGNhbGN1bGF0ZSBjYXRlZ29yeSBwcm9iYWJpbGl0aWVzIGJhc2VkIG9uIHRoZSBnaXZlbiBpbmZvcm1hdGlvbiBvZiB0aGUgbmV3IGZydWl0IGluIHRoZSBmb2xsb3dpbmc6DQoNCiogKipDYWxjdWxhdGUgTGlrZWxpaG9vZHMgdXNpbmcgR2F1c3NpYW4gUERGKioNCg0KJCQNClAoeCBcbWlkIFx0ZXh0e2NsYXNzfSkgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fSBcZXhwXGxlZnQoLVxmcmFjeyh4IC0gXG11KV4yfXsyXHNpZ21hXjJ9XHJpZ2h0KQ0KJCQNCg0KKiAqKkZvciBBcHBsZToqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBQKFx0ZXh0e1dlaWdodH09MTQ1IFxtaWQgXHRleHR7QXBwbGV9KSAmPSBcbWF0aGNhbHtOfSgxNDU7IFxtdT0xNjAsIFxzaWdtYV4yPTY2LjY3KSBcYXBwcm94IDAuMDM1IFxcDQogICAgUChcdGV4dHtTd2VldG5lc3N9PTYuNSBcbWlkIFx0ZXh0e0FwcGxlfSkgJj0gXG1hdGhjYWx7Tn0oNi41OyBcbXU9NSwgXHNpZ21hXjI9MC42NykgXGFwcHJveCAwLjEzOSBcXA0KICAgIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e0FwcGxlfSkgJj0gMC4wMzUgXHRpbWVzIDAuMTM5ID0gMC4wMDQ4NjUNClxlbmR7YWxpZ259DQoNCg0KKiAqKkZvciBPcmFuZ2U6KioNCg0KDQpcYmVnaW57YWxpZ259DQogICAgUChcdGV4dHtXZWlnaHR9PTE0NSBcbWlkIFx0ZXh0e09yYW5nZX0pICY9IFxtYXRoY2Fse059KDE0NTsgXG11PTEzNSwgXHNpZ21hXjI9MjUpIFxhcHByb3ggMC4wMTA4IFxcDQogICAgUChcdGV4dHtTd2VldG5lc3N9PTYuNSBcbWlkIFx0ZXh0e09yYW5nZX0pICY9IFxtYXRoY2Fse059KDYuNTsgXG11PTcuNSwgXHNpZ21hXjI9MC4yNSkgXGFwcHJveCAwLjQ4NCBcXA0KICAgIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e09yYW5nZX0pICY9IDAuMDEwOCBcdGltZXMgMC40ODQgPSAwLjAwNTIyNw0KXGVuZHthbGlnbn0NCg0KDQoqKlN0ZXAgNDogQXBwbHkgQmF5ZXMnIFRoZW9yZW0qKg0KDQoqICoqUG9zdGVyaW9yIFByb2JhYmlsaXRpZXMgKElnbm9yaW5nIERlbm9taW5hdG9yKToqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBQKFx0ZXh0e0FwcGxlfSBcbWlkIFx0ZXh0e2RhdGF9KSAmXHByb3B0byBQKFx0ZXh0e0FwcGxlfSkgXHRpbWVzIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e0FwcGxlfSkgXFwNCiAgICAmPSAwLjYgXHRpbWVzIDAuMDA0ODY1ID0gXG1hdGhiZnswLjAwMjkxOX0gXFxbNnB0XQ0KICAgIFAoXHRleHR7T3JhbmdlfSBcbWlkIFx0ZXh0e2RhdGF9KSAmXHByb3B0byBQKFx0ZXh0e09yYW5nZX0pIFx0aW1lcyBcdGV4dHtMaWtlbGlob29kfShcdGV4dHtPcmFuZ2V9KSBcXA0KICAgICY9IDAuNCBcdGltZXMgMC4wMDUyMjcgPSBcbWF0aGJmezAuMDAyMDkxfQ0KXGVuZHthbGlnbn0NCg0KDQoqICoqTm9ybWFsaXplOioqDQoNCg0KXGJlZ2lue2FsaWdufQ0KICAgIFx0ZXh0e1RvdGFsfSAmPSAwLjAwMjkxOSArIDAuMDAyMDkxID0gMC4wMDUwMSBcXFs2cHRdDQogICAgUChcdGV4dHtBcHBsZX0gXG1pZCBcdGV4dHtkYXRhfSkgJj0gXGZyYWN7MC4wMDI5MTl9ezAuMDA1MDF9IFxhcHByb3ggXG1hdGhiZns1OC4zXCV9IFxcWzZwdF0NCiAgICBQKFx0ZXh0e09yYW5nZX0gXG1pZCBcdGV4dHtkYXRhfSkgJj0gXGZyYWN7MC4wMDIwOTF9ezAuMDA1MDF9IFxhcHByb3ggXG1hdGhiZns0MS43XCV9DQpcZW5ke2FsaWdufQ0KDQoNCioqUHJlZGljdGlvbioqOiA8Zm9udCBjb2xvciA9ICJyZWQiPioqQXBwbGUqKjwvZm9udD4gKGhpZ2hlciBwcm9iYWJpbGl0eSkNCg0KXA0KDQojIyBTZW1pcGFyYW1ldHJpYyBOYWl2ZSBCYXllcw0KDQpXaGVuIGZlYXR1cmUgdmFyaWFibGVzIGluY2x1ZGUgYm90aCBjYXRlZ29yaWNhbCBhbmQgbnVtZXJpY2FsIGZlYXR1cmVzLCAgKipuYWl2ZSBCYXllcyoqIGlzIGEgbmF0dXJhbCBzZW1pcGFyYW1ldHJpYyBtb2RlbC4gVGhlIGZvbGxvd2luZyBpcyBhIG51bWVyaWNhbCBleGFtcGxlLg0KDQoqKkV4YW1wbGUgLSBFbWFpbCBTcGFtIERldGVjdGlvbiB3aXRoIE5haXZlIEJheWVzKio6IENsYXNzaWZ5IGVtYWlscyBhcyBcdGV4dGJme1NwYW0gKDEpfSBvciBcdGV4dGJme05vdCBTcGFtICgwKX0gdXNpbmc6DQoNCiogKipTZW5kZXIgRG9tYWluKiogKGNhdGVnb3JpY2FsKTogJFx7XHRleHR7Z21haWx9LCBcdGV4dHt3b3JrfSwgXHRleHR7dW5rbm93bn1cfSQNCg0KKiAqKkVtYWlsIExlbmd0aCoqIChjb250aW51b3VzKTogTnVtYmVyIG9mIGNoYXJhY3RlcnMgaW4gZW1haWwgYm9keQ0KDQpOZXh0IGZldyBzdGVwcyBpbGx1c3RyYXRlIHRoZSBwcm9jZXNzIG9mIHRyYWluaW5nIHRoZSAqKk5haXZlIEJheWVzKiogbW9kZWwgYW5kIHVzZSB0aGUgdHJhaW5lZCAqKm5haXZlIEJheWVzKiogdG8gbWFrZSBwcmVkaWN0aW9uLg0KDQoqKlN0ZXAgMS4gVHJhaW5pbmcgRGF0YXNldCoqDQoNCg0KfCBFbWFpbCB8IFNlbmRlciBEb21haW4gKCRYXzEkKSB8IEVtYWlsIExlbmd0aCAoJFhfMiQpIHwgQ2xhc3MgKCRZJCkgfA0KfDotLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tfA0KfCAxIHwgIGdtYWlsIHwgIDI1MCB8ICAwIChOb3QgU3BhbSkgfCANCnwgMiB8ICB3b3JrIHwgIDEyMCB8ICAwIHwgDQp8IDMgfCAgdW5rbm93biB8ICA1MDAgfCAgMSAoU3BhbSkgfCANCnwgNCB8ICBnbWFpbCB8ICAzMDAgfCAgMCB8IA0KfCA1IHwgIHVua25vd24gfCAgNDUwIHwgIDEgfCANCnwgNiB8ICB3b3JrIHwgIDE4MCB8ICAwIHwgDQp8IDcgfCAgdW5rbm93biB8ICA0MDAgfCAgMSB8IA0KfCA4IHwgIGdtYWlsIHwgIDI4MCB8ICAwIHwgDQoNCg0KDQoqKlN0ZXAgMi4gUHJpb3JzIENhbGN1bGF0aW9uKioNCg0KJCQNClAoWT0wKSA9IFxmcmFjezV9ezh9ID0gMC42MjUNCiQkDQoNCiQkDQpQKFk9MSkgPSBcZnJhY3szfXs4fSA9IDAuMzc1DQokJA0KDQoqKlN0ZXAgMy4gQ2F0ZWdvcmljYWwgRmVhdHVyZSBMaWtlbGlob29kcyAoU2VuZGVyIERvbWFpbikqKg0KDQoqICoqRm9yICRZPTAkIChOb3QgU3BhbSk6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfSB8IFk9MCkgJj0gMi81ID0gMC40IFxcDQpQKFhfMT1cdGV4dHt3b3JrfSB8IFk9MCkgJj0gMi81ID0gMC40IFxcDQpQKFhfMT1cdGV4dHt1bmtub3dufSB8IFk9MCkgJj0gMS81ID0gMC4yDQpcZW5ke2FsaWduKn0NCg0KKiAqKkZvciAkWT0xJCAoU3BhbSk6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfSB8IFk9MSkgJj0gMC8zID0gMCBcXA0KUChYXzE9XHRleHR7d29ya30gfCBZPTEpICY9IDAvMyA9IDAgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259IHwgWT0xKSAmPSAzLzMgPSAxDQpcZW5ke2FsaWduKn0NCg0KKiAqKldpdGggTGFwbGFjZSBTbW9vdGhpbmcgKCRcYWxwaGE9MSQpOioqIFRvIGF2b2lkIHplcm8gcHJvYmFiaWxpdHkgb2YgZW1wdHkgc3ViY2F0ZWdvcmllcywgd2UgYWRkIGEgc21hbGwgY29uc3RhbnQuDQoNCiQkDQpQKFhfMT1rfFk9YykgPSBcZnJhY3tcdGV4dHtjb3VudH0oayxjKSArIFxhbHBoYX17XHRleHR7Y291bnR9KGMpICsgXGFscGhhIFx0aW1lcyBcdGV4dHtudW1cX2NhdGVnb3JpZXN9fQ0KJCQNCg0KMyBjYXRlZ29yaWVzOiAkXHtcdGV4dHtnbWFpbH0sIFx0ZXh0e3dvcmt9LCBcdGV4dHt1bmtub3dufVx9JA0KDQoNCiogKipGb3IgJFk9MCQ6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfXxZPTApICY9ICgyKzEpLyg1KzMpID0gMy84ID0gMC4zNzUgXFwNClAoWF8xPVx0ZXh0e3dvcmt9fFk9MCkgJj0gKDIrMSkvKDUrMykgPSAzLzggPSAwLjM3NSBcXA0KUChYXzE9XHRleHR7dW5rbm93bn18WT0wKSAmPSAoMSsxKS8oNSszKSA9IDIvOCA9IDAuMjUNClxlbmR7YWxpZ24qfQ0KDQoqICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMT1cdGV4dHtnbWFpbH18WT0xKSAmPSAoMCsxKS8oMyszKSA9IDEvNiBcYXBwcm94IDAuMTY3IFxcDQpQKFhfMT1cdGV4dHt3b3JrfXxZPTEpICY9ICgwKzEpLygzKzMpID0gMS82IFxhcHByb3ggMC4xNjcgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259fFk9MSkgJj0gKDMrMSkvKDMrMykgPSA0LzYgXGFwcHJveCAwLjY2Nw0KXGVuZHthbGlnbip9DQoNCioqU3RlcCA0LiBDb250aW51b3VzIEZlYXR1cmUgKEdhdXNzaWFuKSAtIEVtYWlsIExlbmd0aCoqDQoNCiogKipGb3IgJFk9MCQ6KioNCg0KXGJlZ2lue2FsaWduKn0NClxtdV8wICY9IFxmcmFjezI1MCsxMjArMzAwKzE4MCsyODB9ezV9ID0gXGZyYWN7MTEzMH17NX0gPSAyMjYgXFwNClxzaWdtYV8wXjIgJj0gXGZyYWN7KDI1MC0yMjYpXjIrKDEyMC0yMjYpXjIrKDMwMC0yMjYpXjIrKDE4MC0yMjYpXjIrKDI4MC0yMjYpXjJ9ezR9IFxcDQomPSBcZnJhY3syNDQyMH17NH0gPSA2MTA1IFxcDQpcc2lnbWFfMCAmPSBcc3FydHs2MTA1fSBcYXBwcm94IDc4LjEzDQpcZW5ke2FsaWduKn0NCg0KDQoqICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpcbXVfMSAmPSBcZnJhY3s1MDArNDUwKzQwMH17M30gPSBcZnJhY3sxMzUwfXszfSA9IDQ1MCBcXA0KXHNpZ21hXzFeMiAmPSBcZnJhY3soNTAwLTQ1MCleMisoNDUwLTQ1MCleMisoNDAwLTQ1MCleMn17Mn0gPSBcZnJhY3s1MDAwfXsyfSA9IDI1MDAgXFwNClxzaWdtYV8xICY9IFxzcXJ0ezI1MDB9ID0gNTANClxlbmR7YWxpZ24qfQ0KDQoqKlN0ZXAgNS4gR2F1c3NpYW4gUHJvYmFiaWxpdHkgRGVuc2l0eSBGdW5jdGlvbioqDQoNCiQkDQpQKFhfMj14fFk9YykgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hX2NeMn19IFxleHBcbGVmdCgtXGZyYWN7KHgtXG11X2MpXjJ9ezJcc2lnbWFfY14yfVxyaWdodCkNCiQkDQoNCioqU3RlcCA2LiBDbGFzc2lmaWNhdGlvbiBFeGFtcGxlKioNCg0KTm93LCB3ZSBoYXZlIGFuIGluY29taW5nICoqTmV3IGVtYWlsKiogd2l0aCBmZWF0dXJlczogU2VuZGVyID0gInVua25vd24iLCBMZW5ndGggPSA0ODAgY2hhcmFjdGVycy4gV2Ugd2FudCB0byB1c2UgKipuYWl2ZSBCYXllcyoqIHRvIGNsYXNzaWZ5IGl0IGludG8gZWl0aGVyICoqU3BhbSoqIG9yICoqTm90IFNwYW0qKi4NCg0KVGhlIGNhbGN1bGF0aW9uIGlzIGRpdmlkZWQgaW4gdGhlIGZvbGxvd2luZyBzdGVwcyBhcyBkZXNjcmliZWQgZWFybGllcjoNCg0KKiAqKlN0ZXAgMTogTGlrZWxpaG9vZCBmb3IgY2F0ZWdvcmljYWwgZmVhdHVyZSoqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMT1cdGV4dHt1bmtub3dufXxZPTApICY9IDAuMjUgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259fFk9MSkgJj0gMC42NjcNClxlbmR7YWxpZ24qfQ0KDQoqICoqU3RlcCAyOiBMaWtlbGlob29kIGZvciBjb250aW51b3VzIGZlYXR1cmUgKHVzaW5nIEdhdXNzaWFuIFBERikqKg0KICArICoqRm9yICRZPTAkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMj00ODB8WT0wKSAmPSBcZnJhY3sxfXtcc3FydHsyXHBpIFx0aW1lcyA2MTA1fX0gXGV4cFxsZWZ0KC1cZnJhY3soNDgwLTIyNileMn17MiBcdGltZXMgNjEwNX1ccmlnaHQpIFxcDQomPSBcZnJhY3sxfXsxOTUuNzd9IFxleHBcbGVmdCgtXGZyYWN7NjQ1MTZ9ezEyMjEwfVxyaWdodCkgXFwNCiY9IDAuMDA1MTEgXHRpbWVzIFxleHAoLTUuMjg1KSBcXA0KJj0gMC4wMDUxMSBcdGltZXMgMC4wMDUwNyBcYXBwcm94IDIuNTkgXHRpbWVzIDEwXnstNX0NClxlbmR7YWxpZ24qfQ0KDQogICArICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMj00ODB8WT0xKSAmPSBcZnJhY3sxfXtcc3FydHsyXHBpIFx0aW1lcyAyNTAwfX0gXGV4cFxsZWZ0KC1cZnJhY3soNDgwLTQ1MCleMn17MiBcdGltZXMgMjUwMH1ccmlnaHQpIFxcDQomPSBcZnJhY3sxfXsxMjUuNjZ9IFxleHBcbGVmdCgtXGZyYWN7OTAwfXs1MDAwfVxyaWdodCkgXFwNCiY9IDAuMDA3OTYgXHRpbWVzIFxleHAoLTAuMTgpIFxcDQomPSAwLjAwNzk2IFx0aW1lcyAwLjgzNSBcYXBwcm94IDAuMDA2NjUNClxlbmR7YWxpZ24qfQ0KDQoqICoqU3RlcCAzOiBQb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyAoaWdub3JpbmcgZGVub21pbmF0b3IpKioNCg0KXGJlZ2lue2FsaWduKn0NClAoWT0wfFgpICZccHJvcHRvIFAoWT0wKSBcdGltZXMgUChYXzF8WT0wKSBcdGltZXMgUChYXzJ8WT0wKSBcXA0KJj0gMC42MjUgXHRpbWVzIDAuMjUgXHRpbWVzIDIuNTkgXHRpbWVzIDEwXnstNX0gXGFwcHJveCA0LjA1IFx0aW1lcyAxMF57LTZ9IFxcWzAuNWVtXQ0KUChZPTF8WCkgJlxwcm9wdG8gUChZPTEpIFx0aW1lcyBQKFhfMXxZPTEpIFx0aW1lcyBQKFhfMnxZPTEpIFxcDQomPSAwLjM3NSBcdGltZXMgMC42NjcgXHRpbWVzIDAuMDA2NjUgXGFwcHJveCAwLjAwMTY2DQpcZW5ke2FsaWduKn0NCg0KKiAqKlN0ZXAgNDogTm9ybWFsaXplKioNCg0KXGJlZ2lue2FsaWduKn0NClx0ZXh0e1N1bX0gJj0gNC4wNSBcdGltZXMgMTBeey02fSArIDAuMDAxNjYgXGFwcHJveCAwLjAwMTY2NCBcXFswLjVlbV0NClAoWT0wfFgpICY9IFxmcmFjezQuMDUgXHRpbWVzIDEwXnstNn19ezAuMDAxNjY0fSBcYXBwcm94IDAuMDAyNCBcXFswLjVlbV0NClAoWT0xfFgpICY9IFxmcmFjezAuMDAxNjZ9ezAuMDAxNjY0fSBcYXBwcm94IDAuOTk3Ng0KXGVuZHthbGlnbip9DQoNCg0KPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipQcmVkaWN0aW9uKio6PC9mb250PiAqKlNwYW0gKCRZPTEkKSoqIHdpdGggOTkuNzZcJSBjb25maWRlbmNlDQoNCg0KDQoqKktleSBOYWl2ZSBCYXllcyBBc3N1bXB0aW9ucyoqDQoNCiogKipGZWF0dXJlIEluZGVwZW5kZW5jZSoqOiBBc3N1bWVzIHNlbmRlciBkb21haW4gYW5kIGVtYWlsIGxlbmd0aCBhcmUgaW5kZXBlbmRlbnQgZ2l2ZW4gdGhlIGNsYXNzDQoqICoqR2F1c3NpYW4qKjogRW1haWwgbGVuZ3RoIGZvbGxvd3Mgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoaW4gZWFjaCBjbGFzcw0KKiAqKkNhdGVnb3JpY2FsKio6IFNlbmRlciBkb21haW4gcHJvYmFiaWxpdGllcyBlc3RpbWF0ZWQgd2l0aCBzbW9vdGhpbmcNCiogKipOYWl2ZSoqOiBKb2ludCBwcm9iYWJpbGl0eSA9IHByb2R1Y3Qgb2YgaW5kaXZpZHVhbCBmZWF0dXJlIHByb2JhYmlsaXRpZXMNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KIyBOb24tQ29uanVnYXRlIEJheWVzaWFuIEluZmVyZW5jZQ0KDQpJbiBtYW55IHJlYWwtd29ybGQgbW9kZWxzLCBjb25qdWdhdGUgcHJpb3JzIGFyZSBub3QgYXZhaWxhYmxlIG9yIGFwcHJvcHJpYXRlLiANCg0KKipFeGFtcGxlcyoqOg0KDQoNCiogTG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIEdhdXNzaWFuIHByaW9yIG9uIGNvZWZmaWNpZW50cy4NCg0KKiBDb21wbGV4IGhpZXJhcmNoaWNhbCBtb2RlbHMuDQoNCiogQ3VzdG9tIGxpa2VsaWhvb2QtcHJpb3IgY29tYmluYXRpb25zLg0KDQoNCioqU29sdXRpb24gYXBwcm9hY2hlcyoqOg0KDQoNCiogKipNYXJrb3YgQ2hhaW4gTW9udGUgQ2FybG8gKE1DTUMpKio6IFNhbXBsZSBmcm9tIHBvc3RlcmlvciAoZS5nLiwgR2liYnMgc2FtcGxpbmcsIE1ldHJvcG9saXMtSGFzdGluZ3MpLg0KDQoqICoqVmFyaWF0aW9uYWwgSW5mZXJlbmNlKio6IEFwcHJveGltYXRlIHBvc3RlcmlvciB3aXRoIGEgc2ltcGxlciBkaXN0cmlidXRpb24uDQoNCiogKipMYXBsYWNlIGFwcHJveGltYXRpb24qKjogR2F1c3NpYW4gYXBwcm94aW1hdGlvbiBhcm91bmQgcG9zdGVyaW9yIG1vZGUuDQoNCg0KTm9uLWNvbmp1Z2F0ZSBtZXRob2RzIGFyZSBtb3JlIGZsZXhpYmxlIGJ1dCBjb21wdXRhdGlvbmFsbHkgaW50ZW5zaXZlLCBlbmFibGVkIGJ5IG1vZGVybiBzb2Z0d2FyZSAoU3RhbiwgUHlNQywgSkFHUykuDQoNCg0KIyBTdW1tYXJ5DQoNCiogKipDb25qdWdhdGUgQmF5ZXMqKjogRW5hYmxlcyBleGFjdCwgY2xvc2VkLWZvcm0gcG9zdGVyaW9yIHVwZGF0ZXM7IGlkZWFsIGZvciBzaW1wbGUgbW9kZWxzIHdpdGggc3VpdGFibGUgbGlrZWxpaG9vZC1wcmlvciBwYWlycy4NCg0KKiAqKk5hw692ZSBCYXllcyoqOiBBIGZhc3QsIHNjYWxhYmxlIGNsYXNzaWZpZXIgbGV2ZXJhZ2luZyBjb25kaXRpb25hbCBpbmRlcGVuZGVuY2U7IEdhdXNzaWFuIE5hw692ZSBCYXllcyBleHRlbmRzIHRvIGNvbnRpbnVvdXMgZmVhdHVyZXMuDQoNCiogKipOb24tY29uanVnYXRlIGluZmVyZW5jZSoqOiBVc2VzIG51bWVyaWNhbCBtZXRob2RzIHRvIGFwcHJveGltYXRlIHBvc3RlcnMgZm9yIGNvbXBsZXggbW9kZWxzLCBlc3NlbnRpYWwgZm9yIG1vZGVybiBCYXllc2lhbiBkYXRhIGFuYWx5c2lzLg0KDQoNCg0KDQo=