Objectives
Upon completion of this lesson, you will be able to:
- list the different methods for dealing with missing values
- know when to drop data and when to impute
- apply imputation methods
- consider regulatory and privacy concerns
Introduction
Missing values refer to the absence of data or no data value in an expected place within a dataset. In other words, they’re gaps or blanks in your data.
For example, if you are dealing with a dataset of customer information, there might be some missing values in columns such as “email address” or “phone number” where some customers didn’t provide this information.
Missing values can cause a variety of issues. Many machine learning algorithms require complete datasets to function properly, meaning that if there are missing values, the algorithms might not work or might deliver inaccurate results. Missing data can also bias or distort representations and lead to misleading trends and conclusions.
Motivation
The chalk-talk below by Dr. Martin Schedlbauer of Khoury Boston introduces the topic of missing values and the impact on training machine learning models and doing data analytics.
Missing Data
Missing data refers to the absence of information in a dataset. It can occur due to various reasons such as data entry errors, data corruption, or survey non-responses. There are three main types of missing data:
Missing Completely at Random (MCAR): The missing data is unrelated to any observed or unobserved variables.
Missing at Random (MAR): The missing values are related to the observed data, but not the unobserved data.
Missing Not at Random (MNAR): The missing data is related to the unobserved data. Handling missing data is crucial for accurate and unbiased analysis.
Let’s dig a little more into each one of these.
Missing Completely at Random (MCAR)
MCAR means that the probability of a value being missing is completely unrelated to any observed or unobserved data, i.e., the other features cannot be used to predict the missing value. In other words, the missing value is random and has no pattern. Furthermore, there is no relationship between the missing values and the observed data. The missingness is also unrelated to the unobserved (missing) data itself.
Since the missing data is random and unrelated to any other data, it can be ignored without introducing bias. So, the methods covered in this lesson, including Listwise Deletion, Mean/Median/Mode Imputation or Advanced Imputation Techniques such as K-Nearest Neighbors (KNN) imputation, can be applied.
Missing at Random (MAR)
MAR means that the probability of a value being missing is related to the observed data but not the missing data itself. The missingness can be explained by other observed variables in the dataset. In other words, there is a relationship between the missingness and some of the observed data, but the missingness is unrelated to the missing data itself once the observed data is taken into account.
Since the missingness is related to observed data, one can use the observed data to inform the imputation process. Methods might include Conditional Mean Imputation, Regression Imputation, and Multiple Imputation.
Missing Not at Random (MNAR)
MNAR means that the probability of a value being missing is related to the unobserved data itself. The missingness depends on the value that is missing. The missingness is not entirely explained by the observed data, but rather the missingness is related to the missing values themselves.
MNAR is the most challenging type of missingness to handle because the missingness is directly related to the missing values. Potential methods include Model-Based Methods where we use more complex models that explicitly account for the missing data mechanism, such as Expectation-Maximization (EM) algorithms. Performing analysis to understand how different assumptions about the missing data might affect the results. Adding assumptions or additional external data that can help in modeling the missing data mechanism.
Understanding the nature of the missing data mechanism is crucial for choosing the appropriate method to handle missing values in machine learning and feature engineering.
Dealing with Missing Values
There are several strategies to handle missing values in datasets:
Removal: If the missing data is limited to a small number of observations, you might simply delete those observations from your dataset. This method is direct, but can potentially remove valuable data or introduce bias, especially if data is not missing randomly.
Imputation: You can replace missing values with substituted values. There are many methods of imputation, including mean/mode/median imputation, random imputation, and prediction model imputation.
Mean/Median/Mode Imputation: This involves replacing the missing data for a certain variable with the mean or median (for numerical data) or the mode (for categorical data) of all known values of that variable. This is a common and easy method but can lead to an underestimate of the true variance.
Random Imputation: Randomly selected available values are used to fill in missing data.
Prediction Model Imputation: Machine learning algorithms, like K-Nearest Neighbors (K-NN) and regression models, can be used to predict and impute missing values.
Default Value: If you know why the data is missing, you might assign a value that indicates a data was missing, such as -1 or 9999, for numerical variables, or “Unknown,” for categorical variables. This might be helpful if the fact that data is missing is itself informative.
Multiple Imputation: This method involves imputing the missing values multiple times to create “complete” datasets, analyzing each dataset separately, and pooling the results. It’s a more sophisticated method than single imputation methods like mean/median/mode imputation, and it gives better estimation of the error in imputation.
Advanced Techniques: More advanced techniques, like data augmentation methods or deep learning techniques (like using autoencoders), can be used for dealing with missing data.
Which method to use largely depends on the nature of the data and the problem at hand. Also, the analysis should account for the uncertainty in the imputations. After handling missing data, it’s important to recheck the quality of the data before proceeding with the next steps in your machine learning or data analytics workflow.
Removal/Deletion
“Removal” or “deletion” is one of the simplest methods for dealing with missing data in a dataset. It involves removing the instances (rows) or features (columns) that have missing values. There are two main types of deletion: listwise (or complete) deletion and pairwise deletion.
Listwise (Complete) Deletion: This is the most common form of deletion used. It involves removing entire observations (rows) where at least one value is missing. For example, in a dataset of customer information, if a customer didn’t provide their phone number, their entire record would be deleted.
Pairwise Deletion: In this case, an observation is only excluded if the specific variable that’s being analyzed is missing. Pairwise deletion maximizes all the available data. For example, if you’re analyzing income data and a customer didn’t provide their income, only that specific customer’s income data would be excluded, but the rest of the data for that customer would be used for other variables.
The deletion method is straightforward to implement, but it also has its drawbacks:
- It can lead to a loss of information, particularly if the dataset is small or if the missing data is not random.
- It can introduce bias into the resulting dataset, which could lead to erroneous conclusions or predictions.
- The statistical power decreases with the decreasing size of the dataset.
Therefore, deletion should be used carefully, considering these limitations. It’s often suitable when the amount of missing data is small and appears to be missing completely at random. For example, if a small percentage of users in a survey forgot to answer a particular question, it might be reasonable to just delete those responses.
However, if data is not missing at random and there are patterns in the missing data, deletion can lead to significant bias and should generally be avoided. In these cases, imputation methods might be more suitable.
Imputation
Imputation is a method used to fill in missing data with substituted values. The aim of imputation is to produce a complete dataset that can be used for machine learning models or statistical analysis.
Here are some common imputation techniques:
Mean/Median/Mode Imputation: This involves replacing missing values with the mean (average), median (middle value), or mode (most frequent value) from the non-missing values of that variable. It’s a simple method often used for initial handling of missing data, but it can reduce the variability in the data and potentially introduce bias.
Random Imputation: This involves replacing the missing value with a randomly selected observed value. It’s a relatively easy method to implement and can be more accurate than mean/median/mode imputation, but it’s still a fairly naive method.
Regression Imputation: In this method, a regression model is used to predict missing values based on other data. The observed data is used to estimate the model and then predict the missing values. This method can be more accurate than the previous two, but it makes strong assumptions about the relationships in your data.
K-Nearest Neighbors (K-NN) Imputation: The K-NN method identifies the ‘K’ most similar observations to the one with missing data and imputes the missing value using these similar observations. The similarity is usually calculated using a distance metric such as Euclidean distance.
Multiple Imputation: This is a more sophisticated technique that imputes the missing data multiple times to create several different complete datasets. Each of these datasets is then analyzed, and the results are pooled to give a final result. This method gives a better estimation of the uncertainty around the imputed values.
Advanced Imputation Methods: More advanced methods, such as those using machine learning models or deep learning, can also be used. For example, an autoencoder (a type of neural network) can be trained to learn the most salient features in the data, and then used to impute missing values.
The choice of imputation method depends on the nature of the data and the specific problem. After imputation, it’s also important to validate the quality of the imputed data before using it for further analysis or modeling.
Default Value
The “assignment” method for dealing with missing values involves assigning a unique value to the missing data. This method is often used when the fact that the data is missing is itself potentially informative.
For numerical variables, you might assign a value that is outside the normal range of the variable, such as -1, 0, or 9999. For categorical variables, you might assign a new category like “Unknown” or “Missing”.
For example, consider a dataset of customer information where some customers didn’t provide their income. You could assign a value like -1 to represent missing income data. This approach might be useful if the absence of income information could be indicative of a specific customer behavior or characteristic.
Similarly, in a dataset of patient medical histories, if some patients didn’t answer a question about a specific disease, you might create a new category named “Unknown” for that question. This could be informative, as perhaps these patients were uncomfortable discussing that particular disease, which could be useful information for the analysis.
Assignment can be a useful method when you suspect that the missing data might not be missing at random, and could contain useful information. But it also has potential downsides:
It can introduce bias, particularly if the assigned value is not chosen carefully. For instance, using 0 for missing income data might lead the model to inaccurately associate these customers with a low income group.
It can lead to an artificial relationship between the variable with assigned missing values and other variables, as the assigned value might not reflect the true underlying data distribution.
It might confuse the machine learning model if the value assigned for missing data is not distinct enough from the actual values.
Therefore, it’s important to consider these factors when deciding to use the assignment method to handle missing data. Remember that a missing value could mean something and therefore it alludes to an unknown value that the analyst has not yet discovered.
Advanced Techniques
Advanced techniques for handling missing values often involve statistical or machine learning methods that can model the relationships in the data in a more sophisticated way than simple imputation or deletion.
Here are a few advanced techniques:
Multiple Imputation: This technique involves creating several complete datasets from the one with missing data. Each of these is created by randomly imputing missing values based on a specified model, usually a regression or Bayesian model. The variability across these multiple imputations reflects the uncertainty about the right values to impute. Each dataset is analyzed separately, and then the results are combined, accounting for both within- and between-imputation variability.
Machine Learning Algorithms: Machine learning models like Decision Trees, Random Forests, or Support Vector Machines can be used to predict missing values based on other data. For instance, if we have a dataset with missing age values, we can use other variables (like income, job, marital status, etc.) to train a machine learning model, and then use this model to predict and impute the missing age values.
Deep Learning Techniques: Autoencoders, a type of neural network, can be used to handle missing values. An autoencoder is trained to learn a compressed representation of the data, then recreate the original data from this compressed form. When it encounters missing values, it fills them in with what it would expect based on its training. This approach can be particularly useful with high-dimensional data where simple imputation methods might not work well.
Probabilistic Models: These are statistical techniques that model the data distribution and use this to impute missing values. Examples include Expectation-Maximization (EM) algorithms and Bayesian models. These methods can account for the uncertainty of missing values, but they also require strong assumptions about the data.
Matrix Factorization: This technique is commonly used in recommendation systems. The idea is to factorize the matrix (dataset) into two lower dimensional matrices, and then use these to fill in the missing values.
These advanced techniques can provide more accurate imputations than simpler methods, particularly with large datasets and when the data is not missing at random. However, they also have their drawbacks, including increased computational complexity, difficulty in implementation, and the potential for overfitting.
When choosing an advanced method for handling missing data, you should consider the nature of the missing data (e.g., is it missing at random or not?), the amount of missing data, the complexity of the relationships in your data, and the computational resources available.
Choosing a Techniques
Choosing the appropriate technique to handle missing values in your dataset depends on several factors, including:
The Amount of Missing Data: If only a small percentage of the observations are missing values, it might be reasonable to use listwise deletion (assuming the missingness is completely at random). However, if a large portion of your data is missing, more advanced imputation methods might be more appropriate.
The Pattern of Missingness: If the data is missing completely at random (MCAR), simpler methods like deletion or mean imputation might suffice. But if the data is missing at random (MAR) or not at random (MNAR), where the missingness is related to observed or unobserved data, more advanced techniques like multiple imputation, predictive modeling or matrix factorization would be better.
The Type of Variable: If the variable is categorical, you might use mode imputation or assign a new category to represent missing data. For continuous variables, you could use mean or median imputation, regression imputation, or more advanced methods like K-NN or deep learning-based imputation.
The Importance of the Variable: If the variable with missing data is a crucial feature for your analysis or model, you might want to use a more sophisticated imputation method to preserve its variance and relationships with other variables. If it’s not as important, you might use a simpler method or even consider dropping the variable.
The Complexity of the Data: If the relationships between variables in your dataset are complex, advanced techniques like multiple imputation, machine learning models, or deep learning techniques might be more appropriate, as they can model these complex relationships better than simpler methods.
Computational Resources: More advanced techniques can require significant computational resources and time. If these are limited, you might need to use simpler methods or use a smaller sample of your data for multiple imputation or modeling-based imputation.
It’s often a good idea to try multiple methods and compare the results to see which performs best for your specific situation – data science is the art of experimentation. You might also want to perform sensitivity analysis to understand the potential impact of the missing data on your conclusions or predictions.
Outliers and Missing Values
There are occasions when an extreme outliers should be treated as a missing value. For example, when an outlying value is extreme and there are very few outliers, then treating the outliers as a missing value and applying the aforementioned techniques would be appropriate.
Regulatory and Privacy Considerations
Regulatory and privacy considerations can play a significant role in determining how you deal with missing data in certain contexts. Let’s look at each of these in detail.
Regulatory Considerations:
Certain industries, particularly those related to healthcare, finance, and personal data, have strict regulations that guide how data can be handled, manipulated, and stored. These regulations can impact how you deal with missing data.
For instance, in the healthcare industry, the U.S. Health Insurance Portability and Accountability Act (HIPAA) lays out strict guidelines on how to manage patient health information. Similarly, finance industries have regulations that require accurate reporting and maintaining data integrity, and they may specify acceptable methods for handling missing data.
Regulatory considerations also extend to the fairness and transparency of models, especially in sensitive areas such as credit scoring or hiring. Improperly handling missing data could potentially lead to models that are biased or discriminatory, which would be a regulatory issue.
Privacy Considerations:
Handling missing data by imputation methods involves making an educated guess about what the missing data might be, often based on other data about the same individual. If these inferences are incorrect, they could potentially be misleading or violate an individual’s privacy.
In some cases, the fact that a certain piece of data is missing can reveal something about an individual, even if the actual data isn’t known. For example, if certain health data is missing, it might be because an individual has a particular health condition that they prefer not to disclose.
Also, in privacy-preserving data analysis, the goal is often to add noise to data to protect individual privacy. In these cases, adding synthetic data (like imputed values) to your dataset might be contrary to the goals of privacy protection.
In general, it’s crucial to understand and comply with all relevant regulations and privacy considerations when dealing with missing data. When in doubt, consult with a legal expert or a data privacy officer.
Summary
Missing values in machine learning and data analytics refer to the absence of expected data in a dataset. These gaps can cause issues, as many algorithms require complete data to function correctly, and missing values can distort conclusions or trends.
Dealing with missing values involves several strategies:
Removal: Removing observations with missing data. Effective if missing data is small but can introduce bias.
Imputation: Replacing missing values with substituted values. This can include using mean/median/mode, random values, or predictive models for substitution.
Default Value: Assigning a unique value to represent missing data, which is helpful if the missing status itself carries information.
Multiple Imputation: Imputing missing values multiple times, analyzing each dataset, and pooling the results. This provides better error estimation.
Advanced Techniques: Using methods like data augmentation or deep learning techniques for dealing with missing data.
The chosen method should depend on the nature of the data and the problem at hand, and the data quality should be reassessed after handling missing values.
LS0tCnRpdGxlOiAiTWFuYWdpbmcgTWlzc2luZyBWYWx1ZXMgaW4gRGF0YSIKcGFyYW1zOgogIHR5cGU6IGxlc3NvbgogIGNhdGVnb3J5OiAzCiAgc3RhY2tzOiAwCiAgbnVtYmVyOiAyMDQKICB0aW1lOiA0NQogIGxldmVsOiBiZWdpbm5lcgogIHRhZ3M6IG1pc3NpbmcgZGF0YSxtYWNoaW5lIGxlYXJuaW5nLGRhdGEgY2xlYW5pbmcsaW1wdXRhdGlvbgogIGRlc2NyaXB0aW9uOiAiRXhwbGFpbnMgaG93IHRvIGRlYWwgd2l0aCBtaXNzaW5nIHZhbHVlcy4gRGVtb25zdHJhdGVzIHRoZQogICAgICAgICAgICAgICAgdXNlIG9mIGltcHV0YXRpb24gc3RyYXRlZ2llcy4iCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiIKYXV0aG9yOiAiPHNtYWxsPk1hcnRpbiBTY2hlZGxiYXVlcjwvc21hbGw+IgplbWFpbDogIm0uc2NoZWRsYmF1ZXJAbmV1LmVkdSIKYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgT2JqZWN0aXZlcwoKVXBvbiBjb21wbGV0aW9uIG9mIHRoaXMgbGVzc29uLCB5b3Ugd2lsbCBiZSBhYmxlIHRvOgoKLSAgIGxpc3QgdGhlIGRpZmZlcmVudCBtZXRob2RzIGZvciBkZWFsaW5nIHdpdGggbWlzc2luZyB2YWx1ZXMKLSAgIGtub3cgd2hlbiB0byBkcm9wIGRhdGEgYW5kIHdoZW4gdG8gaW1wdXRlCi0gICBhcHBseSBpbXB1dGF0aW9uIG1ldGhvZHMKLSAgIGNvbnNpZGVyIHJlZ3VsYXRvcnkgYW5kIHByaXZhY3kgY29uY2VybnMKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgSW50cm9kdWN0aW9uCgpNaXNzaW5nIHZhbHVlcyByZWZlciB0byB0aGUgYWJzZW5jZSBvZiBkYXRhIG9yIG5vIGRhdGEgdmFsdWUgaW4gYW4gZXhwZWN0ZWQgcGxhY2Ugd2l0aGluIGEgZGF0YXNldC4gSW4gb3RoZXIgd29yZHMsIHRoZXkncmUgZ2FwcyBvciBibGFua3MgaW4geW91ciBkYXRhLgoKRm9yIGV4YW1wbGUsIGlmIHlvdSBhcmUgZGVhbGluZyB3aXRoIGEgZGF0YXNldCBvZiBjdXN0b21lciBpbmZvcm1hdGlvbiwgdGhlcmUgbWlnaHQgYmUgc29tZSBtaXNzaW5nIHZhbHVlcyBpbiBjb2x1bW5zIHN1Y2ggYXMgImVtYWlsIGFkZHJlc3MiIG9yICJwaG9uZSBudW1iZXIiIHdoZXJlIHNvbWUgY3VzdG9tZXJzIGRpZG4ndCBwcm92aWRlIHRoaXMgaW5mb3JtYXRpb24uCgpNaXNzaW5nIHZhbHVlcyBjYW4gY2F1c2UgYSB2YXJpZXR5IG9mIGlzc3Vlcy4gTWFueSBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMgcmVxdWlyZSBjb21wbGV0ZSBkYXRhc2V0cyB0byBmdW5jdGlvbiBwcm9wZXJseSwgbWVhbmluZyB0aGF0IGlmIHRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcywgdGhlIGFsZ29yaXRobXMgbWlnaHQgbm90IHdvcmsgb3IgbWlnaHQgZGVsaXZlciBpbmFjY3VyYXRlIHJlc3VsdHMuIE1pc3NpbmcgZGF0YSBjYW4gYWxzbyBiaWFzIG9yIGRpc3RvcnQgcmVwcmVzZW50YXRpb25zIGFuZCBsZWFkIHRvIG1pc2xlYWRpbmcgdHJlbmRzIGFuZCBjb25jbHVzaW9ucy4KCiMjIE1vdGl2YXRpb24geyNtb3Rpdn0KClRoZSBjaGFsay10YWxrIGJlbG93IGJ5IERyLiBNYXJ0aW4gU2NoZWRsYmF1ZXIgb2YgS2hvdXJ5IEJvc3RvbiBpbnRyb2R1Y2VzIHRoZSB0b3BpYyBvZiBtaXNzaW5nIHZhbHVlcyBhbmQgdGhlIGltcGFjdCBvbiB0cmFpbmluZyBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyBhbmQgZG9pbmcgZGF0YSBhbmFseXRpY3MuCgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLzgzMjU3MTQ0ND9oPTk5Y2U2YzI4MzcmYW1wO3RpdGxlPTAmYW1wO2J5bGluZT0wJmFtcDtwb3J0cmFpdD0wJmFtcDtzcGVlZD0wJmFtcDtiYWRnZT0wJmFtcDthdXRvcGF1c2U9MCZhbXA7cGxheWVyX2lkPTAmYW1wO2FwcF9pZD01ODQ3OSIgd2lkdGg9IjY0MCIgaGVpZ2h0PSIzNjAiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYXV0b3BsYXk7IGZ1bGxzY3JlZW47IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuIHRpdGxlPSJEZWFsaW5nIHdpdGggTWlzc2luZyBWYWx1ZSIgZGF0YS1leHRlcm5hbD0iMSI+Cgo8L2lmcmFtZT4KCiMjIE1pc3NpbmcgRGF0YQoKTWlzc2luZyBkYXRhIHJlZmVycyB0byB0aGUgYWJzZW5jZSBvZiBpbmZvcm1hdGlvbiBpbiBhIGRhdGFzZXQuIEl0IGNhbiBvY2N1ciBkdWUgdG8gdmFyaW91cyByZWFzb25zIHN1Y2ggYXMgZGF0YSBlbnRyeSBlcnJvcnMsIGRhdGEgY29ycnVwdGlvbiwgb3Igc3VydmV5IG5vbi1yZXNwb25zZXMuIFRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGVzIG9mIG1pc3NpbmcgZGF0YToKCioqTWlzc2luZyBDb21wbGV0ZWx5IGF0IFJhbmRvbSAoTUNBUikqKjogVGhlIG1pc3NpbmcgZGF0YSBpcyB1bnJlbGF0ZWQgdG8gYW55IG9ic2VydmVkIG9yIHVub2JzZXJ2ZWQgdmFyaWFibGVzLgoKKipNaXNzaW5nIGF0IFJhbmRvbSAoTUFSKSoqOiBUaGUgbWlzc2luZyB2YWx1ZXMgYXJlIHJlbGF0ZWQgdG8gdGhlIG9ic2VydmVkIGRhdGEsIGJ1dCBub3QgdGhlIHVub2JzZXJ2ZWQgZGF0YS4KCioqTWlzc2luZyBOb3QgYXQgUmFuZG9tIChNTkFSKSoqOiBUaGUgbWlzc2luZyBkYXRhIGlzIHJlbGF0ZWQgdG8gdGhlIHVub2JzZXJ2ZWQgZGF0YS4gSGFuZGxpbmcgbWlzc2luZyBkYXRhIGlzIGNydWNpYWwgZm9yIGFjY3VyYXRlIGFuZCB1bmJpYXNlZCBhbmFseXNpcy4KCkxldCdzIGRpZyBhIGxpdHRsZSBtb3JlIGludG8gZWFjaCBvbmUgb2YgdGhlc2UuCgojIyMgTWlzc2luZyBDb21wbGV0ZWx5IGF0IFJhbmRvbSAoTUNBUikKCioqTUNBUioqIG1lYW5zIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mIGEgdmFsdWUgYmVpbmcgbWlzc2luZyBpcyBjb21wbGV0ZWx5IHVucmVsYXRlZCB0byBhbnkgb2JzZXJ2ZWQgb3IgdW5vYnNlcnZlZCBkYXRhLCAqaS5lLiosIHRoZSBvdGhlciBmZWF0dXJlcyBjYW5ub3QgYmUgdXNlZCB0byBwcmVkaWN0IHRoZSBtaXNzaW5nIHZhbHVlLiBJbiBvdGhlciB3b3JkcywgdGhlIG1pc3NpbmcgdmFsdWUgaXMgcmFuZG9tIGFuZCBoYXMgbm8gcGF0dGVybi4gRnVydGhlcm1vcmUsIHRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBtaXNzaW5nIHZhbHVlcyBhbmQgdGhlIG9ic2VydmVkIGRhdGEuIFRoZSBtaXNzaW5nbmVzcyBpcyBhbHNvIHVucmVsYXRlZCB0byB0aGUgdW5vYnNlcnZlZCAobWlzc2luZykgZGF0YSBpdHNlbGYuCgpTaW5jZSB0aGUgbWlzc2luZyBkYXRhIGlzIHJhbmRvbSBhbmQgdW5yZWxhdGVkIHRvIGFueSBvdGhlciBkYXRhLCBpdCBjYW4gYmUgaWdub3JlZCB3aXRob3V0IGludHJvZHVjaW5nIGJpYXMuIFNvLCB0aGUgbWV0aG9kcyBjb3ZlcmVkIGluIHRoaXMgbGVzc29uLCBpbmNsdWRpbmcgTGlzdHdpc2UgRGVsZXRpb24sIE1lYW4vTWVkaWFuL01vZGUgSW1wdXRhdGlvbiBvciBBZHZhbmNlZCBJbXB1dGF0aW9uIFRlY2huaXF1ZXMgc3VjaCBhcyBLLU5lYXJlc3QgTmVpZ2hib3JzIChLTk4pIGltcHV0YXRpb24sIGNhbiBiZSBhcHBsaWVkLgoKIyMjIE1pc3NpbmcgYXQgUmFuZG9tIChNQVIpCgoqKk1BUioqIG1lYW5zIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mIGEgdmFsdWUgYmVpbmcgbWlzc2luZyBpcyByZWxhdGVkIHRvIHRoZSBvYnNlcnZlZCBkYXRhIGJ1dCBub3QgdGhlIG1pc3NpbmcgZGF0YSBpdHNlbGYuIFRoZSBtaXNzaW5nbmVzcyBjYW4gYmUgZXhwbGFpbmVkIGJ5IG90aGVyIG9ic2VydmVkIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldC4gSW4gb3RoZXIgd29yZHMsIHRoZXJlIGlzIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG1pc3NpbmduZXNzIGFuZCBzb21lIG9mIHRoZSBvYnNlcnZlZCBkYXRhLCBidXQgdGhlIG1pc3NpbmduZXNzIGlzIHVucmVsYXRlZCB0byB0aGUgbWlzc2luZyBkYXRhIGl0c2VsZiBvbmNlIHRoZSBvYnNlcnZlZCBkYXRhIGlzIHRha2VuIGludG8gYWNjb3VudC4KClNpbmNlIHRoZSBtaXNzaW5nbmVzcyBpcyByZWxhdGVkIHRvIG9ic2VydmVkIGRhdGEsIG9uZSBjYW4gdXNlIHRoZSBvYnNlcnZlZCBkYXRhIHRvIGluZm9ybSB0aGUgaW1wdXRhdGlvbiBwcm9jZXNzLiBNZXRob2RzIG1pZ2h0IGluY2x1ZGUgQ29uZGl0aW9uYWwgTWVhbiBJbXB1dGF0aW9uLCBSZWdyZXNzaW9uIEltcHV0YXRpb24sIGFuZCBNdWx0aXBsZSBJbXB1dGF0aW9uLgoKIyMjIE1pc3NpbmcgTm90IGF0IFJhbmRvbSAoTU5BUikKCioqTU5BUioqIG1lYW5zIHRoYXQgdGhlIHByb2JhYmlsaXR5IG9mIGEgdmFsdWUgYmVpbmcgbWlzc2luZyBpcyByZWxhdGVkIHRvIHRoZSB1bm9ic2VydmVkIGRhdGEgaXRzZWxmLiBUaGUgbWlzc2luZ25lc3MgZGVwZW5kcyBvbiB0aGUgdmFsdWUgdGhhdCBpcyBtaXNzaW5nLiBUaGUgbWlzc2luZ25lc3MgaXMgbm90IGVudGlyZWx5IGV4cGxhaW5lZCBieSB0aGUgb2JzZXJ2ZWQgZGF0YSwgYnV0IHJhdGhlciB0aGUgbWlzc2luZ25lc3MgaXMgcmVsYXRlZCB0byB0aGUgbWlzc2luZyB2YWx1ZXMgdGhlbXNlbHZlcy4KCk1OQVIgaXMgdGhlIG1vc3QgY2hhbGxlbmdpbmcgdHlwZSBvZiBtaXNzaW5nbmVzcyB0byBoYW5kbGUgYmVjYXVzZSB0aGUgbWlzc2luZ25lc3MgaXMgZGlyZWN0bHkgcmVsYXRlZCB0byB0aGUgbWlzc2luZyB2YWx1ZXMuIFBvdGVudGlhbCBtZXRob2RzIGluY2x1ZGUgTW9kZWwtQmFzZWQgTWV0aG9kcyB3aGVyZSB3ZSB1c2UgbW9yZSBjb21wbGV4IG1vZGVscyB0aGF0IGV4cGxpY2l0bHkgYWNjb3VudCBmb3IgdGhlIG1pc3NpbmcgZGF0YSBtZWNoYW5pc20sIHN1Y2ggYXMgRXhwZWN0YXRpb24tTWF4aW1pemF0aW9uIChFTSkgYWxnb3JpdGhtcy4gUGVyZm9ybWluZyBhbmFseXNpcyB0byB1bmRlcnN0YW5kIGhvdyBkaWZmZXJlbnQgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIG1pc3NpbmcgZGF0YSBtaWdodCBhZmZlY3QgdGhlIHJlc3VsdHMuIEFkZGluZyBhc3N1bXB0aW9ucyBvciBhZGRpdGlvbmFsIGV4dGVybmFsIGRhdGEgdGhhdCBjYW4gaGVscCBpbiBtb2RlbGluZyB0aGUgbWlzc2luZyBkYXRhIG1lY2hhbmlzbS4KClVuZGVyc3RhbmRpbmcgdGhlIG5hdHVyZSBvZiB0aGUgbWlzc2luZyBkYXRhIG1lY2hhbmlzbSBpcyBjcnVjaWFsIGZvciBjaG9vc2luZyB0aGUgYXBwcm9wcmlhdGUgbWV0aG9kIHRvIGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBpbiBtYWNoaW5lIGxlYXJuaW5nIGFuZCBmZWF0dXJlIGVuZ2luZWVyaW5nLgoKIyMgRGVhbGluZyB3aXRoIE1pc3NpbmcgVmFsdWVzCgpUaGVyZSBhcmUgc2V2ZXJhbCBzdHJhdGVnaWVzIHRvIGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBpbiBkYXRhc2V0czoKCjEuICAqKlJlbW92YWw6KiogSWYgdGhlIG1pc3NpbmcgZGF0YSBpcyBsaW1pdGVkIHRvIGEgc21hbGwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgeW91IG1pZ2h0IHNpbXBseSBkZWxldGUgdGhvc2Ugb2JzZXJ2YXRpb25zIGZyb20geW91ciBkYXRhc2V0LiBUaGlzIG1ldGhvZCBpcyBkaXJlY3QsIGJ1dCBjYW4gcG90ZW50aWFsbHkgcmVtb3ZlIHZhbHVhYmxlIGRhdGEgb3IgaW50cm9kdWNlIGJpYXMsIGVzcGVjaWFsbHkgaWYgZGF0YSBpcyBub3QgbWlzc2luZyByYW5kb21seS4KCjIuICAqKkltcHV0YXRpb246KiogWW91IGNhbiByZXBsYWNlIG1pc3NpbmcgdmFsdWVzIHdpdGggc3Vic3RpdHV0ZWQgdmFsdWVzLiBUaGVyZSBhcmUgbWFueSBtZXRob2RzIG9mIGltcHV0YXRpb24sIGluY2x1ZGluZyBtZWFuL21vZGUvbWVkaWFuIGltcHV0YXRpb24sIHJhbmRvbSBpbXB1dGF0aW9uLCBhbmQgcHJlZGljdGlvbiBtb2RlbCBpbXB1dGF0aW9uLgoKICAgIC0gICAqKk1lYW4vTWVkaWFuL01vZGUgSW1wdXRhdGlvbjoqKiBUaGlzIGludm9sdmVzIHJlcGxhY2luZyB0aGUgbWlzc2luZyBkYXRhIGZvciBhIGNlcnRhaW4gdmFyaWFibGUgd2l0aCB0aGUgbWVhbiBvciBtZWRpYW4gKGZvciBudW1lcmljYWwgZGF0YSkgb3IgdGhlIG1vZGUgKGZvciBjYXRlZ29yaWNhbCBkYXRhKSBvZiBhbGwga25vd24gdmFsdWVzIG9mIHRoYXQgdmFyaWFibGUuIFRoaXMgaXMgYSBjb21tb24gYW5kIGVhc3kgbWV0aG9kIGJ1dCBjYW4gbGVhZCB0byBhbiB1bmRlcmVzdGltYXRlIG9mIHRoZSB0cnVlIHZhcmlhbmNlLgoKICAgIC0gICAqKlJhbmRvbSBJbXB1dGF0aW9uOioqIFJhbmRvbWx5IHNlbGVjdGVkIGF2YWlsYWJsZSB2YWx1ZXMgYXJlIHVzZWQgdG8gZmlsbCBpbiBtaXNzaW5nIGRhdGEuCgogICAgLSAgICoqUHJlZGljdGlvbiBNb2RlbCBJbXB1dGF0aW9uOioqIE1hY2hpbmUgbGVhcm5pbmcgYWxnb3JpdGhtcywgbGlrZSBLLU5lYXJlc3QgTmVpZ2hib3JzIChLLU5OKSBhbmQgcmVncmVzc2lvbiBtb2RlbHMsIGNhbiBiZSB1c2VkIHRvIHByZWRpY3QgYW5kIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4KCjMuICAqKkRlZmF1bHQgVmFsdWU6KiogSWYgeW91IGtub3cgd2h5IHRoZSBkYXRhIGlzIG1pc3NpbmcsIHlvdSBtaWdodCBhc3NpZ24gYSB2YWx1ZSB0aGF0IGluZGljYXRlcyBhIGRhdGEgd2FzIG1pc3NpbmcsIHN1Y2ggYXMgLTEgb3IgOTk5OSwgZm9yIG51bWVyaWNhbCB2YXJpYWJsZXMsIG9yICJVbmtub3duLCIgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gVGhpcyBtaWdodCBiZSBoZWxwZnVsIGlmIHRoZSBmYWN0IHRoYXQgZGF0YSBpcyBtaXNzaW5nIGlzIGl0c2VsZiBpbmZvcm1hdGl2ZS4KCjQuICAqKk11bHRpcGxlIEltcHV0YXRpb246KiogVGhpcyBtZXRob2QgaW52b2x2ZXMgaW1wdXRpbmcgdGhlIG1pc3NpbmcgdmFsdWVzIG11bHRpcGxlIHRpbWVzIHRvIGNyZWF0ZSAiY29tcGxldGUiIGRhdGFzZXRzLCBhbmFseXppbmcgZWFjaCBkYXRhc2V0IHNlcGFyYXRlbHksIGFuZCBwb29saW5nIHRoZSByZXN1bHRzLiBJdCdzIGEgbW9yZSBzb3BoaXN0aWNhdGVkIG1ldGhvZCB0aGFuIHNpbmdsZSBpbXB1dGF0aW9uIG1ldGhvZHMgbGlrZSBtZWFuL21lZGlhbi9tb2RlIGltcHV0YXRpb24sIGFuZCBpdCBnaXZlcyBiZXR0ZXIgZXN0aW1hdGlvbiBvZiB0aGUgZXJyb3IgaW4gaW1wdXRhdGlvbi4KCjUuICAqKkFkdmFuY2VkIFRlY2huaXF1ZXM6KiogTW9yZSBhZHZhbmNlZCB0ZWNobmlxdWVzLCBsaWtlIGRhdGEgYXVnbWVudGF0aW9uIG1ldGhvZHMgb3IgZGVlcCBsZWFybmluZyB0ZWNobmlxdWVzIChsaWtlIHVzaW5nIGF1dG9lbmNvZGVycyksIGNhbiBiZSB1c2VkIGZvciBkZWFsaW5nIHdpdGggbWlzc2luZyBkYXRhLgoKV2hpY2ggbWV0aG9kIHRvIHVzZSBsYXJnZWx5IGRlcGVuZHMgb24gdGhlIG5hdHVyZSBvZiB0aGUgZGF0YSBhbmQgdGhlIHByb2JsZW0gYXQgaGFuZC4gQWxzbywgdGhlIGFuYWx5c2lzIHNob3VsZCBhY2NvdW50IGZvciB0aGUgdW5jZXJ0YWludHkgaW4gdGhlIGltcHV0YXRpb25zLiBBZnRlciBoYW5kbGluZyBtaXNzaW5nIGRhdGEsIGl0J3MgaW1wb3J0YW50IHRvIHJlY2hlY2sgdGhlIHF1YWxpdHkgb2YgdGhlIGRhdGEgYmVmb3JlIHByb2NlZWRpbmcgd2l0aCB0aGUgbmV4dCBzdGVwcyBpbiB5b3VyIG1hY2hpbmUgbGVhcm5pbmcgb3IgZGF0YSBhbmFseXRpY3Mgd29ya2Zsb3cuCgojIyBSZW1vdmFsL0RlbGV0aW9uCgoiUmVtb3ZhbCIgb3IgImRlbGV0aW9uIiBpcyBvbmUgb2YgdGhlIHNpbXBsZXN0IG1ldGhvZHMgZm9yIGRlYWxpbmcgd2l0aCBtaXNzaW5nIGRhdGEgaW4gYSBkYXRhc2V0LiBJdCBpbnZvbHZlcyByZW1vdmluZyB0aGUgaW5zdGFuY2VzIChyb3dzKSBvciBmZWF0dXJlcyAoY29sdW1ucykgdGhhdCBoYXZlIG1pc3NpbmcgdmFsdWVzLiBUaGVyZSBhcmUgdHdvIG1haW4gdHlwZXMgb2YgZGVsZXRpb246IGxpc3R3aXNlIChvciBjb21wbGV0ZSkgZGVsZXRpb24gYW5kIHBhaXJ3aXNlIGRlbGV0aW9uLgoKMS4gICoqTGlzdHdpc2UgKENvbXBsZXRlKSBEZWxldGlvbjoqKiBUaGlzIGlzIHRoZSBtb3N0IGNvbW1vbiBmb3JtIG9mIGRlbGV0aW9uIHVzZWQuIEl0IGludm9sdmVzIHJlbW92aW5nIGVudGlyZSBvYnNlcnZhdGlvbnMgKHJvd3MpIHdoZXJlIGF0IGxlYXN0IG9uZSB2YWx1ZSBpcyBtaXNzaW5nLiBGb3IgZXhhbXBsZSwgaW4gYSBkYXRhc2V0IG9mIGN1c3RvbWVyIGluZm9ybWF0aW9uLCBpZiBhIGN1c3RvbWVyIGRpZG4ndCBwcm92aWRlIHRoZWlyIHBob25lIG51bWJlciwgdGhlaXIgZW50aXJlIHJlY29yZCB3b3VsZCBiZSBkZWxldGVkLgoKMi4gICoqUGFpcndpc2UgRGVsZXRpb246KiogSW4gdGhpcyBjYXNlLCBhbiBvYnNlcnZhdGlvbiBpcyBvbmx5IGV4Y2x1ZGVkIGlmIHRoZSBzcGVjaWZpYyB2YXJpYWJsZSB0aGF0J3MgYmVpbmcgYW5hbHl6ZWQgaXMgbWlzc2luZy4gUGFpcndpc2UgZGVsZXRpb24gbWF4aW1pemVzIGFsbCB0aGUgYXZhaWxhYmxlIGRhdGEuIEZvciBleGFtcGxlLCBpZiB5b3UncmUgYW5hbHl6aW5nIGluY29tZSBkYXRhIGFuZCBhIGN1c3RvbWVyIGRpZG4ndCBwcm92aWRlIHRoZWlyIGluY29tZSwgb25seSB0aGF0IHNwZWNpZmljIGN1c3RvbWVyJ3MgaW5jb21lIGRhdGEgd291bGQgYmUgZXhjbHVkZWQsIGJ1dCB0aGUgcmVzdCBvZiB0aGUgZGF0YSBmb3IgdGhhdCBjdXN0b21lciB3b3VsZCBiZSB1c2VkIGZvciBvdGhlciB2YXJpYWJsZXMuCgpUaGUgZGVsZXRpb24gbWV0aG9kIGlzIHN0cmFpZ2h0Zm9yd2FyZCB0byBpbXBsZW1lbnQsIGJ1dCBpdCBhbHNvIGhhcyBpdHMgZHJhd2JhY2tzOgoKLSAgIEl0IGNhbiBsZWFkIHRvIGEgbG9zcyBvZiBpbmZvcm1hdGlvbiwgcGFydGljdWxhcmx5IGlmIHRoZSBkYXRhc2V0IGlzIHNtYWxsIG9yIGlmIHRoZSBtaXNzaW5nIGRhdGEgaXMgbm90IHJhbmRvbS4KLSAgIEl0IGNhbiBpbnRyb2R1Y2UgYmlhcyBpbnRvIHRoZSByZXN1bHRpbmcgZGF0YXNldCwgd2hpY2ggY291bGQgbGVhZCB0byBlcnJvbmVvdXMgY29uY2x1c2lvbnMgb3IgcHJlZGljdGlvbnMuCi0gICBUaGUgc3RhdGlzdGljYWwgcG93ZXIgZGVjcmVhc2VzIHdpdGggdGhlIGRlY3JlYXNpbmcgc2l6ZSBvZiB0aGUgZGF0YXNldC4KClRoZXJlZm9yZSwgZGVsZXRpb24gc2hvdWxkIGJlIHVzZWQgY2FyZWZ1bGx5LCBjb25zaWRlcmluZyB0aGVzZSBsaW1pdGF0aW9ucy4gSXQncyBvZnRlbiBzdWl0YWJsZSB3aGVuIHRoZSBhbW91bnQgb2YgbWlzc2luZyBkYXRhIGlzIHNtYWxsIGFuZCBhcHBlYXJzIHRvIGJlIG1pc3NpbmcgY29tcGxldGVseSBhdCByYW5kb20uIEZvciBleGFtcGxlLCBpZiBhIHNtYWxsIHBlcmNlbnRhZ2Ugb2YgdXNlcnMgaW4gYSBzdXJ2ZXkgZm9yZ290IHRvIGFuc3dlciBhIHBhcnRpY3VsYXIgcXVlc3Rpb24sIGl0IG1pZ2h0IGJlIHJlYXNvbmFibGUgdG8ganVzdCBkZWxldGUgdGhvc2UgcmVzcG9uc2VzLgoKSG93ZXZlciwgaWYgZGF0YSBpcyBub3QgbWlzc2luZyBhdCByYW5kb20gYW5kIHRoZXJlIGFyZSBwYXR0ZXJucyBpbiB0aGUgbWlzc2luZyBkYXRhLCBkZWxldGlvbiBjYW4gbGVhZCB0byBzaWduaWZpY2FudCBiaWFzIGFuZCBzaG91bGQgZ2VuZXJhbGx5IGJlIGF2b2lkZWQuIEluIHRoZXNlIGNhc2VzLCBpbXB1dGF0aW9uIG1ldGhvZHMgbWlnaHQgYmUgbW9yZSBzdWl0YWJsZS4KCiMjIEltcHV0YXRpb24KCkltcHV0YXRpb24gaXMgYSBtZXRob2QgdXNlZCB0byBmaWxsIGluIG1pc3NpbmcgZGF0YSB3aXRoIHN1YnN0aXR1dGVkIHZhbHVlcy4gVGhlIGFpbSBvZiBpbXB1dGF0aW9uIGlzIHRvIHByb2R1Y2UgYSBjb21wbGV0ZSBkYXRhc2V0IHRoYXQgY2FuIGJlIHVzZWQgZm9yIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIG9yIHN0YXRpc3RpY2FsIGFuYWx5c2lzLgoKSGVyZSBhcmUgc29tZSBjb21tb24gaW1wdXRhdGlvbiB0ZWNobmlxdWVzOgoKMS4gICoqTWVhbi9NZWRpYW4vTW9kZSBJbXB1dGF0aW9uOioqIFRoaXMgaW52b2x2ZXMgcmVwbGFjaW5nIG1pc3NpbmcgdmFsdWVzIHdpdGggdGhlIG1lYW4gKGF2ZXJhZ2UpLCBtZWRpYW4gKG1pZGRsZSB2YWx1ZSksIG9yIG1vZGUgKG1vc3QgZnJlcXVlbnQgdmFsdWUpIGZyb20gdGhlIG5vbi1taXNzaW5nIHZhbHVlcyBvZiB0aGF0IHZhcmlhYmxlLiBJdCdzIGEgc2ltcGxlIG1ldGhvZCBvZnRlbiB1c2VkIGZvciBpbml0aWFsIGhhbmRsaW5nIG9mIG1pc3NpbmcgZGF0YSwgYnV0IGl0IGNhbiByZWR1Y2UgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBkYXRhIGFuZCBwb3RlbnRpYWxseSBpbnRyb2R1Y2UgYmlhcy4KCjIuICAqKlJhbmRvbSBJbXB1dGF0aW9uOioqIFRoaXMgaW52b2x2ZXMgcmVwbGFjaW5nIHRoZSBtaXNzaW5nIHZhbHVlIHdpdGggYSByYW5kb21seSBzZWxlY3RlZCBvYnNlcnZlZCB2YWx1ZS4gSXQncyBhIHJlbGF0aXZlbHkgZWFzeSBtZXRob2QgdG8gaW1wbGVtZW50IGFuZCBjYW4gYmUgbW9yZSBhY2N1cmF0ZSB0aGFuIG1lYW4vbWVkaWFuL21vZGUgaW1wdXRhdGlvbiwgYnV0IGl0J3Mgc3RpbGwgYSBmYWlybHkgbmFpdmUgbWV0aG9kLgoKMy4gICoqUmVncmVzc2lvbiBJbXB1dGF0aW9uOioqIEluIHRoaXMgbWV0aG9kLCBhIHJlZ3Jlc3Npb24gbW9kZWwgaXMgdXNlZCB0byBwcmVkaWN0IG1pc3NpbmcgdmFsdWVzIGJhc2VkIG9uIG90aGVyIGRhdGEuIFRoZSBvYnNlcnZlZCBkYXRhIGlzIHVzZWQgdG8gZXN0aW1hdGUgdGhlIG1vZGVsIGFuZCB0aGVuIHByZWRpY3QgdGhlIG1pc3NpbmcgdmFsdWVzLiBUaGlzIG1ldGhvZCBjYW4gYmUgbW9yZSBhY2N1cmF0ZSB0aGFuIHRoZSBwcmV2aW91cyB0d28sIGJ1dCBpdCBtYWtlcyBzdHJvbmcgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcHMgaW4geW91ciBkYXRhLgoKNC4gICoqSy1OZWFyZXN0IE5laWdoYm9ycyAoSy1OTikgSW1wdXRhdGlvbjoqKiBUaGUgSy1OTiBtZXRob2QgaWRlbnRpZmllcyB0aGUgJ0snIG1vc3Qgc2ltaWxhciBvYnNlcnZhdGlvbnMgdG8gdGhlIG9uZSB3aXRoIG1pc3NpbmcgZGF0YSBhbmQgaW1wdXRlcyB0aGUgbWlzc2luZyB2YWx1ZSB1c2luZyB0aGVzZSBzaW1pbGFyIG9ic2VydmF0aW9ucy4gVGhlIHNpbWlsYXJpdHkgaXMgdXN1YWxseSBjYWxjdWxhdGVkIHVzaW5nIGEgZGlzdGFuY2UgbWV0cmljIHN1Y2ggYXMgRXVjbGlkZWFuIGRpc3RhbmNlLgoKNS4gICoqTXVsdGlwbGUgSW1wdXRhdGlvbjoqKiBUaGlzIGlzIGEgbW9yZSBzb3BoaXN0aWNhdGVkIHRlY2huaXF1ZSB0aGF0IGltcHV0ZXMgdGhlIG1pc3NpbmcgZGF0YSBtdWx0aXBsZSB0aW1lcyB0byBjcmVhdGUgc2V2ZXJhbCBkaWZmZXJlbnQgY29tcGxldGUgZGF0YXNldHMuIEVhY2ggb2YgdGhlc2UgZGF0YXNldHMgaXMgdGhlbiBhbmFseXplZCwgYW5kIHRoZSByZXN1bHRzIGFyZSBwb29sZWQgdG8gZ2l2ZSBhIGZpbmFsIHJlc3VsdC4gVGhpcyBtZXRob2QgZ2l2ZXMgYSBiZXR0ZXIgZXN0aW1hdGlvbiBvZiB0aGUgdW5jZXJ0YWludHkgYXJvdW5kIHRoZSBpbXB1dGVkIHZhbHVlcy4KCjYuICAqKkFkdmFuY2VkIEltcHV0YXRpb24gTWV0aG9kczoqKiBNb3JlIGFkdmFuY2VkIG1ldGhvZHMsIHN1Y2ggYXMgdGhvc2UgdXNpbmcgbWFjaGluZSBsZWFybmluZyBtb2RlbHMgb3IgZGVlcCBsZWFybmluZywgY2FuIGFsc28gYmUgdXNlZC4gRm9yIGV4YW1wbGUsIGFuIGF1dG9lbmNvZGVyIChhIHR5cGUgb2YgbmV1cmFsIG5ldHdvcmspIGNhbiBiZSB0cmFpbmVkIHRvIGxlYXJuIHRoZSBtb3N0IHNhbGllbnQgZmVhdHVyZXMgaW4gdGhlIGRhdGEsIGFuZCB0aGVuIHVzZWQgdG8gaW1wdXRlIG1pc3NpbmcgdmFsdWVzLgoKVGhlIGNob2ljZSBvZiBpbXB1dGF0aW9uIG1ldGhvZCBkZXBlbmRzIG9uIHRoZSBuYXR1cmUgb2YgdGhlIGRhdGEgYW5kIHRoZSBzcGVjaWZpYyBwcm9ibGVtLiBBZnRlciBpbXB1dGF0aW9uLCBpdCdzIGFsc28gaW1wb3J0YW50IHRvIHZhbGlkYXRlIHRoZSBxdWFsaXR5IG9mIHRoZSBpbXB1dGVkIGRhdGEgYmVmb3JlIHVzaW5nIGl0IGZvciBmdXJ0aGVyIGFuYWx5c2lzIG9yIG1vZGVsaW5nLgoKIyMgRGVmYXVsdCBWYWx1ZQoKVGhlICJhc3NpZ25tZW50IiBtZXRob2QgZm9yIGRlYWxpbmcgd2l0aCBtaXNzaW5nIHZhbHVlcyBpbnZvbHZlcyBhc3NpZ25pbmcgYSB1bmlxdWUgdmFsdWUgdG8gdGhlIG1pc3NpbmcgZGF0YS4gVGhpcyBtZXRob2QgaXMgb2Z0ZW4gdXNlZCB3aGVuIHRoZSBmYWN0IHRoYXQgdGhlIGRhdGEgaXMgbWlzc2luZyBpcyBpdHNlbGYgcG90ZW50aWFsbHkgaW5mb3JtYXRpdmUuCgpGb3IgbnVtZXJpY2FsIHZhcmlhYmxlcywgeW91IG1pZ2h0IGFzc2lnbiBhIHZhbHVlIHRoYXQgaXMgb3V0c2lkZSB0aGUgbm9ybWFsIHJhbmdlIG9mIHRoZSB2YXJpYWJsZSwgc3VjaCBhcyAtMSwgMCwgb3IgOTk5OS4gRm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgeW91IG1pZ2h0IGFzc2lnbiBhIG5ldyBjYXRlZ29yeSBsaWtlICJVbmtub3duIiBvciAiTWlzc2luZyIuCgpGb3IgZXhhbXBsZSwgY29uc2lkZXIgYSBkYXRhc2V0IG9mIGN1c3RvbWVyIGluZm9ybWF0aW9uIHdoZXJlIHNvbWUgY3VzdG9tZXJzIGRpZG4ndCBwcm92aWRlIHRoZWlyIGluY29tZS4gWW91IGNvdWxkIGFzc2lnbiBhIHZhbHVlIGxpa2UgLTEgdG8gcmVwcmVzZW50IG1pc3NpbmcgaW5jb21lIGRhdGEuIFRoaXMgYXBwcm9hY2ggbWlnaHQgYmUgdXNlZnVsIGlmIHRoZSBhYnNlbmNlIG9mIGluY29tZSBpbmZvcm1hdGlvbiBjb3VsZCBiZSBpbmRpY2F0aXZlIG9mIGEgc3BlY2lmaWMgY3VzdG9tZXIgYmVoYXZpb3Igb3IgY2hhcmFjdGVyaXN0aWMuCgpTaW1pbGFybHksIGluIGEgZGF0YXNldCBvZiBwYXRpZW50IG1lZGljYWwgaGlzdG9yaWVzLCBpZiBzb21lIHBhdGllbnRzIGRpZG4ndCBhbnN3ZXIgYSBxdWVzdGlvbiBhYm91dCBhIHNwZWNpZmljIGRpc2Vhc2UsIHlvdSBtaWdodCBjcmVhdGUgYSBuZXcgY2F0ZWdvcnkgbmFtZWQgIlVua25vd24iIGZvciB0aGF0IHF1ZXN0aW9uLiBUaGlzIGNvdWxkIGJlIGluZm9ybWF0aXZlLCBhcyBwZXJoYXBzIHRoZXNlIHBhdGllbnRzIHdlcmUgdW5jb21mb3J0YWJsZSBkaXNjdXNzaW5nIHRoYXQgcGFydGljdWxhciBkaXNlYXNlLCB3aGljaCBjb3VsZCBiZSB1c2VmdWwgaW5mb3JtYXRpb24gZm9yIHRoZSBhbmFseXNpcy4KCkFzc2lnbm1lbnQgY2FuIGJlIGEgdXNlZnVsIG1ldGhvZCB3aGVuIHlvdSBzdXNwZWN0IHRoYXQgdGhlIG1pc3NpbmcgZGF0YSBtaWdodCBub3QgYmUgbWlzc2luZyBhdCByYW5kb20sIGFuZCBjb3VsZCBjb250YWluIHVzZWZ1bCBpbmZvcm1hdGlvbi4gQnV0IGl0IGFsc28gaGFzIHBvdGVudGlhbCBkb3duc2lkZXM6CgoxLiAgSXQgY2FuIGludHJvZHVjZSBiaWFzLCBwYXJ0aWN1bGFybHkgaWYgdGhlIGFzc2lnbmVkIHZhbHVlIGlzIG5vdCBjaG9zZW4gY2FyZWZ1bGx5LiBGb3IgaW5zdGFuY2UsIHVzaW5nIDAgZm9yIG1pc3NpbmcgaW5jb21lIGRhdGEgbWlnaHQgbGVhZCB0aGUgbW9kZWwgdG8gaW5hY2N1cmF0ZWx5IGFzc29jaWF0ZSB0aGVzZSBjdXN0b21lcnMgd2l0aCBhIGxvdyBpbmNvbWUgZ3JvdXAuCgoyLiAgSXQgY2FuIGxlYWQgdG8gYW4gYXJ0aWZpY2lhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdmFyaWFibGUgd2l0aCBhc3NpZ25lZCBtaXNzaW5nIHZhbHVlcyBhbmQgb3RoZXIgdmFyaWFibGVzLCBhcyB0aGUgYXNzaWduZWQgdmFsdWUgbWlnaHQgbm90IHJlZmxlY3QgdGhlIHRydWUgdW5kZXJseWluZyBkYXRhIGRpc3RyaWJ1dGlvbi4KCjMuICBJdCBtaWdodCBjb25mdXNlIHRoZSBtYWNoaW5lIGxlYXJuaW5nIG1vZGVsIGlmIHRoZSB2YWx1ZSBhc3NpZ25lZCBmb3IgbWlzc2luZyBkYXRhIGlzIG5vdCBkaXN0aW5jdCBlbm91Z2ggZnJvbSB0aGUgYWN0dWFsIHZhbHVlcy4KClRoZXJlZm9yZSwgaXQncyBpbXBvcnRhbnQgdG8gY29uc2lkZXIgdGhlc2UgZmFjdG9ycyB3aGVuIGRlY2lkaW5nIHRvIHVzZSB0aGUgYXNzaWdubWVudCBtZXRob2QgdG8gaGFuZGxlIG1pc3NpbmcgZGF0YS4gUmVtZW1iZXIgdGhhdCBhIG1pc3NpbmcgdmFsdWUgY291bGQgbWVhbiBzb21ldGhpbmcgYW5kIHRoZXJlZm9yZSBpdCBhbGx1ZGVzIHRvIGFuIHVua25vd24gdmFsdWUgdGhhdCB0aGUgYW5hbHlzdCBoYXMgbm90IHlldCBkaXNjb3ZlcmVkLgoKIyMgQWR2YW5jZWQgVGVjaG5pcXVlcwoKQWR2YW5jZWQgdGVjaG5pcXVlcyBmb3IgaGFuZGxpbmcgbWlzc2luZyB2YWx1ZXMgb2Z0ZW4gaW52b2x2ZSBzdGF0aXN0aWNhbCBvciBtYWNoaW5lIGxlYXJuaW5nIG1ldGhvZHMgdGhhdCBjYW4gbW9kZWwgdGhlIHJlbGF0aW9uc2hpcHMgaW4gdGhlIGRhdGEgaW4gYSBtb3JlIHNvcGhpc3RpY2F0ZWQgd2F5IHRoYW4gc2ltcGxlIGltcHV0YXRpb24gb3IgZGVsZXRpb24uCgpIZXJlIGFyZSBhIGZldyBhZHZhbmNlZCB0ZWNobmlxdWVzOgoKMS4gICoqTXVsdGlwbGUgSW1wdXRhdGlvbjoqKiBUaGlzIHRlY2huaXF1ZSBpbnZvbHZlcyBjcmVhdGluZyBzZXZlcmFsIGNvbXBsZXRlIGRhdGFzZXRzIGZyb20gdGhlIG9uZSB3aXRoIG1pc3NpbmcgZGF0YS4gRWFjaCBvZiB0aGVzZSBpcyBjcmVhdGVkIGJ5IHJhbmRvbWx5IGltcHV0aW5nIG1pc3NpbmcgdmFsdWVzIGJhc2VkIG9uIGEgc3BlY2lmaWVkIG1vZGVsLCB1c3VhbGx5IGEgcmVncmVzc2lvbiBvciBCYXllc2lhbiBtb2RlbC4gVGhlIHZhcmlhYmlsaXR5IGFjcm9zcyB0aGVzZSBtdWx0aXBsZSBpbXB1dGF0aW9ucyByZWZsZWN0cyB0aGUgdW5jZXJ0YWludHkgYWJvdXQgdGhlIHJpZ2h0IHZhbHVlcyB0byBpbXB1dGUuIEVhY2ggZGF0YXNldCBpcyBhbmFseXplZCBzZXBhcmF0ZWx5LCBhbmQgdGhlbiB0aGUgcmVzdWx0cyBhcmUgY29tYmluZWQsIGFjY291bnRpbmcgZm9yIGJvdGggd2l0aGluLSBhbmQgYmV0d2Vlbi1pbXB1dGF0aW9uIHZhcmlhYmlsaXR5LgoKMi4gICoqTWFjaGluZSBMZWFybmluZyBBbGdvcml0aG1zOioqIE1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIGxpa2UgRGVjaXNpb24gVHJlZXMsIFJhbmRvbSBGb3Jlc3RzLCBvciBTdXBwb3J0IFZlY3RvciBNYWNoaW5lcyBjYW4gYmUgdXNlZCB0byBwcmVkaWN0IG1pc3NpbmcgdmFsdWVzIGJhc2VkIG9uIG90aGVyIGRhdGEuIEZvciBpbnN0YW5jZSwgaWYgd2UgaGF2ZSBhIGRhdGFzZXQgd2l0aCBtaXNzaW5nIGFnZSB2YWx1ZXMsIHdlIGNhbiB1c2Ugb3RoZXIgdmFyaWFibGVzIChsaWtlIGluY29tZSwgam9iLCBtYXJpdGFsIHN0YXR1cywgZXRjLikgdG8gdHJhaW4gYSBtYWNoaW5lIGxlYXJuaW5nIG1vZGVsLCBhbmQgdGhlbiB1c2UgdGhpcyBtb2RlbCB0byBwcmVkaWN0IGFuZCBpbXB1dGUgdGhlIG1pc3NpbmcgYWdlIHZhbHVlcy4KCjMuICAqKkRlZXAgTGVhcm5pbmcgVGVjaG5pcXVlczoqKiBBdXRvZW5jb2RlcnMsIGEgdHlwZSBvZiBuZXVyYWwgbmV0d29yaywgY2FuIGJlIHVzZWQgdG8gaGFuZGxlIG1pc3NpbmcgdmFsdWVzLiBBbiBhdXRvZW5jb2RlciBpcyB0cmFpbmVkIHRvIGxlYXJuIGEgY29tcHJlc3NlZCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSwgdGhlbiByZWNyZWF0ZSB0aGUgb3JpZ2luYWwgZGF0YSBmcm9tIHRoaXMgY29tcHJlc3NlZCBmb3JtLiBXaGVuIGl0IGVuY291bnRlcnMgbWlzc2luZyB2YWx1ZXMsIGl0IGZpbGxzIHRoZW0gaW4gd2l0aCB3aGF0IGl0IHdvdWxkIGV4cGVjdCBiYXNlZCBvbiBpdHMgdHJhaW5pbmcuIFRoaXMgYXBwcm9hY2ggY2FuIGJlIHBhcnRpY3VsYXJseSB1c2VmdWwgd2l0aCBoaWdoLWRpbWVuc2lvbmFsIGRhdGEgd2hlcmUgc2ltcGxlIGltcHV0YXRpb24gbWV0aG9kcyBtaWdodCBub3Qgd29yayB3ZWxsLgoKNC4gICoqUHJvYmFiaWxpc3RpYyBNb2RlbHM6KiogVGhlc2UgYXJlIHN0YXRpc3RpY2FsIHRlY2huaXF1ZXMgdGhhdCBtb2RlbCB0aGUgZGF0YSBkaXN0cmlidXRpb24gYW5kIHVzZSB0aGlzIHRvIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4gRXhhbXBsZXMgaW5jbHVkZSBFeHBlY3RhdGlvbi1NYXhpbWl6YXRpb24gKEVNKSBhbGdvcml0aG1zIGFuZCBCYXllc2lhbiBtb2RlbHMuIFRoZXNlIG1ldGhvZHMgY2FuIGFjY291bnQgZm9yIHRoZSB1bmNlcnRhaW50eSBvZiBtaXNzaW5nIHZhbHVlcywgYnV0IHRoZXkgYWxzbyByZXF1aXJlIHN0cm9uZyBhc3N1bXB0aW9ucyBhYm91dCB0aGUgZGF0YS4KCjUuICAqKk1hdHJpeCBGYWN0b3JpemF0aW9uOioqIFRoaXMgdGVjaG5pcXVlIGlzIGNvbW1vbmx5IHVzZWQgaW4gcmVjb21tZW5kYXRpb24gc3lzdGVtcy4gVGhlIGlkZWEgaXMgdG8gZmFjdG9yaXplIHRoZSBtYXRyaXggKGRhdGFzZXQpIGludG8gdHdvIGxvd2VyIGRpbWVuc2lvbmFsIG1hdHJpY2VzLCBhbmQgdGhlbiB1c2UgdGhlc2UgdG8gZmlsbCBpbiB0aGUgbWlzc2luZyB2YWx1ZXMuCgpUaGVzZSBhZHZhbmNlZCB0ZWNobmlxdWVzIGNhbiBwcm92aWRlIG1vcmUgYWNjdXJhdGUgaW1wdXRhdGlvbnMgdGhhbiBzaW1wbGVyIG1ldGhvZHMsIHBhcnRpY3VsYXJseSB3aXRoIGxhcmdlIGRhdGFzZXRzIGFuZCB3aGVuIHRoZSBkYXRhIGlzIG5vdCBtaXNzaW5nIGF0IHJhbmRvbS4gSG93ZXZlciwgdGhleSBhbHNvIGhhdmUgdGhlaXIgZHJhd2JhY2tzLCBpbmNsdWRpbmcgaW5jcmVhc2VkIGNvbXB1dGF0aW9uYWwgY29tcGxleGl0eSwgZGlmZmljdWx0eSBpbiBpbXBsZW1lbnRhdGlvbiwgYW5kIHRoZSBwb3RlbnRpYWwgZm9yIG92ZXJmaXR0aW5nLgoKV2hlbiBjaG9vc2luZyBhbiBhZHZhbmNlZCBtZXRob2QgZm9yIGhhbmRsaW5nIG1pc3NpbmcgZGF0YSwgeW91IHNob3VsZCBjb25zaWRlciB0aGUgbmF0dXJlIG9mIHRoZSBtaXNzaW5nIGRhdGEgKGUuZy4sIGlzIGl0IG1pc3NpbmcgYXQgcmFuZG9tIG9yIG5vdD8pLCB0aGUgYW1vdW50IG9mIG1pc3NpbmcgZGF0YSwgdGhlIGNvbXBsZXhpdHkgb2YgdGhlIHJlbGF0aW9uc2hpcHMgaW4geW91ciBkYXRhLCBhbmQgdGhlIGNvbXB1dGF0aW9uYWwgcmVzb3VyY2VzIGF2YWlsYWJsZS4KCiMjIENob29zaW5nIGEgVGVjaG5pcXVlcwoKQ2hvb3NpbmcgdGhlIGFwcHJvcHJpYXRlIHRlY2huaXF1ZSB0byBoYW5kbGUgbWlzc2luZyB2YWx1ZXMgaW4geW91ciBkYXRhc2V0IGRlcGVuZHMgb24gc2V2ZXJhbCBmYWN0b3JzLCBpbmNsdWRpbmc6CgoxLiAgKipUaGUgQW1vdW50IG9mIE1pc3NpbmcgRGF0YToqKiBJZiBvbmx5IGEgc21hbGwgcGVyY2VudGFnZSBvZiB0aGUgb2JzZXJ2YXRpb25zIGFyZSBtaXNzaW5nIHZhbHVlcywgaXQgbWlnaHQgYmUgcmVhc29uYWJsZSB0byB1c2UgbGlzdHdpc2UgZGVsZXRpb24gKGFzc3VtaW5nIHRoZSBtaXNzaW5nbmVzcyBpcyBjb21wbGV0ZWx5IGF0IHJhbmRvbSkuIEhvd2V2ZXIsIGlmIGEgbGFyZ2UgcG9ydGlvbiBvZiB5b3VyIGRhdGEgaXMgbWlzc2luZywgbW9yZSBhZHZhbmNlZCBpbXB1dGF0aW9uIG1ldGhvZHMgbWlnaHQgYmUgbW9yZSBhcHByb3ByaWF0ZS4KCjIuICAqKlRoZSBQYXR0ZXJuIG9mIE1pc3NpbmduZXNzOioqIElmIHRoZSBkYXRhIGlzIG1pc3NpbmcgY29tcGxldGVseSBhdCByYW5kb20gKE1DQVIpLCBzaW1wbGVyIG1ldGhvZHMgbGlrZSBkZWxldGlvbiBvciBtZWFuIGltcHV0YXRpb24gbWlnaHQgc3VmZmljZS4gQnV0IGlmIHRoZSBkYXRhIGlzIG1pc3NpbmcgYXQgcmFuZG9tIChNQVIpIG9yIG5vdCBhdCByYW5kb20gKE1OQVIpLCB3aGVyZSB0aGUgbWlzc2luZ25lc3MgaXMgcmVsYXRlZCB0byBvYnNlcnZlZCBvciB1bm9ic2VydmVkIGRhdGEsIG1vcmUgYWR2YW5jZWQgdGVjaG5pcXVlcyBsaWtlIG11bHRpcGxlIGltcHV0YXRpb24sIHByZWRpY3RpdmUgbW9kZWxpbmcgb3IgbWF0cml4IGZhY3Rvcml6YXRpb24gd291bGQgYmUgYmV0dGVyLgoKMy4gICoqVGhlIFR5cGUgb2YgVmFyaWFibGU6KiogSWYgdGhlIHZhcmlhYmxlIGlzIGNhdGVnb3JpY2FsLCB5b3UgbWlnaHQgdXNlIG1vZGUgaW1wdXRhdGlvbiBvciBhc3NpZ24gYSBuZXcgY2F0ZWdvcnkgdG8gcmVwcmVzZW50IG1pc3NpbmcgZGF0YS4gRm9yIGNvbnRpbnVvdXMgdmFyaWFibGVzLCB5b3UgY291bGQgdXNlIG1lYW4gb3IgbWVkaWFuIGltcHV0YXRpb24sIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbiwgb3IgbW9yZSBhZHZhbmNlZCBtZXRob2RzIGxpa2UgSy1OTiBvciBkZWVwIGxlYXJuaW5nLWJhc2VkIGltcHV0YXRpb24uCgo0LiAgKipUaGUgSW1wb3J0YW5jZSBvZiB0aGUgVmFyaWFibGU6KiogSWYgdGhlIHZhcmlhYmxlIHdpdGggbWlzc2luZyBkYXRhIGlzIGEgY3J1Y2lhbCBmZWF0dXJlIGZvciB5b3VyIGFuYWx5c2lzIG9yIG1vZGVsLCB5b3UgbWlnaHQgd2FudCB0byB1c2UgYSBtb3JlIHNvcGhpc3RpY2F0ZWQgaW1wdXRhdGlvbiBtZXRob2QgdG8gcHJlc2VydmUgaXRzIHZhcmlhbmNlIGFuZCByZWxhdGlvbnNoaXBzIHdpdGggb3RoZXIgdmFyaWFibGVzLiBJZiBpdCdzIG5vdCBhcyBpbXBvcnRhbnQsIHlvdSBtaWdodCB1c2UgYSBzaW1wbGVyIG1ldGhvZCBvciBldmVuIGNvbnNpZGVyIGRyb3BwaW5nIHRoZSB2YXJpYWJsZS4KCjUuICAqKlRoZSBDb21wbGV4aXR5IG9mIHRoZSBEYXRhOioqIElmIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIGluIHlvdXIgZGF0YXNldCBhcmUgY29tcGxleCwgYWR2YW5jZWQgdGVjaG5pcXVlcyBsaWtlIG11bHRpcGxlIGltcHV0YXRpb24sIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzLCBvciBkZWVwIGxlYXJuaW5nIHRlY2huaXF1ZXMgbWlnaHQgYmUgbW9yZSBhcHByb3ByaWF0ZSwgYXMgdGhleSBjYW4gbW9kZWwgdGhlc2UgY29tcGxleCByZWxhdGlvbnNoaXBzIGJldHRlciB0aGFuIHNpbXBsZXIgbWV0aG9kcy4KCjYuICAqKkNvbXB1dGF0aW9uYWwgUmVzb3VyY2VzOioqIE1vcmUgYWR2YW5jZWQgdGVjaG5pcXVlcyBjYW4gcmVxdWlyZSBzaWduaWZpY2FudCBjb21wdXRhdGlvbmFsIHJlc291cmNlcyBhbmQgdGltZS4gSWYgdGhlc2UgYXJlIGxpbWl0ZWQsIHlvdSBtaWdodCBuZWVkIHRvIHVzZSBzaW1wbGVyIG1ldGhvZHMgb3IgdXNlIGEgc21hbGxlciBzYW1wbGUgb2YgeW91ciBkYXRhIGZvciBtdWx0aXBsZSBpbXB1dGF0aW9uIG9yIG1vZGVsaW5nLWJhc2VkIGltcHV0YXRpb24uCgpJdCdzIG9mdGVuIGEgZ29vZCBpZGVhIHRvIHRyeSBtdWx0aXBsZSBtZXRob2RzIGFuZCBjb21wYXJlIHRoZSByZXN1bHRzIHRvIHNlZSB3aGljaCBwZXJmb3JtcyBiZXN0IGZvciB5b3VyIHNwZWNpZmljIHNpdHVhdGlvbiAtLSBkYXRhIHNjaWVuY2UgaXMgdGhlIGFydCBvZiBleHBlcmltZW50YXRpb24uIFlvdSBtaWdodCBhbHNvIHdhbnQgdG8gcGVyZm9ybSBzZW5zaXRpdml0eSBhbmFseXNpcyB0byB1bmRlcnN0YW5kIHRoZSBwb3RlbnRpYWwgaW1wYWN0IG9mIHRoZSBtaXNzaW5nIGRhdGEgb24geW91ciBjb25jbHVzaW9ucyBvciBwcmVkaWN0aW9ucy4KCiMjIE91dGxpZXJzIGFuZCBNaXNzaW5nIFZhbHVlcwoKVGhlcmUgYXJlIG9jY2FzaW9ucyB3aGVuIGFuIGV4dHJlbWUgb3V0bGllcnMgc2hvdWxkIGJlIHRyZWF0ZWQgYXMgYSBtaXNzaW5nIHZhbHVlLiBGb3IgZXhhbXBsZSwgd2hlbiBhbiBvdXRseWluZyB2YWx1ZSBpcyBleHRyZW1lIGFuZCB0aGVyZSBhcmUgdmVyeSBmZXcgb3V0bGllcnMsIHRoZW4gdHJlYXRpbmcgdGhlIG91dGxpZXJzIGFzIGEgbWlzc2luZyB2YWx1ZSBhbmQgYXBwbHlpbmcgdGhlIGFmb3JlbWVudGlvbmVkIHRlY2huaXF1ZXMgd291bGQgYmUgYXBwcm9wcmlhdGUuCgojIyBSZWd1bGF0b3J5IGFuZCBQcml2YWN5IENvbnNpZGVyYXRpb25zCgpSZWd1bGF0b3J5IGFuZCBwcml2YWN5IGNvbnNpZGVyYXRpb25zIGNhbiBwbGF5IGEgc2lnbmlmaWNhbnQgcm9sZSBpbiBkZXRlcm1pbmluZyBob3cgeW91IGRlYWwgd2l0aCBtaXNzaW5nIGRhdGEgaW4gY2VydGFpbiBjb250ZXh0cy4gTGV0J3MgbG9vayBhdCBlYWNoIG9mIHRoZXNlIGluIGRldGFpbC4KCioqUmVndWxhdG9yeSBDb25zaWRlcmF0aW9uczoqKgoKQ2VydGFpbiBpbmR1c3RyaWVzLCBwYXJ0aWN1bGFybHkgdGhvc2UgcmVsYXRlZCB0byBoZWFsdGhjYXJlLCBmaW5hbmNlLCBhbmQgcGVyc29uYWwgZGF0YSwgaGF2ZSBzdHJpY3QgcmVndWxhdGlvbnMgdGhhdCBndWlkZSBob3cgZGF0YSBjYW4gYmUgaGFuZGxlZCwgbWFuaXB1bGF0ZWQsIGFuZCBzdG9yZWQuIFRoZXNlIHJlZ3VsYXRpb25zIGNhbiBpbXBhY3QgaG93IHlvdSBkZWFsIHdpdGggbWlzc2luZyBkYXRhLgoKRm9yIGluc3RhbmNlLCBpbiB0aGUgaGVhbHRoY2FyZSBpbmR1c3RyeSwgdGhlIFUuUy4gSGVhbHRoIEluc3VyYW5jZSBQb3J0YWJpbGl0eSBhbmQgQWNjb3VudGFiaWxpdHkgQWN0IChISVBBQSkgbGF5cyBvdXQgc3RyaWN0IGd1aWRlbGluZXMgb24gaG93IHRvIG1hbmFnZSBwYXRpZW50IGhlYWx0aCBpbmZvcm1hdGlvbi4gU2ltaWxhcmx5LCBmaW5hbmNlIGluZHVzdHJpZXMgaGF2ZSByZWd1bGF0aW9ucyB0aGF0IHJlcXVpcmUgYWNjdXJhdGUgcmVwb3J0aW5nIGFuZCBtYWludGFpbmluZyBkYXRhIGludGVncml0eSwgYW5kIHRoZXkgbWF5IHNwZWNpZnkgYWNjZXB0YWJsZSBtZXRob2RzIGZvciBoYW5kbGluZyBtaXNzaW5nIGRhdGEuCgpSZWd1bGF0b3J5IGNvbnNpZGVyYXRpb25zIGFsc28gZXh0ZW5kIHRvIHRoZSBmYWlybmVzcyBhbmQgdHJhbnNwYXJlbmN5IG9mIG1vZGVscywgZXNwZWNpYWxseSBpbiBzZW5zaXRpdmUgYXJlYXMgc3VjaCBhcyBjcmVkaXQgc2NvcmluZyBvciBoaXJpbmcuIEltcHJvcGVybHkgaGFuZGxpbmcgbWlzc2luZyBkYXRhIGNvdWxkIHBvdGVudGlhbGx5IGxlYWQgdG8gbW9kZWxzIHRoYXQgYXJlIGJpYXNlZCBvciBkaXNjcmltaW5hdG9yeSwgd2hpY2ggd291bGQgYmUgYSByZWd1bGF0b3J5IGlzc3VlLgoKKipQcml2YWN5IENvbnNpZGVyYXRpb25zOioqCgpIYW5kbGluZyBtaXNzaW5nIGRhdGEgYnkgaW1wdXRhdGlvbiBtZXRob2RzIGludm9sdmVzIG1ha2luZyBhbiBlZHVjYXRlZCBndWVzcyBhYm91dCB3aGF0IHRoZSBtaXNzaW5nIGRhdGEgbWlnaHQgYmUsIG9mdGVuIGJhc2VkIG9uIG90aGVyIGRhdGEgYWJvdXQgdGhlIHNhbWUgaW5kaXZpZHVhbC4gSWYgdGhlc2UgaW5mZXJlbmNlcyBhcmUgaW5jb3JyZWN0LCB0aGV5IGNvdWxkIHBvdGVudGlhbGx5IGJlIG1pc2xlYWRpbmcgb3IgdmlvbGF0ZSBhbiBpbmRpdmlkdWFsJ3MgcHJpdmFjeS4KCkluIHNvbWUgY2FzZXMsIHRoZSBmYWN0IHRoYXQgYSBjZXJ0YWluIHBpZWNlIG9mIGRhdGEgaXMgbWlzc2luZyBjYW4gcmV2ZWFsIHNvbWV0aGluZyBhYm91dCBhbiBpbmRpdmlkdWFsLCBldmVuIGlmIHRoZSBhY3R1YWwgZGF0YSBpc24ndCBrbm93bi4gRm9yIGV4YW1wbGUsIGlmIGNlcnRhaW4gaGVhbHRoIGRhdGEgaXMgbWlzc2luZywgaXQgbWlnaHQgYmUgYmVjYXVzZSBhbiBpbmRpdmlkdWFsIGhhcyBhIHBhcnRpY3VsYXIgaGVhbHRoIGNvbmRpdGlvbiB0aGF0IHRoZXkgcHJlZmVyIG5vdCB0byBkaXNjbG9zZS4KCkFsc28sIGluIHByaXZhY3ktcHJlc2VydmluZyBkYXRhIGFuYWx5c2lzLCB0aGUgZ29hbCBpcyBvZnRlbiB0byBhZGQgbm9pc2UgdG8gZGF0YSB0byBwcm90ZWN0IGluZGl2aWR1YWwgcHJpdmFjeS4gSW4gdGhlc2UgY2FzZXMsIGFkZGluZyBzeW50aGV0aWMgZGF0YSAobGlrZSBpbXB1dGVkIHZhbHVlcykgdG8geW91ciBkYXRhc2V0IG1pZ2h0IGJlIGNvbnRyYXJ5IHRvIHRoZSBnb2FscyBvZiBwcml2YWN5IHByb3RlY3Rpb24uCgpJbiBnZW5lcmFsLCBpdCdzIGNydWNpYWwgdG8gdW5kZXJzdGFuZCBhbmQgY29tcGx5IHdpdGggYWxsIHJlbGV2YW50IHJlZ3VsYXRpb25zIGFuZCBwcml2YWN5IGNvbnNpZGVyYXRpb25zIHdoZW4gZGVhbGluZyB3aXRoIG1pc3NpbmcgZGF0YS4gV2hlbiBpbiBkb3VidCwgY29uc3VsdCB3aXRoIGEgbGVnYWwgZXhwZXJ0IG9yIGEgZGF0YSBwcml2YWN5IG9mZmljZXIuCgojIyBTdW1tYXJ5CgpNaXNzaW5nIHZhbHVlcyBpbiBtYWNoaW5lIGxlYXJuaW5nIGFuZCBkYXRhIGFuYWx5dGljcyByZWZlciB0byB0aGUgYWJzZW5jZSBvZiBleHBlY3RlZCBkYXRhIGluIGEgZGF0YXNldC4gVGhlc2UgZ2FwcyBjYW4gY2F1c2UgaXNzdWVzLCBhcyBtYW55IGFsZ29yaXRobXMgcmVxdWlyZSBjb21wbGV0ZSBkYXRhIHRvIGZ1bmN0aW9uIGNvcnJlY3RseSwgYW5kIG1pc3NpbmcgdmFsdWVzIGNhbiBkaXN0b3J0IGNvbmNsdXNpb25zIG9yIHRyZW5kcy4KCkRlYWxpbmcgd2l0aCBtaXNzaW5nIHZhbHVlcyBpbnZvbHZlcyBzZXZlcmFsIHN0cmF0ZWdpZXM6CgoxLiAgKipSZW1vdmFsOioqIFJlbW92aW5nIG9ic2VydmF0aW9ucyB3aXRoIG1pc3NpbmcgZGF0YS4gRWZmZWN0aXZlIGlmIG1pc3NpbmcgZGF0YSBpcyBzbWFsbCBidXQgY2FuIGludHJvZHVjZSBiaWFzLgoKMi4gICoqSW1wdXRhdGlvbjoqKiBSZXBsYWNpbmcgbWlzc2luZyB2YWx1ZXMgd2l0aCBzdWJzdGl0dXRlZCB2YWx1ZXMuIFRoaXMgY2FuIGluY2x1ZGUgdXNpbmcgbWVhbi9tZWRpYW4vbW9kZSwgcmFuZG9tIHZhbHVlcywgb3IgcHJlZGljdGl2ZSBtb2RlbHMgZm9yIHN1YnN0aXR1dGlvbi4KCjMuICAqKkRlZmF1bHQgVmFsdWU6KiogQXNzaWduaW5nIGEgdW5pcXVlIHZhbHVlIHRvIHJlcHJlc2VudCBtaXNzaW5nIGRhdGEsIHdoaWNoIGlzIGhlbHBmdWwgaWYgdGhlIG1pc3Npbmcgc3RhdHVzIGl0c2VsZiBjYXJyaWVzIGluZm9ybWF0aW9uLgoKNC4gICoqTXVsdGlwbGUgSW1wdXRhdGlvbjoqKiBJbXB1dGluZyBtaXNzaW5nIHZhbHVlcyBtdWx0aXBsZSB0aW1lcywgYW5hbHl6aW5nIGVhY2ggZGF0YXNldCwgYW5kIHBvb2xpbmcgdGhlIHJlc3VsdHMuIFRoaXMgcHJvdmlkZXMgYmV0dGVyIGVycm9yIGVzdGltYXRpb24uCgo1LiAgKipBZHZhbmNlZCBUZWNobmlxdWVzOioqIFVzaW5nIG1ldGhvZHMgbGlrZSBkYXRhIGF1Z21lbnRhdGlvbiBvciBkZWVwIGxlYXJuaW5nIHRlY2huaXF1ZXMgZm9yIGRlYWxpbmcgd2l0aCBtaXNzaW5nIGRhdGEuCgpUaGUgY2hvc2VuIG1ldGhvZCBzaG91bGQgZGVwZW5kIG9uIHRoZSBuYXR1cmUgb2YgdGhlIGRhdGEgYW5kIHRoZSBwcm9ibGVtIGF0IGhhbmQsIGFuZCB0aGUgZGF0YSBxdWFsaXR5IHNob3VsZCBiZSByZWFzc2Vzc2VkIGFmdGVyIGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzLgoKIyMgVHV0b3JpYWwKCioqUiBOb3RlYm9vayoqOiBbVHV0b3JpYWwgYXBwbHlpbmcgc2V2ZXJhbCB0ZWNobmlxdWVzXSh0LTMtMjA0LW1pc3NpbmctdmFsdWVzLlJtZCkKCiMjIEZpbGVzICYgUmVzb3VyY2VzCgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBMZWFybiBNb3JlCgpbSm9zZXBoLCBKLiAoT2N0IDQsIDIwMTYpLiBIb3cgdG8gVHJlYXQgTWlzc2luZyBWYWx1ZXMgaW4gWW91ciBEYXRhLiBEYXRhIFNjaWVuY2UgQ2VudHJhbF0oaHR0cHM6Ly93d3cuZGF0YXNjaWVuY2VjZW50cmFsLmNvbS9ob3ctdG8tdHJlYXQtbWlzc2luZy12YWx1ZXMtaW4teW91ci1kYXRhLTEpLgoKIyMgRXJyYXRhCgpOb25lIGNvbGxlY3RlZCB5ZXQuIFtMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19kZXBsb3lLbml0LlInKSksIGluY2x1ZGUgPSBGQUxTRX0KYGBgCg==