1 Introduction

Missing data are questions without answers or variables without observations. They are a common and significant challenge in the survey. They often influence the selection of a statistical method of analysis, and, depending on their severity, can undermine the confidence of analysis, or even result in wrong conclusions.

2 Sources of Missing Data

Missing data occur in survey research due to various reasons.

  • Total Non-response: a sampled subject does not participate in the survey. Total non-response results from refusals to participate in the survey, non-contacts (not-at-homes), and other reasons such as a language barrier, deafness, or being too ill to participate.

  • Non-coverage: a subject in the target population is not included in the survey’s sampling frame. It occurs when some subjects in the population of inference for the survey are not included in the survey’s sampling frame. These missing subjects have no chance of selection for the sample and hence go unrepresented.

  • Item Non-response: a responding sampled subject fails to provide acceptable responses to one or more of the survey items. Item non-response may arise because

    • a respondent refuses to answer an item because it is too sensitive, does not know the answer to the item, gives an answer that is inconsistent with answers to other items and hence is deleted in editing;
    • the interviewer fails to ask the question or record the answer.
  • Partial Non-response: Partial non-response falls between total and item non-response. Whereas total non-response relates to a failure to obtain any responses from a sampled subject and item non-response usually implies the failure to obtain responses for only a small number of survey items. Partial non-response involves a substantial number of item non-responses. It can occur, for instance,

    • when a respondent cuts off the interview in the middle,
    • when a respondent in a panel survey fails to provide data for one or more of the waves of the panel, or
    • when a respondent in a multi-phase survey provides data for some but not all phases of data collection.

3 Patterns and Mechanisms of Missing Data

Before choosing appropriate methods to handle missing data, we need to know the patterns and mechanisms of missing data.

3.1 Missing Data Patterns

Missing data can be grouped according to the missing data pattern, which describes which values are observed and which values are missing in the data matrix. In general, missing data patterns can be roughly classified into a variety of groups, such as univariate, multivariate, monotone, non-monotone, and file matching (Little and Rubin, 2002).

A univariate missing pattern indicates a situation where missing data occur only in a single variable. As an extension of the univariate case, the multivariate missing pattern refers to missing data in a set of variables, either for the entire unit or for particular items in a questionnaire.

  • If a variable is missing for a particular subject not only at a specific time point but also at all subsequent time occasions, the missing data pattern for this individual is said to be a monotone missing pattern.

  • If a case is missing at a given time point and then returns at a later follow-up investigation, then the missing data pattern for this subject is referred to as the non-monotone missing data.

In longitudinal data analysis, the non-monotone missing pattern can cause more problems than the monotone pattern and thus deserves close attention. There are more missing data patterns such as the latent-factor patterns with variables that are never observed. For each missing data pattern, there are corresponding statistical techniques to handle its impact on the quality of data analysis.

3.2 Types of Missing Data Mechanisms

Missing data mechanisms concern the relationship between missing data and the values of variables in the data matrix. Given this focus, missing data mechanisms can be categorized into three classes: missing completely at random (MCAR), missing at random (MAR), and missing not at random (MNAR).

  • Missing Completely at Random (MCAR): If missing data are unrelated to both the missing responses and the set of observed responses, the observed values are representative of the entire sample without missing values. This missing data mechanism is referred to as MCAR. This is the best we can hope for since we can simply ignore the records with missing components (list-wise deletion) without introducing bias to the data.

  • Missing at Random (MAR): If missing data depend on the set of observed responses but are unrelated to the missing values, the missing data are said to be MAR. For example, a registry examining depression may encounter data that are MAR if male participants are less likely to complete a survey about depression severity than female participants. That is, if the probability of completion of the survey is related to their sex (which is fully observed) but not the severity of their depression, then the data may be regarded as MAR. Since there is a systematic relationship between the propensity of missing values and the observed data, but not the missing data. What it means, is that the missing data can be predicted by other variables in the data set.

  • Missing Not at Random (MNAR): There is a pattern in the missing data that affects the primary dependent variables. We can extend the above “depression” example if participants with severe depression are more likely to refuse to complete the survey about depression severity. Since the sources of missing data are themselves unmeasured means that (in general) this issue cannot be addressed in analysis, and the estimate of effect will likely be biased. Missing not at random is the worst-case scenario. We should use MNAR data with caution since these missing data cannot be “recovered”.

4 Methods of Handling Missing Data

Methods of handling missing data are dependent on the missing data mechanisms. We have briefly discussed three major types of missing mechanisms in the previous sections. Here is a summary of these mechanisms.

  • In MCAR, the missing mechanism is independent of characteristics of either the observed data or the unobserved values in the data set.

  • In MAR, the missing mechanism is entirely explained by the observed data, that is, after observed values are accounted for, missingness is randomly distributed.

  • In MNAR, missing observations are dependent upon unobserved values; missingness cannot be accounted for by controlling for observed data.

In the subsequent sub-sections, we will outline the major methods used to handle missing data with different types of missing mechanisms.

4.1 Listwise Deletion

Delete all data from any participant with missing values. If the sample is large enough, we likely can drop data without substantial loss of statistical power. Be sure that the values are missing at random and that you are not inadvertently removing a class of participants.

This method is used for MCAR and, occasionally, MAR. It is the easiest and simplest method among all other available methods.

The disadvantages are

  • loss of valuable information;
  • potential contribution to bias;
  • loss of statistical power;

4.2 Mean Replacement

For variable “X” with missing values, take the mean of all included observations. Substitute the mean of “X” for missing values of “X”. This is a type of simple imputation method.

It is valid for MCAR. The advantages are

  • preserving the mean of the data set;
  • simple;
  • allowing use of all observations

The disadvantages are

  • artificially reducing the standard deviation of the data set,
  • distorting relationships between variables;
  • yielding potentially biased estimates;
  • producing results that are highly statistically significant, but inaccurate;

4.3 Regression Replacement

This is another method of single imputation. It estimates the distribution of the missing variable(s), given covariates, takes a random draw from this distribution for each value then performs analysis as usual.

The regression replacement is valid for both MCAR and MAR. The advantages are * avoidance of bias in estimating; * simpler than multiple imputations;

The disadvantages are

  • misrepresenting uncertainty of estimates;
  • more complicated than list-wise deletion or mean replacement
  • reducing confidence intervals of estimates although theoretically unbiased.

4.4 Multiple Imputation

Multiple Imputation is the most sophisticated and, currently, most popular approach to take the regression idea further and take advantage of correlations between responses.

It estimates the distribution (Bayesian posterior distribution) of the missing variable, given covariates; takes random draws from this distribution to produce multiple versions (usually 3–10) of an imputed data set; performs analysis on each imputed data set and pools the results. It is a simulation-based Bayesian method. Most statistical computer programs can do multiple imputations.

It is valid for MCAR or MAR. The advantages are

  • accounting for the extra uncertainty produced by imputing data;
  • producing better estimates of missing values.

The disadvantages are

  • requiring complicated statistical methods or complicated software;
  • harder to understand;
  • taking extra steps;
  • because the method accounts for extra uncertainty, results can be interpreted as if data were not missing.

5 R Packages for Imputation

Several R packages have functions to perform imputation for missing values. This section lists a few commonly used R libraries. We only explain the concepts with no coding.

5.1 MICE Package

MICE (Multivariate Imputation via Chained Equations) is one of the commonly used packages by R users. Creating multiple imputations as compared to a single imputation (such as the mean) takes care of uncertainty in missing values.

MICE assumes that the missing data are Missing at Random (MAR), which means that the probability that a value is missing depends only on the observed value and can be predicted using them. It imputes data on a variable-by-variable basis by specifying an imputation model per variable.

As an example, we consider a data set with variables \(X_1, X_2, \cdots, X_k\). If \(X_1\) has missing values, then it will be regressed on other variables \(X_2\) to \(X_k\). The missing values in \(X_1\) will be then replaced by predictive values obtained. Similarly, if \(X_2\) has missing values, then \(X_1\), \(X_3\) to \(X_k\) variables will be used in the prediction model as independent variables. Later, missing values will be replaced with predicted values.

By default, linear regression is used to predict continuous missing values. Logistic regression is used for categorical missing values. Once this cycle is complete, multiple data sets are generated. These data sets differ only in imputed missing values. Generally, it’s considered to be a good practice to build models on these data sets separately and combine their results.

Precisely, the methods used by this package can be found in the document of the package at https://cran.r-project.org/web/packages/mice/mice.pdf.

5.2 Hmisc Package

Hmisc is a multiple-purpose package useful for data analysis, high–level graphics, imputing missing values, advanced table making, model fitting & diagnostics (linear regression, logistic regression & cox regression), etc. Amidst, the wide range of functions contained in this package, it offers 2 powerful functions for imputing missing values. These are impute() and aregImpute(). Though it also has transcan() function, aregImpute() is better to use.

impute() function simply imputes missing values using a user-defined statistical method (mean, max, mean). Its default is median. On the other hand, aregImpute() allows the mean imputation using additive regression, bootstrapping, and predictive mean matching.

In bootstrapping, different bootstrap resamples are used for each of the multiple imputations. Then, a flexible additive model (non-parametric regression method) is fitted on samples taken with replacements from original data, and missing values (acts as dependent variable) are predicted using non-missing values (independent variable).

Then, it uses predictive mean matching (default) to impute missing values. Predictive mean matching works well for continuous and categorical (binary & multi-level) without the need for computing residuals and maximum likelihood fit.

More functions and updates in Hmisc package can be found at https://cran.r-project.org/web/packages/Hmisc/Hmisc.pdf

6 The MICE Algorithm

The MICE process follows a systematic approach to iteratively impute missing data. It involves creating multiple versions of the data set with plausible estimates for missing values while preserving the relationships among variables.

In the R library mice(), argument maxit = m indicates the number of cycles (iterations) of the iterative imputing process. To illustrate this iterative imputation process, we use the following toy data to show the logical process.

include_graphics("img/MI-Iterative-Imputed-Process.jpg")
Iterative imputation process in MI.

Iterative imputation process in MI.

Below is an algorithm that summarizes the above MICE process.

MICE Algorithm

Step 1: Initialize imputed values
        1.1. For each variable with missing values, impute initial values using 
             a simple imputation method (e.g., mean, median, mode imputation, 
             or regression).
        1.2. These initial imputations will be used as starting values in the 
             iterative process.
Step 2: Set up the imputation model for each variable
        2.1. Define the imputation model for each variable with missing data. 
             The model can be different for each variable and can be based on a 
             regression model (e.g., linear regression, logistic regression) or 
             other models depending on the nature of the data.
        2.2. The variable to be imputed (dependent variable) will be regressed 
             on other variables in the dataset (predictor variables).
Step 3: Iterative imputation process
        3.1. For each iteration t, repeat the following process for each variable 
             with missing values:
             3.1.1. For each variable Vi with missing data, use the current values 
                    of the other variables (including previously imputed values) 
                    to predict the missing values for Vi.
             3.1.2. The model for imputation of Vi is fitted to the complete data 
                    (where no missing values exist for Vi).
             3.1.3. Impute missing values for Vi based on the model fit in step 
                    3.1.2, replacing the missing values with predicted values 
                    (this imputation is stochastic, introducing random variability 
                    to account for uncertainty).
        3.2. Repeat this process for all variables with missing data.
Step 4: Perform multiple imputations
        4.1. Repeat Step 3 m times (with m being the number of imputations) to 
             create m different imputed datasets. Each dataset will contain 
             imputed values for the missing data based on different imputations, 
             reflecting the uncertainty in the imputation process.
Step 5: Analyze each imputed dataset
         5.1. Perform the desired analysis (e.g., regression, hypothesis testing) 
              on each of the m imputed datasets, yielding m sets of results.
Step 6: Pool the results using Rubin's Rules
         6.1. Combine the results from the m datasets using Rubin’s rules:
              6.1.1. Combine the parameter estimates (e.g., regression coefficients) 
                     by averaging them across the m datasets.
              6.1.2. Combine the variance estimates, accounting for both the 
                     within-imputed dataset variance and the between-imputed 
                     dataset variance.
              6.1.3. Calculate the overall standard errors, confidence intervals, 
                     and p-values based on the combined estimates.
Step 7: Report on the combined results
        7.1. Present the final, pooled results, including the combined estimates, 
             standard errors, and confidence intervals.

The R mice library has several functions listed below to extract relevant information in the above algorithm.

