1 Introduction

We have briefly introduced the simple linear regression model earlier with an explicit expression.

\[ y = \beta_0 + \beta_1 x + \epsilon, \]

Where \(y\) is a continuous random numerical variable, \(x\) is either a numerical variable or a binary categorical variable, and \(\epsilon \rightarrow N(0, \sigma)\), the basic applications of a simple linear regression model are twofold:

  1. Assess the linear correlation between the response variable (\(y\)) and the predictor variable (\(x\)).

  2. Predict the response for given new values of the predictor variable \(x\).

In general, regression modeling is an iterative process in real-world applications, as illustrated in the following chart.

In the course project and data analysis, we focus on the iterative loop of model identification and reporting on the final model. To be more specific, assuming we have an analytic data set that is ready for modeling,

  • Select appropriate candidate models to address the practical questions - This includes checking model assumptions and ensuring the analytic dataset contains sufficient information for the candidate models. We have highlighted all assumptions when introducing new models in the previous notes.

  • Fit candidate models to the data - This step involves verifying the outputs to ensure the model parameters (e.g., coefficients) are appropriately estimated.

Note: the fitted models in this step may not be valid or optimal, we should not interpret the model at this point. We only report the final model obtained from the iterative model identification process.

  • Model diagnostics - This is the most crucial step in any regression analysis, where we assess whether all assumptions of the candidate models are satisfied. For example, we apply residual diagnostic methods (commonly used in linear regression) to evaluate linearity, normality, homoscedasticity (constant variance), and other key assumptions. If no violations are detected, we then use application-specific performance measures to select the best model for reporting and implementation.

  • Model remedy and refinement - If one or more assumptions are violated, we need to use various methods to fix the problems. We will not discuss this major topic in this class, but will cover this critical topic in detail in subsequent courses.

  • Enter the refined/modified model into the loop for the next iteration - The refined or modified model will be refitted, analyzed, and diagnosed to determine whether any violations remain. This process continues iteratively until the final valid and optimal model is identified.

  • Final model reporting - This topic will not be emphasized in this class but will be highlighted in subsequent statistical modeling classes.

In this note, we will extend simple linear regression to multiple linear regression by incorporating two or more predictor variables into the model. We begin by revisiting the simple linear regression model discussed earlier this semester. Next, we will generalize the binary categorical predictor to multi-category predictors through the use of binary indicator variables – effectively creating a special case of multiple linear regression with multiple binary categorical variables. This approach integrates ANOVA analysis into the regression framework.


2 Simple Linear Regression Revisited

The term simple linear regression (SLR) simply means that the regression equation has the form \(y = \beta_0 + \beta_1 x + \epsilon\). The predictor variable is either a continuous variable or a binary categorical variable that takes only two possible distinct values, such as success vs failure, disease vs disease-free, etc. The response must be a continuous normal variable whose mean may be influenced by the predictor \(x\) but not the variance.

The key assumptions for SLR are

  • linearity: linear relationship between \(y\) and \(x\);
    • diagnostic check: scatter plot of \(x\) and \(y\)
  • deterministic predictor \(x\): the predictor variable is not a random variable.
    • No direct information, check this assumption
  • normality: the only random variable \(y\) is a normal random variable with density function \(N(\beta+0 + \beta_1 x, \sigma)\), or \(\epsilon \rightarrow N(0, \sigma)\).
    • diagnostic check: Q-Q plot
  • constant variance: this assumption is contained in the above normality assumption.
    • diagnostic check: residual plot, studentized residual plot
  • Influential observations: This is also related to the normality assumption
    • diagnostic check: leverage plot (Cook’s distance)

2.1 SLR with A Continuous Predictor

When the predictor variable is continuous, the interpretation of the slope \(\beta_1\) reflects the change in \(y\) when \(x\) increases by one unit. The sign of \(\beta_1\) reflects the direction of linear association between \(x\) and \(y\). Next, we use a numerical example to illustrate the regression modeling process. The data set can be found at https://pengdsci.github.io/STA200/dataset/EduWage.csv. The R function lm() will be used to perform regression analysis.

The variables in the data set are defined as

  • wage: average hourly earnings
  • educ: years of education
  • exper: years potential experience
  • tenure: years with current employer
  • lwage: log(wage) - in economics, it is called log wage.
  • region: the geographic region of the respondent
  • smsa: A Standard Metropolitan Statistical Area (SMSA) is a geographical region defined by the U.S. Office of Management and Budget that consists of a core urban area with a substantial population, along with adjacent communities that have a high degree of economic and social integration with that core. SMSAs are used for statistical purposes to analyze urbanization, population density, and economic activities in metropolitan areas, providing insights into urban data trends.

Step 1: Load data and explore the dataset.

## Load the dataset
edu.wage <- read.csv("https://pengdsci.github.io/STA200/dataset/EduWage.csv")
## summary of variables in the dataset
summary(edu.wage)
|       wage             educ           exper           tenure      
|  Min.   : 0.530   Min.   : 0.00   Min.   : 1.00   Min.   : 0.000  
|  1st Qu.: 3.330   1st Qu.:12.00   1st Qu.: 5.00   1st Qu.: 0.000  
|  Median : 4.650   Median :12.00   Median :13.50   Median : 2.000  
|  Mean   : 5.896   Mean   :12.56   Mean   :17.02   Mean   : 5.105  
|  3rd Qu.: 6.880   3rd Qu.:14.00   3rd Qu.:26.00   3rd Qu.: 7.000  
|  Max.   :24.980   Max.   :18.00   Max.   :51.00   Max.   :44.000  
|      lwage            region               smsa       
|  Min.   :-0.6349   Length:526         Min.   :0.0000  
|  1st Qu.: 1.2030   Class :character   1st Qu.:0.0000  
|  Median : 1.5369   Mode  :character   Median :1.0000  
|  Mean   : 1.6233                      Mean   :0.7224  
|  3rd Qu.: 1.9286                      3rd Qu.:1.0000  
|  Max.   : 3.2181                      Max.   :1.0000

The R function summary(dataset.name) returns a five-number summary of all numerical variables in the dataset. There is a categorical variable region in the dataset. To see the distribution of categorical variables, we use the R function table(variable.name) to see the frequency distribution of the categorical variables.

table(edu.wage$region)
| 
| northcen    other    south     west 
|      132      118      187       89

Step 2: objective and candidate model - we examine whether education affects the wage. The candidate model to address this objective will be the simple linear regression model. We first make a scatter plot of educ (horizontal axis) and wage (vertical axis).

plot(edu.wage$educ,                 # horizontal axis
     edu.wage$wage,                 # vertical axis
     xlab = "Years of Education",   # horizontal label
     ylab = "Hourly Wage",          # vertical label
     main = "Scatter Plot of Edu vs Wage"    # title of the plot
     )

The above plot shows a linear relationship but also shows non-constant variance. This violates the SLR assumption. Economic studies show that logarithmic wage has less variation. We next try to log wages in the SLR. Before building the model, we make a scatter plot of log wage vs years of education.

plot((edu.wage$educ)[-1],                 # horizontal axis
     (edu.wage$lwage)[-1],                 # vertical axis
     xlab = "Years of Education",   # horizontal label
     ylab = "Hourly log(Wage)",          # vertical label
     main = "Scatter Plot of Edu vs log(Wage)"    # title of the plot
     )

The above scatter indicates that the log wage is a better response for SLR.

Step 3: Fitting SLR: \(\text{log wage} = \beta_0 + \beta_1 \text{educ}\) and perform residual diagnostics.

## linear model
lgw.model <- lm(lwage ~ educ, data = edu.wage)
## residual plot
par(mfrow=c(2,2))    # create a graphic grid with 4 graphical cells 
plot(lgw.model)

Interpretations of Residual Diagnostic Plots:

  • Residual vs Fitted - shows a minor violation of the assumption of constant variance (the variance increases as the fitted value increases)
  • Q_Q Residual Plot - There is no significant violation of the normal distribution
  • Scale-Location Plot - no serious violation except a few outliers (not influential)
  • Residuals-Leverage - shows no influential points.

Overall, there is a minor violation of the constant variance assumption. We will learn methods in subsequent courses to refine the model. For illustration, we decided to report the above model.

Step 4 - summarize the log wage model

summary(lgw.model)
| 
| Call:
| lm(formula = lwage ~ educ, data = edu.wage)
| 
| Residuals:
|      Min       1Q   Median       3Q      Max 
| -2.21158 -0.36393 -0.07263  0.29712  1.52339 
| 
| Coefficients:
|             Estimate Std. Error t value Pr(>|t|)    
| (Intercept) 0.583773   0.097336   5.998 3.74e-09 ***
| educ        0.082744   0.007567  10.935  < 2e-16 ***
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
| 
| Residual standard error: 0.4801 on 524 degrees of freedom
| Multiple R-squared:  0.1858,  Adjusted R-squared:  0.1843 
| F-statistic: 119.6 on 1 and 524 DF,  p-value: < 2.2e-16

Brief Report:

The estimated slope coefficient \(\hat{\beta}_1 = 0.082744\) indicates that log wage increases by 0.082744 for each additional year of education (\(p \approx 0\)). The coefficient of determination \(R^2 \approx 0.1858\) shows that the log wage and years of education have a weak linear correlation.

Remarks: Here are a few comments on the general principles of regression analysis

  • In this example, we use only two variables in the data set with more than 2 variables to illustrate how to implement an SLR. In practice, if you have more information (more variables) available in the data, we should use all relevant information - this is the general principle of all data analysis. This means we need to use multiple regression to include two or more predictor variables! We will cover general MLR in the next note.

  • Implication of SLR: An implication of SLR is that all other variables do not affect the response variable \(y\). This also implies that, in general, an SLR can never be an optimal model if it is invalid.

  • Choose an optimal subset of predictors: This means we always start with multiple candidate models in multiple linear regression (MLR) models. For example, if we have two variables \(x_1\) and \(x_2\), we can fit three different first order (in predictor variables) MLR based on the combinations of \(x_1\), \(x_2\), and \(x_1 + x_2\). More on different MLRs will be discussed in the next note.


2.2 SLR with A Binary Predictor

We have discussed the regression approach to the two-sample t-test at the beginning of the semester. Here we use the sample wage dataset and a binary categorical smsa(Standard Metropolitan Statistical Area) to see whether the average wage in rural and urban areas is different.

Recall the assumption in the two-sample test:

  • Wage distributions in both populations (rural and urban populations) are normal, equivalent to the normality assumption on SLR
  • The variances of wages in both populations are unknown but equal, equivalent to the constant variance assumption in SLR.

When using a software program, we have to specify the predictor variable \(x\) to be a factor (categorical variable). In R, the function factor() converts a categorical or discrete numerical variable (with finite distinct values) to a factor variable.

We next implement the SLR with a binary factor variable (smsa) and use log wage lwage as the response.

# lm model
smsa.lm <- lm(lwage ~ factor(smsa), data = edu.wage)
# residual plots
par(mfrow=c(2,2))
plot(smsa.lm)

1. Interpretations of Residual Diagnostic Plots

  • Residual-fitted Values: does not reveal special patterns. The variances of the two groups seem to be similar to each other.
  • Q-Q Plot: No serious violation of the normality assumption was found from the Q-Q plot. Note that there is an outlier in the plot.
  • Scale-location Plot: does not reveal any special pattern except for an outlier (obs N0. 24).
  • Residuals vs Leverage: The Cook’s distance of observation does not have a significant leverage (no influential).

Overall, there is no significant violation of model assumptions. We report the current model in the following:


2. Interpretations of Regression Coefficients

The binary variablesmsa has two values: 0 = rural area, 1 = urban area. In general, a binary variable (taking values 0 and 1) is also commonly called a dummy variable in statistics and regression analysis.

summary(smsa.lm)
| 
| Call:
| lm(formula = lwage ~ factor(smsa), data = edu.wage)
| 
| Residuals:
|     Min      1Q  Median      3Q     Max 
| -2.3240 -0.3700 -0.0797  0.3422  1.5439 
| 
| Coefficients:
|               Estimate Std. Error t value Pr(>|t|)    
| (Intercept)    1.45182    0.04314  33.652  < 2e-16 ***
| factor(smsa)1  0.23732    0.05076   4.676 3.73e-06 ***
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
| 
| Residual standard error: 0.5213 on 524 degrees of freedom
| Multiple R-squared:  0.04005, Adjusted R-squared:  0.03822 
| F-statistic: 21.86 on 1 and 524 DF,  p-value: 3.733e-06
  • (Intercept): \(\hat{\beta}_0 = 1.41518\) is the average log wage of rural area (smsa = 0 is the baseline of the categorical variable sasa).

\[ \log(\text{wage}_{\text{rural}}) = 1.41518 \ \implies \ \text{wage}_{\text{rural}} = e^{ 1.41518} = 4.117228 \]

The above equations convert the log wage to the original wage. That is, the mean wage in rural areas is 4.117228.

  • slope parameter (factor(sasa)1 = level 1 of factor variable smsa =1: urban area): \(\hat{\beta}_1 = 0.23732\) is the difference of the average log wage between the current category (urban area) and the baseline category (rural area). A more practical interpretation of the slope requires some algebra:

\[ \log(\text{wage}_{\text{urban}}) - \log(\text{wage}_{\text{rural}}) = 0.23732 \ \implies \log \frac{\text{wage}_{\text{urban}}}{\text{wage}_{\text{rural}}} = 0.23732 \]

Expanding both sides of the last equation in the above, we have

\[ \frac{\text{wage}_{\text{urban}}}{\text{wage}_{\text{rural}}} = e^{0.23732} = 1.267847 \implies \text{wage}_{\text{urban}}= 1.267847 \times \text{wage}_{\text{rural}}, \]

We re-express the last equation in the above to get

\[ \text{wage}_{\text{urban}} - \text{wage}_{\text{rural}}= 1.267847 \times \text{wage}_{\text{rural}} - \text{wage}_{\text{rural}} = 0.267847\text{wage}_{\text{rural}} \]

Which is equivalent to

\[ \frac{\text{wage}_{\text{urban}} - \text{wage}_{\text{rural}}}{\text{wage}_{\text{rural}}} = 0.267847. \]

This means that the wage in urban area is 26.7847% higher than the rural area..


3. Relationship between SLR and One-way ANOVA

First of all, we can extract a one-way ANOVA table from a linear regression model using the R function anova(lm.object)

anova(smsa.lm)
| Analysis of Variance Table
| 
| Response: lwage
|               Df  Sum Sq Mean Sq F value    Pr(>F)    
| factor(smsa)   1   5.941  5.9406  21.862 3.733e-06 ***
| Residuals    524 142.389  0.2717                      
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The F statistic in the above ANOVA test (with 1 degree of freedom in the numerator and 524 degrees of freedom in the denominator) is

\[ F = 21.862. \]

The t-test statistic in the SLR is a t distribution with 524 degrees of freedom, which is close to the standard normal distribution.

\[ Z \approx T = 4.676. \]

It can be proven that \(t_{\text{d.f}}^2 = F_{1, \ \text{d.f}}\). This means the result of the t-test in SLR and the F-test in the ANOVA procedure are identical. Therefore, the SLR with a binary predictor can the one-way ANOVA is a special SLR!.


3 Linear Regression Approach to One-Way ANOVA

We claimed that one-way ANOVA is a special linear regression model when there is a binary categorical predictor is included in the model. However, a general CRD allows multiple treatments. In this section, we will illustrate how to use linear regression to perform a general one-way ANOVA with multiple treatment groups.

For ease of presentation, we continue using the wage dataset with log wage as the dependent variable and region as a categorical treatment factor (consisting of four groups: South, West, North-Central, and Other). When performing linear regression with a categorical variable that has more than two categories, we must introduce a series of dummy variables to properly represent the multi-category variable.

Why Use Dummy Variables?

  • Encode Categorical Data: They allow categorical variables (nominal or ordinal) to be included in regression models.

  • Avoid Arbitrary Numerical Assignments: Using numbers like 1, 2, 3 for categories implies an order or magnitude, which may not exist (e.g., Red = 1, Green = 2, Blue = 3 falsely suggests that Green is “greater” than Red).

  • Interpretability: Each dummy variable represents the presence (1) or absence (0) of a category, making coefficients easy to interpret. To be more specific, the coefficient of a dummy variable represents the discrepancy between the category associated with the dummy variable and the baseline category.


Steps to Create Dummy Variables from a Multi-Category Variable

  • choose a baseline category: The baseline category serves as a reference, allowing other categories to be compared against it.

    • Most software programs automatically set the baseline as the category with the smallest value (e.g., the first in alphabetical order for categorical variables).
  • Create Dummy Variables: For each non-baseline category, define a dummy variable labeling that category. For example, region = (northcen, other, south, west), the three dummy variables are defined as

    • dummy.other = 1 if lived in other region, 0 if not in other region.
    • dummy.south = 1 if lived in south and 0 if not in south region;
    • dummy.west = 1 if lived in west and 0 if not in west.

In general, a categorical variable has \(k\) categories, and we need to define \(k-1\) dummy variables. For example,

region dummy.other dummy.south dummy.west
south 0 1 0
west 0 0 1
northcen 0 0 0
other 1 0 0
south 0 1 0
  • Interpretation of Dummy Variables in Regression

The coefficients for other, south, and west represent the difference from the reference category (northcen).

  • Dummy variables in R
    • Categorical variable with character values: In this case, R will define dummy variables internally and use the default reference category.
    • Categorical variable with values in numerical form: In this case, we must use R’s factor() function to convert the categorical variable into a factor variable (numeric values will be treated as category labels). R then internally defines dummy variables and selects the baseline category as the one with the smallest numerical label.
    • If the default reference category is not preferred, you can use R’s relevel() function to manually specify a custom baseline category for easier interpretation.
