1 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})\)


2 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.

2.1 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.

2.1.1 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:

  • Variance decreases as \(\alpha + \beta\) increases (more pseudo-observations \(\Rightarrow\) more certainty)

  • Variance is maximized when \(\alpha = \beta = 1\) (uniform distribution)

2.2 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.

2.2.1 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} \]

2.2.2 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} \]

2.2.3 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.

2.2.4 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.

2.2.5 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}. \]

2.3 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.

2.3.1 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.

2.3.2 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 \]

2.4 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

2.5 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.

3 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})\).

3.1 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

Fruit Weight (g) Sweetness Class
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

  • For Apples + Weight

\[\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}\]

  • For Apples + Sweet

\[\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}\]

  • For Oranges + Weight:

\[\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}\]

  • For Oranges + Sweetness:

\[\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) \]

  • For Apple:

\[\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}\]

  • For Orange:

\[\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}\]

  • Normalize:

\[\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)


3.2 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

Email Sender Domain (\(X_1\)) Email Length (\(X_2\)) Class (\(Y\))
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)

  • For \(Y=0\) (Not Spam):

\[\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*}\]

  • For \(Y=1\) (Spam):

\[\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}\}\)

  • For \(Y=0\):

\[\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*}\]

  • For \(Y=1\):

\[\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

  • For \(Y=0\):

\[\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*}\]

  • For \(Y=1\):

\[\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)
    • For \(Y=0\):

\[\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*}\]

  • For \(Y=1\):

\[\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*}\]

  • Step 4: Normalize