mice() Impute the missing data m times

with() Analyze completed data sets.

pool() Combine parameter estimates.

complete() Export imputed data.

ampute() Generate missing data.

6.1 Numerical Example

For ease of illustration, we use the built-in airquality data in the subsequent examples. The first few records in the data are given below.

library(mice)
data <- airquality  # Example dataset with missing values
data[1:10,]
   Ozone Solar.R Wind Temp Month Day
1     41     190  7.4   67     5   1
2     36     118  8.0   72     5   2
3     12     149 12.6   74     5   3
4     18     313 11.5   62     5   4
5     NA      NA 14.3   56     5   5
6     28      NA 14.9   66     5   6
7     23     299  8.6   65     5   7
8     19      99 13.8   59     5   8
9      8      19 20.1   61     5   9
10    NA     194  8.6   69     5  10

1. Initialization

The process begins by assigning initial values to all missing entries in the data set. These initial values are often derived using simple imputation techniques, such as:

  • Replacing missing numeric values with the mean or median.

  • Filling missing categorical values with the mode.

This step provides a starting point for the iterative process.

init <- mice(data, maxit = 0)  # Check initial imputation setup
init$method                    # View default imputation methods
  Ozone Solar.R    Wind    Temp   Month     Day 
  "pmm"   "pmm"      ""      ""      ""      "" 

2. Imputation Models

Each variable with missing data is assigned a specific imputation model tailored to its data type. Some commonly used models are listed below.

  • Predictive Mean Matching (pmm): For continuous variables.
  • Logistic Regression (logreg): For binary variables.
  • Polytomous Regression (polyreg): For categorical variables.
  • Proportional Odds Model (polr): For ordinal variables.

These models predict missing values based on other observed variables in the data set. As an example, we impute only one data (under the iterative imputing process illustrated earlier).

library(mice)
dat <- airquality  # Example data set with missing values
## individual variable 
imp <- mice(dat, method = c("pmm","pmm", "pmm", "pmm",  "", ""), 
                 maxit = 10,  # iterating 10 cycles to complete each imputed data set
                 m = 1,       # generate 1 imputed data set
                 print=F)     # suppress printouts
## we use complete() tp view the complete data set.
complete(imp, action = 1L)[1:10,]  # The default *action = 1L* returns the first
   Ozone Solar.R Wind Temp Month Day
1     41     190  7.4   67     5   1
2     36     118  8.0   72     5   2
3     12     149 12.6   74     5   3
4     18     313 11.5   62     5   4
5     19     150 14.3   56     5   5
6     28     254 14.9   66     5   6
7     23     299  8.6   65     5   7
8     19      99 13.8   59     5   8
9      8      19 20.1   61     5   9
10    30     194  8.6   69     5  10
                                   # imputed (complete) data set.

3. Iterative Imputation

The core of the MICE process is its iterative nature:

  • Each variable with missing data is treated as a dependent variable, while all other variables act as predictors.

  • Missing values for the target variable are imputed using the assigned model.

  • This process cycles through all variables with missing data, iteratively refining the imputations.

The iterations continue until the imputed values stabilize, indicating convergence.

data <- airquality  # Example data set with missing values
imp <- mice(data, method = "pmm", # using predictive mean matching (ppm)
                  maxit = 10,  # pre-specified cycles in the iterative process
                  m = 2,       # generate 2 imputed data sets
                  seed = 123,  # setting seed to keep reproducibility of the process
                  print=F)     # suppress printouts
complete(imp, action = "broad")[1:10,] # *action = "broad"* combines the two imputed 
   Ozone.1 Solar.R.1 Wind.1 Temp.1 Month.1 Day.1 Ozone.2 Solar.R.2 Wind.2
1       41       190    7.4     67       5     1      41       190    7.4
2       36       118    8.0     72       5     2      36       118    8.0
3       12       149   12.6     74       5     3      12       149   12.6
4       18       313   11.5     62       5     4      18       313   11.5
5        6       273   14.3     56       5     5       8        47   14.3
6       28       186   14.9     66       5     6      28       192   14.9
7       23       299    8.6     65       5     7      23       299    8.6
8       19        99   13.8     59       5     8      19        99   13.8
9        8        19   20.1     61       5     9       8        19   20.1
10      16       194    8.6     69       5    10      24       194    8.6
   Temp.2 Month.2 Day.2
1      67       5     1
2      72       5     2
3      74       5     3
4      62       5     4
5      56       5     5
6      66       5     6
7      65       5     7
8      59       5     8
9      61       5     9
10     69       5    10
                                # data sets in a wide table. There are other 
                                # options to lay out the imputed data sets.

3. Multiple Imputations

Multiple imputed data sets are created to capture the variability introduced by missing data.

imp5 <- mice(data, method = "pmm", m = 5, maxit = 10, seed = 123, print=F)
plot(imp5)
Line plots of means and standard deviations of the two numerical variables with missing values in each imputed data sets.

Line plots of means and standard deviations of the two numerical variables with missing values in each imputed data sets.

Here, m = 5 specifies the number of imputations, and maxit = 10 defines the number of iterations.

4. Analysis and Pooling

Each imputed data set is analyzed independently, and the results are combined using Rubin’s Rules to produce final estimates and standard errors.

model5 <- with(imp5, lm(Ozone ~ Wind + Temp))  # The statistical model to assess
                                               # the relationship between *Ozone*
                                               # and *Wind* and *Temp*.
summary.stats = summary(model5)                # display the regression results of 
                                               # individual imputed data set.
summary.stats 
# A tibble: 15 × 6
   term        estimate std.error statistic  p.value  nobs
   <chr>          <dbl>     <dbl>     <dbl>    <dbl> <int>
 1 (Intercept)   -63.4     19.3       -3.28 1.29e- 3   153
 2 Wind           -3.19     0.554     -5.75 4.74e- 8   153
 3 Temp            1.77     0.206      8.57 1.17e-14   153
 4 (Intercept)   -53.3     20.5       -2.60 1.03e- 2   153
 5 Wind           -3.32     0.588     -5.64 8.15e- 8   153
 6 Temp            1.64     0.219      7.51 5.00e-12   153
 7 (Intercept)   -75.4     19.4       -3.89 1.48e- 4   153
 8 Wind           -2.67     0.556     -4.81 3.69e- 6   153
 9 Temp            1.84     0.207      8.90 1.72e-15   153
10 (Intercept)   -84.4     19.8       -4.27 3.46e- 5   153
11 Wind           -2.38     0.567     -4.19 4.75e- 5   153
12 Temp            1.94     0.211      9.19 3.12e-16   153
13 (Intercept)   -66.5     19.8       -3.35 1.01e- 3   153
14 Wind           -2.82     0.569     -4.95 1.98e- 6   153
15 Temp            1.75     0.212      8.24 7.86e-14   153

To combine the results, we simply take the average of the corresponding estimated regression coefficients.

summary(pool(model5))
         term   estimate  std.error statistic       df      p.value
1 (Intercept) -68.572693 23.6337059 -2.901479 30.90197 6.788592e-03
2        Wind  -2.874688  0.7062186 -4.070535 23.79733 4.468363e-04
3        Temp   1.787463  0.2431392  7.351602 41.42155 4.972123e-09

The above-pooled results are calculated based on the formulas on \(Q, U, B\), and \(T\). The following code illustrates the calculation of the pooled standard error of the intercept.

beta = summary.stats$estimate[seq(1,15,by=3)]  # explicit vector: c(1,4,7,10,13)
beta.var = (summary.stats$std.error[seq(1,15,by=3)])^2 
Q = mean(beta)
U = mean(beta.var)
B = var(beta)
T = U + (6/5)*B
pool.se = sqrt(T)
cbind(pool.se.intercept = pool.se)
     pool.se.intercept
[1,]          23.63371

6.2 Advantages of MICE

MICE offers several benefits:

  • Flexibility: It handles mixed data types (continuous, binary, categorical).
  • Preservation of Relationships: Imputation respects the relationships between variables.
  • Uncertainty Representation: Multiple imputations account for variability in missing data.

In R, the mice package simplifies MICE implementation, allowing users to customize imputation methods for each variable. The main function mice() can detect the missingness of individual variables. If a variable has no missing values, the imputing model will be automatically set to "".

imp6 <- mice(data, method = c("pmm", "pmm", "pmm", "pmm", "", ""), 
            maxit = 5,
            print=F, 
            seed = 123)
imp6$method  
  Ozone Solar.R    Wind    Temp   Month     Day 
  "pmm"   "pmm"      ""      ""      ""      "" 
## without mno specified imputing model
init <- mice(data,   
            maxit = 5,
            print=F, 
            seed = 123)
init$method
  Ozone Solar.R    Wind    Temp   Month     Day 
  "pmm"   "pmm"      ""      ""      ""      "" 

In this example, predictive mean matching (pmm) is used for continuous variables. If there is a binary categorical variable with missing values, logistic regression (logreg) will be used as the imputed model.

6.3 Challenges of MICE

Despite its advantages, MICE comes with challenges:

  • Computational Intensity: Large datasets and high missingness can increase computation time.
  • Model Specification: Poorly chosen imputation models may lead to inaccurate results.
  • Dependence on Data Quality: Errors in observed data can propagate through imputations.

In R, proper pre-processing, including outlier handling and transformation, can mitigate some challenges.

6.4 Practical Applications of MICE

MICE is widely used in various fields, including healthcare, social sciences, and survey research. For instance:

In clinical trials, MICE imputes missing patient data to preserve the study’s integrity.

In surveys, it handles incomplete responses while maintaining representativeness.

# Imputation for a survey dataset
survey_data <- data.frame(
  Age = c(25, 30, NA, 35, 40),
  Gender = c("Male", "Female", "Male", NA, "Female"),
  Income = c(50000, NA, 60000, 65000, 70000)
)
imp <- mice(survey_data, method = c("pmm", "logreg", "pmm"), maxit = 5, 
            print=F, seed = 123)
Warning: Number of logged events: 1
complete_data <- complete(imp)
print(complete_data)
  Age Gender Income
1  25   Male  50000
2  30 Female  70000
3  25   Male  60000
4  35   <NA>  65000
5  40 Female  70000

Here, polyreg is used for categorical variables, showcasing MICE’s versatility.

6.5 Conclusion

MICE is a powerful and flexible tool for handling missing data, ensuring robust and unbiased statistical analyses. Its iterative process, reliance on tailored imputation models, and ability to account for uncertainty make it a cornerstone of modern data science. With tools like the mice package in R, implementing MICE has become more accessible, enabling analysts to address missing data challenges effectively. While it requires careful implementation, the benefits of using MICE far outweigh its challenges, making it an essential technique for high-quality data analysis.