# Example data
data <- data.frame(color = c("Red", "Green", "Blue", "Green", "Red"))

# Set "Green" as the baseline (reference) category
data$color <- factor(data$color)  
data$color <- relevel(data$color, ref = "Green")  

# Check levels (first level is the baseline)
levels(data$color)  # Output: "Green" "Red" "Blue"
| [1] "Green" "Blue"  "Red"


On the Significance of the Categorical Variable:

  • If any of the dummy variables is statistically significant (i.e., p-value < 0.05), the original categorical variable is considered significant.
  • If all dummy variables are statistically insignificant, the original categorical variable is insignificant.
  • If the original categorical variable is insignificant, it should be excluded from the regression model in real real-world application.


In the output of lm(), the F test in the bottom portion provides the significance test of the categorical variable. This F test is the same F test in the one-way ANOVA!!!


An Numerical Example

We use the plant growth dataset to build a regression model with the multi-category predictor group and compare it with a one-way ANOVA procedure. The data set is at <>. We will follow several logical steps to conduct the analysis.

Step 1: fit candidate model and perform diagnostics

## Load the dataset
plant <- read.csv("https://pengdsci.github.io/STA200//dataset/oneWayPlantGrowth.csv")
##
plant.lm <- lm(weight ~ group, data = plant)  # factor(group) will also work
## residual plots
par(mfrow=c(2,2))
plot(plant.lm)

None of the above residual plots shows significant violations of model assumptions except for a few outliers that are not influential. We report the model.

Step 2: Reporting the linear model

summary(plant.lm)
| 
| Call:
| lm(formula = weight ~ group, data = plant)
| 
| Residuals:
|     Min      1Q  Median      3Q     Max 
| -1.0710 -0.4180 -0.0060  0.2627  1.3690 
| 
| Coefficients:
|             Estimate Std. Error t value Pr(>|t|)    
| (Intercept)   5.0320     0.1971  25.527   <2e-16 ***
| grouptrt1    -0.3710     0.2788  -1.331   0.1944    
| grouptrt2     0.4940     0.2788   1.772   0.0877 .  
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
| 
| Residual standard error: 0.6234 on 27 degrees of freedom
| Multiple R-squared:  0.2641,  Adjusted R-squared:  0.2096 
| F-statistic: 4.846 on 2 and 27 DF,  p-value: 0.01591

Interpretation of the output

  • The explicit model formula has only the original group categorical variable with three categories. In fact, the implicit model formula uses dummy variables. In other words, the actual model formula used in the model is \(\text{weight} = \beta_0 + \beta_1 \text{grouptrt1} + \beta_2 \text{grouptrt2}\), where \(\beta_0 = \mu_{\text{ctr}}\), \(\beta_1 = \mu_{\text{trt1}} - \mu_{\text{ctr}}\) and \(\beta_2 = \mu_{\text{trt2}} - \mu_{\text{ctr}}\)

  • The F test in the bottom portion yields a p-value of 0.01591. At a significance level of 0.05, we reject the null hypothesis that region is significant. In other words, this F-test tests the null hypothesis: \(H_0: \beta_1 = \beta_2 = 0\). This equivalent to \(H_0: \mu_{\text{ctr}} = \mu_{\text{trt1}} = \mu_{\text{trt2}}\). This is exactly the F test in the one-way ANOVA! We will extract the one-way ANOVA from the linear model shortly.

  • Interpretation of Regression coefficients: At the significance level of 0.05, neither of the two dummy variables is statistically significant.

    • \(\beta_0 = \mu_{\text{ctr}}\), This represents the mean of the baseline category. The p-value tests the hypothesis \(H_0: \beta_0 = 0\).
    • \(\hat{\beta}_1 = \hat{\mu}_{\text{trt1}} - \hat{\mu}_{\text{ctr}} = -0.3710\): The p-value of 0.1944 corresponds to testing the hypothesis \(H_0: \beta_1 = 0\) (or equivalently, \(H_0: \mu_{\text{trt1}} - \mu_{\text{ctr}} = 0\)). The p-value indicates no statistically significant difference between trt1 and ctr. The negative sign of the estimate suggests that the sample mean of ctr is higher than that of trt1.
    • \(\hat{\beta}_2 = \hat{\mu}_{\text{trt2}} - \hat{\mu}_{\text{ctr}} =0.4940\), The p-value of 0.0877 corresponds to testing the hypothesis \(H_0: \beta_2 = 0\) (or equivalently, \(H_0: \mu_{\text{trt2}} - \mu_{\text{ctr}} = 0\)). The p-value indicates no statistically significant difference between trt2 and ctr. The positive sign of the estimate suggests that the sample mean of trt2 is higher than that of ctr.


Next, we extract the one-way ANOVA table directly from the above linear regression model.

# extract ANOVA table directly from linear regression model
anova(plant.lm)
| Analysis of Variance Table
| 
| Response: weight
|           Df  Sum Sq Mean Sq F value  Pr(>F)  
| group      2  3.7663  1.8832  4.8461 0.01591 *
| Residuals 27 10.4921  0.3886                  
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The F-test from the one-way ANOVA table above is identical to the one reported in the previous regression model. We can also generate the same one-way ANOVA table using R’s built-in functionaov()

The coefficients associated with dummy variables in the regression output represent the difference between the mean of the underlying category and that of the baseline category. That is, \(\hat{\beta}_1 = \hat{\mu}_{\text{trt1}} - \hat{\mu}_{\text{ctr}} = -0.3710\) and \(\hat{\beta}_2 = \hat{\mu}_{\text{trt2}} - \hat{\mu}_{\text{ctr}} =0.4940\). This information is given in Tukey’s HSD (see the output of TukeyHSD())

plant.aov <- aov(weight ~ group, data = plant)
TukeyHSD(plant.aov)
|   Tukey multiple comparisons of means
|     95% family-wise confidence level
| 
| Fit: aov(formula = weight ~ group, data = plant)
| 
| $group
|             diff        lwr       upr     p adj
| trt1-ctrl -0.371 -1.0622161 0.3202161 0.3908711
| trt2-ctrl  0.494 -0.1972161 1.1852161 0.1979960
| trt2-trt1  0.865  0.1737839 1.5562161 0.0120064

The first two estimated differences (trt1 - ctr and trt2 - ctr) correspond to the regression coefficients of the dummy variables in the previous model. The p-values reported in the regression model are unadjusted (based on individual tests), whereas Tukey’s HSD is a group test, and its corresponding p-values are adjusted to control the overall Type I error rate (i.e., to prevent inflation of the false positive rate).


Remarks:

  • The linear regression model used to perform one-way ANOVA has multiple dummy predictor variables in the model formula (although implicitly expressed). In other words, the regression model for the one-way ANOVA is a special multiple linear Regression (MLR) model.

  • Multiple Linear Regression (MLR) maintains the same assumptions as simple linear regression: independent and identically distributed (i.i.d.) observations, deterministic predictors, linearity between response and predictor, normality of residuals, and homoscedasticity (constant variance). Since MLR involves multiple predictor variables, an additional assumption is the absence of high correlations between predictors. Violation of this assumption is referred to as multicollinearity in regression modeling.

  • The reason we encode a categorical variable with k categories into (k-1) dummy variables (rather than k) is to avoid multicollinearity issues. For example, suppose we have a categorical variable Education with 3 levels: High School (baseline/reference), Bachelor’s, and Master’s. If we create 3 dummy variables:

    • D1 = 1 if High School, 0 otherwise
    • D2 = 1 if Bachelor’s, 0 otherwise
    • D3 = 1 if Master’s, 0 otherwise

    This creates perfect multicollinearity because for every observation: D1 + D2 + D3 = 1 (always)!!!