\[\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

4 Non-Conjugate Bayesian Inference

In many real-world models, conjugate priors are not available or appropriate.

Examples:

  • Logistic regression with Gaussian prior on coefficients.

  • Complex hierarchical models.

  • Custom likelihood-prior combinations.

Solution approaches:

  • Markov Chain Monte Carlo (MCMC): Sample from posterior (e.g., Gibbs sampling, Metropolis-Hastings).

  • Variational Inference: Approximate posterior with a simpler distribution.

  • Laplace approximation: Gaussian approximation around posterior mode.

Non-conjugate methods are more flexible but computationally intensive, enabled by modern software (Stan, PyMC, JAGS).

5 Summary

  • Conjugate Bayes: Enables exact, closed-form posterior updates; ideal for simple models with suitable likelihood-prior pairs.

  • Naïve Bayes: A fast, scalable classifier leveraging conditional independence; Gaussian Naïve Bayes extends to continuous features.

  • Non-conjugate inference: Uses numerical methods to approximate posters for complex models, essential for modern Bayesian data analysis.

LS0tDQp0aXRsZTogIkNvbmp1Z2F0ZSBCYXllcyBJbmZlcmVuY2UgYW5kIE5haXZlIEJheWVzIFByZWRpY3Rpb24iDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIldlc3QgQ2hlc3RlciBVbml2ZXJzaXR5Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICBsaWJyYXJ5KHBzeWNoKQ0KfQ0KaWYgKCFyZXF1aXJlKCJSQ29sb3JCcmV3ZXIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQ0KICBsaWJyYXJ5KFJDb2xvckJyZXdlcikNCn0NCg0KaWYgKCFyZXF1aXJlKCJib290IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogIGxpYnJhcnkoYm9vdCkNCn0NCmlmICghcmVxdWlyZSgiZWZmc2l6ZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImVmZnNpemUiKQ0KICBsaWJyYXJ5KGVmZnNpemUpDQp9DQojIyBsaWJyYXJ5KGVmZnNpemUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQpcDQoNCiMgUmV2aWV3IEJheWVzaWFuIFJ1bGUNCg0KQmF5ZXNpYW4gaW5mZXJlbmNlIGlzIGEgcHJvYmFiaWxpc3RpYyBmcmFtZXdvcmsgZm9yIHVwZGF0aW5nIGJlbGllZnMgKGluIHRoZSBmb3JtIG9mIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMpIGFib3V0IHVua25vd24gcGFyYW1ldGVycyAkXGJvbGRzeW1ib2x7XHRoZXRhfSQgYWZ0ZXIgb2JzZXJ2aW5nIGRhdGEgJFxtYXRoYmZ7WH0gPSAoWF8xLCBYXzIsIFxjZG90cywgWF9uKSQuIEl0IGNvbWJpbmVzIHByaW9yIGtub3dsZWRnZSAodGhlICpwcmlvciopIHdpdGggb2JzZXJ2ZWQgZXZpZGVuY2UgKHRoZSAqbGlrZWxpaG9vZCopIHRvIGZvcm0gYW4gdXBkYXRlZCBiZWxpZWYgKHRoZSAqcG9zdGVyaW9yKikuDQoNClRoZSBjb3JlIG1lY2hhbmlzbSBpcyAqKkJheWVzJyBUaGVvcmVtKio6DQoNCg0KJCQNClAoXGJvbGRzeW1ib2x7XHRoZXRhfSBcbWlkIFxtYXRoYmZ7WH0pID0gXGZyYWN7UChcbWF0aGJme1h9IFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfSkgXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KX17UChcbWF0aGJme1h9KX0gXHByb3B0byBQKFxtYXRoYmZ7WH0gXG1pZCBcYm9sZHN5bWJvbHtcdGhldGF9KSBcLCBQKFxib2xkc3ltYm9se1x0aGV0YX0pID0gUFxsZWZ0WyhYXzEsIFhfMiwgXGNkb3RzLCBYX24pIFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfVxyaWdodF0gXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KQ0KJCQNCg0KDQpXaGVyZToNCg0KKiAkUChcYm9sZHN5bWJvbHtcdGhldGF9IFxtaWQgXG1hdGhiZntYfSkkOiAqKlBvc3RlcmlvciBkaXN0cmlidXRpb24qKiAtLSBiZWxpZWYgYWJvdXQgJFxib2xkc3ltYm9se1x0aGV0YX0kIGFmdGVyIHNlZWluZyBkYXRhLg0KDQoqICRQKFxtYXRoYmZ7WH0gXG1pZCBcYm9sZHN5bWJvbHtcdGhldGF9KSQ6ICoqTGlrZWxpaG9vZCoqIC0tIHByb2JhYmlsaXR5IG9mIGRhdGEgZ2l2ZW4gJFxib2xkc3ltYm9se1x0aGV0YX0kLiA8Zm9udCBjb2xvciA9ICJyZWQiPioqVGhpcyBhIGpvaW50IHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBvZiAkKFhfMSwgWF8yLCBcY2RvdHMsIFhfbikgXG1pZCBcdGhldGEkLioqPC9mb250PiA8Zm9udCBjb2xvciA9ICJibHVlIj5MYXRlciwgd2Ugd2lsbCBtYWtlIGEgKipuYcOvdmUqKiBhc3N1bXB0aW9uIG9mIGNvbmRpdGlvbmFsIGluZGVwZW5kZW5jZSwgd2hpY2ggbGVhZHMgdG8gYSBjbGFzc2lmaWNhdGlvbiBtb2RlbCBjYWxsZWQgKipuYcOvdmUgQmF5ZXMqKi48L2ZvbnQ+DQoNCiogJFAoXGJvbGRzeW1ib2x7XHRoZXRhfSkkOiAqKlByaW9yIGRpc3RyaWJ1dGlvbioqIC0tIGJlbGllZiBhYm91dCAkXGJvbGRzeW1ib2x7XHRoZXRhfSQgYmVmb3JlIHNlZWluZyBkYXRhLiBUaGlzIGltcGxpZXMgdGhhdCB3ZSBjYW4gbWFrZSB1c2Ugb2YgcHJpb3IgYXV4aWxpYXJ5IGluZm9ybWF0aW9uIGluIEJheWVzIGluZmVyZW5jZS4NCg0KKiAkUChcbWF0aGJme1h9KSQ6ICoqTWFyZ2luYWwgbGlrZWxpaG9vZCAvIEV2aWRlbmNlKiogLS0gVGhpcyBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIGRhdGEgdW5kZXIgYWxsIHBvc3NpYmxlICRcYm9sZHN5bWJvbHtcdGhldGF9JCAoaS5lLiwgdGhlIG5vcm1hbGl6aW5nIGNvbnN0YW50KS4gQmVjYXVzZSAkUChcbWF0aGJme1h9KSQgaXMgY29uc3RhbnQgd2l0aCByZXNwZWN0IHRvICRcYm9sZHN5bWJvbHtcdGhldGF9JCwgaXRzIGRlcml2YXRpdmUgd2lsbCBiZSB6ZXJvIGluIHRoZSBvcHRpbWl6YXRpb24gZm9yIHBhcmFtZXRlciBlc3RpbWF0aW9uLiBUaGlzIGlzIGFsc28gd2h5ICRQKFxib2xkc3ltYm9se1x0aGV0YX0gXG1pZCBcbWF0aGJme1h9KSBccHJvcHRvIFAoXG1hdGhiZntYfSBcbWlkIFxib2xkc3ltYm9se1x0aGV0YX0pIFwsIFAoXGJvbGRzeW1ib2x7XHRoZXRhfSkkLg0KDQoNCjxmb250IGNvbG9yID0gInJlZCI+KiokUChcbWF0aGJme1h9IFxtaWQgXGJvbGRzeW1ib2x7XHRoZXRhfSkgXCwgUChcYm9sZHN5bWJvbHtcdGhldGF9KSQgaXMgY2FsbGVkIHRoZSBrZXJuZWwgb2YgJFAoXGJvbGRzeW1ib2x7XHRoZXRhfSBcbWlkIFxtYXRoYmZ7WH0pJCoqPC9mb250Pg0KDQoNClwNCg0KIyBDb25qdWdhdGUgQmF5ZXNpYW4gSW5mZXJlbmNlDQoNCkEgKipjb25qdWdhdGUgcHJpb3IqKiBpcyBjaG9zZW4gc3VjaCB0aGF0IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGJlbG9uZ3MgdG8gdGhlIHNhbWUgcHJvYmFiaWxpdHkgZmFtaWx5IGFzIHRoZSBwcmlvci4gVGhpcyBzaW1wbGlmaWVzIGNvbXB1dGF0aW9uIGRyYW1hdGljYWxseSBiZWNhdXNlIHRoZSBwb3N0ZXJpb3IgY2FuIGJlIGRlcml2ZWQgYW5hbHl0aWNhbGx5LiBJZjoNCg0KJCQNClx0ZXh0e1ByaW9yfTogIFx0aGV0YSBcc2ltIFx0ZXh0e0Rpc3R9XzEoXGFscGhhKQ0KJCQNCg0KJCQNClx0ZXh0e0xpa2VsaWhvb2R9OiAgXG1hdGhiZntYfSBcbWlkIFx0aGV0YSBcc2ltIFx0ZXh0e0Rpc3R9XzIoXHRoZXRhKQ0KJCQNCg0KVGhlbiBmb3IgY29uanVnYWN5Og0KDQokJA0KXHRleHR7UG9zdGVyaW9yOiB9IFx0aGV0YSBcbWlkIFxtYXRoYmZ7WH0gXHNpbSBcdGV4dHtEaXN0fV8xKFxhbHBoYScpDQokJA0KDQp3aGVyZSAkXGFscGhhJyQgYXJlIHVwZGF0ZWQgaHlwZXJwYXJhbWV0ZXJzLg0KDQoNCg0KIyMgQmF5ZXNpYW4gRXN0aW1hdGlvbiBCaW5vbWlhbCBEaXN0cmlidXRpb24NCg0KVGhpcyBzZWN0aW9uIHVzZSBCYXllc2lhbiBlc3RpbWF0aW9uIG9mIHRoZSBzdWNjZXNzIHByb2JhYmlsaXR5IG9mIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBhcyBhbiBleGFtcGxlIHRvIGlsbHVzdHJhdGUgdGhlIHByb2Nlc3Mgb2YgY29uanVnYXRlIEJheWVzaWFuIGluZmVyZW5jZS4NCg0KIyMjIEJldGEgRGlzdHJpYnV0aW9uOiBCYXNpY3MgYW5kIFByb3BlcnRpZXMNCg0KVGhlIEJldGEgZGlzdHJpYnV0aW9uIGlzIGEgY29udGludW91cyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gZGVmaW5lZCBvbiB0aGUgaW50ZXJ2YWwgKip7WzAsIDFdKiosIG1ha2luZyBpdCBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBtb2RlbGluZyAqKnByb2JhYmlsaXRpZXMsIHByb3BvcnRpb25zLCBvciBwZXJjZW50YWdlcyoqLiBJdCBpcyB0aGUgKipjb25qdWdhdGUgcHJpb3IqKiBmb3IgdGhlIEJlcm5vdWxsaSwgYmlub21pYWwsIGFuZCBnZW9tZXRyaWMgZGlzdHJpYnV0aW9ucyBpbiBCYXllc2lhbiBpbmZlcmVuY2UuDQoNCkZvciBwYXJhbWV0ZXJzICRcYWxwaGEgPiAwJCBhbmQgJFxiZXRhID4gMCQsIHRoZSBQREYgaXM6DQoNCiQkDQpmKHg7IFxhbHBoYSwgXGJldGEpID0gXGZyYWN7eF57XGFscGhhLTF9KDEteClee1xiZXRhLTF9fXtCKFxhbHBoYSwgXGJldGEpfSwgXHF1YWQgeCBcaW4gWzAsIDFdDQokJA0Kd2hlcmU6DQoNCiogJFxhbHBoYSwgXGJldGEkIGFyZSAqKnNoYXBlIHBhcmFtZXRlcnMqKiB0aGF0IGNvbnRyb2wgdGhlIGRpc3RyaWJ1dGlvbidzIGZvcm0NCiogJEIoXGFscGhhLCBcYmV0YSkkIGlzIHRoZSAqKkJldGEgZnVuY3Rpb24qKjoNCg0KJCQNCiAgICBCKFxhbHBoYSwgXGJldGEpID0gXGludF8wXjEgdF57XGFscGhhLTF9KDEtdClee1xiZXRhLTF9IGR0ID0gXGZyYWN7XEdhbW1hKFxhbHBoYSlcR2FtbWEoXGJldGEpfXtcR2FtbWEoXGFscGhhICsgXGJldGEpfQ0KJCQNCg0KKiAkXEdhbW1hKFxjZG90KSQgaXMgdGhlICoqR2FtbWEgZnVuY3Rpb259OiAkXEdhbW1hKG4pID0gKG4tMSkhJCBmb3IgcG9zaXRpdmUgaW50ZWdlcnMNCg0KVGhlIEJldGEgZnVuY3Rpb24gZW5zdXJlcyB0aGUgUERGIGludGVncmF0ZXMgdG8gMSBvdmVyICRbMCwgMV0kOg0KDQokJA0KXGludF8wXjEgZih4OyBcYWxwaGEsIFxiZXRhKSBcLCBkeCA9IDENCiQkDQoNCioqTWVhbiAoRXhwZWN0ZWQgVmFsdWUpKioNCg0KJCQNClxtYXRoYmJ7RX1bWF0gPSBcZnJhY3tcYWxwaGF9e1xhbHBoYSArIFxiZXRhfQ0KJCQNCg0KKipJbnRlcnByZXRhdGlvbioqOiBUaGUgbWVhbiByZXByZXNlbnRzIGEgd2VpZ2h0ZWQgYXZlcmFnZSB3aGVyZSAkXGFscGhhJCBhbmQgJFxiZXRhJCBhY3QgbGlrZSAqKnBzZXVkby1jb3VudHMqKiBvZiBzdWNjZXNzZXMgYW5kIGZhaWx1cmVzLg0KIA0KKipWYXJpYW5jZSoqDQoNCiQkDQpcdGV4dHtWYXJ9KFgpID0gXGZyYWN7XGFscGhhXGJldGF9eyhcYWxwaGEgKyBcYmV0YSleMihcYWxwaGEgKyBcYmV0YSArIDEpfQ0KJCQNCg0KKipJbnRlcnByZXRhdGlvbioqOg0KDQoqIFZhcmlhbmNlICoqZGVjcmVhc2VzKiogYXMgJFxhbHBoYSArIFxiZXRhJCBpbmNyZWFzZXMgKG1vcmUgKipwc2V1ZG8tb2JzZXJ2YXRpb25zKiogJFxSaWdodGFycm93JCBtb3JlIGNlcnRhaW50eSkNCg0KKiBWYXJpYW5jZSBpcyAqKm1heGltaXplZCoqIHdoZW4gJFxhbHBoYSA9IFxiZXRhID0gMSQgKHVuaWZvcm0gZGlzdHJpYnV0aW9uKQ0KDQoNCg0KIyMgQmF5ZXNpYW4gRXN0aW1hdGlvbiBvZiBCaW5vbWlhbCBTdWNjZXNzIFByb2JhYmlsaXR5DQoNCldlIGNvbmR1Y3QgJG4kIGluZGVwZW5kZW50IEJlcm5vdWxsaSB0cmlhbHMgd2l0aCBzdWNjZXNzIHByb2JhYmlsaXR5ICRcdGhldGEgXGluIFswLDFdJC4gV2Ugb2JzZXJ2ZSAkayQgc3VjY2Vzc2VzLiBXZSB3YW50IHRvIGVzdGltYXRlICRcdGhldGEkIHVzaW5nIEJheWVzaWFuIGluZmVyZW5jZSB3aXRoIGEgY29uanVnYXRlIEJldGEgcHJpb3IuIA0KDQojIyMgTGlrZWxpaG9vZCBGdW5jdGlvbg0KDQpUaGUgZGF0YSAkWCA9IFx7eF8xLCB4XzIsIFxkb3RzLCB4X25cfSQsIHdoZXJlICR4X2kgXGluIFx7MCwxXH0kLg0KDQokJA0KUChYIFxtaWQgXHRoZXRhKSA9IFxwcm9kX3tpPTF9Xm4gXHRoZXRhXnt4X2l9KDEtXHRoZXRhKV57MS14X2l9DQokJA0KDQpMZXQgJGsgPSBcc3VtX3tpPTF9Xm4geF9pJCBiZSB0aGUgdG90YWwgbnVtYmVyIG9mIHN1Y2Nlc3Nlcy4NCg0KJCQNClAoWCBcbWlkIFx0aGV0YSkgPSBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQpUaGlzIGlzIHRoZSAqKmJpbm9taWFsIGxpa2VsaWhvb2QqKiAodXAgdG8gdGhlIGJpbm9taWFsIGNvZWZmaWNpZW50ICRcYmlub217bn17a30kLCB3aGljaCBpcyBjb25zdGFudCB3aXRoIHJlc3BlY3QgdG8gJFx0aGV0YSQpOg0KDQokJA0KUChrIFxtaWQgXHRoZXRhLCBuKSA9IFxiaW5vbXtufXtrfSBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQpGb3IgQmF5ZXNpYW4gdXBkYXRpbmcsIHdlIGNhbiB1c2UgdGhlICoqcHJvcG9ydGlvbmFsIGZvcm0qKjoNCg0KJCQNClAoayBcbWlkIFx0aGV0YSwgbikgXHByb3B0byBcdGhldGFeayAoMS1cdGhldGEpXntuLWt9DQokJA0KDQojIyMgUHJpb3IgRGlzdHJpYnV0aW9uDQoNCldlIGNob29zZSBhICoqQmV0YSBkaXN0cmlidXRpb24qKiBhcyBjb25qdWdhdGUgcHJpb3I6DQoNCiQkDQpQKFx0aGV0YSBcbWlkIFxhbHBoYSwgXGJldGEpID0gXGZyYWN7XHRoZXRhXntcYWxwaGEtMX0oMS1cdGhldGEpXntcYmV0YS0xfX17QihcYWxwaGEsIFxiZXRhKX0NCiQkDQoNCldoZXJlOg0KDQoqICRcYWxwaGEgPiAwJCwgJFxiZXRhID4gMCQgYXJlIGh5cGVycGFyYW1ldGVycw0KKiAkQihcYWxwaGEsIFxiZXRhKSA9IFxmcmFje1xHYW1tYShcYWxwaGEpXEdhbW1hKFxiZXRhKX17XEdhbW1hKFxhbHBoYStcYmV0YSl9JCBpcyB0aGUgQmV0YSBmdW5jdGlvbg0KDQoNClRoZSAqKnByb3BvcnRpb25hbCBmb3JtKiogKGRyb3BwaW5nIHRoZSBub3JtYWxpemluZyBjb25zdGFudCk6DQoNCiQkDQpQKFx0aGV0YSkgXHByb3B0byBcdGhldGFee1xhbHBoYS0xfSgxLVx0aGV0YSlee1xiZXRhLTF9DQokJA0KDQojIyMgQmF5ZXMnIFRoZW9yZW0gQXBwbGljYXRpb24NCg0KJCQNClAoXHRoZXRhIFxtaWQgaywgbikgPSBcZnJhY3tQKGsgXG1pZCBcdGhldGEsIG4pIFAoXHRoZXRhKX17UChrIFxtaWQgbil9DQokJA0KDQpXaGVyZSAkUChrIFxtaWQgbikgPSBcaW50XzBeMSBQKGsgXG1pZCBcdGhldGEsIG4pIFAoXHRoZXRhKSBkXHRoZXRhJCBpcyB0aGUgbWFyZ2luYWwgbGlrZWxpaG9vZC4gPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipUaGUgbnVtYmVyIG9mIEJlcm5vdWxsaSB0cmlhbHMgJG4kIGlzIGEgcHJlZGV0ZXJtaW5lZCBjb25zdGFudC4gSXQgaXMgbm90IGFuIHVua25vd24gcGFyYW1ldGVyIG9mIHRoZSBiaW5vbWlhbCBkaXN0cmlidXRpb24uKio8L2ZvbnQ+DQoNCiMjIyBQb3N0ZXJpb3IgRGVyaXZhdGlvbg0KDQpXZSBpZ25vcmUgYWxsIGNvbnN0YW50cyBhbmQgd29yayBvbmx5IHdpdGggdGhlIGtlcm5lbHMgb2YgcmVsYXRlZCBkaXN0cmlidXRpb25zIHRvIGRlcml2ZSB0aGUga2VybmVsIG9mIHBvc3RlcmlvciBkaXN0cmlidXRpb24gYW5kIGFkZCB0aGUgbm9ybWFsaXppbmcgaW4gdGhlIGVuZCB0byBtYWtlIHRoZSBjb21wbGV0ZSB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbi4NCg0KKipLZXJuZWwgb2YgUG9zdGVyaW9yIERpc3RyaWJ1dGlvbioqDQoNCldlIGZpcnN0IGZpbmQgdGhlIGtlcm5lbCBvZiB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiB0aGUgYWJvdmUgQmF5ZXMgcnVsZSBpbiB0aGUgZm9sbG93aW5nDQoNCiQkDQpQKFx0aGV0YSBcbWlkIGssIG4pIFxwcm9wdG8gUChrIFxtaWQgXHRoZXRhLCBuKSBcY2RvdCBQKFx0aGV0YSkNCiQkDQoNCiQkDQpccHJvcHRvIFxsZWZ0W1x0aGV0YV5rICgxLVx0aGV0YSlee24ta31ccmlnaHRdIFxjZG90IFxsZWZ0W1x0aGV0YV57XGFscGhhLTF9KDEtXHRoZXRhKV57XGJldGEtMX1ccmlnaHRdDQokJA0KDQokJA0KPSBcdGhldGFee2sgKyBcYWxwaGEgLSAxfSAoMS1cdGhldGEpXntuIC0gayArIFxiZXRhIC0gMX0NCiQkDQoNCiQkDQo9IFx0aGV0YV57XGFscGhhJyAtIDF9ICgxLVx0aGV0YSlee1xiZXRhJyAtIDF9DQokJA0KDQpXaGVyZToNCg0KJCQNClxhbHBoYScgPSBcYWxwaGEgKyBrLCBccXVhZCBcYmV0YScgPSBcYmV0YSArIChuIC0gaykNCiQkDQoNCioqQ29tcGxldGUgUG9zdGVyaW9yIERpc3RyaWJ1dGlvbioqDQoNCldlIG5leHQgZmluZCB0aGUgbm9ybWFsaXppbmcgY29lZmZpY2llbnQgdG8gbWFrZSB0aGUgYWJvdmUga2VybmVsIGluIGEgdmFsaWQgZGlzdHJpYnV0aW9uLg0KDQokJA0KUChcdGhldGEgXG1pZCBrLCBuKSA9IFxmcmFje1x0aGV0YV57XGFscGhhJy0xfSgxLVx0aGV0YSlee1xiZXRhJy0xfX17QihcYWxwaGEnLCBcYmV0YScpfQ0KJCQNCg0KJCQNClx0aGV0YSBcbWlkIGssIG4gXHNpbSBcdGV4dHtCZXRhfShcYWxwaGEnLCBcYmV0YScpDQokJA0KDQpXaGVyZToNCg0KJCQNClxhbHBoYScgPSBcYWxwaGEgKyBrLCBccXVhZCBcYmV0YScgPSBcYmV0YSArIG4gLSBrDQokJA0KDQoNClRoZSBoeXBlcnBhcmFtZXRlcnMgJFxhbHBoYSQgYW5kICRcYmV0YSQgYWN0IGFzICoqcHNldWRvLWNvdW50cyoqOg0KDQoqICRcYWxwaGEtMSQgPSBwcmlvciBudW1iZXIgb2Ygc3VjY2Vzc2VzDQoNCiogJFxiZXRhLTEkID0gcHJpb3IgbnVtYmVyIG9mIGZhaWx1cmVzDQoNCiogJFxhbHBoYSArIFxiZXRhIC0gMiQgPSB0b3RhbCBwcmlvciBvYnNlcnZhdGlvbnMNCg0KVGhlIHBvc3RlcmlvciBzaW1wbHkgYWRkcyB0aGUgKipvYnNlcnZlZCBjb3VudHMqKiB0byB0aGUgcHJpb3IgcHNldWRvLWNvdW50cy4NCg0KDQojIyMgUG9zdGVyaW9yIFN0YXRpc3RpY3MNCg0KS2V5IHN0YXRpc3RpY3MgdXNlZCBpbiBCYXllc2lhbiBpbmZlcmVuY2UNCg0KKipNZWFuKio6DQoNCiQkDQpcbWF0aGJie0V9W1x0aGV0YSBcbWlkIGssIG5dID0gXGZyYWN7XGFscGhhJ317XGFscGhhJyArIFxiZXRhJ30gPSBcYm94ZWR7XGZyYWN7XGFscGhhICsga317XGFscGhhICsgXGJldGEgKyBufSB9DQokJA0KDQpUaGUgYWJvdmUgZXhwcmVzc2lvbiBpbiB0aGUgYWJvdmUgYm94IGNhbiBiZSByZS13cml0dGVuIGluIHRoZSBmb2xsb3dpbmcgdG8gbWFrZSB0aGUgY29ubmVjdGlvbiBiZXR3ZWVuIHRoZSBNTEUgb2YgJFx0aGV0YSQsIGRlbm90ZWQgYnkgJFxoYXR7cH1fe01MRX0kLg0KDQoNCiQkDQo9IFxmcmFje1xmcmFje1xhbHBoYX17bn0rXGZyYWN7a317cH19e1xmcmFje1xhbHBoYX17bn0rXGZyYWN7XGJldGF9e259KzF9ID0gXGZyYWN7XGZyYWN7XGFscGhhfXtufStcaGF0e3B9X3tNTEV9fXtcZnJhY3tcYWxwaGF9e259K1xmcmFje1xiZXRhfXtufSsxfSAgXHhyaWdodGFycm93e1x0ZXh0e2FzIG4gZ2V0cyBiaWdnZXJ9fSBcaGF0e3B9X3tNTEV9DQokJA0KDQp3aGVyZSAkXGhhdHtwfV97TUxFfSA9IGsvbiQuIEFzICRuIFx0byBcaW5mdHkkLCAkXGFscGhhL24gXHRvIDAkIGFuZCAkXGJldGEvbiBcdG8gMCQuDQoNCg0KKipWYXJpYW5jZSoqOg0KDQokJA0KXHRleHR7VmFyfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFje1xhbHBoYSdcYmV0YSd9eyhcYWxwaGEnK1xiZXRhJyleMihcYWxwaGEnK1xiZXRhJysxKX0gPSBcYm94ZWR7XGZyYWN7KFxhbHBoYStrKShcYmV0YStuLWspfXsoXGFscGhhK1xiZXRhK24pXjIoXGFscGhhK1xiZXRhK24rMSl9fQ0KJCQNCg0KVGhlIHBvc3RlcmlvciB2YXJpYW5jZSBpbiB0aGUgYWJvdmUgYm94IGNhbiBhbHNvIGJlIHJlLXdyaXR0ZW4gaW4gdGhlIGZvbGxvd2luZyB0byBtYWtlIHRoZSBjb25uZWN0aW9uIHdpdGggdGhlIE1MRSBvZiB2YXJpYW5jZS4gV2UgZGl2aWRlIGJvdGggbnVtZXJhdG9yIGFuZCBkZW5vbWluYXRvciBieSAkbl4zJA0KDQoNCiQkDQpcZnJhY3soXGFscGhhK2spKFxiZXRhK24tayl9eyhcYWxwaGErXGJldGErbileMihcYWxwaGErXGJldGErbisxKX0gPSBcZnJhY3tcZnJhY3sxfXtufShcZnJhY3tcYWxwaGF9e259K1xmcmFje2t9e259KShcZnJhY3tcYmV0YX17bn0rMS1cZnJhY3trfXtufSl9eyhcZnJhY3tcYWxwaGF9e259K1xmcmFje1xiZXRhfXtufSsxKV4yKFxmcmFje1xhbHBoYX17bn0rXGZyYWN7XGJldGF9e259KzErXGZyYWN7MX17bn0pfSBcYXBwcm94IFxmcmFje1xoYXR7cH1fe01MRX0oMS1caGF0e3B9X3tNTEV9KX17bn0sIFwgXCBcdGV4dHsgYXMgbiBnZXRzIGJpZ2dlcn0uDQokJA0KDQoNCg0KIyMgTnVtZXJpY2FsIEV4YW1wbGUNCg0KQ29uc2lkZXIgYW4gZXhwZXJpbWVudHMgb2YgMjAgQmVybm91bGxpIHRyaWFscyAoJG4gPSAyMCQpIHdpdGggMTQgc3VjY2Vzc2VzICgkayA9IDE0JCkuIFdlIHdhbnQgdG8gZmluZCB0aGUgQmF5ZXMgZXN0aW1hdGUgb2YgdGhlIHN1Y2Nlc3MgcHJvYmFiaWxpdHkgJFxoYXR7cH1fe1x0ZXh0e0JheWVzfX0kIHdpdGggdGhlIHByaW9yIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdHJ1ZSBzdWNjZXNzIHByb2JhYmlsaXR5ICRcdGhldGEkLCBpLmUuLCAkXHRoZXRhIFxzaW0gXHRleHR7QmV0YX0oMywgMykkIHdoaWNoIGlzIHN5bW1ldHJpYywgY2VudGVyZWQgYXQgMC41Lg0KDQoNCiMjIyBCYXllc2lhbiBFc3RpbWF0aW9uDQoNClRoZSBvYmplY3RpdmUgaXMgdG8gY29uc3RydWN0IGEgOTVcJSBCYXllc2lhbiBjcmVkaWJsZSBpbnRlcnZhbCBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gaW4gdGhlIGV4cGVyaW1lbnQgKGkuZS4sIHNhbXBsZSBkYXRhKS4NCg0KKipTZXR1cCoqDQoNCiogKipQcmlvcioqOiAkXHRoZXRhIFxzaW0gXHRleHR7QmV0YX0oMywgMykkIChzeW1tZXRyaWMsIGNlbnRlcmVkIGF0IDAuNSkNCiogKipEYXRhKio6ICRuID0gMjAkIHRyaWFscywgJGsgPSAxNCQgc3VjY2Vzc2VzDQoqICoqTUxFKio6ICRcaGF0e1x0aGV0YX1fe1x0ZXh0e01MRX19ID0gMTQvMjAgPSAwLjckDQoNCg0KKipQb3N0ZXJpb3IgQ2FsY3VsYXRpb24qKg0KDQpCYXNlZCBvbiB0aGUgZGVyaXZhdGlvbiBvZiB0aGUgYWJvdmUgc3Vic2VjdGlvbiwgdGhlICoqUHJpb3IgcGFyYW1ldGVycyoqIGFyZSBnaXZlbiBieQ0KDQoqICoqUHJpb3IgUGFyYW1ldGVycyoqOiAkXGFscGhhID0gMyQsICRcYmV0YSA9IDMkDQoqICoqUHJpb3IgbWVhbioqOiAkMy8oMyszKSA9IDAuNSQNCiogKipQcmlvciBzdHJlbmd0aCoqOiAkXGFscGhhICsgXGJldGEgPSA2JCAoZXF1aXZhbGVudCB0byA0IHBzZXVkby1vYnNlcnZhdGlvbnMpDQoNCg0KKipQb3N0ZXJpb3IgcGFyYW1ldGVycyoqOg0KDQokJA0KXGFscGhhJyA9IDMgKyAxNCA9IDE3LCBccXVhZCBcYmV0YScgPSAzICsgKDIwIC0gMTQpID0gMyArIDYgPSA5DQokJA0KDQoNCioqUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbioqOg0KDQokJA0KXHRoZXRhIFxtaWQgaywgbiBcc2ltIFx0ZXh0e0JldGF9KDE3LCA5KQ0KJCQNCg0KKipQb3N0ZXJpb3Igc3RhdGlzdGljcyoqOg0KDQokJA0KXG1hdGhiYntFfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFjezE3fXsxNyArIDl9ID0gXGZyYWN7MTd9ezI2fSBcYXBwcm94IDAuNjU0DQokJA0KDQokJA0KXHRleHR7VmFyfVtcdGhldGEgXG1pZCBrLCBuXSA9IFxmcmFjezE3IFx0aW1lcyA5fXsoMjYpXjIoMjcpfSA9IFxmcmFjezE1M317MTgyNTJ9IFxhcHByb3ggMC4wMDgzOA0KJCQNCg0KJCQNClx0ZXh0e1NEfVtcdGhldGEgXG1pZCBrLCBuXSBcYXBwcm94IFxzcXJ0ezAuMDA4Mzh9IFxhcHByb3ggMC4wOTE2DQokJA0KDQoqKjk1XCUgQ3JlZGlibGUgSW50ZXJ2YWwqKg0KDQpUaGUgJDEwMCgxLVxhbHBoYSlcJSQgY3JlZGlibGUgaW50ZXJ2YWwgJFtMLCBVXSQgc2F0aXNmaWVzOg0KDQokJA0KUChMIFxsZXEgXHRoZXRhIFxsZXEgVSBcbWlkIGssIG4pID0gMC45NQ0KJCQNCg0KRm9yIEJldGEoMTcsOSksIHdlIHVzZSBSIHRvIGZpbmQgMi41dGggYW5kIDk3LjV0aCBwZXJjZW50aWxlcyB0byB0aGUgb2J0YWluIHRoZSBsb3dlciBhbmQgdXBwZXIgY3JlZGlibGUgbGltaXRzIGluIHRoZSBmb2xsb3dpbmcNCg0KKiAkTCA9IFx0ZXh0e0JldGF9XnstMX0oMC4wMjU7IDE3LCA5KSBcYXBwcm94IDAuNDc4JA0KDQoqICRVID0gXHRleHR7QmV0YX1eey0xfSgwLjk3NTsgMTcsIDkpIFxhcHByb3ggMC44MTMkDQoNClRoZXJlZm9yZSwgJFx0aGV0YSBcaW4gWzAuNDc4LCAwLjgxM10kIHdpdGggOTVcJSBwb3N0ZXJpb3IgcHJvYmFiaWxpdHkuDQoNCg0KIyMjIEJheWVzaWFuIFByZWRpY3Rpb24gPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KE9wdGlvbmFsKTwvZm9udD4NCg0KQmFzZWQgb24gdGhlIEJheWVzaWFuIGVzdGltYXRlcyBvZiB0aGUgcGFyYW1ldGVyIG9idGFpbmVkIHByZXZpb3VzbHksIHdlIHdhbnQgdG8gcHJlZGljdCB0aGUgb3V0Y29tZSBvZiB0aGUgbmV4dCAkbSQgdHJpYWxzLiBUaGUgZ2VuZXJhbCBmb3JtdWxhIGZvciB0aGUgcHJvYmFiaWxpdHkgb2Ygc3VjY2VzcyBpbiBuZXh0ICRtJCB0cmlhbHMgd2l0aCAkeSQgc3VjY2Vzc2VzOg0KDQokJA0KUCh5IFxtaWQgaywgbiwgbSkgPSBcaW50XzBeMSBQKHkgXG1pZCBcdGhldGEsIG0pIFAoXHRoZXRhIFxtaWQgaywgbikgZFx0aGV0YQ0KJCQNCg0KJCQNCj0gXGludF8wXjEgXGJpbm9te219e3l9IFx0aGV0YV55ICgxLVx0aGV0YSlee20teX0gXGNkb3QgXGZyYWN7XHRoZXRhXntcYWxwaGEnLTF9KDEtXHRoZXRhKV57XGJldGEnLTF9fXtCKFxhbHBoYScsIFxiZXRhJyl9IGRcdGhldGENCiQkDQoNCiQkDQo9IFxiaW5vbXttfXt5fSBcZnJhY3tCKFxhbHBoYScgKyB5LCBcYmV0YScgKyBtIC0geSl9e0IoXGFscGhhJywgXGJldGEnKX0NCiQkDQoNClRoaXMgaXMgYWdhaW4gYSAqKkJldGEtYmlub21pYWwgZGlzdHJpYnV0aW9uKiouIE5leHQsIHdlIGxvb2sgYXQgcHJlZGljdGlvbiB3aXRoIHNwZWNpYWwgJG0kLiBJbiB0aGUgZm9sbG93aW5nIHNwZWNpYWwgY2FzZXMsICRuID0gMjAkIGFuZCAkayA9IDE0JDoNCg0KKiBGb3IgMSBuZXh0IHRyaWFsICgkbT0xJCwgaS5lLiwgQmVybm91bGxpIHRyaWFsKSB3aXRoIHRoZSBvdXRjb21lIG9mIGEgc3VjY2VzczoNCg0KJCQNClAoXHRleHR7c3VjY2Vzc30gXG1pZCBrLCBuKSA9IFxtYXRoYmJ7RX1bXHRoZXRhIFxtaWQgaywgbl0gPSBcZnJhY3tcYWxwaGEnfXtcYWxwaGEnICsgXGJldGEnfSBcYXBwcm94IDAuNjU0DQokJA0KDQoqIEZvciA1IG5leHQgdHJpYWxzICgkbT01JCkgd2l0aCAkeSA9IDMkIHN1Y2Nlc3NlczoNCg0KJCQNClAoeT0zIFxtaWQgaywgbiwgbT01KSA9IFxiaW5vbXs1fXszfSBcZnJhY3tCKDE3KzMsIDkrMil9e0IoMTcsIDkpfSA9IDEwIFxjZG90IFxmcmFje0IoMjAsIDExKX17QigxNywgOSl9IFxhcHByb3ggMC4zNDQNCiQkDQoNCg0KIyMgQ29tbW9uIENvbmp1Z2F0ZSBGYW1pbGllcw0KDQpUaGUgcHJpbWFyeSBwdXJwb3NlIG9mIHVzaW5nIGEgY29uanVnYXRlIHByaW9yIGluIEJheWVzaWFuIGluZmVyZW5jZSBpcyB0byBlbnN1cmUgbWF0aGVtYXRpY2FsIHRyYWN0YWJpbGl0eSBieSBndWFyYW50ZWVpbmcgdGhhdCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBiZWxvbmdzIHRvIHRoZSBzYW1lIHByb2JhYmlsaXR5IGZhbWlseSBhcyB0aGUgcHJpb3IsIHdoaWNoIGFsbG93cyBmb3IgY2xvc2VkLWZvcm0gYW5hbHl0aWNhbCB1cGRhdGVzIHJhdGhlciB0aGFuIGNvbXB1dGF0aW9uYWxseSBpbnRlbnNpdmUgbnVtZXJpY2FsIGFwcHJveGltYXRpb25zLiBUaGlzIGNvbmp1Z2FjeSBlbmFibGVzIHN0cmFpZ2h0Zm9yd2FyZCBzZXF1ZW50aWFsIGxlYXJuaW5nLCB3aGVyZSBwb3N0ZXJpb3IgcGFyYW1ldGVycyBhcmUgc2ltcGx5IHVwZGF0ZWQgdGhyb3VnaCBhZGRpdGlvbiBvZiBvYnNlcnZlZCBkYXRhIHN0YXRpc3RpY3MgdG8gcHJpb3IgaHlwZXJwYXJhbWV0ZXJzLCBtYWtpbmcgaXQgaWRlYWwgZm9yIHJlYWwtdGltZSBvciBzdHJlYW1pbmcgZGF0YSBhcHBsaWNhdGlvbnMuIFdoaWxlIG1vZGVybiBjb21wdXRhdGlvbmFsIG1ldGhvZHMgaGF2ZSByZWR1Y2VkIHRoZSBuZWNlc3NpdHkgb2Ygc3RyaWN0IGNvbmp1Z2FjeSwgaXQgcmVtYWlucyBhIHBvd2VyZnVsIHRvb2wgZm9yIHBlZGFnb2dpY2FsIGNsYXJpdHksIHJhcGlkIHByb3RvdHlwaW5nLCBhbmQgYXBwbGljYXRpb25zIHdoZXJlIGNvbXB1dGF0aW9uYWwgZWZmaWNpZW5jeSBhbmQgdHJhbnNwYXJlbmN5IGFyZSBwcmlvcml0aXplZCBvdmVyIGZ1bGwgcHJpb3IgZmxleGliaWxpdHkuDQoNClRoZSBmb2xsb3dpbmcgaXMgYSBsaXN0IG9mIHNvbWUgY29tbW9ubHkgdXNlZCBjb25qdWdhdGUgcHJpb3JzIGFzc29jaWF0ZWQgd2l0aCBhIGZldyBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbnMuDQoNCiogQmVybm91bGxpL0Jpbm9taWFsICRcbGVmdHJpZ2h0YXJyb3ckIEJldGENCg0KKiBQb2lzc29uICRcbGVmdHJpZ2h0YXJyb3ckIEdhbW1hDQoNCiogTm9ybWFsICh3aXRoIGtub3duIHZhcmlhbmNlKSAkXGxlZnRyaWdodGFycm93JCBOb3JtYWwgKGZvciBtZWFuKQ0KDQoqIE5vcm1hbCAod2l0aCBrbm93biBtZWFuKSAkXGxlZnRyaWdodGFycm93JCBJbnZlcnNlLUdhbW1hIChmb3IgdmFyaWFuY2UpDQoNCiogTXVsdGlub21pYWwgJFxsZWZ0cmlnaHRhcnJvdyQgRGlyaWNobGV0DQoNCg0KDQojIyAgUHJhY3RpY2FsIEFwcGxpY2F0aW9ucw0KDQoqICoqQS9CIHRlc3RpbmcqKjogVXBkYXRlIHN1Y2Nlc3MgcmF0ZSBwb3N0ZXJpb3JzIGZvciB0d28gd2VicGFnZSB2YXJpYW50cy4NCg0KKiAqKlF1YWxpdHkgY29udHJvbCoqOiBFc3RpbWF0ZSBkZWZlY3QgcmF0ZXMgd2l0aCBoaXN0b3JpY2FsIHByaW9yLg0KDQoqICoqUGhhcm1hY29raW5ldGljcyoqOiBVcGRhdGUgZHJ1ZyBlZmZlY3Qgc2l6ZSBkaXN0cmlidXRpb24gZnJvbSB0cmlhbHMuDQoNCg0KDQojIE5hw692ZSBCYXllcyBDbGFzc2lmaWVyDQoNCg0KUmVjYWxsIHRoZSAqKkJheWVzIFJ1bGUqKiB3aXRoIG11bHRpcGxlIGZlYXR1cmUgdmFyaWFibGVzICRcbWF0aGJme1h9ID0gKFhfMSwgWF8yLCBcY2RvdHMsIFhfaykkIGFuZCBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlICRcbWF0aGJme0N9PShDXzEsIENfMi4gXGNkb3RzLCBDX2QpJCB3aXRoICRkJCBjYXRlZ29yaWVzLiANCg0KDQpUaGUgY29yZSBtZWNoYW5pc20gaXMgKipCYXllcycgVGhlb3JlbSoqOg0KDQoNCiQkDQpQKENfaiBcbWlkIFxtYXRoYmZ7WH0pID0gXGZyYWN7UChcbWF0aGJme1h9IFxtaWQgQ19qKSBcLCBQKENfail9e1AoXG1hdGhiZntYfSl9IFxwcm9wdG8gUChcbWF0aGJme1h9IFxtaWQgQ19qKSBcLCBQKENfaikgPSBQXGxlZnRbKFhfMSwgWF8yLCBcY2RvdHMsIFhfaykgXG1pZCBDX2pccmlnaHRdIFwsIFAoQ19qKQ0KJCQNCg0KQSBwcm9iYWJpbGlzdGljIGNsYXNzaWZpZXIgYmFzZWQgb24gQmF5ZXMgdGhlb3JlbSB3aXRoIGEgc3Ryb25nICgqKm5haXZlKiopIGFzc3VtcHRpb246ICoqZmVhdHVyZXMgYXJlIGNvbmRpdGlvbmFsbHkgaW5kZXBlbmRlbnQgZ2l2ZW4gdGhlIGNsYXNzIGxhYmVsKiouDQoNCiQkDQpQXGxlZnRbKFhfMSwgWF8yLCBcY2RvdHMsIFhfZCkgXG1pZCBDX2pccmlnaHRdID0gXHByb2Rfe2k9MX1eayBQKFhfaVxtaWQgQ19qKSwgXCBcIFx0ZXh0eyB3aGVyZSB9IFwgXCAxIFxsZSBqIFxsZSBkLg0KJCQNCg0KVGhhdCBpcywgdW5kZXIgdGhlIGZyYW1ld29yayBvZiAqKk5haXZlIEJheWVzKiosIHRoZSBjYXRlZ29yeSBwcm9iYWJpbGl0eSAob3IgcHJvcG9ydGlvbmFsIHRvIHRoZSBwcm9iYWJpbGl0eSkgaXMgY2FsY3VsYXRlZCBieQ0KDQoNCiQkDQpQKENfaiBcbWlkIFxtYXRoYmZ7WH0pIFxwcm9wdG8gUChDX2opIFxwcm9kX3tpPTF9XntkfSBQKHhfaiBcbWlkIENfaikNCiQkDQoNCiogKiokUChDX2spJCoqOiBQcmlvciBwcm9iYWJpbGl0eSBvZiBjbGFzcyAkayQuDQoNCiogKiokUCh4X2ogXG1pZCBDX2spJCoqOiBMaWtlbGlob29kIG9mIGZlYXR1cmUgJGokIGdpdmVuIGNsYXNzICRrJC4NCg0KKiAqKkRlY2lzaW9uIHJ1bGUgZm9yIGNsYXNzaWZpY2F0aW9uKio6IENob29zZSBjbGFzcyB3aXRoIGhpZ2hlc3QgcG9zdGVyaW9yICRQKENfayBcbWlkIFxtYXRoYmZ7eH0pJC4NCg0KDQojIyBHYXVzc2lhbiBOYcOvdmUgQmF5ZXMNCg0KV2hlbiBmZWF0dXJlcyBhcmUgY29udGludW91cywgYXNzdW1lICRQKHhfaiBcbWlkIENfaykkIGlzIEdhdXNzaWFuOg0KDQokJA0KUCh4X2ogXG1pZCBDX2spID0gXGZyYWN7MX17XHNxcnR7MlxwaVxzaWdtYV97amt9XjJ9fSBcZXhwXGxlZnQoLVxmcmFjeyh4X2ogLSBcbXVfe2prfSleMn17MlxzaWdtYV97amt9XjJ9XHJpZ2h0KQ0KJCQNCg0KUGFyYW1ldGVycyAkXG11X3tqa30sIFxzaWdtYV97amt9XjIkIGVzdGltYXRlZCB2aWEgTUxFIGZyb20gdHJhaW5pbmcgZGF0YSBmb3IgZWFjaCBjbGFzcyAkayQgYW5kIGZlYXR1cmUgJGokLg0KDQoNCioqQW4gTnVtZXJpY2FsIEV4YW1wbGUgLSBDbGFzc2lmeSBGcnVpdHMgQmFzZWQgb24gV2VpZ2h0IGFuZCBTd2VldG5lc3MqKjogV2Ugd2FudCB0byBwcmVkaWN0IHdoZXRoZXIgYSBmcnVpdCBpcyBhbiAqKkFwcGxlKiogb3IgKipPcmFuZ2UqKiBiYXNlZCBvbjoNCg0KKiAqKldlaWdodCoqIChpbiBncmFtcykNCiogKipTd2VldG5lc3MqKiAoc2NhbGUgMS0xMCwgd2hlcmUgMTAgaXMgdmVyeSBzd2VldCkNCg0KVGhlIHRyYWluaW5nIERhdGEgaXMgZ2l2ZW4gYnkNCg0KfCBGcnVpdCB8IFdlaWdodCAoZykgfCBTd2VldG5lc3MgfCBDbGFzcyB8DQp8Oi0tLS0tfDotLS0tLS18Oi0tLS0tLS0tLS0tfDotLS0tLS0tLS0tfA0KfCAgMSB8ICAgMTUwIHwgICA2IHwgICBBcHBsZSB8ICANCnwgIDIgfCAgIDEzMCB8ICAgOCB8ICAgT3JhbmdlIHwgIA0KfCAgMyB8ICAgMTYwIHwgICA1IHwgICBBcHBsZSB8ICANCnwgIDQgfCAgIDE0MCB8ICAgNyB8ICAgT3JhbmdlfCAgDQp8ICA1IHwgICAxNzAgfCAgIDQgfCAgIEFwcGxlIHwgIA0KDQpUaGUgZm9sbG93aW5nIGFyZSB0aGUgc3RlcHMgZm9yIG1ha2luZyBwcmVkaWN0aW9uLg0KDQoqKlN0ZXAgMTogQ2FsY3VsYXRlIENsYXNzIFByb2JhYmlsaXRpZXMqKg0KDQoqIFRvdGFsIGZydWl0czogNQ0KKiBBcHBsZXM6IDMgJFxyaWdodGFycm93IFAoXHRleHR7QXBwbGV9KSA9IFxmcmFjezN9ezV9ID0gMC42JA0KKiBPcmFuZ2VzOiAyICRccmlnaHRhcnJvdyBQKFx0ZXh0e09yYW5nZX0pID0gXGZyYWN7Mn17NX0gPSAwLjQkDQoNCg0KKipTdGVwIDI6IENhbGN1bGF0ZSBHYXVzc2lhbiBQYXJhbWV0ZXJzIGZvciBFYWNoIEZlYXR1cmUgcGVyIENsYXNzKioNCg0KKiAqKkZvciBBcHBsZXMgKyBXZWlnaHQqKg0KIA0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHt3ZWlnaHQsQXBwbGV9fSAmPSBcZnJhY3sxNTAgKyAxNjAgKyAxNzB9ezN9ID0gMTYwIFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3dlaWdodCxBcHBsZX19ICY9IFxmcmFjeygxNTAtMTYwKV4yICsgKDE2MC0xNjApXjIgKyAoMTcwLTE2MCleMn17M30gXFwNCiAgICAmPSBcZnJhY3sxMDAgKyAwICsgMTAwfXszfSA9IDY2LjY3IFxcDQogICAgXHNpZ21hX3tcdGV4dHt3ZWlnaHQsQXBwbGV9fSAmPSBcc3FydHs2Ni42N30gXGFwcHJveCA4LjE2DQpcZW5ke2FsaWdufQ0KDQoNCiogKipGb3IgQXBwbGVzICsgU3dlZXQqKiANCg0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHtzd2VldCxBcHBsZX19ICY9IFxmcmFjezYgKyA1ICsgNH17M30gPSA1IFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3N3ZWV0LEFwcGxlfX0gJj0gXGZyYWN7KDYtNSleMiArICg1LTUpXjIgKyAoNC01KV4yfXszfSBcXA0KICAgICY9IFxmcmFjezEgKyAwICsgMX17M30gPSAwLjY3IFxcDQogICAgXHNpZ21hX3tcdGV4dHtzd2VldCxBcHBsZX19ICY9IFxzcXJ0ezAuNjd9IFxhcHByb3ggMC44Mg0KXGVuZHthbGlnbn0NCg0KDQoNCiogKipGb3IgT3JhbmdlcyArIFdlaWdodDoqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBcbXVfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcZnJhY3sxMzAgKyAxNDB9ezJ9ID0gMTM1IFxcDQogICAgXHNpZ21hXjJfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcZnJhY3soMTMwLTEzNSleMiArICgxNDAtMTM1KV4yfXsyfSBcXA0KICAgICY9IFxmcmFjezI1ICsgMjV9ezJ9ID0gMjUgXFwNCiAgICBcc2lnbWFfe1x0ZXh0e3dlaWdodCxPcmFuZ2V9fSAmPSBcc3FydHsyNX0gPSA1DQogICAgXGVuZHthbGlnbn0NCg0KDQoqICoqRm9yIE9yYW5nZXMgKyBTd2VldG5lc3M6KioNCg0KDQpcYmVnaW57YWxpZ259DQogICAgXG11X3tcdGV4dHtzd2VldCxPcmFuZ2V9fSAmPSBcZnJhY3s4ICsgN317Mn0gPSA3LjUgXFwNCiAgICBcc2lnbWFeMl97XHRleHR7c3dlZXQsT3JhbmdlfX0gJj0gXGZyYWN7KDgtNy41KV4yICsgKDctNy41KV4yfXsyfSBcXA0KICAgICY9IFxmcmFjezAuMjUgKyAwLjI1fXsyfSA9IDAuMjUgXFwNCiAgICBcc2lnbWFfe1x0ZXh0e3N3ZWV0LE9yYW5nZX19ICY9IFxzcXJ0ezAuMjV9ID0gMC41DQpcZW5ke2FsaWdufQ0KDQoNCioqU3RlcCAzOiBNYWtlIGEgUHJlZGljdGlvbiBmb3IgYSBOZXcgRnJ1aXQqKjogR2l2ZW4gYSAqKk5ldyBmcnVpdCoqIHdpdGggV2VpZ2h0ID0gMTQ1ZyBhbmQgU3dlZXRuZXNzID0gNi41LiBUaGUgb2JqZWN0aXZlIGlzIHRvIHVzZSAqKk5haXZlIEJheWVzKiogdG8gcHJlZGljdCB3aGV0aGVyIHRoaXMgZnJ1aXQgaXMgKipBcHBsZSoqIG9yICoqT3JhbmdlKiouIFRvIHByb2NlZWQsIHdlIGNhbGN1bGF0ZSBjYXRlZ29yeSBwcm9iYWJpbGl0aWVzIGJhc2VkIG9uIHRoZSBnaXZlbiBpbmZvcm1hdGlvbiBvZiB0aGUgbmV3IGZydWl0IGluIHRoZSBmb2xsb3dpbmc6DQoNCiogKipDYWxjdWxhdGUgTGlrZWxpaG9vZHMgdXNpbmcgR2F1c3NpYW4gUERGKioNCg0KJCQNClAoeCBcbWlkIFx0ZXh0e2NsYXNzfSkgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fSBcZXhwXGxlZnQoLVxmcmFjeyh4IC0gXG11KV4yfXsyXHNpZ21hXjJ9XHJpZ2h0KQ0KJCQNCg0KKiAqKkZvciBBcHBsZToqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBQKFx0ZXh0e1dlaWdodH09MTQ1IFxtaWQgXHRleHR7QXBwbGV9KSAmPSBcbWF0aGNhbHtOfSgxNDU7IFxtdT0xNjAsIFxzaWdtYV4yPTY2LjY3KSBcYXBwcm94IDAuMDM1IFxcDQogICAgUChcdGV4dHtTd2VldG5lc3N9PTYuNSBcbWlkIFx0ZXh0e0FwcGxlfSkgJj0gXG1hdGhjYWx7Tn0oNi41OyBcbXU9NSwgXHNpZ21hXjI9MC42NykgXGFwcHJveCAwLjEzOSBcXA0KICAgIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e0FwcGxlfSkgJj0gMC4wMzUgXHRpbWVzIDAuMTM5ID0gMC4wMDQ4NjUNClxlbmR7YWxpZ259DQoNCg0KKiAqKkZvciBPcmFuZ2U6KioNCg0KDQpcYmVnaW57YWxpZ259DQogICAgUChcdGV4dHtXZWlnaHR9PTE0NSBcbWlkIFx0ZXh0e09yYW5nZX0pICY9IFxtYXRoY2Fse059KDE0NTsgXG11PTEzNSwgXHNpZ21hXjI9MjUpIFxhcHByb3ggMC4wMTA4IFxcDQogICAgUChcdGV4dHtTd2VldG5lc3N9PTYuNSBcbWlkIFx0ZXh0e09yYW5nZX0pICY9IFxtYXRoY2Fse059KDYuNTsgXG11PTcuNSwgXHNpZ21hXjI9MC4yNSkgXGFwcHJveCAwLjQ4NCBcXA0KICAgIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e09yYW5nZX0pICY9IDAuMDEwOCBcdGltZXMgMC40ODQgPSAwLjAwNTIyNw0KXGVuZHthbGlnbn0NCg0KDQoqKlN0ZXAgNDogQXBwbHkgQmF5ZXMnIFRoZW9yZW0qKg0KDQoqICoqUG9zdGVyaW9yIFByb2JhYmlsaXRpZXMgKElnbm9yaW5nIERlbm9taW5hdG9yKToqKg0KDQoNClxiZWdpbnthbGlnbn0NCiAgICBQKFx0ZXh0e0FwcGxlfSBcbWlkIFx0ZXh0e2RhdGF9KSAmXHByb3B0byBQKFx0ZXh0e0FwcGxlfSkgXHRpbWVzIFx0ZXh0e0xpa2VsaWhvb2R9KFx0ZXh0e0FwcGxlfSkgXFwNCiAgICAmPSAwLjYgXHRpbWVzIDAuMDA0ODY1ID0gXG1hdGhiZnswLjAwMjkxOX0gXFxbNnB0XQ0KICAgIFAoXHRleHR7T3JhbmdlfSBcbWlkIFx0ZXh0e2RhdGF9KSAmXHByb3B0byBQKFx0ZXh0e09yYW5nZX0pIFx0aW1lcyBcdGV4dHtMaWtlbGlob29kfShcdGV4dHtPcmFuZ2V9KSBcXA0KICAgICY9IDAuNCBcdGltZXMgMC4wMDUyMjcgPSBcbWF0aGJmezAuMDAyMDkxfQ0KXGVuZHthbGlnbn0NCg0KDQoqICoqTm9ybWFsaXplOioqDQoNCg0KXGJlZ2lue2FsaWdufQ0KICAgIFx0ZXh0e1RvdGFsfSAmPSAwLjAwMjkxOSArIDAuMDAyMDkxID0gMC4wMDUwMSBcXFs2cHRdDQogICAgUChcdGV4dHtBcHBsZX0gXG1pZCBcdGV4dHtkYXRhfSkgJj0gXGZyYWN7MC4wMDI5MTl9ezAuMDA1MDF9IFxhcHByb3ggXG1hdGhiZns1OC4zXCV9IFxcWzZwdF0NCiAgICBQKFx0ZXh0e09yYW5nZX0gXG1pZCBcdGV4dHtkYXRhfSkgJj0gXGZyYWN7MC4wMDIwOTF9ezAuMDA1MDF9IFxhcHByb3ggXG1hdGhiZns0MS43XCV9DQpcZW5ke2FsaWdufQ0KDQoNCioqUHJlZGljdGlvbioqOiA8Zm9udCBjb2xvciA9ICJyZWQiPioqQXBwbGUqKjwvZm9udD4gKGhpZ2hlciBwcm9iYWJpbGl0eSkNCg0KXA0KDQojIyBTZW1pcGFyYW1ldHJpYyBOYWl2ZSBCYXllcw0KDQpXaGVuIGZlYXR1cmUgdmFyaWFibGVzIGluY2x1ZGUgYm90aCBjYXRlZ29yaWNhbCBhbmQgbnVtZXJpY2FsIGZlYXR1cmVzLCAgKipuYWl2ZSBCYXllcyoqIGlzIGEgbmF0dXJhbCBzZW1pcGFyYW1ldHJpYyBtb2RlbC4gVGhlIGZvbGxvd2luZyBpcyBhIG51bWVyaWNhbCBleGFtcGxlLg0KDQoqKkV4YW1wbGUgLSBFbWFpbCBTcGFtIERldGVjdGlvbiB3aXRoIE5haXZlIEJheWVzKio6IENsYXNzaWZ5IGVtYWlscyBhcyBcdGV4dGJme1NwYW0gKDEpfSBvciBcdGV4dGJme05vdCBTcGFtICgwKX0gdXNpbmc6DQoNCiogKipTZW5kZXIgRG9tYWluKiogKGNhdGVnb3JpY2FsKTogJFx7XHRleHR7Z21haWx9LCBcdGV4dHt3b3JrfSwgXHRleHR7dW5rbm93bn1cfSQNCg0KKiAqKkVtYWlsIExlbmd0aCoqIChjb250aW51b3VzKTogTnVtYmVyIG9mIGNoYXJhY3RlcnMgaW4gZW1haWwgYm9keQ0KDQpOZXh0IGZldyBzdGVwcyBpbGx1c3RyYXRlIHRoZSBwcm9jZXNzIG9mIHRyYWluaW5nIHRoZSAqKk5haXZlIEJheWVzKiogbW9kZWwgYW5kIHVzZSB0aGUgdHJhaW5lZCAqKm5haXZlIEJheWVzKiogdG8gbWFrZSBwcmVkaWN0aW9uLg0KDQoqKlN0ZXAgMS4gVHJhaW5pbmcgRGF0YXNldCoqDQoNCg0KfCBFbWFpbCB8IFNlbmRlciBEb21haW4gKCRYXzEkKSB8IEVtYWlsIExlbmd0aCAoJFhfMiQpIHwgQ2xhc3MgKCRZJCkgfA0KfDotLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tfA0KfCAxIHwgIGdtYWlsIHwgIDI1MCB8ICAwIChOb3QgU3BhbSkgfCANCnwgMiB8ICB3b3JrIHwgIDEyMCB8ICAwIHwgDQp8IDMgfCAgdW5rbm93biB8ICA1MDAgfCAgMSAoU3BhbSkgfCANCnwgNCB8ICBnbWFpbCB8ICAzMDAgfCAgMCB8IA0KfCA1IHwgIHVua25vd24gfCAgNDUwIHwgIDEgfCANCnwgNiB8ICB3b3JrIHwgIDE4MCB8ICAwIHwgDQp8IDcgfCAgdW5rbm93biB8ICA0MDAgfCAgMSB8IA0KfCA4IHwgIGdtYWlsIHwgIDI4MCB8ICAwIHwgDQoNCg0KDQoqKlN0ZXAgMi4gUHJpb3JzIENhbGN1bGF0aW9uKioNCg0KJCQNClAoWT0wKSA9IFxmcmFjezV9ezh9ID0gMC42MjUNCiQkDQoNCiQkDQpQKFk9MSkgPSBcZnJhY3szfXs4fSA9IDAuMzc1DQokJA0KDQoqKlN0ZXAgMy4gQ2F0ZWdvcmljYWwgRmVhdHVyZSBMaWtlbGlob29kcyAoU2VuZGVyIERvbWFpbikqKg0KDQoqICoqRm9yICRZPTAkIChOb3QgU3BhbSk6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfSB8IFk9MCkgJj0gMi81ID0gMC40IFxcDQpQKFhfMT1cdGV4dHt3b3JrfSB8IFk9MCkgJj0gMi81ID0gMC40IFxcDQpQKFhfMT1cdGV4dHt1bmtub3dufSB8IFk9MCkgJj0gMS81ID0gMC4yDQpcZW5ke2FsaWduKn0NCg0KKiAqKkZvciAkWT0xJCAoU3BhbSk6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfSB8IFk9MSkgJj0gMC8zID0gMCBcXA0KUChYXzE9XHRleHR7d29ya30gfCBZPTEpICY9IDAvMyA9IDAgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259IHwgWT0xKSAmPSAzLzMgPSAxDQpcZW5ke2FsaWduKn0NCg0KKiAqKldpdGggTGFwbGFjZSBTbW9vdGhpbmcgKCRcYWxwaGE9MSQpOioqIFRvIGF2b2lkIHplcm8gcHJvYmFiaWxpdHkgb2YgZW1wdHkgc3ViY2F0ZWdvcmllcywgd2UgYWRkIGEgc21hbGwgY29uc3RhbnQuDQoNCiQkDQpQKFhfMT1rfFk9YykgPSBcZnJhY3tcdGV4dHtjb3VudH0oayxjKSArIFxhbHBoYX17XHRleHR7Y291bnR9KGMpICsgXGFscGhhIFx0aW1lcyBcdGV4dHtudW1cX2NhdGVnb3JpZXN9fQ0KJCQNCg0KMyBjYXRlZ29yaWVzOiAkXHtcdGV4dHtnbWFpbH0sIFx0ZXh0e3dvcmt9LCBcdGV4dHt1bmtub3dufVx9JA0KDQoNCiogKipGb3IgJFk9MCQ6KioNCg0KXGJlZ2lue2FsaWduKn0NClAoWF8xPVx0ZXh0e2dtYWlsfXxZPTApICY9ICgyKzEpLyg1KzMpID0gMy84ID0gMC4zNzUgXFwNClAoWF8xPVx0ZXh0e3dvcmt9fFk9MCkgJj0gKDIrMSkvKDUrMykgPSAzLzggPSAwLjM3NSBcXA0KUChYXzE9XHRleHR7dW5rbm93bn18WT0wKSAmPSAoMSsxKS8oNSszKSA9IDIvOCA9IDAuMjUNClxlbmR7YWxpZ24qfQ0KDQoqICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMT1cdGV4dHtnbWFpbH18WT0xKSAmPSAoMCsxKS8oMyszKSA9IDEvNiBcYXBwcm94IDAuMTY3IFxcDQpQKFhfMT1cdGV4dHt3b3JrfXxZPTEpICY9ICgwKzEpLygzKzMpID0gMS82IFxhcHByb3ggMC4xNjcgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259fFk9MSkgJj0gKDMrMSkvKDMrMykgPSA0LzYgXGFwcHJveCAwLjY2Nw0KXGVuZHthbGlnbip9DQoNCioqU3RlcCA0LiBDb250aW51b3VzIEZlYXR1cmUgKEdhdXNzaWFuKSAtIEVtYWlsIExlbmd0aCoqDQoNCiogKipGb3IgJFk9MCQ6KioNCg0KXGJlZ2lue2FsaWduKn0NClxtdV8wICY9IFxmcmFjezI1MCsxMjArMzAwKzE4MCsyODB9ezV9ID0gXGZyYWN7MTEzMH17NX0gPSAyMjYgXFwNClxzaWdtYV8wXjIgJj0gXGZyYWN7KDI1MC0yMjYpXjIrKDEyMC0yMjYpXjIrKDMwMC0yMjYpXjIrKDE4MC0yMjYpXjIrKDI4MC0yMjYpXjJ9ezR9IFxcDQomPSBcZnJhY3syNDQyMH17NH0gPSA2MTA1IFxcDQpcc2lnbWFfMCAmPSBcc3FydHs2MTA1fSBcYXBwcm94IDc4LjEzDQpcZW5ke2FsaWduKn0NCg0KDQoqICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpcbXVfMSAmPSBcZnJhY3s1MDArNDUwKzQwMH17M30gPSBcZnJhY3sxMzUwfXszfSA9IDQ1MCBcXA0KXHNpZ21hXzFeMiAmPSBcZnJhY3soNTAwLTQ1MCleMisoNDUwLTQ1MCleMisoNDAwLTQ1MCleMn17Mn0gPSBcZnJhY3s1MDAwfXsyfSA9IDI1MDAgXFwNClxzaWdtYV8xICY9IFxzcXJ0ezI1MDB9ID0gNTANClxlbmR7YWxpZ24qfQ0KDQoqKlN0ZXAgNS4gR2F1c3NpYW4gUHJvYmFiaWxpdHkgRGVuc2l0eSBGdW5jdGlvbioqDQoNCiQkDQpQKFhfMj14fFk9YykgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hX2NeMn19IFxleHBcbGVmdCgtXGZyYWN7KHgtXG11X2MpXjJ9ezJcc2lnbWFfY14yfVxyaWdodCkNCiQkDQoNCioqU3RlcCA2LiBDbGFzc2lmaWNhdGlvbiBFeGFtcGxlKioNCg0KTm93LCB3ZSBoYXZlIGFuIGluY29taW5nICoqTmV3IGVtYWlsKiogd2l0aCBmZWF0dXJlczogU2VuZGVyID0gInVua25vd24iLCBMZW5ndGggPSA0ODAgY2hhcmFjdGVycy4gV2Ugd2FudCB0byB1c2UgKipuYWl2ZSBCYXllcyoqIHRvIGNsYXNzaWZ5IGl0IGludG8gZWl0aGVyICoqU3BhbSoqIG9yICoqTm90IFNwYW0qKi4NCg0KVGhlIGNhbGN1bGF0aW9uIGlzIGRpdmlkZWQgaW4gdGhlIGZvbGxvd2luZyBzdGVwcyBhcyBkZXNjcmliZWQgZWFybGllcjoNCg0KKiAqKlN0ZXAgMTogTGlrZWxpaG9vZCBmb3IgY2F0ZWdvcmljYWwgZmVhdHVyZSoqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMT1cdGV4dHt1bmtub3dufXxZPTApICY9IDAuMjUgXFwNClAoWF8xPVx0ZXh0e3Vua25vd259fFk9MSkgJj0gMC42NjcNClxlbmR7YWxpZ24qfQ0KDQoqICoqU3RlcCAyOiBMaWtlbGlob29kIGZvciBjb250aW51b3VzIGZlYXR1cmUgKHVzaW5nIEdhdXNzaWFuIFBERikqKg0KICArICoqRm9yICRZPTAkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMj00ODB8WT0wKSAmPSBcZnJhY3sxfXtcc3FydHsyXHBpIFx0aW1lcyA2MTA1fX0gXGV4cFxsZWZ0KC1cZnJhY3soNDgwLTIyNileMn17MiBcdGltZXMgNjEwNX1ccmlnaHQpIFxcDQomPSBcZnJhY3sxfXsxOTUuNzd9IFxleHBcbGVmdCgtXGZyYWN7NjQ1MTZ9ezEyMjEwfVxyaWdodCkgXFwNCiY9IDAuMDA1MTEgXHRpbWVzIFxleHAoLTUuMjg1KSBcXA0KJj0gMC4wMDUxMSBcdGltZXMgMC4wMDUwNyBcYXBwcm94IDIuNTkgXHRpbWVzIDEwXnstNX0NClxlbmR7YWxpZ24qfQ0KDQogICArICoqRm9yICRZPTEkOioqDQoNClxiZWdpbnthbGlnbip9DQpQKFhfMj00ODB8WT0xKSAmPSBcZnJhY3sxfXtcc3FydHsyXHBpIFx0aW1lcyAyNTAwfX0gXGV4cFxsZWZ0KC1cZnJhY3soNDgwLTQ1MCleMn17MiBcdGltZXMgMjUwMH1ccmlnaHQpIFxcDQomPSBcZnJhY3sxfXsxMjUuNjZ9IFxleHBcbGVmdCgtXGZyYWN7OTAwfXs1MDAwfVxyaWdodCkgXFwNCiY9IDAuMDA3OTYgXHRpbWVzIFxleHAoLTAuMTgpIFxcDQomPSAwLjAwNzk2IFx0aW1lcyAwLjgzNSBcYXBwcm94IDAuMDA2NjUNClxlbmR7YWxpZ24qfQ0KDQoqICoqU3RlcCAzOiBQb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyAoaWdub3JpbmcgZGVub21pbmF0b3IpKioNCg0KXGJlZ2lue2FsaWduKn0NClAoWT0wfFgpICZccHJvcHRvIFAoWT0wKSBcdGltZXMgUChYXzF8WT0wKSBcdGltZXMgUChYXzJ8WT0wKSBcXA0KJj0gMC42MjUgXHRpbWVzIDAuMjUgXHRpbWVzIDIuNTkgXHRpbWVzIDEwXnstNX0gXGFwcHJveCA0LjA1IFx0aW1lcyAxMF57LTZ9IFxcWzAuNWVtXQ0KUChZPTF8WCkgJlxwcm9wdG8gUChZPTEpIFx0aW1lcyBQKFhfMXxZPTEpIFx0aW1lcyBQKFhfMnxZPTEpIFxcDQomPSAwLjM3NSBcdGltZXMgMC42NjcgXHRpbWVzIDAuMDA2NjUgXGFwcHJveCAwLjAwMTY2DQpcZW5ke2FsaWduKn0NCg0KKiAqKlN0ZXAgNDogTm9ybWFsaXplKioNCg0KXGJlZ2lue2FsaWduKn0NClx0ZXh0e1N1bX0gJj0gNC4wNSBcdGltZXMgMTBeey02fSArIDAuMDAxNjYgXGFwcHJveCAwLjAwMTY2NCBcXFswLjVlbV0NClAoWT0wfFgpICY9IFxmcmFjezQuMDUgXHRpbWVzIDEwXnstNn19ezAuMDAxNjY0fSBcYXBwcm94IDAuMDAyNCBcXFswLjVlbV0NClAoWT0xfFgpICY9IFxmcmFjezAuMDAxNjZ9ezAuMDAxNjY0fSBcYXBwcm94IDAuOTk3Ng0KXGVuZHthbGlnbip9DQoNCg0KPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipQcmVkaWN0aW9uKio6PC9mb250PiAqKlNwYW0gKCRZPTEkKSoqIHdpdGggOTkuNzZcJSBjb25maWRlbmNlDQoNCg0KDQoqKktleSBOYWl2ZSBCYXllcyBBc3N1bXB0aW9ucyoqDQoNCiogKipGZWF0dXJlIEluZGVwZW5kZW5jZSoqOiBBc3N1bWVzIHNlbmRlciBkb21haW4gYW5kIGVtYWlsIGxlbmd0aCBhcmUgaW5kZXBlbmRlbnQgZ2l2ZW4gdGhlIGNsYXNzDQoqICoqR2F1c3NpYW4qKjogRW1haWwgbGVuZ3RoIGZvbGxvd3Mgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoaW4gZWFjaCBjbGFzcw0KKiAqKkNhdGVnb3JpY2FsKio6IFNlbmRlciBkb21haW4gcHJvYmFiaWxpdGllcyBlc3RpbWF0ZWQgd2l0aCBzbW9vdGhpbmcNCiogKipOYWl2ZSoqOiBKb2ludCBwcm9iYWJpbGl0eSA9IHByb2R1Y3Qgb2YgaW5kaXZpZHVhbCBmZWF0dXJlIHByb2JhYmlsaXRpZXMNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KIyBOb24tQ29uanVnYXRlIEJheWVzaWFuIEluZmVyZW5jZQ0KDQpJbiBtYW55IHJlYWwtd29ybGQgbW9kZWxzLCBjb25qdWdhdGUgcHJpb3JzIGFyZSBub3QgYXZhaWxhYmxlIG9yIGFwcHJvcHJpYXRlLiANCg0KKipFeGFtcGxlcyoqOg0KDQoNCiogTG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIEdhdXNzaWFuIHByaW9yIG9uIGNvZWZmaWNpZW50cy4NCg0KKiBDb21wbGV4IGhpZXJhcmNoaWNhbCBtb2RlbHMuDQoNCiogQ3VzdG9tIGxpa2VsaWhvb2QtcHJpb3IgY29tYmluYXRpb25zLg0KDQoNCioqU29sdXRpb24gYXBwcm9hY2hlcyoqOg0KDQoNCiogKipNYXJrb3YgQ2hhaW4gTW9udGUgQ2FybG8gKE1DTUMpKio6IFNhbXBsZSBmcm9tIHBvc3RlcmlvciAoZS5nLiwgR2liYnMgc2FtcGxpbmcsIE1ldHJvcG9saXMtSGFzdGluZ3MpLg0KDQoqICoqVmFyaWF0aW9uYWwgSW5mZXJlbmNlKio6IEFwcHJveGltYXRlIHBvc3RlcmlvciB3aXRoIGEgc2ltcGxlciBkaXN0cmlidXRpb24uDQoNCiogKipMYXBsYWNlIGFwcHJveGltYXRpb24qKjogR2F1c3NpYW4gYXBwcm94aW1hdGlvbiBhcm91bmQgcG9zdGVyaW9yIG1vZGUuDQoNCg0KTm9uLWNvbmp1Z2F0ZSBtZXRob2RzIGFyZSBtb3JlIGZsZXhpYmxlIGJ1dCBjb21wdXRhdGlvbmFsbHkgaW50ZW5zaXZlLCBlbmFibGVkIGJ5IG1vZGVybiBzb2Z0d2FyZSAoU3RhbiwgUHlNQywgSkFHUykuDQoNCg0KIyBTdW1tYXJ5DQoNCiogKipDb25qdWdhdGUgQmF5ZXMqKjogRW5hYmxlcyBleGFjdCwgY2xvc2VkLWZvcm0gcG9zdGVyaW9yIHVwZGF0ZXM7IGlkZWFsIGZvciBzaW1wbGUgbW9kZWxzIHdpdGggc3VpdGFibGUgbGlrZWxpaG9vZC1wcmlvciBwYWlycy4NCg0KKiAqKk5hw692ZSBCYXllcyoqOiBBIGZhc3QsIHNjYWxhYmxlIGNsYXNzaWZpZXIgbGV2ZXJhZ2luZyBjb25kaXRpb25hbCBpbmRlcGVuZGVuY2U7IEdhdXNzaWFuIE5hw692ZSBCYXllcyBleHRlbmRzIHRvIGNvbnRpbnVvdXMgZmVhdHVyZXMuDQoNCiogKipOb24tY29uanVnYXRlIGluZmVyZW5jZSoqOiBVc2VzIG51bWVyaWNhbCBtZXRob2RzIHRvIGFwcHJveGltYXRlIHBvc3RlcnMgZm9yIGNvbXBsZXggbW9kZWxzLCBlc3NlbnRpYWwgZm9yIG1vZGVybiBCYXllc2lhbiBkYXRhIGFuYWx5c2lzLg0KDQoNCg0KDQo=