LS0tDQp0aXRsZTogIkhhbmRsaW5nIE1pc3NpbmcgRGF0YSBpbiBTdXJ2ZXkiDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIiAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAga2VlcF90ZXg6IGZhbHNlDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiA1DQogICAgZmlnX2hlaWdodDogNA0KLS0tDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjBweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCjwvc3R5bGU+DQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoIndlYnNob3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygid2Vic2hvdCIpDQogICBsaWJyYXJ5KHdlYnNob3QpDQp9DQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikNCiAgIGxpYnJhcnkocHN5Y2gpDQp9DQppZiAoIXJlcXVpcmUoImNvY3JvbiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJjb2Nyb24iKQ0KICAgbGlicmFyeShjb2Nyb24pDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQoNCg0KIyBrbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICJDOi9Vc2Vycy83NUNQRU5HL09uZURyaXZlIC0gV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkgb2YgUEEvRG9jdW1lbnRzIikNCiMga25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiQzpcXFNUQTQ5MFxcdzA1IikNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduPSdjZW50ZXInLCANCiAgICAgICAgICAgICAgICAgICAgICBmaWcucG9zID0gJ2h0JykNCmBgYA0KDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KTWlzc2luZyBkYXRhIGFyZSBxdWVzdGlvbnMgd2l0aG91dCBhbnN3ZXJzIG9yIHZhcmlhYmxlcyB3aXRob3V0IG9ic2VydmF0aW9ucy4gVGhleSBhcmUgYSBjb21tb24gYW5kIHNpZ25pZmljYW50IGNoYWxsZW5nZSBpbiB0aGUgc3VydmV5LiBUaGV5IG9mdGVuIGluZmx1ZW5jZSB0aGUgc2VsZWN0aW9uIG9mIGEgc3RhdGlzdGljYWwgbWV0aG9kIG9mIGFuYWx5c2lzLCBhbmQsIGRlcGVuZGluZyBvbiB0aGVpciBzZXZlcml0eSwgY2FuIHVuZGVybWluZSB0aGUgY29uZmlkZW5jZSBvZiBhbmFseXNpcywgb3IgZXZlbiByZXN1bHQgaW4gd3JvbmcgY29uY2x1c2lvbnMuDQoNCiMgU291cmNlcyBvZiBNaXNzaW5nIERhdGENCg0KTWlzc2luZyBkYXRhIG9jY3VyIGluIHN1cnZleSByZXNlYXJjaCBkdWUgdG8gdmFyaW91cyByZWFzb25zLg0KDQoqICoqVG90YWwgTm9uLXJlc3BvbnNlKio6IGEgc2FtcGxlZCBzdWJqZWN0IGRvZXMgbm90IHBhcnRpY2lwYXRlIGluIHRoZSBzdXJ2ZXkuIFRvdGFsIG5vbi1yZXNwb25zZSByZXN1bHRzIGZyb20gcmVmdXNhbHMgdG8gcGFydGljaXBhdGUgaW4gdGhlIHN1cnZleSwgbm9uLWNvbnRhY3RzIChub3QtYXQtaG9tZXMpLCBhbmQgb3RoZXIgcmVhc29ucyBzdWNoIGFzIGEgbGFuZ3VhZ2UgYmFycmllciwgZGVhZm5lc3MsIG9yIGJlaW5nIHRvbyBpbGwgdG8gcGFydGljaXBhdGUuIA0KDQoqICoqTm9uLWNvdmVyYWdlKio6IGEgc3ViamVjdCBpbiB0aGUgdGFyZ2V0IHBvcHVsYXRpb24gaXMgbm90IGluY2x1ZGVkIGluIHRoZSBzdXJ2ZXnigJlzIHNhbXBsaW5nIGZyYW1lLiBJdCBvY2N1cnMgd2hlbiBzb21lIHN1YmplY3RzIGluIHRoZSBwb3B1bGF0aW9uIG9mIGluZmVyZW5jZSBmb3IgdGhlIHN1cnZleSBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBzdXJ2ZXnigJlzIHNhbXBsaW5nIGZyYW1lLiBUaGVzZSBtaXNzaW5nIHN1YmplY3RzIGhhdmUgbm8gY2hhbmNlIG9mIHNlbGVjdGlvbiBmb3IgdGhlIHNhbXBsZSBhbmQgaGVuY2UgZ28gdW5yZXByZXNlbnRlZC4gDQoNCiogKipJdGVtIE5vbi1yZXNwb25zZSoqOiBhIHJlc3BvbmRpbmcgc2FtcGxlZCBzdWJqZWN0IGZhaWxzIHRvIHByb3ZpZGUgYWNjZXB0YWJsZSByZXNwb25zZXMgdG8gb25lIG9yIG1vcmUgb2YgdGhlIHN1cnZleSBpdGVtcy4gIEl0ZW0gbm9uLXJlc3BvbnNlIG1heSBhcmlzZSBiZWNhdXNlIA0KICAtIGEgcmVzcG9uZGVudCByZWZ1c2VzIHRvIGFuc3dlciBhbiBpdGVtIGJlY2F1c2UgaXQgaXMgdG9vIHNlbnNpdGl2ZSwgZG9lcyBub3Qga25vdyB0aGUgYW5zd2VyIHRvIHRoZSBpdGVtLCBnaXZlcyBhbiBhbnN3ZXIgdGhhdCBpcyBpbmNvbnNpc3RlbnQgd2l0aCBhbnN3ZXJzIHRvIG90aGVyIGl0ZW1zIGFuZCBoZW5jZSBpcyBkZWxldGVkIGluIGVkaXRpbmc7DQogIC0gdGhlIGludGVydmlld2VyIGZhaWxzIHRvIGFzayB0aGUgcXVlc3Rpb24gb3IgcmVjb3JkIHRoZSBhbnN3ZXIuIA0KDQoqICoqUGFydGlhbCBOb24tcmVzcG9uc2UqKjogUGFydGlhbCBub24tcmVzcG9uc2UgZmFsbHMgYmV0d2VlbiB0b3RhbCBhbmQgaXRlbSBub24tcmVzcG9uc2UuIFdoZXJlYXMgdG90YWwgbm9uLXJlc3BvbnNlIHJlbGF0ZXMgdG8gYSBmYWlsdXJlIHRvIG9idGFpbiBhbnkgcmVzcG9uc2VzIGZyb20gYSBzYW1wbGVkIHN1YmplY3QgYW5kIGl0ZW0gbm9uLXJlc3BvbnNlIHVzdWFsbHkgaW1wbGllcyB0aGUgZmFpbHVyZSB0byBvYnRhaW4gcmVzcG9uc2VzIGZvciBvbmx5IGEgc21hbGwgbnVtYmVyIG9mIHN1cnZleSBpdGVtcy4gUGFydGlhbCBub24tcmVzcG9uc2UgaW52b2x2ZXMgYSBzdWJzdGFudGlhbCBudW1iZXIgb2YgaXRlbSBub24tcmVzcG9uc2VzLiBJdCBjYW4gb2NjdXIsIGZvciBpbnN0YW5jZSwNCiAgLSB3aGVuIGEgcmVzcG9uZGVudCBjdXRzIG9mZiB0aGUgaW50ZXJ2aWV3IGluIHRoZSBtaWRkbGUsIA0KICAtIHdoZW4gYSByZXNwb25kZW50IGluIGEgcGFuZWwgc3VydmV5IGZhaWxzIHRvIHByb3ZpZGUgZGF0YSBmb3Igb25lIG9yIG1vcmUgb2YgdGhlIHdhdmVzIG9mIHRoZSBwYW5lbCwgb3IgDQogIC0gd2hlbiBhIHJlc3BvbmRlbnQgaW4gYSBtdWx0aS1waGFzZSBzdXJ2ZXkgcHJvdmlkZXMgZGF0YSBmb3Igc29tZSBidXQgbm90IGFsbCBwaGFzZXMgb2YgZGF0YSBjb2xsZWN0aW9uLiANCg0KDQojIFBhdHRlcm5zIGFuZCBNZWNoYW5pc21zIG9mIE1pc3NpbmcgRGF0YQ0KDQpCZWZvcmUgY2hvb3NpbmcgYXBwcm9wcmlhdGUgbWV0aG9kcyB0byBoYW5kbGUgbWlzc2luZyBkYXRhLCB3ZSBuZWVkIHRvIGtub3cgdGhlIHBhdHRlcm5zIGFuZCBtZWNoYW5pc21zIG9mIG1pc3NpbmcgZGF0YS4NCg0KIyMgTWlzc2luZyBEYXRhIFBhdHRlcm5zDQoNCk1pc3NpbmcgZGF0YSBjYW4gYmUgZ3JvdXBlZCBhY2NvcmRpbmcgdG8gdGhlIG1pc3NpbmcgZGF0YSBwYXR0ZXJuLCB3aGljaCBkZXNjcmliZXMgd2hpY2ggdmFsdWVzIGFyZSBvYnNlcnZlZCBhbmQgd2hpY2ggdmFsdWVzIGFyZSBtaXNzaW5nIGluIHRoZSBkYXRhIG1hdHJpeC4gSW4gZ2VuZXJhbCwgbWlzc2luZyBkYXRhIHBhdHRlcm5zIGNhbiBiZSByb3VnaGx5IGNsYXNzaWZpZWQgaW50byBhIHZhcmlldHkgb2YgZ3JvdXBzLCBzdWNoIGFzIHVuaXZhcmlhdGUsIG11bHRpdmFyaWF0ZSwgbW9ub3RvbmUsIG5vbi1tb25vdG9uZSwgYW5kIGZpbGUgbWF0Y2hpbmcgKExpdHRsZSBhbmQgUnViaW4sIDIwMDIpLg0KDQpBIHVuaXZhcmlhdGUgbWlzc2luZyBwYXR0ZXJuIGluZGljYXRlcyBhIHNpdHVhdGlvbiB3aGVyZSBtaXNzaW5nIGRhdGEgb2NjdXIgb25seSBpbiBhIHNpbmdsZSB2YXJpYWJsZS4gQXMgYW4gZXh0ZW5zaW9uIG9mIHRoZSB1bml2YXJpYXRlIGNhc2UsIHRoZSBtdWx0aXZhcmlhdGUgbWlzc2luZyBwYXR0ZXJuIHJlZmVycyB0byBtaXNzaW5nIGRhdGEgaW4gYSBzZXQgb2YgdmFyaWFibGVzLCBlaXRoZXIgZm9yIHRoZSBlbnRpcmUgdW5pdCBvciBmb3IgcGFydGljdWxhciBpdGVtcyBpbiBhIHF1ZXN0aW9ubmFpcmUuIA0KDQoqIElmIGEgdmFyaWFibGUgaXMgbWlzc2luZyBmb3IgYSBwYXJ0aWN1bGFyIHN1YmplY3Qgbm90IG9ubHkgYXQgYSBzcGVjaWZpYyB0aW1lIHBvaW50IGJ1dCBhbHNvIGF0IGFsbCBzdWJzZXF1ZW50IHRpbWUgb2NjYXNpb25zLCB0aGUgbWlzc2luZyBkYXRhIHBhdHRlcm4gZm9yIHRoaXMgaW5kaXZpZHVhbCBpcyBzYWlkIHRvIGJlIGEgbW9ub3RvbmUgbWlzc2luZyBwYXR0ZXJuLiANCg0KKiBJZiBhIGNhc2UgaXMgbWlzc2luZyBhdCBhIGdpdmVuIHRpbWUgcG9pbnQgYW5kIHRoZW4gcmV0dXJucyBhdCBhIGxhdGVyIGZvbGxvdy11cCBpbnZlc3RpZ2F0aW9uLCB0aGVuIHRoZSBtaXNzaW5nIGRhdGEgcGF0dGVybiBmb3IgdGhpcyBzdWJqZWN0IGlzIHJlZmVycmVkIHRvIGFzIHRoZSBub24tbW9ub3RvbmUgbWlzc2luZyBkYXRhLiANCg0KSW4gbG9uZ2l0dWRpbmFsIGRhdGEgYW5hbHlzaXMsIHRoZSBub24tbW9ub3RvbmUgbWlzc2luZyBwYXR0ZXJuIGNhbiBjYXVzZSBtb3JlIHByb2JsZW1zIHRoYW4gdGhlIG1vbm90b25lIHBhdHRlcm4gYW5kIHRodXMgZGVzZXJ2ZXMgY2xvc2UgYXR0ZW50aW9uLiBUaGVyZSBhcmUgbW9yZSBtaXNzaW5nIGRhdGEgcGF0dGVybnMgc3VjaCBhcyB0aGUgbGF0ZW50LWZhY3RvciBwYXR0ZXJucyB3aXRoIHZhcmlhYmxlcyB0aGF0IGFyZSBuZXZlciBvYnNlcnZlZC4gRm9yIGVhY2ggbWlzc2luZyBkYXRhIHBhdHRlcm4sIHRoZXJlIGFyZSBjb3JyZXNwb25kaW5nIHN0YXRpc3RpY2FsIHRlY2huaXF1ZXMgdG8gaGFuZGxlIGl0cyBpbXBhY3Qgb24gdGhlIHF1YWxpdHkgb2YgZGF0YSBhbmFseXNpcy4NCg0KIyMgVHlwZXMgb2YgTWlzc2luZyBEYXRhIE1lY2hhbmlzbXMNCg0KTWlzc2luZyBkYXRhIG1lY2hhbmlzbXMgY29uY2VybiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWlzc2luZyBkYXRhIGFuZCB0aGUgdmFsdWVzIG9mIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBtYXRyaXguIEdpdmVuIHRoaXMgZm9jdXMsIG1pc3NpbmcgZGF0YSBtZWNoYW5pc21zIGNhbiBiZSBjYXRlZ29yaXplZCBpbnRvIHRocmVlIGNsYXNzZXM6IG1pc3NpbmcgY29tcGxldGVseSBhdCByYW5kb20gKE1DQVIpLCBtaXNzaW5nIGF0IHJhbmRvbSAoTUFSKSwgYW5kIG1pc3Npbmcgbm90IGF0IHJhbmRvbSAoTU5BUikuIA0KDQoqICoqTWlzc2luZyBDb21wbGV0ZWx5IGF0IFJhbmRvbSAoTUNBUikqKjogSWYgbWlzc2luZyBkYXRhIGFyZSB1bnJlbGF0ZWQgdG8gYm90aCB0aGUgbWlzc2luZyByZXNwb25zZXMgYW5kIHRoZSBzZXQgb2Ygb2JzZXJ2ZWQgcmVzcG9uc2VzLCB0aGUgb2JzZXJ2ZWQgdmFsdWVzIGFyZSByZXByZXNlbnRhdGl2ZSBvZiB0aGUgZW50aXJlIHNhbXBsZSB3aXRob3V0IG1pc3NpbmcgdmFsdWVzLiBUaGlzIG1pc3NpbmcgZGF0YSBtZWNoYW5pc20gaXMgcmVmZXJyZWQgdG8gYXMgTUNBUi4gVGhpcyBpcyB0aGUgYmVzdCB3ZSBjYW4gaG9wZSBmb3Igc2luY2Ugd2UgY2FuIHNpbXBseSBpZ25vcmUgdGhlIHJlY29yZHMgd2l0aCBtaXNzaW5nIGNvbXBvbmVudHMgKGxpc3Qtd2lzZSBkZWxldGlvbikgd2l0aG91dCBpbnRyb2R1Y2luZyBiaWFzIHRvIHRoZSBkYXRhLg0KDQoNCiogKipNaXNzaW5nIGF0IFJhbmRvbSAoTUFSKSoqOiBJZiBtaXNzaW5nIGRhdGEgZGVwZW5kIG9uIHRoZSBzZXQgb2Ygb2JzZXJ2ZWQgcmVzcG9uc2VzIGJ1dCBhcmUgdW5yZWxhdGVkIHRvIHRoZSBtaXNzaW5nIHZhbHVlcywgdGhlIG1pc3NpbmcgZGF0YSBhcmUgc2FpZCB0byBiZSBNQVIuIEZvciBleGFtcGxlLCBhIHJlZ2lzdHJ5IGV4YW1pbmluZyBkZXByZXNzaW9uIG1heSBlbmNvdW50ZXIgZGF0YSB0aGF0IGFyZSBNQVIgaWYgbWFsZSBwYXJ0aWNpcGFudHMgYXJlIGxlc3MgbGlrZWx5IHRvIGNvbXBsZXRlIGEgc3VydmV5IGFib3V0IGRlcHJlc3Npb24gc2V2ZXJpdHkgdGhhbiBmZW1hbGUgcGFydGljaXBhbnRzLiBUaGF0IGlzLCBpZiB0aGUgcHJvYmFiaWxpdHkgb2YgY29tcGxldGlvbiBvZiB0aGUgc3VydmV5IGlzIHJlbGF0ZWQgdG8gdGhlaXIgc2V4ICh3aGljaCBpcyBmdWxseSBvYnNlcnZlZCkgYnV0IG5vdCB0aGUgc2V2ZXJpdHkgb2YgdGhlaXIgZGVwcmVzc2lvbiwgdGhlbiB0aGUgZGF0YSBtYXkgYmUgcmVnYXJkZWQgYXMgTUFSLiAgU2luY2UgdGhlcmUgaXMgYSBzeXN0ZW1hdGljIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwcm9wZW5zaXR5IG9mIG1pc3NpbmcgdmFsdWVzIGFuZCB0aGUgb2JzZXJ2ZWQgZGF0YSwgYnV0IG5vdCB0aGUgbWlzc2luZyBkYXRhLiBXaGF0IGl0IG1lYW5zLCBpcyB0aGF0IHRoZSBtaXNzaW5nIGRhdGEgY2FuIGJlIHByZWRpY3RlZCBieSBvdGhlciB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0LiANCg0KDQoqICoqTWlzc2luZyBOb3QgYXQgUmFuZG9tIChNTkFSKSoqOiBUaGVyZSBpcyBhIHBhdHRlcm4gaW4gdGhlIG1pc3NpbmcgZGF0YSB0aGF0IGFmZmVjdHMgdGhlIHByaW1hcnkgZGVwZW5kZW50IHZhcmlhYmxlcy4gV2UgY2FuIGV4dGVuZCB0aGUgYWJvdmUgImRlcHJlc3Npb24iIGV4YW1wbGUgaWYgcGFydGljaXBhbnRzIHdpdGggc2V2ZXJlIGRlcHJlc3Npb24gYXJlIG1vcmUgbGlrZWx5IHRvIHJlZnVzZSB0byBjb21wbGV0ZSB0aGUgc3VydmV5IGFib3V0IGRlcHJlc3Npb24gc2V2ZXJpdHkuIFNpbmNlIHRoZSBzb3VyY2VzIG9mIG1pc3NpbmcgZGF0YSBhcmUgdGhlbXNlbHZlcyB1bm1lYXN1cmVkIG1lYW5zIHRoYXQgKGluIGdlbmVyYWwpIHRoaXMgaXNzdWUgY2Fubm90IGJlIGFkZHJlc3NlZCBpbiBhbmFseXNpcywgYW5kIHRoZSBlc3RpbWF0ZSBvZiBlZmZlY3Qgd2lsbCBsaWtlbHkgYmUgYmlhc2VkLiBNaXNzaW5nIG5vdCBhdCByYW5kb20gaXMgdGhlIHdvcnN0LWNhc2Ugc2NlbmFyaW8uIFdlIHNob3VsZCB1c2UgTU5BUiBkYXRhIHdpdGggY2F1dGlvbiBzaW5jZSB0aGVzZSBtaXNzaW5nIGRhdGEgY2Fubm90IGJlICJyZWNvdmVyZWQiLg0KDQoNCiMgTWV0aG9kcyBvZiBIYW5kbGluZyBNaXNzaW5nIERhdGENCg0KTWV0aG9kcyBvZiBoYW5kbGluZyBtaXNzaW5nIGRhdGEgYXJlIGRlcGVuZGVudCBvbiB0aGUgbWlzc2luZyBkYXRhIG1lY2hhbmlzbXMuICBXZSBoYXZlIGJyaWVmbHkgZGlzY3Vzc2VkIHRocmVlIG1ham9yIHR5cGVzIG9mIG1pc3NpbmcgbWVjaGFuaXNtcyBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbnMuIEhlcmUgaXMgYSBzdW1tYXJ5IG9mIHRoZXNlIG1lY2hhbmlzbXMuDQoNCiogSW4gKipNQ0FSKiosIHRoZSBtaXNzaW5nIG1lY2hhbmlzbSBpcyBpbmRlcGVuZGVudCBvZiBjaGFyYWN0ZXJpc3RpY3Mgb2YgZWl0aGVyIHRoZSBvYnNlcnZlZCBkYXRhIG9yIHRoZSB1bm9ic2VydmVkIHZhbHVlcyBpbiB0aGUgZGF0YSBzZXQuDQoNCiogSW4gKipNQVIqKiwgdGhlIG1pc3NpbmcgbWVjaGFuaXNtIGlzIGVudGlyZWx5IGV4cGxhaW5lZCBieSB0aGUgb2JzZXJ2ZWQgZGF0YSwgdGhhdCBpcywgYWZ0ZXIgb2JzZXJ2ZWQgdmFsdWVzIGFyZSBhY2NvdW50ZWQgZm9yLCBtaXNzaW5nbmVzcyBpcyByYW5kb21seSBkaXN0cmlidXRlZC4NCg0KKiBJbiAqKk1OQVIqKiwgbWlzc2luZyBvYnNlcnZhdGlvbnMgYXJlIGRlcGVuZGVudCB1cG9uIHVub2JzZXJ2ZWQgdmFsdWVzOyBtaXNzaW5nbmVzcyBjYW5ub3QgYmUgYWNjb3VudGVkIGZvciBieSBjb250cm9sbGluZyBmb3Igb2JzZXJ2ZWQgZGF0YS4NCg0KDQpJbiB0aGUgc3Vic2VxdWVudCBzdWItc2VjdGlvbnMsIHdlIHdpbGwgb3V0bGluZSB0aGUgbWFqb3IgbWV0aG9kcyB1c2VkIHRvIGhhbmRsZSBtaXNzaW5nIGRhdGEgd2l0aCBkaWZmZXJlbnQgdHlwZXMgb2YgbWlzc2luZyBtZWNoYW5pc21zLg0KDQojIyBMaXN0d2lzZSBEZWxldGlvbg0KDQpEZWxldGUgYWxsIGRhdGEgZnJvbSBhbnkgcGFydGljaXBhbnQgd2l0aCBtaXNzaW5nIHZhbHVlcy4gSWYgdGhlIHNhbXBsZSBpcyBsYXJnZSBlbm91Z2gsIHdlIGxpa2VseSBjYW4gZHJvcCBkYXRhIHdpdGhvdXQgc3Vic3RhbnRpYWwgbG9zcyBvZiBzdGF0aXN0aWNhbCBwb3dlci4gQmUgc3VyZSB0aGF0IHRoZSB2YWx1ZXMgYXJlIG1pc3NpbmcgYXQgcmFuZG9tIGFuZCB0aGF0IHlvdSBhcmUgbm90IGluYWR2ZXJ0ZW50bHkgcmVtb3ZpbmcgYSBjbGFzcyBvZiBwYXJ0aWNpcGFudHMuDQoNClRoaXMgbWV0aG9kIGlzIHVzZWQgZm9yIE1DQVIgYW5kLCBvY2Nhc2lvbmFsbHksIE1BUi4gSXQgaXMgdGhlIGVhc2llc3QgYW5kIHNpbXBsZXN0IG1ldGhvZCBhbW9uZyBhbGwgb3RoZXIgYXZhaWxhYmxlIG1ldGhvZHMuDQoNClRoZSBkaXNhZHZhbnRhZ2VzIGFyZQ0KDQoqIGxvc3Mgb2YgdmFsdWFibGUgaW5mb3JtYXRpb247DQoqIHBvdGVudGlhbCBjb250cmlidXRpb24gdG8gYmlhczsNCiogbG9zcyBvZiBzdGF0aXN0aWNhbCBwb3dlcjsNCg0KIyMgTWVhbiBSZXBsYWNlbWVudCANCg0KRm9yIHZhcmlhYmxlIOKAnFjigJ0gd2l0aCBtaXNzaW5nIHZhbHVlcywgdGFrZSB0aGUgbWVhbiBvZiBhbGwgaW5jbHVkZWQgb2JzZXJ2YXRpb25zLiBTdWJzdGl0dXRlIHRoZSBtZWFuIG9mIOKAnFjigJ0gZm9yIG1pc3NpbmcgdmFsdWVzIG9mIOKAnFjigJ0uIFRoaXMgaXMgYSB0eXBlIG9mIHNpbXBsZSBpbXB1dGF0aW9uIG1ldGhvZC4gDQoNCkl0IGlzIHZhbGlkIGZvciBNQ0FSLiBUaGUgYWR2YW50YWdlcyBhcmUNCg0KKiBwcmVzZXJ2aW5nIHRoZSBtZWFuIG9mIHRoZSBkYXRhIHNldDsgDQoqIHNpbXBsZTsNCiogYWxsb3dpbmcgdXNlIG9mIGFsbCBvYnNlcnZhdGlvbnMNCg0KVGhlIGRpc2FkdmFudGFnZXMgYXJlDQoNCiogYXJ0aWZpY2lhbGx5IHJlZHVjaW5nIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGRhdGEgc2V0LCANCiogZGlzdG9ydGluZyByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzOw0KKiB5aWVsZGluZyBwb3RlbnRpYWxseSBiaWFzZWQgZXN0aW1hdGVzOw0KKiBwcm9kdWNpbmcgcmVzdWx0cyB0aGF0IGFyZSBoaWdobHkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgYnV0IGluYWNjdXJhdGU7DQoNCg0KIyMgUmVncmVzc2lvbiBSZXBsYWNlbWVudA0KDQpUaGlzIGlzIGFub3RoZXIgbWV0aG9kIG9mIHNpbmdsZSBpbXB1dGF0aW9uLiBJdCBlc3RpbWF0ZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWlzc2luZyB2YXJpYWJsZShzKSwgZ2l2ZW4gY292YXJpYXRlcywgdGFrZXMgYSByYW5kb20gZHJhdyBmcm9tIHRoaXMgZGlzdHJpYnV0aW9uIGZvciBlYWNoIHZhbHVlIHRoZW4gcGVyZm9ybXMgYW5hbHlzaXMgYXMgdXN1YWwuDQoNClRoZSByZWdyZXNzaW9uIHJlcGxhY2VtZW50IGlzIHZhbGlkIGZvciBib3RoIE1DQVIgYW5kIE1BUi4gVGhlIGFkdmFudGFnZXMgYXJlIA0KKiBhdm9pZGFuY2Ugb2YgIGJpYXMgaW4gZXN0aW1hdGluZzsNCiogc2ltcGxlciB0aGFuIG11bHRpcGxlIGltcHV0YXRpb25zOw0KDQoNClRoZSBkaXNhZHZhbnRhZ2VzIGFyZQ0KDQoqIG1pc3JlcHJlc2VudGluZyB1bmNlcnRhaW50eSBvZiBlc3RpbWF0ZXM7IA0KKiBtb3JlIGNvbXBsaWNhdGVkIHRoYW4gbGlzdC13aXNlIGRlbGV0aW9uIG9yIG1lYW4gcmVwbGFjZW1lbnQNCiogcmVkdWNpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgZXN0aW1hdGVzIGFsdGhvdWdoIHRoZW9yZXRpY2FsbHkgdW5iaWFzZWQuIA0KDQoNCiMjIE11bHRpcGxlIEltcHV0YXRpb24NCg0KTXVsdGlwbGUgSW1wdXRhdGlvbiBpcyB0aGUgbW9zdCBzb3BoaXN0aWNhdGVkIGFuZCwgY3VycmVudGx5LCBtb3N0IHBvcHVsYXIgYXBwcm9hY2ggdG8gdGFrZSB0aGUgcmVncmVzc2lvbiBpZGVhIGZ1cnRoZXIgYW5kIHRha2UgYWR2YW50YWdlIG9mIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHJlc3BvbnNlcy4gDQoNCkl0IGVzdGltYXRlcyB0aGUgZGlzdHJpYnV0aW9uIChCYXllc2lhbiBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uKSBvZiB0aGUgbWlzc2luZyB2YXJpYWJsZSwgZ2l2ZW4gY292YXJpYXRlczsgdGFrZXMgcmFuZG9tIGRyYXdzIGZyb20gdGhpcyBkaXN0cmlidXRpb24gdG8gcHJvZHVjZSBtdWx0aXBsZSB2ZXJzaW9ucyAodXN1YWxseSAz4oCTMTApIG9mIGFuIGltcHV0ZWQgZGF0YSBzZXQ7IHBlcmZvcm1zIGFuYWx5c2lzIG9uIGVhY2ggaW1wdXRlZCBkYXRhIHNldCBhbmQgcG9vbHMgdGhlIHJlc3VsdHMuIEl0IGlzIGEgc2ltdWxhdGlvbi1iYXNlZCBCYXllc2lhbiBtZXRob2QuIE1vc3Qgc3RhdGlzdGljYWwgY29tcHV0ZXIgcHJvZ3JhbXMgY2FuIGRvIG11bHRpcGxlIGltcHV0YXRpb25zLg0KDQpJdCBpcyB2YWxpZCBmb3IgTUNBUiBvciBNQVIuIFRoZSBhZHZhbnRhZ2VzIGFyZQ0KDQoqIGFjY291bnRpbmcgZm9yIHRoZSBleHRyYSB1bmNlcnRhaW50eSBwcm9kdWNlZCBieSBpbXB1dGluZyBkYXRhOw0KKiBwcm9kdWNpbmcgYmV0dGVyIGVzdGltYXRlcyBvZiBtaXNzaW5nIHZhbHVlcy4NCg0KVGhlIGRpc2FkdmFudGFnZXMgYXJlDQoNCiogcmVxdWlyaW5nIGNvbXBsaWNhdGVkIHN0YXRpc3RpY2FsIG1ldGhvZHMgb3IgY29tcGxpY2F0ZWQgc29mdHdhcmU7DQoqIGhhcmRlciB0byB1bmRlcnN0YW5kOyANCiogdGFraW5nIGV4dHJhIHN0ZXBzOw0KKiBiZWNhdXNlIHRoZSBtZXRob2QgYWNjb3VudHMgZm9yIGV4dHJhIHVuY2VydGFpbnR5LCByZXN1bHRzIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBpZiBkYXRhIHdlcmUgbm90IG1pc3NpbmcuDQoNCiMgUiBQYWNrYWdlcyBmb3IgSW1wdXRhdGlvbg0KDQpTZXZlcmFsIFIgcGFja2FnZXMgaGF2ZSBmdW5jdGlvbnMgdG8gcGVyZm9ybSBpbXB1dGF0aW9uIGZvciBtaXNzaW5nIHZhbHVlcy4gVGhpcyBzZWN0aW9uIGxpc3RzIGEgZmV3IGNvbW1vbmx5IHVzZWQgUiBsaWJyYXJpZXMuIFdlIG9ubHkgZXhwbGFpbiB0aGUgY29uY2VwdHMgd2l0aCBubyBjb2RpbmcuDQoNCiMjIE1JQ0UgUGFja2FnZQ0KDQpNSUNFIChNdWx0aXZhcmlhdGUgSW1wdXRhdGlvbiB2aWEgQ2hhaW5lZCBFcXVhdGlvbnMpIGlzIG9uZSBvZiB0aGUgY29tbW9ubHkgdXNlZCBwYWNrYWdlcyBieSBSIHVzZXJzLiBDcmVhdGluZyBtdWx0aXBsZSBpbXB1dGF0aW9ucyBhcyBjb21wYXJlZCB0byBhIHNpbmdsZSBpbXB1dGF0aW9uIChzdWNoIGFzIHRoZSBtZWFuKSB0YWtlcyBjYXJlIG9mIHVuY2VydGFpbnR5IGluIG1pc3NpbmcgdmFsdWVzLg0KDQpNSUNFIGFzc3VtZXMgdGhhdCB0aGUgbWlzc2luZyBkYXRhIGFyZSBNaXNzaW5nIGF0IFJhbmRvbSAoTUFSKSwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHZhbHVlIGlzIG1pc3NpbmcgZGVwZW5kcyBvbmx5IG9uIHRoZSBvYnNlcnZlZCB2YWx1ZSBhbmQgY2FuIGJlIHByZWRpY3RlZCB1c2luZyB0aGVtLiBJdCBpbXB1dGVzIGRhdGEgb24gYSB2YXJpYWJsZS1ieS12YXJpYWJsZSBiYXNpcyBieSBzcGVjaWZ5aW5nIGFuIGltcHV0YXRpb24gbW9kZWwgcGVyIHZhcmlhYmxlLg0KDQpBcyBhbiBleGFtcGxlLCB3ZSBjb25zaWRlciBhIGRhdGEgc2V0IHdpdGggdmFyaWFibGVzICRYXzEsIFhfMiwgXGNkb3RzLCBYX2skLiBJZiAkWF8xJCBoYXMgbWlzc2luZyB2YWx1ZXMsIHRoZW4gaXQgd2lsbCBiZSByZWdyZXNzZWQgb24gb3RoZXIgdmFyaWFibGVzICRYXzIkIHRvICRYX2skLiBUaGUgbWlzc2luZyB2YWx1ZXMgaW4gJFhfMSQgd2lsbCBiZSB0aGVuIHJlcGxhY2VkIGJ5IHByZWRpY3RpdmUgdmFsdWVzIG9idGFpbmVkLiBTaW1pbGFybHksIGlmICRYXzIkIGhhcyBtaXNzaW5nIHZhbHVlcywgdGhlbiAkWF8xJCwgJFhfMyQgdG8gJFhfayQgdmFyaWFibGVzIHdpbGwgYmUgdXNlZCBpbiB0aGUgcHJlZGljdGlvbiBtb2RlbCBhcyBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIExhdGVyLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIHJlcGxhY2VkIHdpdGggcHJlZGljdGVkIHZhbHVlcy4NCg0KQnkgZGVmYXVsdCwgbGluZWFyIHJlZ3Jlc3Npb24gaXMgdXNlZCB0byBwcmVkaWN0IGNvbnRpbnVvdXMgbWlzc2luZyB2YWx1ZXMuIExvZ2lzdGljIHJlZ3Jlc3Npb24gaXMgdXNlZCBmb3IgY2F0ZWdvcmljYWwgbWlzc2luZyB2YWx1ZXMuIE9uY2UgdGhpcyBjeWNsZSBpcyBjb21wbGV0ZSwgbXVsdGlwbGUgZGF0YSBzZXRzIGFyZSBnZW5lcmF0ZWQuIFRoZXNlIGRhdGEgc2V0cyBkaWZmZXIgb25seSBpbiBpbXB1dGVkIG1pc3NpbmcgdmFsdWVzLiBHZW5lcmFsbHksIGl04oCZcyBjb25zaWRlcmVkIHRvIGJlIGEgZ29vZCBwcmFjdGljZSB0byBidWlsZCBtb2RlbHMgb24gdGhlc2UgZGF0YSBzZXRzIHNlcGFyYXRlbHkgYW5kIGNvbWJpbmUgdGhlaXIgcmVzdWx0cy4NCg0KUHJlY2lzZWx5LCB0aGUgbWV0aG9kcyB1c2VkIGJ5IHRoaXMgcGFja2FnZSBjYW4gYmUgZm91bmQgaW4gdGhlIGRvY3VtZW50IG9mIHRoZSBwYWNrYWdlIGF0IDxodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWljZS9taWNlLnBkZj4uDQoNCiMjIEhtaXNjIFBhY2thZ2UNCg0KSG1pc2MgaXMgYSBtdWx0aXBsZS1wdXJwb3NlIHBhY2thZ2UgdXNlZnVsIGZvciBkYXRhIGFuYWx5c2lzLCBoaWdo4oCTbGV2ZWwgZ3JhcGhpY3MsIGltcHV0aW5nIG1pc3NpbmcgdmFsdWVzLCBhZHZhbmNlZCB0YWJsZSBtYWtpbmcsIG1vZGVsIGZpdHRpbmcgJiBkaWFnbm9zdGljcyAobGluZWFyIHJlZ3Jlc3Npb24sIGxvZ2lzdGljIHJlZ3Jlc3Npb24gJiBjb3ggcmVncmVzc2lvbiksIGV0Yy4gQW1pZHN0LCB0aGUgd2lkZSByYW5nZSBvZiBmdW5jdGlvbnMgY29udGFpbmVkIGluIHRoaXMgcGFja2FnZSwgaXQgb2ZmZXJzIDIgcG93ZXJmdWwgZnVuY3Rpb25zIGZvciBpbXB1dGluZyBtaXNzaW5nIHZhbHVlcy4gVGhlc2UgYXJlIGltcHV0ZSgpIGFuZCBhcmVnSW1wdXRlKCkuIFRob3VnaCBpdCBhbHNvIGhhcyB0cmFuc2NhbigpIGZ1bmN0aW9uLCBhcmVnSW1wdXRlKCkgaXMgYmV0dGVyIHRvIHVzZS4NCg0KaW1wdXRlKCkgZnVuY3Rpb24gc2ltcGx5IGltcHV0ZXMgbWlzc2luZyB2YWx1ZXMgdXNpbmcgYSB1c2VyLWRlZmluZWQgc3RhdGlzdGljYWwgbWV0aG9kIChtZWFuLCBtYXgsIG1lYW4pLiBJdHMgZGVmYXVsdCBpcyBtZWRpYW4uIE9uIHRoZSBvdGhlciBoYW5kLCBhcmVnSW1wdXRlKCkgYWxsb3dzIHRoZSBtZWFuIGltcHV0YXRpb24gdXNpbmcgYWRkaXRpdmUgcmVncmVzc2lvbiwgYm9vdHN0cmFwcGluZywgYW5kIHByZWRpY3RpdmUgbWVhbiBtYXRjaGluZy4NCg0KSW4gYm9vdHN0cmFwcGluZywgZGlmZmVyZW50IGJvb3RzdHJhcCByZXNhbXBsZXMgYXJlIHVzZWQgZm9yIGVhY2ggb2YgdGhlIG11bHRpcGxlIGltcHV0YXRpb25zLiBUaGVuLCBhIGZsZXhpYmxlIGFkZGl0aXZlIG1vZGVsIChub24tcGFyYW1ldHJpYyByZWdyZXNzaW9uIG1ldGhvZCkgaXMgZml0dGVkIG9uIHNhbXBsZXMgdGFrZW4gd2l0aCByZXBsYWNlbWVudHMgZnJvbSBvcmlnaW5hbCBkYXRhLCBhbmQgbWlzc2luZyB2YWx1ZXMgKGFjdHMgYXMgZGVwZW5kZW50IHZhcmlhYmxlKSBhcmUgcHJlZGljdGVkIHVzaW5nIG5vbi1taXNzaW5nIHZhbHVlcyAoaW5kZXBlbmRlbnQgdmFyaWFibGUpLg0KDQpUaGVuLCBpdCB1c2VzIHByZWRpY3RpdmUgbWVhbiBtYXRjaGluZyAoZGVmYXVsdCkgdG8gaW1wdXRlIG1pc3NpbmcgdmFsdWVzLiBQcmVkaWN0aXZlIG1lYW4gbWF0Y2hpbmcgd29ya3Mgd2VsbCBmb3IgY29udGludW91cyBhbmQgY2F0ZWdvcmljYWwgKGJpbmFyeSAmIG11bHRpLWxldmVsKSB3aXRob3V0IHRoZSBuZWVkIGZvciBjb21wdXRpbmcgcmVzaWR1YWxzIGFuZCBtYXhpbXVtIGxpa2VsaWhvb2QgZml0Lg0KDQpNb3JlIGZ1bmN0aW9ucyBhbmQgdXBkYXRlcyBpbiBIbWlzYyBwYWNrYWdlIGNhbiBiZSBmb3VuZCBhdCA8aHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL0htaXNjL0htaXNjLnBkZj4gDQoNCg0KDQojIFRoZSBNSUNFIEFsZ29yaXRobQ0KDQpUaGUgTUlDRSBwcm9jZXNzIGZvbGxvd3MgYSBzeXN0ZW1hdGljIGFwcHJvYWNoIHRvIGl0ZXJhdGl2ZWx5IGltcHV0ZSBtaXNzaW5nIGRhdGEuIEl0IGludm9sdmVzIGNyZWF0aW5nIG11bHRpcGxlIHZlcnNpb25zIG9mIHRoZSBkYXRhIHNldCB3aXRoIHBsYXVzaWJsZSBlc3RpbWF0ZXMgZm9yIG1pc3NpbmcgdmFsdWVzIHdoaWxlIHByZXNlcnZpbmcgdGhlIHJlbGF0aW9uc2hpcHMgYW1vbmcgdmFyaWFibGVzLiANCg0KSW4gdGhlIFIgbGlicmFyeSBgbWljZSgpYCwgYXJndW1lbnQgYG1heGl0ID0gbWAgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgY3ljbGVzIChpdGVyYXRpb25zKSBvZiB0aGUgaXRlcmF0aXZlIGltcHV0aW5nIHByb2Nlc3MuIFRvIGlsbHVzdHJhdGUgdGhpcyBpdGVyYXRpdmUgaW1wdXRhdGlvbiBwcm9jZXNzLCB3ZSB1c2UgdGhlIGZvbGxvd2luZyB0b3kgZGF0YSB0byBzaG93IHRoZSBsb2dpY2FsIHByb2Nlc3MuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjgwJSIsIGZpZy5jYXA9Ikl0ZXJhdGl2ZSBpbXB1dGF0aW9uIHByb2Nlc3MgaW4gTUkuIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9NSS1JdGVyYXRpdmUtSW1wdXRlZC1Qcm9jZXNzLmpwZyIpDQpgYGANCg0KDQpCZWxvdyBpcyBhbiBhbGdvcml0aG0gdGhhdCBzdW1tYXJpemVzIHRoZSBhYm92ZSBNSUNFIHByb2Nlc3MuDQoNCg0KKipNSUNFIEFsZ29yaXRobSoqDQoNCmBgYA0KU3RlcCAxOiBJbml0aWFsaXplIGltcHV0ZWQgdmFsdWVzDQogICAgICAgIDEuMS4gRm9yIGVhY2ggdmFyaWFibGUgd2l0aCBtaXNzaW5nIHZhbHVlcywgaW1wdXRlIGluaXRpYWwgdmFsdWVzIHVzaW5nIA0KICAgICAgICAgICAgIGEgc2ltcGxlIGltcHV0YXRpb24gbWV0aG9kIChlLmcuLCBtZWFuLCBtZWRpYW4sIG1vZGUgaW1wdXRhdGlvbiwgDQogICAgICAgICAgICAgb3IgcmVncmVzc2lvbikuDQogICAgICAgIDEuMi4gVGhlc2UgaW5pdGlhbCBpbXB1dGF0aW9ucyB3aWxsIGJlIHVzZWQgYXMgc3RhcnRpbmcgdmFsdWVzIGluIHRoZSANCiAgICAgICAgICAgICBpdGVyYXRpdmUgcHJvY2Vzcy4NClN0ZXAgMjogU2V0IHVwIHRoZSBpbXB1dGF0aW9uIG1vZGVsIGZvciBlYWNoIHZhcmlhYmxlDQogICAgICAgIDIuMS4gRGVmaW5lIHRoZSBpbXB1dGF0aW9uIG1vZGVsIGZvciBlYWNoIHZhcmlhYmxlIHdpdGggbWlzc2luZyBkYXRhLiANCiAgICAgICAgICAgICBUaGUgbW9kZWwgY2FuIGJlIGRpZmZlcmVudCBmb3IgZWFjaCB2YXJpYWJsZSBhbmQgY2FuIGJlIGJhc2VkIG9uIGEgDQogICAgICAgICAgICAgcmVncmVzc2lvbiBtb2RlbCAoZS5nLiwgbGluZWFyIHJlZ3Jlc3Npb24sIGxvZ2lzdGljIHJlZ3Jlc3Npb24pIG9yIA0KICAgICAgICAgICAgIG90aGVyIG1vZGVscyBkZXBlbmRpbmcgb24gdGhlIG5hdHVyZSBvZiB0aGUgZGF0YS4NCiAgICAgICAgMi4yLiBUaGUgdmFyaWFibGUgdG8gYmUgaW1wdXRlZCAoZGVwZW5kZW50IHZhcmlhYmxlKSB3aWxsIGJlIHJlZ3Jlc3NlZCANCiAgICAgICAgICAgICBvbiBvdGhlciB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgKHByZWRpY3RvciB2YXJpYWJsZXMpLg0KU3RlcCAzOiBJdGVyYXRpdmUgaW1wdXRhdGlvbiBwcm9jZXNzDQogICAgICAgIDMuMS4gRm9yIGVhY2ggaXRlcmF0aW9uIHQsIHJlcGVhdCB0aGUgZm9sbG93aW5nIHByb2Nlc3MgZm9yIGVhY2ggdmFyaWFibGUgDQogICAgICAgICAgICAgd2l0aCBtaXNzaW5nIHZhbHVlczoNCiAgICAgICAgICAgICAzLjEuMS4gRm9yIGVhY2ggdmFyaWFibGUgVmkgd2l0aCBtaXNzaW5nIGRhdGEsIHVzZSB0aGUgY3VycmVudCB2YWx1ZXMgDQogICAgICAgICAgICAgICAgICAgIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgKGluY2x1ZGluZyBwcmV2aW91c2x5IGltcHV0ZWQgdmFsdWVzKSANCiAgICAgICAgICAgICAgICAgICAgdG8gcHJlZGljdCB0aGUgbWlzc2luZyB2YWx1ZXMgZm9yIFZpLg0KICAgICAgICAgICAgIDMuMS4yLiBUaGUgbW9kZWwgZm9yIGltcHV0YXRpb24gb2YgVmkgaXMgZml0dGVkIHRvIHRoZSBjb21wbGV0ZSBkYXRhIA0KICAgICAgICAgICAgICAgICAgICAod2hlcmUgbm8gbWlzc2luZyB2YWx1ZXMgZXhpc3QgZm9yIFZpKS4NCiAgICAgICAgICAgICAzLjEuMy4gSW1wdXRlIG1pc3NpbmcgdmFsdWVzIGZvciBWaSBiYXNlZCBvbiB0aGUgbW9kZWwgZml0IGluIHN0ZXAgDQogICAgICAgICAgICAgICAgICAgIDMuMS4yLCByZXBsYWNpbmcgdGhlIG1pc3NpbmcgdmFsdWVzIHdpdGggcHJlZGljdGVkIHZhbHVlcyANCiAgICAgICAgICAgICAgICAgICAgKHRoaXMgaW1wdXRhdGlvbiBpcyBzdG9jaGFzdGljLCBpbnRyb2R1Y2luZyByYW5kb20gdmFyaWFiaWxpdHkgDQogICAgICAgICAgICAgICAgICAgIHRvIGFjY291bnQgZm9yIHVuY2VydGFpbnR5KS4NCiAgICAgICAgMy4yLiBSZXBlYXQgdGhpcyBwcm9jZXNzIGZvciBhbGwgdmFyaWFibGVzIHdpdGggbWlzc2luZyBkYXRhLg0KU3RlcCA0OiBQZXJmb3JtIG11bHRpcGxlIGltcHV0YXRpb25zDQogICAgICAgIDQuMS4gUmVwZWF0IFN0ZXAgMyBtIHRpbWVzICh3aXRoIG0gYmVpbmcgdGhlIG51bWJlciBvZiBpbXB1dGF0aW9ucykgdG8gDQogICAgICAgICAgICAgY3JlYXRlIG0gZGlmZmVyZW50IGltcHV0ZWQgZGF0YXNldHMuIEVhY2ggZGF0YXNldCB3aWxsIGNvbnRhaW4gDQogICAgICAgICAgICAgaW1wdXRlZCB2YWx1ZXMgZm9yIHRoZSBtaXNzaW5nIGRhdGEgYmFzZWQgb24gZGlmZmVyZW50IGltcHV0YXRpb25zLCANCiAgICAgICAgICAgICByZWZsZWN0aW5nIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgaW1wdXRhdGlvbiBwcm9jZXNzLg0KU3RlcCA1OiBBbmFseXplIGVhY2ggaW1wdXRlZCBkYXRhc2V0DQogICAgICAgICA1LjEuIFBlcmZvcm0gdGhlIGRlc2lyZWQgYW5hbHlzaXMgKGUuZy4sIHJlZ3Jlc3Npb24sIGh5cG90aGVzaXMgdGVzdGluZykgDQogICAgICAgICAgICAgIG9uIGVhY2ggb2YgdGhlIG0gaW1wdXRlZCBkYXRhc2V0cywgeWllbGRpbmcgbSBzZXRzIG9mIHJlc3VsdHMuDQpTdGVwIDY6IFBvb2wgdGhlIHJlc3VsdHMgdXNpbmcgUnViaW4ncyBSdWxlcw0KICAgICAgICAgNi4xLiBDb21iaW5lIHRoZSByZXN1bHRzIGZyb20gdGhlIG0gZGF0YXNldHMgdXNpbmcgUnViaW7igJlzIHJ1bGVzOg0KICAgICAgICAgICAgICA2LjEuMS4gQ29tYmluZSB0aGUgcGFyYW1ldGVyIGVzdGltYXRlcyAoZS5nLiwgcmVncmVzc2lvbiBjb2VmZmljaWVudHMpIA0KICAgICAgICAgICAgICAgICAgICAgYnkgYXZlcmFnaW5nIHRoZW0gYWNyb3NzIHRoZSBtIGRhdGFzZXRzLg0KICAgICAgICAgICAgICA2LjEuMi4gQ29tYmluZSB0aGUgdmFyaWFuY2UgZXN0aW1hdGVzLCBhY2NvdW50aW5nIGZvciBib3RoIHRoZSANCiAgICAgICAgICAgICAgICAgICAgIHdpdGhpbi1pbXB1dGVkIGRhdGFzZXQgdmFyaWFuY2UgYW5kIHRoZSBiZXR3ZWVuLWltcHV0ZWQgDQogICAgICAgICAgICAgICAgICAgICBkYXRhc2V0IHZhcmlhbmNlLg0KICAgICAgICAgICAgICA2LjEuMy4gQ2FsY3VsYXRlIHRoZSBvdmVyYWxsIHN0YW5kYXJkIGVycm9ycywgY29uZmlkZW5jZSBpbnRlcnZhbHMsIA0KICAgICAgICAgICAgICAgICAgICAgYW5kIHAtdmFsdWVzIGJhc2VkIG9uIHRoZSBjb21iaW5lZCBlc3RpbWF0ZXMuDQpTdGVwIDc6IFJlcG9ydCBvbiB0aGUgY29tYmluZWQgcmVzdWx0cw0KICAgICAgICA3LjEuIFByZXNlbnQgdGhlIGZpbmFsLCBwb29sZWQgcmVzdWx0cywgaW5jbHVkaW5nIHRoZSBjb21iaW5lZCBlc3RpbWF0ZXMsIA0KICAgICAgICAgICAgIHN0YW5kYXJkIGVycm9ycywgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLg0KYGBgDQoNClRoZSBSIGBtaWNlIGxpYnJhcnlgIGhhcyBzZXZlcmFsIGZ1bmN0aW9ucyBsaXN0ZWQgYmVsb3cgdG8gZXh0cmFjdCByZWxldmFudCBpbmZvcm1hdGlvbiBpbiB0aGUgYWJvdmUgYWxnb3JpdGhtLiANCg0KDQpgbWljZSgpYAlJbXB1dGUgdGhlIG1pc3NpbmcgZGF0YSAqbSogdGltZXMNCg0KYHdpdGgoKWAJQW5hbHl6ZSBjb21wbGV0ZWQgZGF0YSBzZXRzLg0KDQpgcG9vbCgpYAlDb21iaW5lIHBhcmFtZXRlciBlc3RpbWF0ZXMuDQoNCmBjb21wbGV0ZSgpYAlFeHBvcnQgaW1wdXRlZCBkYXRhLg0KDQpgYW1wdXRlKClgCUdlbmVyYXRlIG1pc3NpbmcgZGF0YS4NCg0KDQoNCiMjIE51bWVyaWNhbCBFeGFtcGxlDQoNCkZvciBlYXNlIG9mIGlsbHVzdHJhdGlvbiwgd2UgdXNlIHRoZSBidWlsdC1pbiBgYWlycXVhbGl0eWAgZGF0YSBpbiB0aGUgc3Vic2VxdWVudCBleGFtcGxlcy4gIFRoZSBmaXJzdCBmZXcgcmVjb3JkcyBpbiB0aGUgZGF0YSBhcmUgZ2l2ZW4gYmVsb3cuDQoNCg0KYGBge3J9DQpsaWJyYXJ5KG1pY2UpDQpkYXRhIDwtIGFpcnF1YWxpdHkgICMgRXhhbXBsZSBkYXRhc2V0IHdpdGggbWlzc2luZyB2YWx1ZXMNCmRhdGFbMToxMCxdDQpgYGANCg0KDQoqKjEuIEluaXRpYWxpemF0aW9uKioNCg0KVGhlIHByb2Nlc3MgYmVnaW5zIGJ5IGFzc2lnbmluZyBpbml0aWFsIHZhbHVlcyB0byBhbGwgbWlzc2luZyBlbnRyaWVzIGluIHRoZSBkYXRhIHNldC4gVGhlc2UgaW5pdGlhbCB2YWx1ZXMgYXJlIG9mdGVuIGRlcml2ZWQgdXNpbmcgc2ltcGxlIGltcHV0YXRpb24gdGVjaG5pcXVlcywgc3VjaCBhczoNCg0KKiBSZXBsYWNpbmcgbWlzc2luZyBudW1lcmljIHZhbHVlcyB3aXRoIHRoZSBtZWFuIG9yIG1lZGlhbi4NCg0KKiBGaWxsaW5nIG1pc3NpbmcgY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggdGhlIG1vZGUuDQoNClRoaXMgc3RlcCBwcm92aWRlcyBhIHN0YXJ0aW5nIHBvaW50IGZvciB0aGUgaXRlcmF0aXZlIHByb2Nlc3MuDQoNCg0KYGBge3J9DQppbml0IDwtIG1pY2UoZGF0YSwgbWF4aXQgPSAwKSAgIyBDaGVjayBpbml0aWFsIGltcHV0YXRpb24gc2V0dXANCmluaXQkbWV0aG9kICAgICAgICAgICAgICAgICAgICAjIFZpZXcgZGVmYXVsdCBpbXB1dGF0aW9uIG1ldGhvZHMNCmBgYA0KDQoqKjIuIEltcHV0YXRpb24gTW9kZWxzKioNCg0KRWFjaCB2YXJpYWJsZSB3aXRoIG1pc3NpbmcgZGF0YSBpcyBhc3NpZ25lZCBhIHNwZWNpZmljIGltcHV0YXRpb24gbW9kZWwgdGFpbG9yZWQgdG8gaXRzIGRhdGEgdHlwZS4gU29tZSBjb21tb25seSB1c2VkIG1vZGVscyBhcmUgbGlzdGVkIGJlbG93Lg0KDQoqICoqUHJlZGljdGl2ZSBNZWFuIE1hdGNoaW5nIChwbW0pKio6IEZvciBjb250aW51b3VzIHZhcmlhYmxlcy4NCiogKipMb2dpc3RpYyBSZWdyZXNzaW9uIChsb2dyZWcpKio6IEZvciBiaW5hcnkgdmFyaWFibGVzLg0KKiAqKlBvbHl0b21vdXMgUmVncmVzc2lvbiAocG9seXJlZykqKjogRm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4NCiogKipQcm9wb3J0aW9uYWwgT2RkcyBNb2RlbCAocG9scikqKjogRm9yIG9yZGluYWwgdmFyaWFibGVzLg0KDQpUaGVzZSBtb2RlbHMgcHJlZGljdCBtaXNzaW5nIHZhbHVlcyBiYXNlZCBvbiBvdGhlciBvYnNlcnZlZCB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0LiBBcyBhbiBleGFtcGxlLCB3ZSBpbXB1dGUgb25seSBvbmUgZGF0YSAodW5kZXIgdGhlIGl0ZXJhdGl2ZSBpbXB1dGluZyBwcm9jZXNzIGlsbHVzdHJhdGVkIGVhcmxpZXIpLg0KDQpgYGB7cn0NCmxpYnJhcnkobWljZSkNCmRhdCA8LSBhaXJxdWFsaXR5ICAjIEV4YW1wbGUgZGF0YSBzZXQgd2l0aCBtaXNzaW5nIHZhbHVlcw0KIyMgaW5kaXZpZHVhbCB2YXJpYWJsZSANCmltcCA8LSBtaWNlKGRhdCwgbWV0aG9kID0gYygicG1tIiwicG1tIiwgInBtbSIsICJwbW0iLCAgIiIsICIiKSwgDQogICAgICAgICAgICAgICAgIG1heGl0ID0gMTAsICAjIGl0ZXJhdGluZyAxMCBjeWNsZXMgdG8gY29tcGxldGUgZWFjaCBpbXB1dGVkIGRhdGEgc2V0DQogICAgICAgICAgICAgICAgIG0gPSAxLCAgICAgICAjIGdlbmVyYXRlIDEgaW1wdXRlZCBkYXRhIHNldA0KICAgICAgICAgICAgICAgICBwcmludD1GKSAgICAgIyBzdXBwcmVzcyBwcmludG91dHMNCiMjIHdlIHVzZSBjb21wbGV0ZSgpIHRwIHZpZXcgdGhlIGNvbXBsZXRlIGRhdGEgc2V0Lg0KY29tcGxldGUoaW1wLCBhY3Rpb24gPSAxTClbMToxMCxdICAjIFRoZSBkZWZhdWx0ICphY3Rpb24gPSAxTCogcmV0dXJucyB0aGUgZmlyc3QNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbXB1dGVkIChjb21wbGV0ZSkgZGF0YSBzZXQuDQpgYGANCg0KKiozLiBJdGVyYXRpdmUgSW1wdXRhdGlvbioqDQoNClRoZSBjb3JlIG9mIHRoZSBNSUNFIHByb2Nlc3MgaXMgaXRzIGl0ZXJhdGl2ZSBuYXR1cmU6DQoNCiogRWFjaCB2YXJpYWJsZSB3aXRoIG1pc3NpbmcgZGF0YSBpcyB0cmVhdGVkIGFzIGEgZGVwZW5kZW50IHZhcmlhYmxlLCB3aGlsZSBhbGwgb3RoZXIgdmFyaWFibGVzIGFjdCBhcyBwcmVkaWN0b3JzLg0KDQoqIE1pc3NpbmcgdmFsdWVzIGZvciB0aGUgdGFyZ2V0IHZhcmlhYmxlIGFyZSBpbXB1dGVkIHVzaW5nIHRoZSBhc3NpZ25lZCBtb2RlbC4NCg0KKiBUaGlzIHByb2Nlc3MgY3ljbGVzIHRocm91Z2ggYWxsIHZhcmlhYmxlcyB3aXRoIG1pc3NpbmcgZGF0YSwgaXRlcmF0aXZlbHkgcmVmaW5pbmcgdGhlIGltcHV0YXRpb25zLg0KDQpUaGUgaXRlcmF0aW9ucyBjb250aW51ZSB1bnRpbCB0aGUgaW1wdXRlZCB2YWx1ZXMgc3RhYmlsaXplLCBpbmRpY2F0aW5nIGNvbnZlcmdlbmNlLg0KDQoNCmBgYHtyfQ0KZGF0YSA8LSBhaXJxdWFsaXR5ICAjIEV4YW1wbGUgZGF0YSBzZXQgd2l0aCBtaXNzaW5nIHZhbHVlcw0KaW1wIDwtIG1pY2UoZGF0YSwgbWV0aG9kID0gInBtbSIsICMgdXNpbmcgcHJlZGljdGl2ZSBtZWFuIG1hdGNoaW5nIChwcG0pDQogICAgICAgICAgICAgICAgICBtYXhpdCA9IDEwLCAgIyBwcmUtc3BlY2lmaWVkIGN5Y2xlcyBpbiB0aGUgaXRlcmF0aXZlIHByb2Nlc3MNCiAgICAgICAgICAgICAgICAgIG0gPSAyLCAgICAgICAjIGdlbmVyYXRlIDIgaW1wdXRlZCBkYXRhIHNldHMNCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjMsICAjIHNldHRpbmcgc2VlZCB0byBrZWVwIHJlcHJvZHVjaWJpbGl0eSBvZiB0aGUgcHJvY2Vzcw0KICAgICAgICAgICAgICAgICAgcHJpbnQ9RikgICAgICMgc3VwcHJlc3MgcHJpbnRvdXRzDQpjb21wbGV0ZShpbXAsIGFjdGlvbiA9ICJicm9hZCIpWzE6MTAsXSAjICphY3Rpb24gPSAiYnJvYWQiKiBjb21iaW5lcyB0aGUgdHdvIGltcHV0ZWQgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGF0YSBzZXRzIGluIGEgd2lkZSB0YWJsZS4gVGhlcmUgYXJlIG90aGVyIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9wdGlvbnMgdG8gbGF5IG91dCB0aGUgaW1wdXRlZCBkYXRhIHNldHMuDQpgYGANCg0KKiozLiBNdWx0aXBsZSBJbXB1dGF0aW9ucyoqDQoNCk11bHRpcGxlIGltcHV0ZWQgZGF0YSBzZXRzIGFyZSBjcmVhdGVkIHRvIGNhcHR1cmUgdGhlIHZhcmlhYmlsaXR5IGludHJvZHVjZWQgYnkgbWlzc2luZyBkYXRhLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9IkxpbmUgcGxvdHMgb2YgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlIHR3byBudW1lcmljYWwgdmFyaWFibGVzIHdpdGggbWlzc2luZyB2YWx1ZXMgaW4gZWFjaCBpbXB1dGVkIGRhdGEgc2V0cy4ifQ0KaW1wNSA8LSBtaWNlKGRhdGEsIG1ldGhvZCA9ICJwbW0iLCBtID0gNSwgbWF4aXQgPSAxMCwgc2VlZCA9IDEyMywgcHJpbnQ9RikNCnBsb3QoaW1wNSkNCmBgYA0KDQpIZXJlLCBtID0gNSBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiBpbXB1dGF0aW9ucywgYW5kIG1heGl0ID0gMTAgZGVmaW5lcyB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMuDQoNCg0KKio0LiBBbmFseXNpcyBhbmQgUG9vbGluZyoqDQoNCkVhY2ggaW1wdXRlZCBkYXRhIHNldCBpcyBhbmFseXplZCBpbmRlcGVuZGVudGx5LCBhbmQgdGhlIHJlc3VsdHMgYXJlIGNvbWJpbmVkIHVzaW5nIFJ1Ymlu4oCZcyBSdWxlcyB0byBwcm9kdWNlIGZpbmFsIGVzdGltYXRlcyBhbmQgc3RhbmRhcmQgZXJyb3JzLg0KDQoNCmBgYHtyfQ0KbW9kZWw1IDwtIHdpdGgoaW1wNSwgbG0oT3pvbmUgfiBXaW5kICsgVGVtcCkpICAjIFRoZSBzdGF0aXN0aWNhbCBtb2RlbCB0byBhc3Nlc3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gKk96b25lKg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFuZCAqV2luZCogYW5kICpUZW1wKi4NCnN1bW1hcnkuc3RhdHMgPSBzdW1tYXJ5KG1vZGVsNSkgICAgICAgICAgICAgICAgIyBkaXNwbGF5IHRoZSByZWdyZXNzaW9uIHJlc3VsdHMgb2YgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW5kaXZpZHVhbCBpbXB1dGVkIGRhdGEgc2V0Lg0Kc3VtbWFyeS5zdGF0cyANCmBgYA0KDQpUbyBjb21iaW5lIHRoZSByZXN1bHRzLCB3ZSBzaW1wbHkgdGFrZSB0aGUgYXZlcmFnZSBvZiB0aGUgY29ycmVzcG9uZGluZyBlc3RpbWF0ZWQgcmVncmVzc2lvbiBjb2VmZmljaWVudHMuDQoNCmBgYHtyfQ0Kc3VtbWFyeShwb29sKG1vZGVsNSkpDQpgYGANCg0KVGhlIGFib3ZlLXBvb2xlZCByZXN1bHRzIGFyZSBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZSBmb3JtdWxhcyBvbiAkUSwgVSwgQiQsIGFuZCAkVCQuIFRoZSBmb2xsb3dpbmcgY29kZSBpbGx1c3RyYXRlcyB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIHBvb2xlZCBzdGFuZGFyZCBlcnJvciBvZiB0aGUgaW50ZXJjZXB0Lg0KDQpgYGB7cn0NCmJldGEgPSBzdW1tYXJ5LnN0YXRzJGVzdGltYXRlW3NlcSgxLDE1LGJ5PTMpXSAgIyBleHBsaWNpdCB2ZWN0b3I6IGMoMSw0LDcsMTAsMTMpDQpiZXRhLnZhciA9IChzdW1tYXJ5LnN0YXRzJHN0ZC5lcnJvcltzZXEoMSwxNSxieT0zKV0pXjIgDQpRID0gbWVhbihiZXRhKQ0KVSA9IG1lYW4oYmV0YS52YXIpDQpCID0gdmFyKGJldGEpDQpUID0gVSArICg2LzUpKkINCnBvb2wuc2UgPSBzcXJ0KFQpDQpjYmluZChwb29sLnNlLmludGVyY2VwdCA9IHBvb2wuc2UpDQpgYGANCg0KIyMgQWR2YW50YWdlcyBvZiBNSUNFDQoNCk1JQ0Ugb2ZmZXJzIHNldmVyYWwgYmVuZWZpdHM6DQoNCiogKipGbGV4aWJpbGl0eSoqOiBJdCBoYW5kbGVzIG1peGVkIGRhdGEgdHlwZXMgKGNvbnRpbnVvdXMsIGJpbmFyeSwgY2F0ZWdvcmljYWwpLg0KKiAqKlByZXNlcnZhdGlvbiBvZiBSZWxhdGlvbnNoaXBzKio6IEltcHV0YXRpb24gcmVzcGVjdHMgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuDQoqICoqVW5jZXJ0YWludHkgUmVwcmVzZW50YXRpb24qKjogTXVsdGlwbGUgaW1wdXRhdGlvbnMgYWNjb3VudCBmb3IgdmFyaWFiaWxpdHkgaW4gbWlzc2luZyBkYXRhLg0KDQpJbiBSLCB0aGUgbWljZSBwYWNrYWdlIHNpbXBsaWZpZXMgTUlDRSBpbXBsZW1lbnRhdGlvbiwgYWxsb3dpbmcgdXNlcnMgdG8gY3VzdG9taXplIGltcHV0YXRpb24gbWV0aG9kcyBmb3IgZWFjaCB2YXJpYWJsZS4gVGhlIG1haW4gZnVuY3Rpb24gYG1pY2UoKWAgY2FuIGRldGVjdCB0aGUgbWlzc2luZ25lc3Mgb2YgaW5kaXZpZHVhbCB2YXJpYWJsZXMuIElmIGEgdmFyaWFibGUgaGFzIG5vIG1pc3NpbmcgdmFsdWVzLCB0aGUgaW1wdXRpbmcgbW9kZWwgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHNldCB0byBgIiJgLiAgDQoNCg0KYGBge3J9DQppbXA2IDwtIG1pY2UoZGF0YSwgbWV0aG9kID0gYygicG1tIiwgInBtbSIsICJwbW0iLCAicG1tIiwgIiIsICIiKSwgDQogICAgICAgICAgICBtYXhpdCA9IDUsDQogICAgICAgICAgICBwcmludD1GLCANCiAgICAgICAgICAgIHNlZWQgPSAxMjMpDQppbXA2JG1ldGhvZCAgDQojIyB3aXRob3V0IG1ubyBzcGVjaWZpZWQgaW1wdXRpbmcgbW9kZWwNCmluaXQgPC0gbWljZShkYXRhLCAgIA0KICAgICAgICAgICAgbWF4aXQgPSA1LA0KICAgICAgICAgICAgcHJpbnQ9RiwgDQogICAgICAgICAgICBzZWVkID0gMTIzKQ0KaW5pdCRtZXRob2QNCmBgYA0KDQoNCkluIHRoaXMgZXhhbXBsZSwgcHJlZGljdGl2ZSBtZWFuIG1hdGNoaW5nIChgcG1tYCkgaXMgdXNlZCBmb3IgY29udGludW91cyB2YXJpYWJsZXMuIElmIHRoZXJlIGlzIGEgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlIHdpdGggbWlzc2luZyB2YWx1ZXMsIGxvZ2lzdGljIHJlZ3Jlc3Npb24gKGBsb2dyZWdgKSB3aWxsIGJlIHVzZWQgYXMgdGhlIGltcHV0ZWQgbW9kZWwuDQoNCg0KIyMgQ2hhbGxlbmdlcyBvZiBNSUNFDQoNCkRlc3BpdGUgaXRzIGFkdmFudGFnZXMsIE1JQ0UgY29tZXMgd2l0aCBjaGFsbGVuZ2VzOg0KDQoqICoqQ29tcHV0YXRpb25hbCBJbnRlbnNpdHkqKjogTGFyZ2UgZGF0YXNldHMgYW5kIGhpZ2ggbWlzc2luZ25lc3MgY2FuIGluY3JlYXNlIGNvbXB1dGF0aW9uIHRpbWUuDQoqICoqTW9kZWwgU3BlY2lmaWNhdGlvbioqOiBQb29ybHkgY2hvc2VuIGltcHV0YXRpb24gbW9kZWxzIG1heSBsZWFkIHRvIGluYWNjdXJhdGUgcmVzdWx0cy4NCiogKipEZXBlbmRlbmNlIG9uIERhdGEgUXVhbGl0eSoqOiBFcnJvcnMgaW4gb2JzZXJ2ZWQgZGF0YSBjYW4gcHJvcGFnYXRlIHRocm91Z2ggaW1wdXRhdGlvbnMuDQoNCkluIFIsIHByb3BlciBwcmUtcHJvY2Vzc2luZywgaW5jbHVkaW5nIG91dGxpZXIgaGFuZGxpbmcgYW5kIHRyYW5zZm9ybWF0aW9uLCBjYW4gbWl0aWdhdGUgc29tZSBjaGFsbGVuZ2VzLg0KDQoNCiMjIFByYWN0aWNhbCBBcHBsaWNhdGlvbnMgb2YgTUlDRQ0KDQpNSUNFIGlzIHdpZGVseSB1c2VkIGluIHZhcmlvdXMgZmllbGRzLCBpbmNsdWRpbmcgaGVhbHRoY2FyZSwgc29jaWFsIHNjaWVuY2VzLCBhbmQgc3VydmV5IHJlc2VhcmNoLiBGb3IgaW5zdGFuY2U6DQoNCkluIGNsaW5pY2FsIHRyaWFscywgTUlDRSBpbXB1dGVzIG1pc3NpbmcgcGF0aWVudCBkYXRhIHRvIHByZXNlcnZlIHRoZSBzdHVkeeKAmXMgaW50ZWdyaXR5Lg0KDQpJbiBzdXJ2ZXlzLCBpdCBoYW5kbGVzIGluY29tcGxldGUgcmVzcG9uc2VzIHdoaWxlIG1haW50YWluaW5nIHJlcHJlc2VudGF0aXZlbmVzcy4NCg0KDQpgYGB7cn0NCiMgSW1wdXRhdGlvbiBmb3IgYSBzdXJ2ZXkgZGF0YXNldA0Kc3VydmV5X2RhdGEgPC0gZGF0YS5mcmFtZSgNCiAgQWdlID0gYygyNSwgMzAsIE5BLCAzNSwgNDApLA0KICBHZW5kZXIgPSBjKCJNYWxlIiwgIkZlbWFsZSIsICJNYWxlIiwgTkEsICJGZW1hbGUiKSwNCiAgSW5jb21lID0gYyg1MDAwMCwgTkEsIDYwMDAwLCA2NTAwMCwgNzAwMDApDQopDQppbXAgPC0gbWljZShzdXJ2ZXlfZGF0YSwgbWV0aG9kID0gYygicG1tIiwgImxvZ3JlZyIsICJwbW0iKSwgbWF4aXQgPSA1LCANCiAgICAgICAgICAgIHByaW50PUYsIHNlZWQgPSAxMjMpDQpjb21wbGV0ZV9kYXRhIDwtIGNvbXBsZXRlKGltcCkNCnByaW50KGNvbXBsZXRlX2RhdGEpDQpgYGANCg0KSGVyZSwgcG9seXJlZyBpcyB1c2VkIGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIHNob3djYXNpbmcgTUlDRSdzIHZlcnNhdGlsaXR5Lg0KDQoNCiMjIENvbmNsdXNpb24NCg0KTUlDRSBpcyBhIHBvd2VyZnVsIGFuZCBmbGV4aWJsZSB0b29sIGZvciBoYW5kbGluZyBtaXNzaW5nIGRhdGEsIGVuc3VyaW5nIHJvYnVzdCBhbmQgdW5iaWFzZWQgc3RhdGlzdGljYWwgYW5hbHlzZXMuIEl0cyBpdGVyYXRpdmUgcHJvY2VzcywgcmVsaWFuY2Ugb24gdGFpbG9yZWQgaW1wdXRhdGlvbiBtb2RlbHMsIGFuZCBhYmlsaXR5IHRvIGFjY291bnQgZm9yIHVuY2VydGFpbnR5IG1ha2UgaXQgYSBjb3JuZXJzdG9uZSBvZiBtb2Rlcm4gZGF0YSBzY2llbmNlLiBXaXRoIHRvb2xzIGxpa2UgdGhlIG1pY2UgcGFja2FnZSBpbiBSLCBpbXBsZW1lbnRpbmcgTUlDRSBoYXMgYmVjb21lIG1vcmUgYWNjZXNzaWJsZSwgZW5hYmxpbmcgYW5hbHlzdHMgdG8gYWRkcmVzcyBtaXNzaW5nIGRhdGEgY2hhbGxlbmdlcyBlZmZlY3RpdmVseS4gV2hpbGUgaXQgcmVxdWlyZXMgY2FyZWZ1bCBpbXBsZW1lbnRhdGlvbiwgdGhlIGJlbmVmaXRzIG9mIHVzaW5nIE1JQ0UgZmFyIG91dHdlaWdoIGl0cyBjaGFsbGVuZ2VzLCBtYWtpbmcgaXQgYW4gZXNzZW50aWFsIHRlY2huaXF1ZSBmb3IgaGlnaC1xdWFsaXR5IGRhdGEgYW5hbHlzaXMuDQoNCg0KDQoNCg==