To conclude this section, watch the YouTube video (https://www.youtube.com/watch?v=CMAwKuCw5CM&list=PLfQppi3mzF5nQzSm-RWQnvHFg46GQVK_4&index=4) that focuses on the ANOVA table extracted from the linear regression.



4 Multiple Linear Regression Approach to Two-way ANOVA

This section focuses on linear regression with two categorical variables, each with multiple levels. We have previously learned about two-way ANOVA based on a replicated Randomized Block Design (RBD), which allows for inference on interaction effects. The linear regression model to be discussed will also include an interaction term.

Since the underlying concept is similar to the one-way ANOVA covered in the previous section, the explicit model formula remains relatively simple. However, the implicit model formula for linear regression with two categorical variables (including an interaction effect) is more complex than that of one-way ANOVA. We will use an example to illustrate some key features of multiple linear regression (MLR) involving only categorical variables with an interaction term.

The dataset recorded the yield of different crops under different fertilizers. The two-way data table is given below.

We have used various R commands earlier to convert a two-way data table to an R dataframe for regression modeling. We next use similar code to convert the above table to a dataframe.

## To avoid typing errors, we input the table cell by cell from the data table
crop.data <- data.frame(
  Fertilizer = rep(c("Blend X", "Blend Y", "Blend Z"), each = 20),
  Crop = rep(rep(c("Wheat", "Corn", "Soy", "Rice"), each = 5), times = 3),
  Yield = c(123, 156, 112, 100, 168,   # Blend X - Wheat
            128, 150, 174, 116, 109,   # Blend X - Corn
            166, 178, 187, 133, 195,   # Blend X - Soy
            151, 125, 117, 155, 138,   # Blend X - Rice
            ##
            135, 130, 176, 120, 155,   # Blend Y - Wheat
            175, 132, 120, 187, 184,   # Blend Y - Corn
            140, 145, 159, 131, 126,   # Blend Y - Soy
            167, 188, 142, 167, 168,   # Blend Y - Rice
            ##
            156, 180, 147, 146, 193,   # Blend Z - Wheat
            186, 138, 178, 176, 190,   # Blend Z - Corn
            185, 206, 188, 165, 188,   # Blend Z - Soy
            175, 173, 154, 191, 169)   # Blend Z - Rice
)

# Convert factors to factors (important for modeling)
crop.data$Fertilizer <- as.factor(crop.data$Fertilizer)
crop.data$Crop <- as.factor(crop.data$Crop)

Next, we fit a linear regression model with an interaction term and list the terms (dummy variables) in the implicit internal model formula by using two R functions model.matrix(model.name) and colnames(model.matrix.name). See how these R functions are called in the following code chunk.

## Explicit form is still a simple
crop.lm <- lm(Yield ~ Crop * Fertilizer, data = crop.data)
## model matrix provides all dummy variables implicitly defined in the R
model.mtx <- model.matrix(crop.lm)
## extract the column names of the model matrix ==> list of dummy variables in the
## implicit internal model formula
colnames(model.mtx)
|  [1] "(Intercept)"                 "CropRice"                   
|  [3] "CropSoy"                     "CropWheat"                  
|  [5] "FertilizerBlend Y"           "FertilizerBlend Z"          
|  [7] "CropRice:FertilizerBlend Y"  "CropSoy:FertilizerBlend Y"  
|  [9] "CropWheat:FertilizerBlend Y" "CropRice:FertilizerBlend Z" 
| [11] "CropSoy:FertilizerBlend Z"   "CropWheat:FertilizerBlend Z"

These dummy variables will appear in the output of the regression model in the subsequent model output. Before summarizing the model, we check the model assumptions to see whether significant violations exist using residual diagnostic plots.

par(mfrow = c(2,2))  # define the layout with 2x2 graphical panels
plot(crop.lm)

The residual plots look fine except for a pattern in the Q-Q plot, which indicates the distribution of the residuals is slightly skewed to the left. We will not explore methods of remedies in this class, but they will be discussed in the subsequent classes. Next, we report the results of the models.

summary(crop.lm)
| 
| Call:
| lm(formula = Yield ~ Crop * Fertilizer, data = crop.data)
| 
| Residuals:
|    Min     1Q Median     3Q    Max 
| -39.60 -15.00   0.70  15.45  38.60 
| 
| Coefficients:
|                             Estimate Std. Error t value Pr(>|t|)    
| (Intercept)                  135.400      9.639  14.048  < 2e-16 ***
| CropRice                       1.800     13.631   0.132  0.89549    
| CropSoy                       36.400     13.631   2.670  0.01031 *  
| CropWheat                     -3.600     13.631  -0.264  0.79283    
| FertilizerBlend Y             24.200     13.631   1.775  0.08218 .  
| FertilizerBlend Z             38.200     13.631   2.802  0.00729 ** 
| CropRice:FertilizerBlend Y     5.000     19.277   0.259  0.79646    
| CropSoy:FertilizerBlend Y    -55.800     19.277  -2.895  0.00570 ** 
| CropWheat:FertilizerBlend Y  -12.800     19.277  -0.664  0.50987    
| CropRice:FertilizerBlend Z    -3.000     19.277  -0.156  0.87698    
| CropSoy:FertilizerBlend Z    -23.600     19.277  -1.224  0.22683    
| CropWheat:FertilizerBlend Z   -5.600     19.277  -0.291  0.77269    
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
| 
| Residual standard error: 21.55 on 48 degrees of freedom
| Multiple R-squared:  0.4543,  Adjusted R-squared:  0.3292 
| F-statistic: 3.632 on 11 and 48 DF,  p-value: 0.0008828

Output Interpretations

  • The F-test in the bottom portion of the output indicates that at least one factor (crop or fertilizer or both) is significant ()

  • Intercept - the mean of yields of corn using fertilizer X. i.e., (128 + 150 + 174 + 116 + 109)/5 = 135.4. This is the baseline category, defined by Corn and Blend X. All other categories will be compared to this baseline either directly or indirectly.

    • The coefficients for CropRice, CropSoy, and CropWheat represent the difference in mean yield between these crops and Corn when using Blend X fertilizer.
    • The coefficients for FertilizerBlend Y and FertilizerBlend Z represent the difference in mean yield for Corn when comparing Blend Y and Blend Z to the baseline (Blend X).
    • The coefficients for the interaction terms are not straightforward to interpret because they represent combined effects. Refer to the annotated output and original data table below to understand how these interaction term coefficients were calculated.

As we did with the one-way ANOVA, we can also extract the two-way ANOVA table directly from the linear regression model above.

anova(crop.lm)
| Analysis of Variance Table
| 
| Response: Yield
|                 Df  Sum Sq Mean Sq F value    Pr(>F)    
| Crop             3  2965.7   988.6  2.1282 0.1089382    
| Fertilizer       2  9702.2  4851.1 10.4436 0.0001716 ***
| Crop:Fertilizer  6  5892.6   982.1  2.1143 0.0687635 .  
| Residuals       48 22296.4   464.5                      
| ---
| Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The two-way ANOVA table provides three F-tests for assessing the two individual factors and their interaction effect, whereas the F-test in the regression output only tests whether all factors are jointly insignificant—a global goodness-of-fit measure. From this perspective, the two-way ANOVA F-tests offer more granular insights. However, regression coefficient inference allows for more detailed testing at individual factor levels, as well as for interaction effects between factor levels. Although Tukey’s HSD procedure provides confidence intervals (and family-wise tests for simultaneous comparisons), it does not explicitly account for interaction effects in the multiple comparisons.

## fit an anova model since TukeyHSD() requires the aov() object
crop.aov <- aov(Yield ~ Crop * Fertilizer, data = crop.data)
## HSD calls
TukeyHSD(crop.aov)
|   Tukey multiple comparisons of means
|     95% family-wise confidence level
| 
| Fit: aov(formula = Yield ~ Crop * Fertilizer, data = crop.data)
| 
| $Crop
|                  diff       lwr       upr     p adj
| Rice-Corn    2.466667 -18.47792 23.411252 0.9891976
| Soy-Corn     9.933333 -11.01125 30.877918 0.5910428
| Wheat-Corn  -9.733333 -30.67792 11.211252 0.6069146
| Soy-Rice     7.466667 -13.47792 28.411252 0.7787573
| Wheat-Rice -12.200000 -33.14459  8.744585 0.4163283
| Wheat-Soy  -19.666667 -40.61125  1.277918 0.0728352
| 
| $Fertilizer
|                  diff       lwr      upr     p adj
| Blend Y-Blend X  8.30 -8.183166 24.78317 0.4486138
| Blend Z-Blend X 30.15 13.666834 46.63317 0.0001620
| Blend Z-Blend Y 21.85  5.366834 38.33317 0.0066534
| 
| $`Crop:Fertilizer`
|                              diff         lwr        upr     p adj
| Rice:Blend X-Corn:Blend X     1.8 -45.0050873  48.605087 1.0000000
| Soy:Blend X-Corn:Blend X     36.4 -10.4050873  83.205087 0.2718890
| Wheat:Blend X-Corn:Blend X   -3.6 -50.4050873  43.205087 1.0000000
| Corn:Blend Y-Corn:Blend X    24.2 -22.6050873  71.005087 0.8228174
| Rice:Blend Y-Corn:Blend X    31.0 -15.8050873  77.805087 0.5076482
| Soy:Blend Y-Corn:Blend X      4.8 -42.0050873  51.605087 0.9999999
| Wheat:Blend Y-Corn:Blend X    7.8 -39.0050873  54.605087 0.9999854
| Corn:Blend Z-Corn:Blend X    38.2  -8.6050873  85.005087 0.2115608
| Rice:Blend Z-Corn:Blend X    37.0  -9.8050873  83.805087 0.2506320
| Soy:Blend Z-Corn:Blend X     51.0   4.1949127  97.805087 0.0219849
| Wheat:Blend Z-Corn:Blend X   29.0 -17.8050873  75.805087 0.6066374
| Soy:Blend X-Rice:Blend X     34.6 -12.2050873  81.405087 0.3423125
| Wheat:Blend X-Rice:Blend X   -5.4 -52.2050873  41.405087 0.9999997
| Corn:Blend Y-Rice:Blend X    22.4 -24.4050873  69.205087 0.8838055
| Rice:Blend Y-Rice:Blend X    29.2 -17.6050873  76.005087 0.5967325
| Soy:Blend Y-Rice:Blend X      3.0 -43.8050873  49.805087 1.0000000
| Wheat:Blend Y-Rice:Blend X    6.0 -40.8050873  52.805087 0.9999990
| Corn:Blend Z-Rice:Blend X    36.4 -10.4050873  83.205087 0.2718890
| Rice:Blend Z-Rice:Blend X    35.2 -11.6050873  82.005087 0.3177646
| Soy:Blend Z-Rice:Blend X     49.2   2.3949127  96.005087 0.0315296
| Wheat:Blend Z-Rice:Blend X   27.2 -19.6050873  74.005087 0.6939901
| Wheat:Blend X-Soy:Blend X   -40.0 -86.8050873   6.805087 0.1614830
| Corn:Blend Y-Soy:Blend X    -12.2 -59.0050873  34.605087 0.9988789
| Rice:Blend Y-Soy:Blend X     -5.4 -52.2050873  41.405087 0.9999997
| Soy:Blend Y-Soy:Blend X     -31.6 -78.4050873  15.205087 0.4784497
| Wheat:Blend Y-Soy:Blend X   -28.6 -75.4050873  18.205087 0.6263743
| Corn:Blend Z-Soy:Blend X      1.8 -45.0050873  48.605087 1.0000000
| Rice:Blend Z-Soy:Blend X      0.6 -46.2050873  47.405087 1.0000000
| Soy:Blend Z-Soy:Blend X      14.6 -32.2050873  61.405087 0.9946081
| Wheat:Blend Z-Soy:Blend X    -7.4 -54.2050873  39.405087 0.9999915
| Corn:Blend Y-Wheat:Blend X   27.8 -19.0050873  74.605087 0.6653705
| Rice:Blend Y-Wheat:Blend X   34.6 -12.2050873  81.405087 0.3423125
| Soy:Blend Y-Wheat:Blend X     8.4 -38.4050873  55.205087 0.9999691
| Wheat:Blend Y-Wheat:Blend X  11.4 -35.4050873  58.205087 0.9993994
| Corn:Blend Z-Wheat:Blend X   41.8  -5.0050873  88.605087 0.1210713
| Rice:Blend Z-Wheat:Blend X   40.6  -6.2050873  87.405087 0.1469832
| Soy:Blend Z-Wheat:Blend X    54.6   7.7949127 101.405087 0.0103529
| Wheat:Blend Z-Wheat:Blend X  32.6 -14.2050873  79.405087 0.4309559
| Rice:Blend Y-Corn:Blend Y     6.8 -40.0050873  53.605087 0.9999964
| Soy:Blend Y-Corn:Blend Y    -19.4 -66.2050873  27.405087 0.9529104
| Wheat:Blend Y-Corn:Blend Y  -16.4 -63.2050873  30.405087 0.9861932
| Corn:Blend Z-Corn:Blend Y    14.0 -32.8050873  60.805087 0.9962200
| Rice:Blend Z-Corn:Blend Y    12.8 -34.0050873  59.605087 0.9982727
| Soy:Blend Z-Corn:Blend Y     26.8 -20.0050873  73.605087 0.7126723
| Wheat:Blend Z-Corn:Blend Y    4.8 -42.0050873  51.605087 0.9999999
| Soy:Blend Y-Rice:Blend Y    -26.2 -73.0050873  20.605087 0.7399717
| Wheat:Blend Y-Rice:Blend Y  -23.2 -70.0050873  23.605087 0.8584571
| Corn:Blend Z-Rice:Blend Y     7.2 -39.6050873  54.005087 0.9999936
| Rice:Blend Z-Rice:Blend Y     6.0 -40.8050873  52.805087 0.9999990
| Soy:Blend Z-Rice:Blend Y     20.0 -26.8050873  66.805087 0.9422853
| Wheat:Blend Z-Rice:Blend Y   -2.0 -48.8050873  44.805087 1.0000000
| Wheat:Blend Y-Soy:Blend Y     3.0 -43.8050873  49.805087 1.0000000
| Corn:Blend Z-Soy:Blend Y     33.4 -13.4050873  80.205087 0.3943466
| Rice:Blend Z-Soy:Blend Y     32.2 -14.6050873  79.005087 0.4497486
| Soy:Blend Z-Soy:Blend Y      46.2  -0.6050873  93.005087 0.0559743
| Wheat:Blend Z-Soy:Blend Y    24.2 -22.6050873  71.005087 0.8228174
| Corn:Blend Z-Wheat:Blend Y   30.4 -16.4050873  77.205087 0.5372002
| Rice:Blend Z-Wheat:Blend Y   29.2 -17.6050873  76.005087 0.5967325
| Soy:Blend Z-Wheat:Blend Y    43.2  -3.6050873  90.005087 0.0956612
| Wheat:Blend Z-Wheat:Blend Y  21.2 -25.6050873  68.005087 0.9163288
| Rice:Blend Z-Corn:Blend Z    -1.2 -48.0050873  45.605087 1.0000000
| Soy:Blend Z-Corn:Blend Z     12.8 -34.0050873  59.605087 0.9982727
| Wheat:Blend Z-Corn:Blend Z   -9.2 -56.0050873  37.605087 0.9999234
| Soy:Blend Z-Rice:Blend Z     14.0 -32.8050873  60.805087 0.9962200
| Wheat:Blend Z-Rice:Blend Z   -8.0 -54.8050873  38.805087 0.9999811
| Wheat:Blend Z-Soy:Blend Z   -22.0 -68.8050873  24.805087 0.8953849

The following annotated output illustrates how to calculate various differences in the results of Tukey’s HSD procedure.

We can see that Tukey’s HSD.

The following YouTube video (28 minutes) is one of the very few that uses a linear regression approach to perform ANOVA analysis (https://www.youtube.com/watch?v=CS5ogBL-MHo). Please pay close attention to the explanation of the linear regression output, particularly the explanation of the two-way ANOVA with interaction term.


Finally, practice two-way ANOVA using regression approaches based on the following data table with two binary factors. Because both factors are binary, the interpretation of the output should be straightforward.

LS0tDQp0aXRsZTogIkxpbmVhciBSZWdyZXNzaW9uIE1vZGVscyB3aXRoIENhdGVnb3JpY2FsIFByZWRpY3RvcnMiDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIlNUQTIwMCBTdGF0aXN0aWNzIElJICINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IGx1bWVuDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDUNCiAgICBmaWdfaGVpZ2h0OiA0DQotLS0NCg0KYGBgez1odG1sfQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCjwvc3R5bGU+DQpgYGANCg0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQoNCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCiMga25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiQzovVXNlcnMvNzVDUEVORy9PbmVEcml2ZSAtIFdlc3QgQ2hlc3RlciBVbml2ZXJzaXR5IG9mIFBBL0RvY3VtZW50cyIpDQojIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIkM6XFxTVEE0OTBcXHcwNSIpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSAifCIpDQpgYGANCg0KXA0KDQoNCiMgSW50cm9kdWN0aW9uDQoNCldlIGhhdmUgYnJpZWZseSBpbnRyb2R1Y2VkIHRoZSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgZWFybGllciB3aXRoIGFuIGV4cGxpY2l0IGV4cHJlc3Npb24uDQoNCiQkDQp5ID0gXGJldGFfMCArIFxiZXRhXzEgeCArIFxlcHNpbG9uLA0KJCQNCg0KV2hlcmUgJHkkIGlzIGEgY29udGludW91cyByYW5kb20gbnVtZXJpY2FsIHZhcmlhYmxlLCAkeCQgaXMgZWl0aGVyIGEgbnVtZXJpY2FsIHZhcmlhYmxlIG9yIGEgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBhbmQgJFxlcHNpbG9uIFxyaWdodGFycm93IE4oMCwgXHNpZ21hKSQsIHRoZSBiYXNpYyBhcHBsaWNhdGlvbnMgb2YgYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgYXJlIHR3b2ZvbGQ6DQoNCigxKSAqKkFzc2VzcyoqIHRoZSBsaW5lYXIgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUgKCR5JCkgYW5kIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgKCR4JCkuDQoNCigyKSAqKlByZWRpY3QqKiB0aGUgcmVzcG9uc2UgZm9yIGdpdmVuIG5ldyB2YWx1ZXMgb2YgdGhlIHByZWRpY3RvciB2YXJpYWJsZSAkeCQuDQoNCkluIGdlbmVyYWwsIHJlZ3Jlc3Npb24gbW9kZWxpbmcgaXMgYW4gaXRlcmF0aXZlIHByb2Nlc3MgaW4gcmVhbC13b3JsZCBhcHBsaWNhdGlvbnMsIGFzIGlsbHVzdHJhdGVkIGluIHRoZSBmb2xsb3dpbmcgY2hhcnQuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjcwJSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJ3ZWVrMDUvcmVnLXByb2Nlc3MucG5nIikNCmBgYA0KDQpJbiB0aGUgY291cnNlIHByb2plY3QgYW5kIGRhdGEgYW5hbHlzaXMsIHdlIGZvY3VzIG9uIHRoZSBpdGVyYXRpdmUgbG9vcCBvZiBtb2RlbCBpZGVudGlmaWNhdGlvbiBhbmQgcmVwb3J0aW5nIG9uIHRoZSBmaW5hbCBtb2RlbC4gVG8gYmUgbW9yZSBzcGVjaWZpYywgYXNzdW1pbmcgd2UgaGF2ZSBhbiBhbmFseXRpYyBkYXRhIHNldCB0aGF0IGlzIHJlYWR5IGZvciBtb2RlbGluZywNCg0KKiAqKlNlbGVjdCBhcHByb3ByaWF0ZSBjYW5kaWRhdGUgbW9kZWxzIHRvIGFkZHJlc3MgdGhlIHByYWN0aWNhbCBxdWVzdGlvbnMqKiAtIFRoaXMgaW5jbHVkZXMgY2hlY2tpbmcgbW9kZWwgYXNzdW1wdGlvbnMgYW5kIGVuc3VyaW5nIHRoZSBhbmFseXRpYyBkYXRhc2V0IGNvbnRhaW5zIHN1ZmZpY2llbnQgaW5mb3JtYXRpb24gZm9yIHRoZSBjYW5kaWRhdGUgbW9kZWxzLiA8Zm9udCBjb2xvciA9ICJibHVlIj4qXGNvbG9ye2JsdWV9V2UgaGF2ZSBoaWdobGlnaHRlZCBhbGwgYXNzdW1wdGlvbnMgd2hlbiBpbnRyb2R1Y2luZyBuZXcgbW9kZWxzIGluIHRoZSBwcmV2aW91cyBub3Rlcy4qPC9mb250Pg0KDQoqICoqRml0IGNhbmRpZGF0ZSBtb2RlbHMgdG8gdGhlIGRhdGEqKiAtIFRoaXMgc3RlcCBpbnZvbHZlcyB2ZXJpZnlpbmcgdGhlIG91dHB1dHMgdG8gZW5zdXJlIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIChlLmcuLCBjb2VmZmljaWVudHMpIGFyZSBhcHByb3ByaWF0ZWx5IGVzdGltYXRlZC4NCg0KPiA8Zm9udCBjb2xvciA9ICJyZWQiPioqXGNvbG9ye3JlZH1Ob3RlOioqICp0aGUgZml0dGVkIG1vZGVscyBpbiB0aGlzIHN0ZXAgbWF5IG5vdCBiZSB2YWxpZCBvciBvcHRpbWFsLCB3ZSBzaG91bGQgbm90IGludGVycHJldCB0aGUgbW9kZWwgYXQgdGhpcyBwb2ludC4qICoqV2Ugb25seSByZXBvcnQgdGhlIGZpbmFsIG1vZGVsIG9idGFpbmVkIGZyb20gdGhlIGl0ZXJhdGl2ZSBtb2RlbCBpZGVudGlmaWNhdGlvbiBwcm9jZXNzLioqIDwvZm9udD4NCg0KKiAqKk1vZGVsIGRpYWdub3N0aWNzKiogLSBUaGlzIGlzIHRoZSBtb3N0IGNydWNpYWwgc3RlcCBpbiBhbnkgcmVncmVzc2lvbiBhbmFseXNpcywgd2hlcmUgd2UgYXNzZXNzIHdoZXRoZXIgYWxsIGFzc3VtcHRpb25zIG9mIHRoZSBjYW5kaWRhdGUgbW9kZWxzIGFyZSBzYXRpc2ZpZWQuIEZvciBleGFtcGxlLCB3ZSBhcHBseSByZXNpZHVhbCBkaWFnbm9zdGljIG1ldGhvZHMgKGNvbW1vbmx5IHVzZWQgaW4gbGluZWFyIHJlZ3Jlc3Npb24pIHRvIGV2YWx1YXRlIGxpbmVhcml0eSwgbm9ybWFsaXR5LCBob21vc2NlZGFzdGljaXR5IChjb25zdGFudCB2YXJpYW5jZSksIGFuZCBvdGhlciBrZXkgYXNzdW1wdGlvbnMuIElmIG5vIHZpb2xhdGlvbnMgYXJlIGRldGVjdGVkLCB3ZSB0aGVuIHVzZSBhcHBsaWNhdGlvbi1zcGVjaWZpYyBwZXJmb3JtYW5jZSBtZWFzdXJlcyB0byBzZWxlY3QgdGhlIGJlc3QgbW9kZWwgZm9yIHJlcG9ydGluZyBhbmQgaW1wbGVtZW50YXRpb24uDQoNCiogKipNb2RlbCByZW1lZHkgYW5kIHJlZmluZW1lbnQqKiAtIElmIG9uZSBvciBtb3JlIGFzc3VtcHRpb25zIGFyZSB2aW9sYXRlZCwgd2UgbmVlZCB0byB1c2UgdmFyaW91cyBtZXRob2RzIHRvIGZpeCB0aGUgcHJvYmxlbXMuICpXZSB3aWxsIG5vdCBkaXNjdXNzIHRoaXMgbWFqb3IgdG9waWMgaW4gdGhpcyBjbGFzcywgYnV0IHdpbGwgY292ZXIgdGhpcyBjcml0aWNhbCB0b3BpYyBpbiBkZXRhaWwgaW4gc3Vic2VxdWVudCBjb3Vyc2VzKi4gIA0KDQoqICoqRW50ZXIgdGhlIHJlZmluZWQvbW9kaWZpZWQgbW9kZWwgaW50byB0aGUgbG9vcCBmb3IgdGhlIG5leHQgaXRlcmF0aW9uKiogLSBUaGUgcmVmaW5lZCBvciBtb2RpZmllZCBtb2RlbCB3aWxsIGJlIHJlZml0dGVkLCBhbmFseXplZCwgYW5kIGRpYWdub3NlZCB0byBkZXRlcm1pbmUgd2hldGhlciBhbnkgdmlvbGF0aW9ucyByZW1haW4uIFRoaXMgcHJvY2VzcyBjb250aW51ZXMgaXRlcmF0aXZlbHkgdW50aWwgdGhlIGZpbmFsIHZhbGlkIGFuZCBvcHRpbWFsIG1vZGVsIGlzIGlkZW50aWZpZWQuDQoNCiogKipGaW5hbCBtb2RlbCByZXBvcnRpbmcqKiAtIFRoaXMgdG9waWMgd2lsbCBub3QgYmUgZW1waGFzaXplZCBpbiB0aGlzIGNsYXNzIGJ1dCB3aWxsIGJlIGhpZ2hsaWdodGVkIGluIHN1YnNlcXVlbnQgc3RhdGlzdGljYWwgbW9kZWxpbmcgY2xhc3Nlcy4NCg0KDQpJbiB0aGlzIG5vdGUsIHdlIHdpbGwgZXh0ZW5kIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiB0byBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiBieSBpbmNvcnBvcmF0aW5nIHR3byBvciBtb3JlIHByZWRpY3RvciB2YXJpYWJsZXMgaW50byB0aGUgbW9kZWwuIFdlIGJlZ2luIGJ5IHJldmlzaXRpbmcgdGhlIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBkaXNjdXNzZWQgZWFybGllciB0aGlzIHNlbWVzdGVyLiBOZXh0LCB3ZSB3aWxsIGdlbmVyYWxpemUgdGhlIGJpbmFyeSBjYXRlZ29yaWNhbCBwcmVkaWN0b3IgdG8gbXVsdGktY2F0ZWdvcnkgcHJlZGljdG9ycyB0aHJvdWdoIHRoZSB1c2Ugb2YgYmluYXJ5IGluZGljYXRvciB2YXJpYWJsZXMg4oCTIGVmZmVjdGl2ZWx5IGNyZWF0aW5nIGEgc3BlY2lhbCBjYXNlIG9mIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIHdpdGggbXVsdGlwbGUgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gVGhpcyBhcHByb2FjaCBpbnRlZ3JhdGVzIEFOT1ZBIGFuYWx5c2lzIGludG8gdGhlIHJlZ3Jlc3Npb24gZnJhbWV3b3JrLg0KDQpcDQoNCiMgU2ltcGxlIExpbmVhciBSZWdyZXNzaW9uIFJldmlzaXRlZA0KDQpUaGUgdGVybSAqKnNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbioqIChTTFIpIHNpbXBseSBtZWFucyB0aGF0IHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uIGhhcyB0aGUgZm9ybSAkeSA9IFxiZXRhXzAgKyBcYmV0YV8xIHggKyBcZXBzaWxvbiQuIFRoZSBwcmVkaWN0b3IgdmFyaWFibGUgaXMgZWl0aGVyIGEgY29udGludW91cyB2YXJpYWJsZSBvciBhIGJpbmFyeSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0aGF0IHRha2VzIG9ubHkgdHdvIHBvc3NpYmxlIGRpc3RpbmN0IHZhbHVlcywgc3VjaCBhcyAqc3VjY2VzcyogdnMgKmZhaWx1cmUqLCAqZGlzZWFzZSogdnMgKmRpc2Vhc2UtZnJlZSosIGV0Yy4gKipUaGUgcmVzcG9uc2UgbXVzdCBiZSBhIGNvbnRpbnVvdXMgbm9ybWFsIHZhcmlhYmxlIHdob3NlIG1lYW4gbWF5IGJlIGluZmx1ZW5jZWQgYnkgdGhlIHByZWRpY3RvciAkeCQgYnV0IG5vdCB0aGUgdmFyaWFuY2UuKioNCg0KVGhlIGtleSBhc3N1bXB0aW9ucyBmb3IgU0xSIGFyZQ0KDQoqICoqbGluZWFyaXR5Kio6IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiAkeSQgYW5kICR4JDsgDQogICsgZGlhZ25vc3RpYyBjaGVjazogc2NhdHRlciBwbG90IG9mICR4JCBhbmQgJHkkDQoqICoqZGV0ZXJtaW5pc3RpYyBwcmVkaWN0b3IgJHgkKio6IHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgaXMgbm90IGEgcmFuZG9tIHZhcmlhYmxlLg0KICArIE5vIGRpcmVjdCBpbmZvcm1hdGlvbiwgY2hlY2sgdGhpcyBhc3N1bXB0aW9uDQoqICoqbm9ybWFsaXR5Kio6IHRoZSBvbmx5IHJhbmRvbSB2YXJpYWJsZSAkeSQgaXMgYSBub3JtYWwgcmFuZG9tIHZhcmlhYmxlIHdpdGggZGVuc2l0eSBmdW5jdGlvbiAkTihcYmV0YSswICsgXGJldGFfMSB4LCBcc2lnbWEpJCwgb3IgJFxlcHNpbG9uIFxyaWdodGFycm93IE4oMCwgXHNpZ21hKSQuDQogICsgZGlhZ25vc3RpYyBjaGVjazogUS1RIHBsb3QNCiogKipjb25zdGFudCB2YXJpYW5jZSoqOiB0aGlzIGFzc3VtcHRpb24gaXMgY29udGFpbmVkIGluIHRoZSBhYm92ZSAqKm5vcm1hbGl0eSoqIGFzc3VtcHRpb24uIA0KICArIGRpYWdub3N0aWMgY2hlY2s6IHJlc2lkdWFsIHBsb3QsIHN0dWRlbnRpemVkIHJlc2lkdWFsIHBsb3QNCiogKipJbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMqKjogVGhpcyBpcyBhbHNvIHJlbGF0ZWQgdG8gdGhlICoqbm9ybWFsaXR5IGFzc3VtcHRpb24qKiANCiAgKyBkaWFnbm9zdGljIGNoZWNrOiBsZXZlcmFnZSBwbG90IChDb29rJ3MgZGlzdGFuY2UpDQoNCg0KDQoNCiMjIFNMUiB3aXRoIEEgQ29udGludW91cyBQcmVkaWN0b3INCg0KV2hlbiB0aGUgcHJlZGljdG9yIHZhcmlhYmxlIGlzIGNvbnRpbnVvdXMsIHRoZSBpbnRlcnByZXRhdGlvbiBvZiB0aGUgc2xvcGUgJFxiZXRhXzEkIHJlZmxlY3RzIHRoZSBjaGFuZ2UgaW4gJHkkIHdoZW4gJHgkIGluY3JlYXNlcyBieSBvbmUgdW5pdC4gVGhlIHNpZ24gb2YgJFxiZXRhXzEkIHJlZmxlY3RzIHRoZSBkaXJlY3Rpb24gb2YgbGluZWFyIGFzc29jaWF0aW9uIGJldHdlZW4gJHgkIGFuZCAkeSQuIE5leHQsIHdlIHVzZSBhIG51bWVyaWNhbCBleGFtcGxlIHRvIGlsbHVzdHJhdGUgdGhlIHJlZ3Jlc3Npb24gbW9kZWxpbmcgcHJvY2Vzcy4gVGhlIGRhdGEgc2V0IGNhbiBiZSBmb3VuZCBhdCA8aHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBMjAwL2RhdGFzZXQvRWR1V2FnZS5jc3Y+LiBUaGUgUiBmdW5jdGlvbiBgbG0oKWAgd2lsbCBiZSB1c2VkIHRvIHBlcmZvcm0gcmVncmVzc2lvbiBhbmFseXNpcy4NCg0KVGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgYXJlIGRlZmluZWQgYXMNCg0KKiAqKndhZ2UqKjogYXZlcmFnZSBob3VybHkgZWFybmluZ3MNCiogKiplZHVjKio6IHllYXJzIG9mIGVkdWNhdGlvbg0KKiAqKmV4cGVyKio6IHllYXJzIHBvdGVudGlhbCBleHBlcmllbmNlDQoqICoqdGVudXJlKio6ICB5ZWFycyB3aXRoIGN1cnJlbnQgZW1wbG95ZXINCiogKipsd2FnZSoqOiAgbG9nKHdhZ2UpIC0gaW4gZWNvbm9taWNzLCBpdCBpcyBjYWxsZWQgbG9nIHdhZ2UuDQoqICoqcmVnaW9uKio6IHRoZSBnZW9ncmFwaGljIHJlZ2lvbiBvZiB0aGUgcmVzcG9uZGVudA0KKiAqKnNtc2EqKjogQSBTdGFuZGFyZCBNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYSAoU01TQSkgaXMgYSBnZW9ncmFwaGljYWwgcmVnaW9uIGRlZmluZWQgYnkgdGhlIFUuUy4gT2ZmaWNlIG9mIE1hbmFnZW1lbnQgYW5kIEJ1ZGdldCB0aGF0IGNvbnNpc3RzIG9mIGEgY29yZSB1cmJhbiBhcmVhIHdpdGggYSBzdWJzdGFudGlhbCBwb3B1bGF0aW9uLCBhbG9uZyB3aXRoIGFkamFjZW50IGNvbW11bml0aWVzIHRoYXQgaGF2ZSBhIGhpZ2ggZGVncmVlIG9mIGVjb25vbWljIGFuZCBzb2NpYWwgaW50ZWdyYXRpb24gd2l0aCB0aGF0IGNvcmUuIFNNU0FzIGFyZSB1c2VkIGZvciBzdGF0aXN0aWNhbCBwdXJwb3NlcyB0byBhbmFseXplIHVyYmFuaXphdGlvbiwgcG9wdWxhdGlvbiBkZW5zaXR5LCBhbmQgZWNvbm9taWMgYWN0aXZpdGllcyBpbiBtZXRyb3BvbGl0YW4gYXJlYXMsIHByb3ZpZGluZyBpbnNpZ2h0cyBpbnRvIHVyYmFuIGRhdGEgdHJlbmRzLg0KDQoNCg0KKipTdGVwIDEqKjogTG9hZCBkYXRhIGFuZCBleHBsb3JlIHRoZSBkYXRhc2V0Lg0KDQpgYGB7cn0NCiMjIExvYWQgdGhlIGRhdGFzZXQNCmVkdS53YWdlIDwtIHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEEyMDAvZGF0YXNldC9FZHVXYWdlLmNzdiIpDQojIyBzdW1tYXJ5IG9mIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldA0Kc3VtbWFyeShlZHUud2FnZSkNCmBgYA0KDQpUaGUgUiBmdW5jdGlvbiBgc3VtbWFyeShkYXRhc2V0Lm5hbWUpYCByZXR1cm5zIGEgZml2ZS1udW1iZXIgc3VtbWFyeSBvZiBhbGwgbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldC4gVGhlcmUgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBgcmVnaW9uYCBpbiB0aGUgZGF0YXNldC4gVG8gc2VlIHRoZSBkaXN0cmlidXRpb24gb2YgKipjYXRlZ29yaWNhbCB2YXJpYWJsZXMqKiwgd2UgdXNlIHRoZSBSIGZ1bmN0aW9uIGB0YWJsZSh2YXJpYWJsZS5uYW1lKWAgdG8gc2VlIHRoZSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuDQoNCmBgYHtyfQ0KdGFibGUoZWR1LndhZ2UkcmVnaW9uKQ0KYGBgDQoNCioqU3RlcCAyKio6IG9iamVjdGl2ZSBhbmQgY2FuZGlkYXRlIG1vZGVsIC0gd2UgZXhhbWluZSB3aGV0aGVyIGVkdWNhdGlvbiBhZmZlY3RzIHRoZSB3YWdlLiBUaGUgY2FuZGlkYXRlIG1vZGVsIHRvIGFkZHJlc3MgdGhpcyBvYmplY3RpdmUgd2lsbCBiZSB0aGUgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLiBXZSBmaXJzdCBtYWtlIGEgc2NhdHRlciBwbG90IG9mIGBlZHVjYCAoaG9yaXpvbnRhbCBheGlzKSBhbmQgYHdhZ2VgICh2ZXJ0aWNhbCBheGlzKS4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0KcGxvdChlZHUud2FnZSRlZHVjLCAgICAgICAgICAgICAgICAgIyBob3Jpem9udGFsIGF4aXMNCiAgICAgZWR1LndhZ2Ukd2FnZSwgICAgICAgICAgICAgICAgICMgdmVydGljYWwgYXhpcw0KICAgICB4bGFiID0gIlllYXJzIG9mIEVkdWNhdGlvbiIsICAgIyBob3Jpem9udGFsIGxhYmVsDQogICAgIHlsYWIgPSAiSG91cmx5IFdhZ2UiLCAgICAgICAgICAjIHZlcnRpY2FsIGxhYmVsDQogICAgIG1haW4gPSAiU2NhdHRlciBQbG90IG9mIEVkdSB2cyBXYWdlIiAgICAjIHRpdGxlIG9mIHRoZSBwbG90DQogICAgICkNCmBgYA0KDQpUaGUgYWJvdmUgcGxvdCBzaG93cyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYnV0IGFsc28gc2hvd3Mgbm9uLWNvbnN0YW50IHZhcmlhbmNlLiBUaGlzIHZpb2xhdGVzIHRoZSBTTFIgYXNzdW1wdGlvbi4gRWNvbm9taWMgc3R1ZGllcyBzaG93IHRoYXQgbG9nYXJpdGhtaWMgd2FnZSBoYXMgbGVzcyB2YXJpYXRpb24uICBXZSBuZXh0IHRyeSB0byBsb2cgd2FnZXMgaW4gdGhlIFNMUi4gQmVmb3JlIGJ1aWxkaW5nIHRoZSBtb2RlbCwgd2UgbWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBsb2cgd2FnZSB2cyB5ZWFycyBvZiBlZHVjYXRpb24uDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0NCnBsb3QoKGVkdS53YWdlJGVkdWMpWy0xXSwgICAgICAgICAgICAgICAgICMgaG9yaXpvbnRhbCBheGlzDQogICAgIChlZHUud2FnZSRsd2FnZSlbLTFdLCAgICAgICAgICAgICAgICAgIyB2ZXJ0aWNhbCBheGlzDQogICAgIHhsYWIgPSAiWWVhcnMgb2YgRWR1Y2F0aW9uIiwgICAjIGhvcml6b250YWwgbGFiZWwNCiAgICAgeWxhYiA9ICJIb3VybHkgbG9nKFdhZ2UpIiwgICAgICAgICAgIyB2ZXJ0aWNhbCBsYWJlbA0KICAgICBtYWluID0gIlNjYXR0ZXIgUGxvdCBvZiBFZHUgdnMgbG9nKFdhZ2UpIiAgICAjIHRpdGxlIG9mIHRoZSBwbG90DQogICAgICkNCmBgYA0KDQpUaGUgYWJvdmUgc2NhdHRlciBpbmRpY2F0ZXMgdGhhdCB0aGUgbG9nIHdhZ2UgaXMgYSBiZXR0ZXIgcmVzcG9uc2UgZm9yIFNMUi4NCg0KKipTdGVwIDMqKjogRml0dGluZyBTTFI6ICAkXHRleHR7bG9nIHdhZ2V9ID0gXGJldGFfMCArIFxiZXRhXzEgXHRleHR7ZWR1Y30kIGFuZCBwZXJmb3JtIHJlc2lkdWFsIGRpYWdub3N0aWNzLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTZ9DQojIyBsaW5lYXIgbW9kZWwNCmxndy5tb2RlbCA8LSBsbShsd2FnZSB+IGVkdWMsIGRhdGEgPSBlZHUud2FnZSkNCiMjIHJlc2lkdWFsIHBsb3QNCnBhcihtZnJvdz1jKDIsMikpICAgICMgY3JlYXRlIGEgZ3JhcGhpYyBncmlkIHdpdGggNCBncmFwaGljYWwgY2VsbHMgDQpwbG90KGxndy5tb2RlbCkNCmBgYA0KDQpJbnRlcnByZXRhdGlvbnMgb2YgUmVzaWR1YWwgRGlhZ25vc3RpYyBQbG90czoNCg0KKiAqKlJlc2lkdWFsIHZzIEZpdHRlZCoqIC0gc2hvd3MgYSBtaW5vciB2aW9sYXRpb24gb2YgdGhlIGFzc3VtcHRpb24gb2YgY29uc3RhbnQgdmFyaWFuY2UgKHRoZSB2YXJpYW5jZSBpbmNyZWFzZXMgYXMgdGhlIGZpdHRlZCB2YWx1ZSBpbmNyZWFzZXMpDQoqICoqUV9RIFJlc2lkdWFsIFBsb3QqKiAtIFRoZXJlIGlzIG5vIHNpZ25pZmljYW50IHZpb2xhdGlvbiBvZiB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KKiAqKlNjYWxlLUxvY2F0aW9uIFBsb3QqKiAtIG5vIHNlcmlvdXMgdmlvbGF0aW9uIGV4Y2VwdCBhIGZldyBvdXRsaWVycyAobm90IGluZmx1ZW50aWFsKQ0KKiAqKlJlc2lkdWFscy1MZXZlcmFnZSoqIC0gc2hvd3Mgbm8gaW5mbHVlbnRpYWwgcG9pbnRzLg0KDQpPdmVyYWxsLCB0aGVyZSBpcyBhIG1pbm9yIHZpb2xhdGlvbiBvZiB0aGUgY29uc3RhbnQgdmFyaWFuY2UgYXNzdW1wdGlvbi4gV2Ugd2lsbCBsZWFybiBtZXRob2RzIGluIHN1YnNlcXVlbnQgY291cnNlcyB0byByZWZpbmUgdGhlIG1vZGVsLiBGb3IgaWxsdXN0cmF0aW9uLCB3ZSBkZWNpZGVkIHRvIHJlcG9ydCB0aGUgYWJvdmUgbW9kZWwuDQoNCioqU3RlcCA0KiogLSBzdW1tYXJpemUgdGhlIGxvZyB3YWdlIG1vZGVsDQoNCmBgYHtyfQ0Kc3VtbWFyeShsZ3cubW9kZWwpDQpgYGANCg0KKipCcmllZiBSZXBvcnQqKjoNCg0KVGhlIGVzdGltYXRlZCBzbG9wZSBjb2VmZmljaWVudCAkXGhhdHtcYmV0YX1fMSA9IDAuMDgyNzQ0JCBpbmRpY2F0ZXMgdGhhdCBsb2cgd2FnZSBpbmNyZWFzZXMgYnkgMC4wODI3NDQgZm9yIGVhY2ggYWRkaXRpb25hbCB5ZWFyIG9mIGVkdWNhdGlvbiAoJHAgXGFwcHJveCAwJCkuIFRoZSBjb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uICRSXjIgXGFwcHJveCAwLjE4NTgkIHNob3dzIHRoYXQgdGhlIGxvZyB3YWdlIGFuZCB5ZWFycyBvZiBlZHVjYXRpb24gaGF2ZSBhIHdlYWsgbGluZWFyIGNvcnJlbGF0aW9uLg0KDQoqKlJlbWFya3MqKjogSGVyZSBhcmUgYSBmZXcgY29tbWVudHMgb24gdGhlIGdlbmVyYWwgcHJpbmNpcGxlcyBvZiByZWdyZXNzaW9uIGFuYWx5c2lzDQoNCiogSW4gdGhpcyBleGFtcGxlLCB3ZSB1c2Ugb25seSB0d28gdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCB3aXRoIG1vcmUgdGhhbiAyIHZhcmlhYmxlcyB0byBpbGx1c3RyYXRlIGhvdyB0byBpbXBsZW1lbnQgYW4gU0xSLiBJbiBwcmFjdGljZSwgaWYgeW91IGhhdmUgbW9yZSBpbmZvcm1hdGlvbiAobW9yZSB2YXJpYWJsZXMpIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSwgd2Ugc2hvdWxkIHVzZSBhbGwgcmVsZXZhbnQgaW5mb3JtYXRpb24gLSAqKnRoaXMgaXMgdGhlIGdlbmVyYWwgcHJpbmNpcGxlIG9mIGFsbCBkYXRhIGFuYWx5c2lzKiouIFRoaXMgbWVhbnMgd2UgbmVlZCB0byB1c2UgbXVsdGlwbGUgcmVncmVzc2lvbiB0byBpbmNsdWRlIHR3byBvciBtb3JlIHByZWRpY3RvciB2YXJpYWJsZXMhIFdlIHdpbGwgY292ZXIgZ2VuZXJhbCBNTFIgaW4gdGhlIG5leHQgbm90ZS4NCg0KKiAqKkltcGxpY2F0aW9uIG9mIFNMUioqOiBBbiBpbXBsaWNhdGlvbiBvZiBTTFIgaXMgdGhhdCBhbGwgb3RoZXIgdmFyaWFibGVzIGRvIG5vdCBhZmZlY3QgdGhlIHJlc3BvbnNlIHZhcmlhYmxlICR5JC4gVGhpcyBhbHNvIGltcGxpZXMgdGhhdCwgaW4gZ2VuZXJhbCwgYW4gU0xSIGNhbiBuZXZlciBiZSBhbiBvcHRpbWFsIG1vZGVsIGlmIGl0IGlzIGludmFsaWQuDQoNCiogKipDaG9vc2UgYW4gb3B0aW1hbCBzdWJzZXQgb2YgcHJlZGljdG9ycyoqOiBUaGlzIG1lYW5zIHdlIGFsd2F5cyBzdGFydCB3aXRoIG11bHRpcGxlIGNhbmRpZGF0ZSBtb2RlbHMgaW4gbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gKE1MUikgbW9kZWxzLiBGb3IgZXhhbXBsZSwgaWYgd2UgaGF2ZSB0d28gdmFyaWFibGVzICR4XzEkIGFuZCAkeF8yJCwgd2UgY2FuIGZpdCB0aHJlZSBkaWZmZXJlbnQgKipmaXJzdCBvcmRlcioqIChpbiBwcmVkaWN0b3IgdmFyaWFibGVzKSBNTFIgYmFzZWQgb24gdGhlIGNvbWJpbmF0aW9ucyBvZiAkeF8xJCwgJHhfMiQsIGFuZCAkeF8xICsgeF8yJC4gTW9yZSBvbiBkaWZmZXJlbnQgTUxScyB3aWxsIGJlIGRpc2N1c3NlZCBpbiB0aGUgbmV4dCBub3RlLg0KDQoNCg0KXA0KDQoNCiMjIFNMUiB3aXRoIEEgQmluYXJ5IFByZWRpY3Rvcg0KDQpXZSBoYXZlIGRpc2N1c3NlZCB0aGUgcmVncmVzc2lvbiBhcHByb2FjaCB0byB0aGUgdHdvLXNhbXBsZSB0LXRlc3QgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2VtZXN0ZXIuIEhlcmUgd2UgdXNlIHRoZSBzYW1wbGUgd2FnZSBkYXRhc2V0IGFuZCBhIGJpbmFyeSBjYXRlZ29yaWNhbCBgc21zYWAoU3RhbmRhcmQgTWV0cm9wb2xpdGFuIFN0YXRpc3RpY2FsIEFyZWEpIHRvIHNlZSB3aGV0aGVyIHRoZSBhdmVyYWdlIHdhZ2UgaW4gKipydXJhbCoqIGFuZCAqKnVyYmFuKiogYXJlYXMgaXMgZGlmZmVyZW50LiANCg0KUmVjYWxsIHRoZSBhc3N1bXB0aW9uIGluIHRoZSB0d28tc2FtcGxlIHRlc3Q6DQoNCiogV2FnZSBkaXN0cmlidXRpb25zIGluIGJvdGggcG9wdWxhdGlvbnMgKHJ1cmFsIGFuZCB1cmJhbiBwb3B1bGF0aW9ucykgYXJlIG5vcm1hbCwgZXF1aXZhbGVudCB0byB0aGUgKipub3JtYWxpdHkgYXNzdW1wdGlvbioqIG9uIFNMUg0KKiBUaGUgdmFyaWFuY2VzIG9mIHdhZ2VzIGluIGJvdGggcG9wdWxhdGlvbnMgYXJlIHVua25vd24gYnV0IGVxdWFsLCBlcXVpdmFsZW50IHRvIHRoZSAqKmNvbnN0YW50IHZhcmlhbmNlIGFzc3VtcHRpb24qKiBpbiBTTFIuIA0KDQpXaGVuIHVzaW5nIGEgc29mdHdhcmUgcHJvZ3JhbSwgd2UgaGF2ZSB0byBzcGVjaWZ5IHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgJHgkIHRvIGJlIGEgZmFjdG9yIChjYXRlZ29yaWNhbCB2YXJpYWJsZSkuIEluIFIsIHRoZSBmdW5jdGlvbiBgZmFjdG9yKClgIGNvbnZlcnRzIGEgY2F0ZWdvcmljYWwgb3IgZGlzY3JldGUgbnVtZXJpY2FsIHZhcmlhYmxlICh3aXRoIGZpbml0ZSBkaXN0aW5jdCB2YWx1ZXMpIHRvIGEgZmFjdG9yIHZhcmlhYmxlLg0KDQpXZSBuZXh0IGltcGxlbWVudCB0aGUgU0xSIHdpdGggYSBiaW5hcnkgZmFjdG9yIHZhcmlhYmxlIChgc21zYWApIGFuZCB1c2UgbG9nIHdhZ2UgYGx3YWdlYCBhcyB0aGUgcmVzcG9uc2UuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD03fQ0KIyBsbSBtb2RlbA0Kc21zYS5sbSA8LSBsbShsd2FnZSB+IGZhY3RvcihzbXNhKSwgZGF0YSA9IGVkdS53YWdlKQ0KIyByZXNpZHVhbCBwbG90cw0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3Qoc21zYS5sbSkNCmBgYA0KDQo8Zm9udCBjb2xvciA9ICJibHVlIiBzaXplID00PioqMS4gSW50ZXJwcmV0YXRpb25zIG9mIFJlc2lkdWFsIERpYWdub3N0aWMgUGxvdHMqKjwvZm9udD4NCg0KDQoqICoqUmVzaWR1YWwtZml0dGVkIFZhbHVlcyoqOiBkb2VzIG5vdCByZXZlYWwgc3BlY2lhbCBwYXR0ZXJucy4gVGhlIHZhcmlhbmNlcyBvZiB0aGUgdHdvIGdyb3VwcyBzZWVtIHRvIGJlIHNpbWlsYXIgdG8gZWFjaCBvdGhlci4NCiogKipRLVEgUGxvdCoqOiBObyBzZXJpb3VzIHZpb2xhdGlvbiBvZiB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gd2FzIGZvdW5kIGZyb20gdGhlIFEtUSBwbG90LiBOb3RlIHRoYXQgdGhlcmUgaXMgYW4gb3V0bGllciBpbiB0aGUgcGxvdC4NCiogKipTY2FsZS1sb2NhdGlvbiBQbG90Kio6IGRvZXMgbm90IHJldmVhbCBhbnkgc3BlY2lhbCBwYXR0ZXJuIGV4Y2VwdCBmb3IgYW4gb3V0bGllciAob2JzIE4wLiAyNCkuDQoqICoqUmVzaWR1YWxzIHZzIExldmVyYWdlKio6IFRoZSBDb29rJ3MgZGlzdGFuY2Ugb2Ygb2JzZXJ2YXRpb24gZG9lcyBub3QgaGF2ZSBhIHNpZ25pZmljYW50IGxldmVyYWdlIChubyBpbmZsdWVudGlhbCkuDQoNCk92ZXJhbGwsIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IHZpb2xhdGlvbiBvZiBtb2RlbCBhc3N1bXB0aW9ucy4gV2UgcmVwb3J0IHRoZSBjdXJyZW50IG1vZGVsIGluIHRoZSBmb2xsb3dpbmc6DQoNClwNCg0KPGZvbnQgY29sb3IgPSAiYmx1ZSIgc2l6ZSA9ND4qKjIuIEludGVycHJldGF0aW9ucyBvZiBSZWdyZXNzaW9uIENvZWZmaWNpZW50cyoqPC9mb250Pg0KDQpUaGUgYmluYXJ5IHZhcmlhYmxlYHNtc2FgIGhhcyB0d28gdmFsdWVzOiAwID0gcnVyYWwgYXJlYSwgMSA9IHVyYmFuIGFyZWEuICBJbiBnZW5lcmFsLCBhIGJpbmFyeSB2YXJpYWJsZSAodGFraW5nIHZhbHVlcyAwIGFuZCAxKSBpcyBhbHNvIGNvbW1vbmx5IGNhbGxlZCBhICoqZHVtbXkgdmFyaWFibGUqKiBpbiBzdGF0aXN0aWNzIGFuZCByZWdyZXNzaW9uIGFuYWx5c2lzLg0KDQpgYGB7cn0NCnN1bW1hcnkoc21zYS5sbSkNCmBgYA0KDQoqICoqKEludGVyY2VwdCkqKjogJFxoYXR7XGJldGF9XzAgPSAgMS40MTUxOCQgaXMgdGhlIGF2ZXJhZ2UgbG9nIHdhZ2Ugb2YgKipydXJhbCBhcmVhKiogKGBzbXNhID0gMGAgaXMgdGhlIGJhc2VsaW5lIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBgc2FzYWApLg0KDQokJA0KXGxvZyhcdGV4dHt3YWdlfV97XHRleHR7cnVyYWx9fSkgPSAgMS40MTUxOCBcIFxpbXBsaWVzIFwgXHRleHR7d2FnZX1fe1x0ZXh0e3J1cmFsfX0gPSBlXnsgMS40MTUxOH0gPSA0LjExNzIyOA0KJCQNCg0KVGhlIGFib3ZlIGVxdWF0aW9ucyBjb252ZXJ0IHRoZSBsb2cgd2FnZSB0byB0aGUgb3JpZ2luYWwgd2FnZS4gVGhhdCBpcywgdGhlIG1lYW4gd2FnZSBpbiBydXJhbCBhcmVhcyBpcyA0LjExNzIyOC4NCg0KDQoqICoqc2xvcGUgcGFyYW1ldGVyKiogKGBmYWN0b3Ioc2FzYSkxYCA9IGxldmVsIDEgb2YgZmFjdG9yIHZhcmlhYmxlIGBzbXNhID0xYDogdXJiYW4gYXJlYSk6ICRcaGF0e1xiZXRhfV8xID0gMC4yMzczMiQgaXMgdGhlIGRpZmZlcmVuY2Ugb2YgdGhlIGF2ZXJhZ2UgbG9nIHdhZ2UgYmV0d2VlbiB0aGUgY3VycmVudCBjYXRlZ29yeSAodXJiYW4gYXJlYSkgYW5kIHRoZSBiYXNlbGluZSBjYXRlZ29yeSAocnVyYWwgYXJlYSkuIEEgbW9yZSBwcmFjdGljYWwgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHNsb3BlIHJlcXVpcmVzIHNvbWUgYWxnZWJyYToNCg0KJCQNClxsb2coXHRleHR7d2FnZX1fe1x0ZXh0e3VyYmFufX0pIC0gXGxvZyhcdGV4dHt3YWdlfV97XHRleHR7cnVyYWx9fSkgPSAwLjIzNzMyIFwgXGltcGxpZXMgXGxvZyBcZnJhY3tcdGV4dHt3YWdlfV97XHRleHR7dXJiYW59fX17XHRleHR7d2FnZX1fe1x0ZXh0e3J1cmFsfX19ID0gMC4yMzczMg0KJCQNCg0KRXhwYW5kaW5nIGJvdGggc2lkZXMgb2YgdGhlIGxhc3QgZXF1YXRpb24gaW4gdGhlIGFib3ZlLCB3ZSBoYXZlDQoNCiQkDQogXGZyYWN7XHRleHR7d2FnZX1fe1x0ZXh0e3VyYmFufX19e1x0ZXh0e3dhZ2V9X3tcdGV4dHtydXJhbH19fSA9IGVeezAuMjM3MzJ9ID0gMS4yNjc4NDcgXGltcGxpZXMgXHRleHR7d2FnZX1fe1x0ZXh0e3VyYmFufX09IDEuMjY3ODQ3IFx0aW1lcyBcdGV4dHt3YWdlfV97XHRleHR7cnVyYWx9fSwNCiQkDQoNCldlIHJlLWV4cHJlc3MgdGhlIGxhc3QgZXF1YXRpb24gaW4gdGhlIGFib3ZlIHRvIGdldA0KDQokJA0KXHRleHR7d2FnZX1fe1x0ZXh0e3VyYmFufX0gLSBcdGV4dHt3YWdlfV97XHRleHR7cnVyYWx9fT0gMS4yNjc4NDcgXHRpbWVzIFx0ZXh0e3dhZ2V9X3tcdGV4dHtydXJhbH19IC0gXHRleHR7d2FnZX1fe1x0ZXh0e3J1cmFsfX0gPSAwLjI2Nzg0N1x0ZXh0e3dhZ2V9X3tcdGV4dHtydXJhbH19DQokJA0KDQpXaGljaCBpcyBlcXVpdmFsZW50IHRvDQoNCiQkDQpcZnJhY3tcdGV4dHt3YWdlfV97XHRleHR7dXJiYW59fSAtIFx0ZXh0e3dhZ2V9X3tcdGV4dHtydXJhbH19fXtcdGV4dHt3YWdlfV97XHRleHR7cnVyYWx9fX0gPSAwLjI2Nzg0Ny4NCiQkDQoNCg0KVGhpcyBtZWFucyB0aGF0IDxmb250IGNvbG9yID0gInJlZCI+KipcY29sb3J7cmVkfXRoZSB3YWdlIGluIHVyYmFuIGFyZWEgaXMgMjYuNzg0NyUgaGlnaGVyIHRoYW4gdGhlIHJ1cmFsIGFyZWEqKi48L2ZvbnQ+Lg0KDQpcDQoNCjxmb250IGNvbG9yID0gImJsdWUiIHNpemUgPTQ+KiozLiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBTTFIgYW5kIE9uZS13YXkgQU5PVkEqKjwvZm9udD4NCg0KRmlyc3Qgb2YgYWxsLCB3ZSBjYW4gZXh0cmFjdCBhIG9uZS13YXkgQU5PVkEgdGFibGUgZnJvbSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIHRoZSBSIGZ1bmN0aW9uIGBhbm92YShsbS5vYmplY3QpYA0KDQpgYGB7cn0NCmFub3ZhKHNtc2EubG0pDQpgYGANCg0KVGhlIEYgc3RhdGlzdGljIGluIHRoZSBhYm92ZSBBTk9WQSB0ZXN0ICh3aXRoIDEgZGVncmVlIG9mIGZyZWVkb20gaW4gdGhlIG51bWVyYXRvciBhbmQgNTI0IGRlZ3JlZXMgb2YgZnJlZWRvbSBpbiB0aGUgZGVub21pbmF0b3IpIGlzIA0KDQokJA0KRiA9IDIxLjg2Mi4NCiQkDQoNClRoZSB0LXRlc3Qgc3RhdGlzdGljIGluIHRoZSBTTFIgaXMgYSB0IGRpc3RyaWJ1dGlvbiB3aXRoIDUyNCBkZWdyZWVzIG9mIGZyZWVkb20sIHdoaWNoIGlzIGNsb3NlIHRvIHRoZSBzdGFuZGFyZCBub3JtYWwgZGlzdHJpYnV0aW9uLiANCg0KJCQNClogXGFwcHJveCBUID0gNC42NzYuDQokJA0KDQpJdCBjYW4gYmUgcHJvdmVuIHRoYXQgJHRfe1x0ZXh0e2QuZn19XjIgPSBGX3sxLCBcIFx0ZXh0e2QuZn19JC4gVGhpcyBtZWFucyB0aGUgcmVzdWx0IG9mIHRoZSB0LXRlc3QgaW4gU0xSIGFuZCB0aGUgRi10ZXN0IGluIHRoZSBBTk9WQSBwcm9jZWR1cmUgYXJlIGlkZW50aWNhbC4gVGhlcmVmb3JlLCA8Zm9udCBjb2xvciA9ICJyZWQiIHNpemUgPSA0PioqdGhlIFNMUiB3aXRoIGEgYmluYXJ5IHByZWRpY3RvciBjYW4gdGhlIG9uZS13YXkgQU5PVkEgaXMgYSBzcGVjaWFsIFNMUiEqKjwvZm9udD4uICAgDQoNCg0KDQoNClwNCg0KIyBMaW5lYXIgUmVncmVzc2lvbiBBcHByb2FjaCB0byBPbmUtV2F5IEFOT1ZBDQoNCldlIGNsYWltZWQgdGhhdCBvbmUtd2F5IEFOT1ZBIGlzIGEgc3BlY2lhbCBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB3aGVuIHRoZXJlIGlzIGEgYmluYXJ5IGNhdGVnb3JpY2FsIHByZWRpY3RvciBpcyBpbmNsdWRlZCBpbiB0aGUgbW9kZWwuIEhvd2V2ZXIsIGEgZ2VuZXJhbCBDUkQgYWxsb3dzIG11bHRpcGxlIHRyZWF0bWVudHMuICBJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgaWxsdXN0cmF0ZSBob3cgdG8gdXNlIGxpbmVhciByZWdyZXNzaW9uIHRvIHBlcmZvcm0gYSBnZW5lcmFsIG9uZS13YXkgQU5PVkEgd2l0aCBtdWx0aXBsZSB0cmVhdG1lbnQgZ3JvdXBzLg0KDQpGb3IgZWFzZSBvZiBwcmVzZW50YXRpb24sIHdlIGNvbnRpbnVlIHVzaW5nIHRoZSB3YWdlIGRhdGFzZXQgd2l0aCBsb2cgd2FnZSBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCByZWdpb24gYXMgYSBjYXRlZ29yaWNhbCB0cmVhdG1lbnQgZmFjdG9yIChjb25zaXN0aW5nIG9mIGZvdXIgZ3JvdXBzOiBTb3V0aCwgV2VzdCwgTm9ydGgtQ2VudHJhbCwgYW5kIE90aGVyKS4gV2hlbiBwZXJmb3JtaW5nIGxpbmVhciByZWdyZXNzaW9uIHdpdGggYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0aGF0IGhhcyBtb3JlIHRoYW4gdHdvIGNhdGVnb3JpZXMsIHdlIG11c3QgaW50cm9kdWNlIGEgc2VyaWVzIG9mIGR1bW15IHZhcmlhYmxlcyB0byBwcm9wZXJseSByZXByZXNlbnQgdGhlIG11bHRpLWNhdGVnb3J5IHZhcmlhYmxlLg0KDQoqKldoeSBVc2UgRHVtbXkgVmFyaWFibGVzPyoqDQoNCiogKipFbmNvZGUgQ2F0ZWdvcmljYWwgRGF0YSoqOiBUaGV5IGFsbG93IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAobm9taW5hbCBvciBvcmRpbmFsKSB0byBiZSBpbmNsdWRlZCBpbiByZWdyZXNzaW9uIG1vZGVscy4NCg0KKiAqKkF2b2lkIEFyYml0cmFyeSBOdW1lcmljYWwgQXNzaWdubWVudHMqKjogVXNpbmcgbnVtYmVycyBsaWtlIDEsIDIsIDMgZm9yIGNhdGVnb3JpZXMgaW1wbGllcyBhbiBvcmRlciBvciBtYWduaXR1ZGUsIHdoaWNoIG1heSBub3QgZXhpc3QgKGUuZy4sIGBSZWQgPSAxLCBHcmVlbiA9IDIsIEJsdWUgPSAzYCBmYWxzZWx5IHN1Z2dlc3RzIHRoYXQgR3JlZW4gaXMgImdyZWF0ZXIiIHRoYW4gUmVkKS4NCg0KKiAqKkludGVycHJldGFiaWxpdHkqKjogRWFjaCBkdW1teSB2YXJpYWJsZSByZXByZXNlbnRzIHRoZSBwcmVzZW5jZSAoMSkgb3IgYWJzZW5jZSAoMCkgb2YgYSBjYXRlZ29yeSwgbWFraW5nIGNvZWZmaWNpZW50cyBlYXN5IHRvIGludGVycHJldC4gVG8gYmUgbW9yZSBzcGVjaWZpYywgdGhlIGNvZWZmaWNpZW50IG9mIGEgZHVtbXkgdmFyaWFibGUgcmVwcmVzZW50cyB0aGUgZGlzY3JlcGFuY3kgYmV0d2VlbiB0aGUgY2F0ZWdvcnkgYXNzb2NpYXRlZCB3aXRoIHRoZSBkdW1teSB2YXJpYWJsZSBhbmQgdGhlIGJhc2VsaW5lIGNhdGVnb3J5Lg0KDQpcDQoNCioqU3RlcHMgdG8gQ3JlYXRlIER1bW15IFZhcmlhYmxlcyBmcm9tIGEgTXVsdGktQ2F0ZWdvcnkgVmFyaWFibGUqKg0KDQoqICoqY2hvb3NlIGEgYmFzZWxpbmUgY2F0ZWdvcnkqKjogIFRoZSBiYXNlbGluZSBjYXRlZ29yeSBzZXJ2ZXMgYXMgYSByZWZlcmVuY2UsIGFsbG93aW5nIG90aGVyIGNhdGVnb3JpZXMgdG8gYmUgY29tcGFyZWQgYWdhaW5zdCBpdC4NCiAgKyBNb3N0IHNvZnR3YXJlIHByb2dyYW1zIGF1dG9tYXRpY2FsbHkgc2V0IHRoZSBiYXNlbGluZSBhcyB0aGUgY2F0ZWdvcnkgd2l0aCB0aGUgc21hbGxlc3QgdmFsdWUgKGUuZy4sIHRoZSBmaXJzdCBpbiBhbHBoYWJldGljYWwgb3JkZXIgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcykuDQoNCiogKipDcmVhdGUgRHVtbXkgVmFyaWFibGVzKio6IEZvciBlYWNoIG5vbi1iYXNlbGluZSBjYXRlZ29yeSwgZGVmaW5lIGEgZHVtbXkgdmFyaWFibGUgbGFiZWxpbmcgdGhhdCBjYXRlZ29yeS4gRm9yIGV4YW1wbGUsIGByZWdpb24gPSAobm9ydGhjZW4sIG90aGVyLCBzb3V0aCwgd2VzdClgLCB0aGUgdGhyZWUgZHVtbXkgdmFyaWFibGVzIGFyZSBkZWZpbmVkIGFzIA0KDQogICsgZHVtbXkub3RoZXIgPSAxIGlmIGxpdmVkIGluIGBvdGhlcmAgcmVnaW9uLCAwIGlmIG5vdCBpbiBgb3RoZXJgIHJlZ2lvbi4NCiAgKyBkdW1teS5zb3V0aCA9IDEgaWYgbGl2ZWQgaW4gYHNvdXRoYCBhbmQgMCBpZiBub3QgaW4gYHNvdXRoYCByZWdpb247DQogICsgZHVtbXkud2VzdCA9IDEgaWYgbGl2ZWQgaW4gYHdlc3RgIGFuZCAwIGlmIG5vdCBpbiBgd2VzdGAuDQoNCkluIGdlbmVyYWwsIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaGFzICRrJCBjYXRlZ29yaWVzLCBhbmQgd2UgbmVlZCB0byBkZWZpbmUgJGstMSQgZHVtbXkgdmFyaWFibGVzLiBGb3IgZXhhbXBsZSwgDQoNCnwgKipyZWdpb24qKiAgfCAqKmR1bW15Lm90aGVyKiogfCAqKmR1bW15LnNvdXRoKiogIHwgKipkdW1teS53ZXN0KiogIHwNCnw6LS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLXwNCnwgIHNvdXRoICAgICB8ICAgICAgMCAgICAgICAgICB8ICAgICAgIDEgICAgICAgICAgIHwgICAgMCAgICAgICAgICAgICB8DQp8ICB3ZXN0ICAgICAgfCAgICAgIDAgICAgICAgICAgfCAgICAgICAwICAgICAgICAgICB8ICAgIDEgICAgICAgICAgICAgfA0KfG5vcnRoY2VuICAgIHwgICAgICAwICAgICAgICAgIHwgICAgICAgMCAgICAgICAgICAgfCAgICAwICAgICAgICAgICAgIHwNCnxvdGhlciAgICAgICB8ICAgICAgMSAgICAgICAgICB8ICAgICAgIDAgICAgICAgICAgIHwgICAgMCAgICAgICAgICAgICB8DQp8ICBzb3V0aCAgICAgfCAgICAgIDAgICAgICAgICAgfCAgICAgICAxICAgICAgICAgICB8ICAgIDAgICAgICAgICAgICAgfA0KIA0KDQoqICoqSW50ZXJwcmV0YXRpb24gb2YgRHVtbXkgVmFyaWFibGVzIGluIFJlZ3Jlc3Npb24qKg0KDQpUaGUgY29lZmZpY2llbnRzIGZvciBgb3RoZXJgLCBgc291dGhgLCBhbmQgYHdlc3RgIHJlcHJlc2VudCB0aGUgZGlmZmVyZW5jZSBmcm9tIHRoZSByZWZlcmVuY2UgY2F0ZWdvcnkgKGBub3J0aGNlbmApLg0KDQoqICoqRHVtbXkgdmFyaWFibGVzIGluIFIqKg0KICArICoqQ2F0ZWdvcmljYWwgdmFyaWFibGUgd2l0aCBjaGFyYWN0ZXIgdmFsdWVzKio6IEluIHRoaXMgY2FzZSwgUiB3aWxsIGRlZmluZSBkdW1teSB2YXJpYWJsZXMgaW50ZXJuYWxseSBhbmQgdXNlIHRoZSBkZWZhdWx0IHJlZmVyZW5jZSBjYXRlZ29yeS4NCiAgKyAqKkNhdGVnb3JpY2FsIHZhcmlhYmxlIHdpdGggdmFsdWVzIGluIG51bWVyaWNhbCBmb3JtKio6IEluIHRoaXMgY2FzZSwgd2UgbXVzdCB1c2UgUuKAmXMgYGZhY3RvcigpYCBmdW5jdGlvbiB0byBjb252ZXJ0IHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpbnRvIGEgZmFjdG9yIHZhcmlhYmxlIChudW1lcmljIHZhbHVlcyB3aWxsIGJlIHRyZWF0ZWQgYXMgY2F0ZWdvcnkgbGFiZWxzKS4gUiB0aGVuIGludGVybmFsbHkgZGVmaW5lcyBkdW1teSB2YXJpYWJsZXMgYW5kIHNlbGVjdHMgdGhlIGJhc2VsaW5lIGNhdGVnb3J5IGFzIHRoZSBvbmUgd2l0aCB0aGUgc21hbGxlc3QgbnVtZXJpY2FsIGxhYmVsLg0KICArIElmIHRoZSBkZWZhdWx0IHJlZmVyZW5jZSBjYXRlZ29yeSBpcyBub3QgcHJlZmVycmVkLCB5b3UgY2FuIHVzZSBSJ3MgYHJlbGV2ZWwoKWAgZnVuY3Rpb24gdG8gbWFudWFsbHkgc3BlY2lmeSBhIGN1c3RvbSBiYXNlbGluZSBjYXRlZ29yeSBmb3IgZWFzaWVyIGludGVycHJldGF0aW9uLiANCiAgDQogIA0KYGBge3J9DQojIEV4YW1wbGUgZGF0YQ0KZGF0YSA8LSBkYXRhLmZyYW1lKGNvbG9yID0gYygiUmVkIiwgIkdyZWVuIiwgIkJsdWUiLCAiR3JlZW4iLCAiUmVkIikpDQoNCiMgU2V0ICJHcmVlbiIgYXMgdGhlIGJhc2VsaW5lIChyZWZlcmVuY2UpIGNhdGVnb3J5DQpkYXRhJGNvbG9yIDwtIGZhY3RvcihkYXRhJGNvbG9yKSAgDQpkYXRhJGNvbG9yIDwtIHJlbGV2ZWwoZGF0YSRjb2xvciwgcmVmID0gIkdyZWVuIikgIA0KDQojIENoZWNrIGxldmVscyAoZmlyc3QgbGV2ZWwgaXMgdGhlIGJhc2VsaW5lKQ0KbGV2ZWxzKGRhdGEkY29sb3IpICAjIE91dHB1dDogIkdyZWVuIiAiUmVkIiAiQmx1ZSINCmBgYA0KDQoNClwNCg0KPGZvbnQgY29sb3IgPSAicmVkIiBzaXplID0gND4qKlxjb2xvcntyZWR9T24gdGhlIFNpZ25pZmljYW5jZSBvZiB0aGUgQ2F0ZWdvcmljYWwgVmFyaWFibGUqKjogDQoNCiogSWYgKiphbnkqKiBvZiB0aGUgZHVtbXkgdmFyaWFibGVzIGlzIHN0YXRpc3RpY2FsbHkgKipzaWduaWZpY2FudCoqIChpLmUuLCAqcCotdmFsdWUgPCAwLjA1KSwgdGhlIG9yaWdpbmFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzIGNvbnNpZGVyZWQgKipzaWduaWZpY2FudCoqLg0KKiBJZiAqKmFsbCoqIGR1bW15IHZhcmlhYmxlcyBhcmUgc3RhdGlzdGljYWxseSAqKmluc2lnbmlmaWNhbnQqKiwgdGhlIG9yaWdpbmFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzICoqaW5zaWduaWZpY2FudCoqLiA8L2ZvbnQ+ICANCiogSWYgdGhlIG9yaWdpbmFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzICoqaW5zaWduaWZpY2FudCoqLCBpdCBzaG91bGQgYmUgZXhjbHVkZWQgZnJvbSB0aGUgcmVncmVzc2lvbiBtb2RlbCBpbiByZWFsIHJlYWwtd29ybGQgYXBwbGljYXRpb24uIA0KDQoNClwNCiAgDQo8Zm9udCBjb2xvciA9ICJibHVlIiBzaXplID0gND4qKlxjb2xvcntibHVlfUluIHRoZSBvdXRwdXQgb2YgYGxtKClgLCB0aGUgRiB0ZXN0IGluIHRoZSBib3R0b20gcG9ydGlvbiBwcm92aWRlcyB0aGUgc2lnbmlmaWNhbmNlIHRlc3Qgb2YgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlLioqIDwvZm9udD48Zm9udCBjb2xvciA9ICJyZWQiIHNpemUgPSA0PioqXGNvbG9ye3JlZH1UaGlzIEYgdGVzdCBpcyB0aGUgc2FtZSBGIHRlc3QgaW4gdGhlIG9uZS13YXkgQU5PVkEhISEqKjwvZm9udD4gIA0KICANCiANCiAgDQpcDQoNCjxmb250IGNvbG9yID0gInJlZCIgc2l6ZSA9IDQ+KipcY29sb3J7cmVkfUFuIE51bWVyaWNhbCBFeGFtcGxlKio8L2ZvbnQ+IA0KDQpXZSB1c2UgdGhlICoqcGxhbnQgZ3Jvd3RoKiogZGF0YXNldCB0byBidWlsZCBhIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCB0aGUgbXVsdGktY2F0ZWdvcnkgcHJlZGljdG9yIGBncm91cGAgYW5kIGNvbXBhcmUgaXQgd2l0aCBhIG9uZS13YXkgQU5PVkEgcHJvY2VkdXJlLiBUaGUgZGF0YSBzZXQgaXMgYXQgPD4uICBXZSB3aWxsIGZvbGxvdyBzZXZlcmFsIGxvZ2ljYWwgc3RlcHMgdG8gY29uZHVjdCB0aGUgYW5hbHlzaXMuDQoNCg0KKipTdGVwIDEqKjogZml0IGNhbmRpZGF0ZSBtb2RlbCBhbmQgcGVyZm9ybSBkaWFnbm9zdGljcw0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9DQojIyBMb2FkIHRoZSBkYXRhc2V0DQpwbGFudCA8LSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBMjAwLy9kYXRhc2V0L29uZVdheVBsYW50R3Jvd3RoLmNzdiIpDQojIw0KcGxhbnQubG0gPC0gbG0od2VpZ2h0IH4gZ3JvdXAsIGRhdGEgPSBwbGFudCkgICMgZmFjdG9yKGdyb3VwKSB3aWxsIGFsc28gd29yaw0KIyMgcmVzaWR1YWwgcGxvdHMNCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KHBsYW50LmxtKQ0KYGBgDQoNCg0KTm9uZSBvZiB0aGUgYWJvdmUgcmVzaWR1YWwgcGxvdHMgc2hvd3Mgc2lnbmlmaWNhbnQgdmlvbGF0aW9ucyBvZiBtb2RlbCBhc3N1bXB0aW9ucyBleGNlcHQgZm9yIGEgZmV3IG91dGxpZXJzIHRoYXQgYXJlIG5vdCBpbmZsdWVudGlhbC4gV2UgcmVwb3J0IHRoZSBtb2RlbC4gDQoNCioqU3RlcCAyKio6IFJlcG9ydGluZyB0aGUgbGluZWFyIG1vZGVsDQoNCmBgYHtyfQ0Kc3VtbWFyeShwbGFudC5sbSkNCmBgYA0KDQoqKkludGVycHJldGF0aW9uIG9mIHRoZSBvdXRwdXQqKg0KDQoqIFRoZSBleHBsaWNpdCBtb2RlbCBmb3JtdWxhIGhhcyBvbmx5IHRoZSBvcmlnaW5hbCBncm91cCBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIHRocmVlIGNhdGVnb3JpZXMuIEluIGZhY3QsIHRoZSBpbXBsaWNpdCBtb2RlbCBmb3JtdWxhIHVzZXMgZHVtbXkgdmFyaWFibGVzLiBJbiBvdGhlciB3b3JkcywgdGhlIGFjdHVhbCBtb2RlbCBmb3JtdWxhIHVzZWQgaW4gdGhlIG1vZGVsIGlzICRcdGV4dHt3ZWlnaHR9ID0gXGJldGFfMCArIFxiZXRhXzEgXHRleHR7Z3JvdXB0cnQxfSArIFxiZXRhXzIgXHRleHR7Z3JvdXB0cnQyfSQsIDxmb250IGNvbG9yID0gInJlZCIgc2l6ZSA9IDQ+KipcY29sb3J7cmVkfSB3aGVyZSAkXGJldGFfMCA9IFxtdV97XHRleHR7Y3RyfX0kLCAgJFxiZXRhXzEgPSBcbXVfe1x0ZXh0e3RydDF9fSAtIFxtdV97XHRleHR7Y3RyfX0kIGFuZCAkXGJldGFfMiA9IFxtdV97XHRleHR7dHJ0Mn19IC0gXG11X3tcdGV4dHtjdHJ9fSQqKjwvZm9udD4gDQoNCiogVGhlIEYgdGVzdCBpbiB0aGUgYm90dG9tIHBvcnRpb24geWllbGRzIGEgcC12YWx1ZSBvZiAwLjAxNTkxLiBBdCBhIHNpZ25pZmljYW5jZSBsZXZlbCBvZiAwLjA1LCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IDxmb250IGNvbG9yID0gInJlZCI+KipcY29sb3J7cmVkfXJlZ2lvbiBpcyBzaWduaWZpY2FudCoqLjwvZm9udD4gSW4gb3RoZXIgd29yZHMsIHRoaXMgRi10ZXN0IHRlc3RzIHRoZSA8Zm9udCBjb2xvciA9ICJyZWQiIHNpemUgPSA0PioqXGNvbG9ye3JlZH1udWxsIGh5cG90aGVzaXM6ICRIXzA6IFxiZXRhXzEgPSBcYmV0YV8yID0gMCQuKio8L2ZvbnQ+IFRoaXMgZXF1aXZhbGVudCB0byA8Zm9udCBjb2xvciA9ICJyZWQiIHNpemUgPSA0PioqXGNvbG9ye3JlZH0kSF8wOiBcbXVfe1x0ZXh0e2N0cn19ID0gXG11X3tcdGV4dHt0cnQxfX0gPSBcbXVfe1x0ZXh0e3RydDJ9fSQqKi48L2ZvbnQ+IDxmb250IGNvbG9yPSJibHVlIiBzaXplID0gND4qKlxjb2xvcntibHVlfVRoaXMgaXMgZXhhY3RseSB0aGUgRiB0ZXN0IGluIHRoZSBvbmUtd2F5IEFOT1ZBISoqPC9mb250PiBXZSB3aWxsIGV4dHJhY3QgdGhlIG9uZS13YXkgQU5PVkEgZnJvbSB0aGUgbGluZWFyIG1vZGVsIHNob3J0bHkuDQoNCiogKipJbnRlcnByZXRhdGlvbiBvZiBSZWdyZXNzaW9uIGNvZWZmaWNpZW50cyoqOiBBdCB0aGUgc2lnbmlmaWNhbmNlIGxldmVsIG9mIDAuMDUsIG5laXRoZXIgb2YgdGhlIHR3byBkdW1teSB2YXJpYWJsZXMgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4NCiAgKyAkXGJldGFfMCAgPSBcbXVfe1x0ZXh0e2N0cn19JCwgVGhpcyByZXByZXNlbnRzIHRoZSBtZWFuIG9mIHRoZSBiYXNlbGluZSBjYXRlZ29yeS4gVGhlIHAtdmFsdWUgdGVzdHMgdGhlIGh5cG90aGVzaXMgJEhfMDogXGJldGFfMCA9IDAkLg0KICArICRcaGF0e1xiZXRhfV8xID0gXGhhdHtcbXV9X3tcdGV4dHt0cnQxfX0gLSBcaGF0e1xtdX1fe1x0ZXh0e2N0cn19ID0gLTAuMzcxMCQ6IFRoZSBwLXZhbHVlIG9mICoqMC4xOTQ0KiogY29ycmVzcG9uZHMgdG8gdGVzdGluZyB0aGUgaHlwb3RoZXNpcyAkSF8wOiBcYmV0YV8xID0gMCQgKG9yIGVxdWl2YWxlbnRseSwgJEhfMDogXG11X3tcdGV4dHt0cnQxfX0gLSBcbXVfe1x0ZXh0e2N0cn19ID0gMCQpLiBUaGUgcC12YWx1ZSBpbmRpY2F0ZXMgKipubyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2UqKiBiZXR3ZWVuIGB0cnQxYCBhbmQgYGN0cmAuIFRoZSBuZWdhdGl2ZSBzaWduIG9mIHRoZSBlc3RpbWF0ZSBzdWdnZXN0cyB0aGF0IHRoZSBzYW1wbGUgbWVhbiBvZiBgY3RyYCBpcyBoaWdoZXIgdGhhbiB0aGF0IG9mIGB0cnQxYC4NCiAgKyAkXGhhdHtcYmV0YX1fMiA9IFxoYXR7XG11fV97XHRleHR7dHJ0Mn19IC0gXGhhdHtcbXV9X3tcdGV4dHtjdHJ9fSA9MC40OTQwJCwgVGhlIHAtdmFsdWUgb2YgKiowLjA4NzcqKiBjb3JyZXNwb25kcyB0byB0ZXN0aW5nIHRoZSBoeXBvdGhlc2lzICRIXzA6IFxiZXRhXzIgPSAwJCAob3IgZXF1aXZhbGVudGx5LCAkSF8wOiBcbXVfe1x0ZXh0e3RydDJ9fSAtIFxtdV97XHRleHR7Y3RyfX0gPSAwJCkuIFRoZSBwLXZhbHVlIGluZGljYXRlcyAqKm5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSoqIGJldHdlZW4gYHRydDJgIGFuZCBgY3RyYC4gVGhlIHBvc2l0aXZlIHNpZ24gb2YgdGhlIGVzdGltYXRlIHN1Z2dlc3RzIHRoYXQgdGhlIHNhbXBsZSBtZWFuIG9mIGB0cnQyYCBpcyBoaWdoZXIgdGhhbiB0aGF0IG9mIGBjdHJgLg0KICANClwNCg0KTmV4dCwgd2UgZXh0cmFjdCB0aGUgb25lLXdheSBBTk9WQSB0YWJsZSBkaXJlY3RseSBmcm9tIHRoZSBhYm92ZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbC4NCg0KDQpgYGB7cn0NCiMgZXh0cmFjdCBBTk9WQSB0YWJsZSBkaXJlY3RseSBmcm9tIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsDQphbm92YShwbGFudC5sbSkNCmBgYA0KDQpUaGUgRi10ZXN0IGZyb20gdGhlIG9uZS13YXkgQU5PVkEgdGFibGUgYWJvdmUgaXMgaWRlbnRpY2FsIHRvIHRoZSBvbmUgcmVwb3J0ZWQgaW4gdGhlIHByZXZpb3VzIHJlZ3Jlc3Npb24gbW9kZWwuIFdlIGNhbiBhbHNvIGdlbmVyYXRlIHRoZSBzYW1lIG9uZS13YXkgQU5PVkEgdGFibGUgdXNpbmcgUuKAmXMgYnVpbHQtaW4gZnVuY3Rpb25gYW92KClgIA0KDQoNClRoZSBjb2VmZmljaWVudHMgYXNzb2NpYXRlZCB3aXRoIGR1bW15IHZhcmlhYmxlcyBpbiB0aGUgcmVncmVzc2lvbiBvdXRwdXQgcmVwcmVzZW50IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gb2YgdGhlIHVuZGVybHlpbmcgY2F0ZWdvcnkgYW5kIHRoYXQgb2YgdGhlIGJhc2VsaW5lIGNhdGVnb3J5LiBUaGF0IGlzLCAkXGhhdHtcYmV0YX1fMSA9IFxoYXR7XG11fV97XHRleHR7dHJ0MX19IC0gXGhhdHtcbXV9X3tcdGV4dHtjdHJ9fSA9IC0wLjM3MTAkIGFuZCAkXGhhdHtcYmV0YX1fMiA9IFxoYXR7XG11fV97XHRleHR7dHJ0Mn19IC0gXGhhdHtcbXV9X3tcdGV4dHtjdHJ9fSA9MC40OTQwJC4gVGhpcyBpbmZvcm1hdGlvbiBpcyBnaXZlbiBpbiBUdWtleSdzIEhTRCAoc2VlIHRoZSBvdXRwdXQgb2YgYFR1a2V5SFNEKClgKQ0KDQoNCmBgYHtyfQ0KcGxhbnQuYW92IDwtIGFvdih3ZWlnaHQgfiBncm91cCwgZGF0YSA9IHBsYW50KQ0KVHVrZXlIU0QocGxhbnQuYW92KQ0KYGBgDQoNClRoZSBmaXJzdCB0d28gZXN0aW1hdGVkIGRpZmZlcmVuY2VzIChgdHJ0MSAtIGN0cmAgYW5kIGB0cnQyIC0gY3RyYCkgY29ycmVzcG9uZCB0byB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgb2YgdGhlIGR1bW15IHZhcmlhYmxlcyBpbiB0aGUgcHJldmlvdXMgbW9kZWwuIFRoZSBwLXZhbHVlcyByZXBvcnRlZCBpbiB0aGUgcmVncmVzc2lvbiBtb2RlbCBhcmUgdW5hZGp1c3RlZCAoYmFzZWQgb24gaW5kaXZpZHVhbCB0ZXN0cyksIHdoZXJlYXMgVHVrZXkncyBIU0QgaXMgYSBncm91cCB0ZXN0LCBhbmQgaXRzIGNvcnJlc3BvbmRpbmcgcC12YWx1ZXMgYXJlIGFkanVzdGVkIHRvIGNvbnRyb2wgdGhlIG92ZXJhbGwgVHlwZSBJIGVycm9yIHJhdGUgKGkuZS4sIHRvIHByZXZlbnQgaW5mbGF0aW9uIG9mIHRoZSBmYWxzZSBwb3NpdGl2ZSByYXRlKS4NCg0KDQpcDQoNCjxmb250IGNvbG9yID0gInJlZCIgc2l6ZSA9IDQ+KipcY29sb3J7cmVkfVJlbWFya3M6Kio8L2ZvbnQ+DQoNCiogVGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHVzZWQgdG8gcGVyZm9ybSBvbmUtd2F5IEFOT1ZBIGhhcyAqKm11bHRpcGxlIGR1bW15IHByZWRpY3RvciB2YXJpYWJsZXMqKiBpbiB0aGUgbW9kZWwgZm9ybXVsYSAoYWx0aG91Z2ggaW1wbGljaXRseSBleHByZXNzZWQpLiBJbiBvdGhlciB3b3JkcywgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHRoZSBvbmUtd2F5IEFOT1ZBIGlzIGEgc3BlY2lhbCAqKm11bHRpcGxlIGxpbmVhciBSZWdyZXNzaW9uKiogKE1MUikgbW9kZWwuDQoNCiogTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24gKE1MUikgbWFpbnRhaW5zIHRoZSBzYW1lIGFzc3VtcHRpb25zIGFzIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbjogaW5kZXBlbmRlbnQgYW5kIGlkZW50aWNhbGx5IGRpc3RyaWJ1dGVkIChpLmkuZC4pIG9ic2VydmF0aW9ucywgZGV0ZXJtaW5pc3RpYyBwcmVkaWN0b3JzLCBsaW5lYXJpdHkgYmV0d2VlbiByZXNwb25zZSBhbmQgcHJlZGljdG9yLCBub3JtYWxpdHkgb2YgcmVzaWR1YWxzLCBhbmQgaG9tb3NjZWRhc3RpY2l0eSAoY29uc3RhbnQgdmFyaWFuY2UpLiBTaW5jZSBNTFIgaW52b2x2ZXMgbXVsdGlwbGUgcHJlZGljdG9yIHZhcmlhYmxlcywgYW4gYWRkaXRpb25hbCBhc3N1bXB0aW9uIGlzIHRoZSBhYnNlbmNlIG9mIGhpZ2ggY29ycmVsYXRpb25zIGJldHdlZW4gcHJlZGljdG9ycy4gVmlvbGF0aW9uIG9mIHRoaXMgYXNzdW1wdGlvbiBpcyByZWZlcnJlZCB0byBhcyAqKm11bHRpY29sbGluZWFyaXR5KiogaW4gcmVncmVzc2lvbiBtb2RlbGluZy4NCg0KKiBUaGUgcmVhc29uIHdlIGVuY29kZSBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHdpdGggayBjYXRlZ29yaWVzIGludG8gKGstMSkgZHVtbXkgdmFyaWFibGVzIChyYXRoZXIgdGhhbiBrKSBpcyB0byBhdm9pZCBtdWx0aWNvbGxpbmVhcml0eSBpc3N1ZXMuIEZvciBleGFtcGxlLCBzdXBwb3NlIHdlIGhhdmUgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSAqKkVkdWNhdGlvbioqIHdpdGggMyBsZXZlbHM6IEhpZ2ggU2Nob29sIChiYXNlbGluZS9yZWZlcmVuY2UpLCBCYWNoZWxvcidzLCBhbmQgTWFzdGVyJ3MuIElmIHdlIGNyZWF0ZSAzIGR1bW15IHZhcmlhYmxlczoNCiAgKyBEMSA9IDEgaWYgSGlnaCBTY2hvb2wsIDAgb3RoZXJ3aXNlDQogICsgRDIgPSAxIGlmIEJhY2hlbG9yJ3MsIDAgb3RoZXJ3aXNlDQogICsgRDMgPSAxIGlmIE1hc3RlcidzLCAwIG90aGVyd2lzZQ0KDQogIDxmb250IGNvbG9yID0gInJlZCI+VGhpcyBjcmVhdGVzIHBlcmZlY3QgKiptdWx0aWNvbGxpbmVhcml0eSoqIGJlY2F1c2UgZm9yIGV2ZXJ5IG9ic2VydmF0aW9uOiBEMSArIEQyICsgRDMgPSAxIChhbHdheXMpISEhPC9mb250Pg0KDQoNClRvIGNvbmNsdWRlIHRoaXMgc2VjdGlvbiwgd2F0Y2ggdGhlIFlvdVR1YmUgdmlkZW8gKDxodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUNNQXdLdUN3NUNNJmxpc3Q9UExmUXBwaTNtekY1blF6U20tUldRbnZIRmc0NkdRVktfNCZpbmRleD00PikgdGhhdCBmb2N1c2VzIG9uIHRoZSBBTk9WQSB0YWJsZSBleHRyYWN0ZWQgZnJvbSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24uICANCg0KDQpcDQoNCjxjZW50ZXI+PGEgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1DTUF3S3VDdzVDTSZsaXN0PVBMZlFwcGkzbXpGNW5RelNtLVJXUW52SEZnNDZHUVZLXzQmaW5kZXg9NCIgdGFyZ2V0PSJwb3B1cCIgDQogICAgICAgICAgICAgICAgICAgb25jbGljaz0id2luZG93Lm9wZW4oJ2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9Q01Bd0t1Q3c1Q00mbGlzdD1QTGZRcHBpM216RjVuUXpTbS1SV1FudkhGZzQ2R1FWS180JmluZGV4PTQnLA0KICAgICAgICAgICAgICAgICAgICAgICduYW1lJywnd2lkdGg9ODUwLGhlaWdodD01MDAnKSI+PGltZyBzcmMgPSAiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vTUFUMTIxVzUvaW1nL1ZpZGVvSWNvbi5wbmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIj48L2E+DQo8L2NlbnRlcj4NCg0KDQoNClwNCg0KDQojIE11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIEFwcHJvYWNoIHRvIFR3by13YXkgQU5PVkENCg0KKipUaGlzIHNlY3Rpb24gZm9jdXNlcyBvbiBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIGVhY2ggd2l0aCBtdWx0aXBsZSBsZXZlbHMuKiogV2UgaGF2ZSBwcmV2aW91c2x5IGxlYXJuZWQgYWJvdXQgdHdvLXdheSBBTk9WQSBiYXNlZCBvbiBhIHJlcGxpY2F0ZWQgUmFuZG9taXplZCBCbG9jayBEZXNpZ24gKFJCRCksIHdoaWNoIGFsbG93cyBmb3IgaW5mZXJlbmNlIG9uIGludGVyYWN0aW9uIGVmZmVjdHMuIFRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB0byBiZSBkaXNjdXNzZWQgd2lsbCBhbHNvIGluY2x1ZGUgYW4gaW50ZXJhY3Rpb24gdGVybS4NCg0KU2luY2UgdGhlIHVuZGVybHlpbmcgY29uY2VwdCBpcyBzaW1pbGFyIHRvIHRoZSBvbmUtd2F5IEFOT1ZBIGNvdmVyZWQgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24sIHRoZSBleHBsaWNpdCBtb2RlbCBmb3JtdWxhIHJlbWFpbnMgcmVsYXRpdmVseSBzaW1wbGUuIEhvd2V2ZXIsIHRoZSBpbXBsaWNpdCBtb2RlbCBmb3JtdWxhIGZvciBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGluY2x1ZGluZyBhbiBpbnRlcmFjdGlvbiBlZmZlY3QpIGlzIG1vcmUgY29tcGxleCB0aGFuIHRoYXQgb2Ygb25lLXdheSBBTk9WQS4gV2Ugd2lsbCB1c2UgYW4gZXhhbXBsZSB0byBpbGx1c3RyYXRlIHNvbWUga2V5IGZlYXR1cmVzIG9mIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIChNTFIpIGludm9sdmluZyBvbmx5IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGFuIGludGVyYWN0aW9uIHRlcm0uDQoNCg0KVGhlIGRhdGFzZXQgcmVjb3JkZWQgdGhlIHlpZWxkIG9mIGRpZmZlcmVudCBjcm9wcyB1bmRlciBkaWZmZXJlbnQgZmVydGlsaXplcnMuIFRoZSB0d28td2F5IGRhdGEgdGFibGUgaXMgZ2l2ZW4gYmVsb3cuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjQwJSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJ3ZWVrMDUvVHdvLXdheS1EYXRhLnBuZyIpDQpgYGANCg0KV2UgaGF2ZSB1c2VkIHZhcmlvdXMgUiBjb21tYW5kcyBlYXJsaWVyIHRvIGNvbnZlcnQgYSB0d28td2F5IGRhdGEgdGFibGUgdG8gYW4gUiBkYXRhZnJhbWUgZm9yIHJlZ3Jlc3Npb24gbW9kZWxpbmcuIFdlIG5leHQgdXNlIHNpbWlsYXIgY29kZSB0byBjb252ZXJ0IHRoZSBhYm92ZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCg0KYGBge3J9DQojIyBUbyBhdm9pZCB0eXBpbmcgZXJyb3JzLCB3ZSBpbnB1dCB0aGUgdGFibGUgY2VsbCBieSBjZWxsIGZyb20gdGhlIGRhdGEgdGFibGUNCmNyb3AuZGF0YSA8LSBkYXRhLmZyYW1lKA0KICBGZXJ0aWxpemVyID0gcmVwKGMoIkJsZW5kIFgiLCAiQmxlbmQgWSIsICJCbGVuZCBaIiksIGVhY2ggPSAyMCksDQogIENyb3AgPSByZXAocmVwKGMoIldoZWF0IiwgIkNvcm4iLCAiU295IiwgIlJpY2UiKSwgZWFjaCA9IDUpLCB0aW1lcyA9IDMpLA0KICBZaWVsZCA9IGMoMTIzLCAxNTYsIDExMiwgMTAwLCAxNjgsICAgIyBCbGVuZCBYIC0gV2hlYXQNCiAgICAgICAgICAgIDEyOCwgMTUwLCAxNzQsIDExNiwgMTA5LCAgICMgQmxlbmQgWCAtIENvcm4NCiAgICAgICAgICAgIDE2NiwgMTc4LCAxODcsIDEzMywgMTk1LCAgICMgQmxlbmQgWCAtIFNveQ0KICAgICAgICAgICAgMTUxLCAxMjUsIDExNywgMTU1LCAxMzgsICAgIyBCbGVuZCBYIC0gUmljZQ0KICAgICAgICAgICAgIyMNCiAgICAgICAgICAgIDEzNSwgMTMwLCAxNzYsIDEyMCwgMTU1LCAgICMgQmxlbmQgWSAtIFdoZWF0DQogICAgICAgICAgICAxNzUsIDEzMiwgMTIwLCAxODcsIDE4NCwgICAjIEJsZW5kIFkgLSBDb3JuDQogICAgICAgICAgICAxNDAsIDE0NSwgMTU5LCAxMzEsIDEyNiwgICAjIEJsZW5kIFkgLSBTb3kNCiAgICAgICAgICAgIDE2NywgMTg4LCAxNDIsIDE2NywgMTY4LCAgICMgQmxlbmQgWSAtIFJpY2UNCiAgICAgICAgICAgICMjDQogICAgICAgICAgICAxNTYsIDE4MCwgMTQ3LCAxNDYsIDE5MywgICAjIEJsZW5kIFogLSBXaGVhdA0KICAgICAgICAgICAgMTg2LCAxMzgsIDE3OCwgMTc2LCAxOTAsICAgIyBCbGVuZCBaIC0gQ29ybg0KICAgICAgICAgICAgMTg1LCAyMDYsIDE4OCwgMTY1LCAxODgsICAgIyBCbGVuZCBaIC0gU295DQogICAgICAgICAgICAxNzUsIDE3MywgMTU0LCAxOTEsIDE2OSkgICAjIEJsZW5kIFogLSBSaWNlDQopDQoNCiMgQ29udmVydCBmYWN0b3JzIHRvIGZhY3RvcnMgKGltcG9ydGFudCBmb3IgbW9kZWxpbmcpDQpjcm9wLmRhdGEkRmVydGlsaXplciA8LSBhcy5mYWN0b3IoY3JvcC5kYXRhJEZlcnRpbGl6ZXIpDQpjcm9wLmRhdGEkQ3JvcCA8LSBhcy5mYWN0b3IoY3JvcC5kYXRhJENyb3ApDQpgYGANCg0KTmV4dCwgd2UgZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBhbiBpbnRlcmFjdGlvbiB0ZXJtIGFuZCBsaXN0IHRoZSB0ZXJtcyAoZHVtbXkgdmFyaWFibGVzKSBpbiB0aGUgaW1wbGljaXQgaW50ZXJuYWwgbW9kZWwgZm9ybXVsYSBieSB1c2luZyB0d28gUiBmdW5jdGlvbnMgYG1vZGVsLm1hdHJpeChtb2RlbC5uYW1lKWAgYW5kIGBjb2xuYW1lcyhtb2RlbC5tYXRyaXgubmFtZSlgLiBTZWUgaG93IHRoZXNlIFIgZnVuY3Rpb25zIGFyZSBjYWxsZWQgaW4gdGhlIGZvbGxvd2luZyBjb2RlIGNodW5rLg0KDQpgYGB7cn0NCiMjIEV4cGxpY2l0IGZvcm0gaXMgc3RpbGwgYSBzaW1wbGUNCmNyb3AubG0gPC0gbG0oWWllbGQgfiBDcm9wICogRmVydGlsaXplciwgZGF0YSA9IGNyb3AuZGF0YSkNCiMjIG1vZGVsIG1hdHJpeCBwcm92aWRlcyBhbGwgZHVtbXkgdmFyaWFibGVzIGltcGxpY2l0bHkgZGVmaW5lZCBpbiB0aGUgUg0KbW9kZWwubXR4IDwtIG1vZGVsLm1hdHJpeChjcm9wLmxtKQ0KIyMgZXh0cmFjdCB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBtb2RlbCBtYXRyaXggPT0+IGxpc3Qgb2YgZHVtbXkgdmFyaWFibGVzIGluIHRoZQ0KIyMgaW1wbGljaXQgaW50ZXJuYWwgbW9kZWwgZm9ybXVsYQ0KY29sbmFtZXMobW9kZWwubXR4KQ0KYGBgDQoNClRoZXNlIGR1bW15IHZhcmlhYmxlcyB3aWxsIGFwcGVhciBpbiB0aGUgb3V0cHV0IG9mIHRoZSByZWdyZXNzaW9uIG1vZGVsIGluIHRoZSBzdWJzZXF1ZW50IG1vZGVsIG91dHB1dC4gQmVmb3JlIHN1bW1hcml6aW5nIHRoZSBtb2RlbCwgd2UgY2hlY2sgdGhlIG1vZGVsIGFzc3VtcHRpb25zIHRvIHNlZSB3aGV0aGVyIHNpZ25pZmljYW50IHZpb2xhdGlvbnMgZXhpc3QgdXNpbmcgcmVzaWR1YWwgZGlhZ25vc3RpYyBwbG90cy4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD03fQ0KcGFyKG1mcm93ID0gYygyLDIpKSAgIyBkZWZpbmUgdGhlIGxheW91dCB3aXRoIDJ4MiBncmFwaGljYWwgcGFuZWxzDQpwbG90KGNyb3AubG0pDQpgYGANCg0KDQpUaGUgcmVzaWR1YWwgcGxvdHMgbG9vayBmaW5lIGV4Y2VwdCBmb3IgYSBwYXR0ZXJuIGluIHRoZSBRLVEgcGxvdCwgd2hpY2ggaW5kaWNhdGVzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHJlc2lkdWFscyBpcyBzbGlnaHRseSBza2V3ZWQgdG8gdGhlIGxlZnQuIFdlIHdpbGwgbm90IGV4cGxvcmUgbWV0aG9kcyBvZiByZW1lZGllcyBpbiB0aGlzIGNsYXNzLCBidXQgdGhleSB3aWxsIGJlIGRpc2N1c3NlZCBpbiB0aGUgc3Vic2VxdWVudCBjbGFzc2VzLiBOZXh0LCB3ZSByZXBvcnQgdGhlIHJlc3VsdHMgb2YgdGhlIG1vZGVscy4NCg0KYGBge3J9DQpzdW1tYXJ5KGNyb3AubG0pDQpgYGANCg0KPGZvbnQgY29sb3IgPSAiYmx1ZSIgc2l6ZSA9IDQ+KipcY29sb3J7Ymx1ZX1PdXRwdXQgSW50ZXJwcmV0YXRpb25zKio8L2ZvbnQ+DQoNCiogVGhlIEYtdGVzdCBpbiB0aGUgYm90dG9tIHBvcnRpb24gb2YgdGhlIG91dHB1dCBpbmRpY2F0ZXMgdGhhdCBhdCBsZWFzdCBvbmUgZmFjdG9yIChgY3JvcGAgb3IgYGZlcnRpbGl6ZXJgIG9yIGJvdGgpIGlzIHNpZ25pZmljYW50ICgpDQoNCiogKipJbnRlcmNlcHQqKiAtIHRoZSBtZWFuIG9mIHlpZWxkcyBvZiBjb3JuIHVzaW5nIGZlcnRpbGl6ZXIgWC4gaS5lLiwgPGZvbnQgY29sb3IgPSAicmVkIj4qKlxjb2xvcntyZWR9KDEyOCArIDE1MCArIDE3NCArIDExNiArIDEwOSkvNSA9IDEzNS40LioqPC9mb250PiBUaGlzIGlzIHRoZSBiYXNlbGluZSBjYXRlZ29yeSwgZGVmaW5lZCBieSBgQ29ybmAgYW5kIGBCbGVuZCBYYC4gQWxsIG90aGVyIGNhdGVnb3JpZXMgd2lsbCBiZSBjb21wYXJlZCB0byB0aGlzIGJhc2VsaW5lIGVpdGhlciBkaXJlY3RseSBvciBpbmRpcmVjdGx5Lg0KDQogICsgVGhlIGNvZWZmaWNpZW50cyBmb3IgYENyb3BSaWNlYCwgYENyb3BTb3lgLCBhbmQgYENyb3BXaGVhdGAgcmVwcmVzZW50IHRoZSBkaWZmZXJlbmNlIGluICoqbWVhbiB5aWVsZCoqIGJldHdlZW4gdGhlc2UgY3JvcHMgYW5kIGBDb3JuYCB3aGVuIHVzaW5nIGBCbGVuZCBYYCBmZXJ0aWxpemVyLg0KICArIFRoZSBjb2VmZmljaWVudHMgZm9yIGBGZXJ0aWxpemVyQmxlbmQgWWAgYW5kIGBGZXJ0aWxpemVyQmxlbmQgWmAgcmVwcmVzZW50IHRoZSBkaWZmZXJlbmNlIGluICoqbWVhbiB5aWVsZCoqIGZvciBgQ29ybmAgd2hlbiBjb21wYXJpbmcgYEJsZW5kIFlgIGFuZCBgQmxlbmQgWmAgdG8gdGhlIGJhc2VsaW5lIChgQmxlbmQgWGApLg0KICArIFRoZSBjb2VmZmljaWVudHMgZm9yIHRoZSBpbnRlcmFjdGlvbiB0ZXJtcyBhcmUgbm90IHN0cmFpZ2h0Zm9yd2FyZCB0byBpbnRlcnByZXQgYmVjYXVzZSB0aGV5IHJlcHJlc2VudCBjb21iaW5lZCBlZmZlY3RzLiBSZWZlciB0byB0aGUgYW5ub3RhdGVkIG91dHB1dCBhbmQgb3JpZ2luYWwgZGF0YSB0YWJsZSBiZWxvdyB0byB1bmRlcnN0YW5kIGhvdyB0aGVzZSBpbnRlcmFjdGlvbiB0ZXJtIGNvZWZmaWNpZW50cyB3ZXJlIGNhbGN1bGF0ZWQuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9Ijk5JSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJ3ZWVrMDUvQW5ub2F0ZWQyd2F5QU5PVkEucG5nIikNCmBgYA0KDQpBcyB3ZSBkaWQgd2l0aCB0aGUgb25lLXdheSBBTk9WQSwgd2UgY2FuIGFsc28gZXh0cmFjdCB0aGUgdHdvLXdheSBBTk9WQSB0YWJsZSBkaXJlY3RseSBmcm9tIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBhYm92ZS4NCg0KYGBge3J9DQphbm92YShjcm9wLmxtKQ0KYGBgDQoNClRoZSB0d28td2F5IEFOT1ZBIHRhYmxlIHByb3ZpZGVzIHRocmVlIEYtdGVzdHMgZm9yIGFzc2Vzc2luZyB0aGUgdHdvIGluZGl2aWR1YWwgZmFjdG9ycyBhbmQgdGhlaXIgaW50ZXJhY3Rpb24gZWZmZWN0LCB3aGVyZWFzIHRoZSBGLXRlc3QgaW4gdGhlIHJlZ3Jlc3Npb24gb3V0cHV0IG9ubHkgdGVzdHMgd2hldGhlciBhbGwgZmFjdG9ycyBhcmUgam9pbnRseSBpbnNpZ25pZmljYW504oCUYSBnbG9iYWwgZ29vZG5lc3Mtb2YtZml0IG1lYXN1cmUuIEZyb20gdGhpcyBwZXJzcGVjdGl2ZSwgdGhlIHR3by13YXkgQU5PVkEgRi10ZXN0cyBvZmZlciBtb3JlIGdyYW51bGFyIGluc2lnaHRzLiBIb3dldmVyLCByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGluZmVyZW5jZSBhbGxvd3MgZm9yIG1vcmUgZGV0YWlsZWQgdGVzdGluZyBhdCBpbmRpdmlkdWFsIGZhY3RvciBsZXZlbHMsIGFzIHdlbGwgYXMgZm9yIGludGVyYWN0aW9uIGVmZmVjdHMgYmV0d2VlbiBmYWN0b3IgbGV2ZWxzLiBBbHRob3VnaCBUdWtleeKAmXMgSFNEIHByb2NlZHVyZSBwcm92aWRlcyBjb25maWRlbmNlIGludGVydmFscyAoYW5kIGZhbWlseS13aXNlIHRlc3RzIGZvciBzaW11bHRhbmVvdXMgY29tcGFyaXNvbnMpLCBpdCBkb2VzIG5vdCBleHBsaWNpdGx5IGFjY291bnQgZm9yIGludGVyYWN0aW9uIGVmZmVjdHMgaW4gdGhlIG11bHRpcGxlIGNvbXBhcmlzb25zLg0KDQoNCmBgYHtyfQ0KIyMgZml0IGFuIGFub3ZhIG1vZGVsIHNpbmNlIFR1a2V5SFNEKCkgcmVxdWlyZXMgdGhlIGFvdigpIG9iamVjdA0KY3JvcC5hb3YgPC0gYW92KFlpZWxkIH4gQ3JvcCAqIEZlcnRpbGl6ZXIsIGRhdGEgPSBjcm9wLmRhdGEpDQojIyBIU0QgY2FsbHMNClR1a2V5SFNEKGNyb3AuYW92KQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgYW5ub3RhdGVkIG91dHB1dCBpbGx1c3RyYXRlcyBob3cgdG8gY2FsY3VsYXRlIHZhcmlvdXMgZGlmZmVyZW5jZXMgaW4gdGhlIHJlc3VsdHMgb2YgVHVrZXnigJlzIEhTRCBwcm9jZWR1cmUuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9Ijk5JSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJ3ZWVrMDUvSFNELUFubm90YXRpb24ucG5nIikNCmBgYA0KDQoNCldlIGNhbiBzZWUgdGhhdCBUdWtleSdzIEhTRC4gDQoNCg0KVGhlIGZvbGxvd2luZyBZb3VUdWJlIHZpZGVvICgyOCBtaW51dGVzKSBpcyBvbmUgb2YgdGhlIHZlcnkgZmV3IHRoYXQgdXNlcyBhIGxpbmVhciByZWdyZXNzaW9uIGFwcHJvYWNoIHRvIHBlcmZvcm0gQU5PVkEgYW5hbHlzaXMgKDxodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUNTNW9nQkwtTUhvPikuIFBsZWFzZSBwYXkgY2xvc2UgYXR0ZW50aW9uIHRvIHRoZSBleHBsYW5hdGlvbiBvZiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gb3V0cHV0LCBwYXJ0aWN1bGFybHkgdGhlIGV4cGxhbmF0aW9uIG9mIHRoZSB0d28td2F5IEFOT1ZBIHdpdGggaW50ZXJhY3Rpb24gdGVybS4NClwNCg0KPGNlbnRlcj48YSBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUNTNW9nQkwtTUhvIiB0YXJnZXQ9InBvcHVwIiANCiAgICAgICAgICAgICAgICAgICBvbmNsaWNrPSJ3aW5kb3cub3BlbignaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1DUzVvZ0JMLU1IbycsDQogICAgICAgICAgICAgICAgICAgICAgJ25hbWUnLCd3aWR0aD04NTAsaGVpZ2h0PTUwMCcpIj48aW1nIHNyYyA9ICJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9NQVQxMjFXNS9pbWcvVmlkZW9JY29uLnBuZyIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiPjwvYT4NCjwvY2VudGVyPg0KDQpcDQoNCkZpbmFsbHksIHByYWN0aWNlIHR3by13YXkgQU5PVkEgdXNpbmcgcmVncmVzc2lvbiBhcHByb2FjaGVzIGJhc2VkIG9uIHRoZSBmb2xsb3dpbmcgZGF0YSB0YWJsZSB3aXRoIHR3byBiaW5hcnkgZmFjdG9ycy4gQmVjYXVzZSBib3RoIGZhY3RvcnMgYXJlIGJpbmFyeSwgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSBvdXRwdXQgc2hvdWxkIGJlIHN0cmFpZ2h0Zm9yd2FyZC4gDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjcwJSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJ3ZWVrMDQvUmVwbGljYXRlUkJELXdvcmtpbmdEYXRhLnBuZyIpDQpgYGANCg0KDQo=