1 Introduction

The US National Institute of Standards and Technology (NIST) defines EDA as:

An approach/philosophy for data analysis that employs a variety of techniques (mostly graphical) to maximize insight into a data set, uncover underlying structure, extract important variables, detect outliers and anomalies, test underlying assumptions, develop parsimonious models, and determine optimal factor settings.

The term EDA was coined by John Tukey in the 1970s. According to Tukey: “It (EDA) is important to understand what you CAN DO before you learn to measure how WELL you seem to have DONE it… Exploratory data analysis can never be the whole story, but nothing else can serve as the foundation stone – as the first step.

Tukey clearly explains the purpose of EDA. In classical statistics, EDA has been primarily used to inspect the distribution of variables and observe patterns to make hypotheses and test (validating). To be more specific, EDA is for

  1. inspecting the distribution of variables,

  2. detecting (and/or removing) outliers,

  3. examining the trend of variables

  4. assess the associations between variables

The general tools used for EDA in classical statistics are numerical descriptive statistics with basic graphics such as histograms and scatter plots, etc. A cautionary note about EDA is its descriptive nature. EDA is NOT an inferential method.

In Data Science, more EDA tools will be used for feature engineering in order to improve the performance of underlying models and algorithms. This note will systematically outline EDA tools and their applications in both classical statistics and data science.

Working Data Set

For convenience, we use a data set to illustrate the concepts and methods as we proceed. The data set can be found at https://pengdsci.github.io/datasets/MelbourneHousingMarket/MelbourneHousing.csv

MelbourneHousePrice = read.csv("https://pengdsci.github.io/datasets/MelbourneHousingMarket/MelbourneHousing.csv")


2 The EDA process

Conducting EDA requires expertise in multiple tools and programming languages. The EDA process can be summed up in three major steps:

  • Understanding the data
  • Cleaning the data
  • Performing descriptive analysis of the relationship between variables

2.1 Understanding the data

The first step is to import the required libraries and load data to your computer system appropriately. The initial inspection includes

  • Check whether all records were loaded to the system.
  • check the data dictionary map variable names with corresponding column names and understand the type of information that is available in the data set.
  • Check the variable types, formats, abnormalities, etc. by printing out segments of the data set.

2.2 Cleaning the Data

Once the data is successfully loaded, the next step is to perform initial cleaning for the data set such as renaming the columns or the rows using naming conventions. Please keep in mind that changing the values of a variable brings wrong information to the data. When possible, we don’t change the values of individual variables unless the change is supported by theory. The most common initial cleaning steps include

  • Check for null values Check for any null values in the variables.
    • If any of the variables in a data set have null values, it can affect the analysis results.
    • If your data set has missing data, handle them through approaches like imputation, deletion of observations or variables, or using models that can handle missing data.
  • Dropping the redundant data and removing outliers If any redundant data in the data set does not add value to the output, we can remove them from the data set.

2.3 Analysis of the relationship between variables

The final step in the process of EDA is to analyze the relationship between variables. It involves the following:

  • Correlation analysis: We can use the correlation matrix between variables to identify which variables are strongly correlated with each other.

  • Visualization: Visualizations can be used to explore the relationship between variables. This includes scatter plots, heatmaps, etc.

  • Hypothesis testing: We can perform statistical tests to test hypotheses about the relationship between variables.

3 Tools of EDA and Applications

This section summarizes the tools of EDA and their applications in both classical statistics and data science.

3.1 Descriptive Statistics Approach

This approach uses tables and summarized statistics to uncover the pattern in the data. These patterns include the distribution of feature variables, the correlation between variables, missing values proportions, outliers, etc. Measures such five number summary, quartiles, IQR, and standardization of numerical variables.

R has a powerful function summary() that produces summarized descriptive statistics for every variable in the data set.

summary(MelbourneHousePrice)
    Suburb            Address              Rooms            Type          
 Length:34857       Length:34857       Min.   : 1.000   Length:34857      
 Class :character   Class :character   1st Qu.: 2.000   Class :character  
 Mode  :character   Mode  :character   Median : 3.000   Mode  :character  
                                       Mean   : 3.031                     
                                       3rd Qu.: 4.000                     
                                       Max.   :16.000                     
                                                                          
     Price             Method            SellerG              Date          
 Min.   :   85000   Length:34857       Length:34857       Length:34857      
 1st Qu.:  635000   Class :character   Class :character   Class :character  
 Median :  870000   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 1050173                                                           
 3rd Qu.: 1295000                                                           
 Max.   :11200000                                                           
 NA's   :7610                                                               
   Distance           Postcode            Bedroom2         Bathroom     
 Length:34857       Length:34857       Min.   : 0.000   Min.   : 0.000  
 Class :character   Class :character   1st Qu.: 2.000   1st Qu.: 1.000  
 Mode  :character   Mode  :character   Median : 3.000   Median : 2.000  
                                       Mean   : 3.085   Mean   : 1.625  
                                       3rd Qu.: 4.000   3rd Qu.: 2.000  
                                       Max.   :30.000   Max.   :12.000  
                                       NA's   :8217     NA's   :8226    
      Car            Landsize         BuildingArea       YearBuilt    
 Min.   : 0.000   Min.   :     0.0   Min.   :    0.0   Min.   :1196   
 1st Qu.: 1.000   1st Qu.:   224.0   1st Qu.:  102.0   1st Qu.:1940   
 Median : 2.000   Median :   521.0   Median :  136.0   Median :1970   
 Mean   : 1.729   Mean   :   593.6   Mean   :  160.3   Mean   :1965   
 3rd Qu.: 2.000   3rd Qu.:   670.0   3rd Qu.:  188.0   3rd Qu.:2000   
 Max.   :26.000   Max.   :433014.0   Max.   :44515.0   Max.   :2106   
 NA's   :8728     NA's   :11810      NA's   :21115     NA's   :19306  
 CouncilArea          Lattitude        Longtitude     Regionname       
 Length:34857       Min.   :-38.19   Min.   :144.4   Length:34857      
 Class :character   1st Qu.:-37.86   1st Qu.:144.9   Class :character  
 Mode  :character   Median :-37.81   Median :145.0   Mode  :character  
                    Mean   :-37.81   Mean   :145.0                     
                    3rd Qu.:-37.75   3rd Qu.:145.1                     
                    Max.   :-37.39   Max.   :145.5                     
                    NA's   :7976     NA's   :7976                      
 Propertycount     
 Length:34857      
 Class :character  
 Mode  :character  
                   
                   
                   
                   

We observe from the above summary tables that (1) most of the numeric variables have missing values; (2) The distribution of some of these numeric variables is skewed. We will discuss how to use these observations in feature engineering later.

Remarks: Handling missing values in classical statistics is crucial particularly when the sample size is small. In data science, most of the projects are based on large data sets. Furthermore, the sample is usually not the ransom sample taken from a well-defined population. Therefore, imputing missing values is less important in many data science projects are less important (usually assumed missing at random). Next, we delete all records with missing components.

HousePrice = na.omit(MelbourneHousePrice)

For a categorical variable, we can use a frequency table to display its distribution. For example,

table(HousePrice$Bedroom2)

   0    1    2    3    4    5    6    7    8    9   10   12 
   5  348 1965 3837 2183  487   50    5    2    3    1    1 

3.2 Graphical Approach

This approach uses basic statistical graphics to visualize the shape of the data to discover the distributional information of variables from the data and the potential relationships between variables. Graphics that are commonly used are histograms, box plots, serial plots, etc.

par(mfrow = c(2,2))
hist(HousePrice$Price, main = "Distribution of House Price")
Suburb = table(HousePrice$Suburb)
barplot(Suburb, main="Suburb Information")
Type = table(HousePrice$Type)
pie(Type, main="Distribution of House Type")
den <- density(HousePrice$Price)
plot(den, frame = FALSE, col = "blue",main = "Density House Prices")

We can see We will discuss how to use these observed patterns in feature engineering to yield better results later.

3.3 Algorithm-based Method

If there exist some groups (data points clustered), we may want to assign an ID for each group to reduce the overall variations of the data. Including this cluster ID will improve the performance of the underlying model. The clustering algorithm uses a lot of computing resources. As an example, we use the well-known iris data set based on the 4 numerical variables.

library(cluster)
ggplot(iris, aes(Petal.Length, Petal.Width)) + geom_point(aes(col=Species), size=4)

iris0 = iris[,-5]
res.hc <- eclust(iris0, "hclust", k = 3)
#fviz_dend(res.hc)              # dendrogam
 fviz_cluster(res.hc)       # scatter plot

NewIris = iris
NewIris$Cluster = res.hc$cluster
kable(NewIris[sample(1:150,25, replace = FALSE),], caption = "Iris with cluster ID being included.")
Iris with cluster ID being included.
Sepal.Length Sepal.Width Petal.Length Petal.Width Species Cluster
14 4.3 3.0 1.1 0.1 setosa 1
50 5.0 3.3 1.4 0.2 setosa 1
118 7.7 3.8 6.7 2.2 virginica 3
43 4.4 3.2 1.3 0.2 setosa 1
150 5.9 3.0 5.1 1.8 virginica 2
148 6.5 3.0 5.2 2.0 virginica 3
90 5.5 2.5 4.0 1.3 versicolor 2
91 5.5 2.6 4.4 1.2 versicolor 2
143 5.8 2.7 5.1 1.9 virginica 2
92 6.1 3.0 4.6 1.4 versicolor 2
137 6.3 3.4 5.6 2.4 virginica 3
99 5.1 2.5 3.0 1.1 versicolor 2
72 6.1 2.8 4.0 1.3 versicolor 2
26 5.0 3.0 1.6 0.2 setosa 1
7 4.6 3.4 1.4 0.3 setosa 1
78 6.7 3.0 5.0 1.7 versicolor 3
81 5.5 2.4 3.8 1.1 versicolor 2
147 6.3 2.5 5.0 1.9 virginica 2
103 7.1 3.0 5.9 2.1 virginica 3
117 6.5 3.0 5.5 1.8 virginica 3
76 6.6 3.0 4.4 1.4 versicolor 2
32 5.4 3.4 1.5 0.4 setosa 1
106 7.6 3.0 6.6 2.1 virginica 3
109 6.7 2.5 5.8 1.8 virginica 3
136 7.7 3.0 6.1 2.3 virginica 3

4 Visual Techniques of EDA

EDA is particularly effective for low-dimensional data. The following discussion will be based on the number and type of variables.

4.1 Univariate EDA

4.1.1 Numerical Variable

The commonly used visual techniques for numerical variables are histograms, density curves, box plots, serial plots, etc.

par(mfrow = c(2,2))
hist(HousePrice$Price, xlab = "Price", ylab = "count", main = "House Prices")
den=density(HousePrice$Price)
plot(den, xlab = "Price", ylab = "count", main = "House Prices")
##
boxplot(HousePrice$Price, xlab = "Price", ylab = "count", main = "House Prices")
##
# Get the data points in the form of an R vector.
rainfall <- c(799,1174.8,865.1,1334.6,635.4,918.5,685.5,998.6,784.2,985,882.8,1071)
# Convert it to a time series object.
rainfall.timeseries <- ts(rainfall,start = c(2012,1),frequency = 12)
# Plot a graph of the time series.
plot(rainfall.timeseries, ylab = "Rainfall", main = "Rainfall Trend")

One can also create a frequency table to look at the distribution.

options(digits = 7)
bound = round(seq(100000,9000000, length=15),1)
as.data.frame(table(cut(HousePrice$Price, breaks=bound)))
                  Var1 Freq
1     (1e+05,7.36e+05] 3101
2  (7.36e+05,1.37e+06] 3669
3  (1.37e+06,2.01e+06] 1374
4  (2.01e+06,2.64e+06]  442
5  (2.64e+06,3.28e+06]  172
6  (3.28e+06,3.91e+06]   77
7  (3.91e+06,4.55e+06]   24
8  (4.55e+06,5.19e+06]   11
9  (5.19e+06,5.82e+06]    8
10 (5.82e+06,6.46e+06]    5
11 (6.46e+06,7.09e+06]    1
12 (7.09e+06,7.73e+06]    1
13 (7.73e+06,8.36e+06]    1
14    (8.36e+06,9e+06]    1

The above frequency table gives a similar distribution as shown in the histogram and the density curve.

4.1.2 Categorical Variable

The commonly used visual techniques for numerical variables are bar charts and pie charts.

par(mfrow=c(1,2))
freq.tbl = table(HousePrice$Bedroom2)
barplot(freq.tbl, xlab="Number of Bedrooms", ylab = "Counts", main="Distribution of number of Bedrooms")
pie(freq.tbl, xlab="Number of Bedrooms", ylab = "Counts", main="Distribution of number of Bedrooms")

kable(as.data.frame(table(HousePrice$Bedroom2)))
Var1 Freq
0 5
1 348
2 1965
3 3837
4 2183
5 487
6 50
7 5
8 2
9 3
10 1
12 1

4.2 Two Variables

Three different cases involve two variables.

4.2.1 Two Numeric Variables

In the case of two numeric variables, the key interest is to look at the potential association between the two. The most effective visual representation is a scatter plot.

plot(HousePrice$Price, HousePrice$BuildingArea)

The above scatter plot indicates a linear trend between the house price and the building area.

4.2.2 Two Categorical Variable

For given two categorical variables, we may be interested in exploring whether they are independent. The two-way table and be used to visualize the potential relationship between the two categorical variables.

ftable(HousePrice$Bathroom, HousePrice$Bedroom2)
      0    1    2    3    4    5    6    7    8    9   10   12
                                                              
1     2  345 1667 1921  255   10    1    0    0    0    0    0
2     3    2  295 1788 1495  203   13    1    0    0    0    0
3     0    1    3  124  394  206   26    2    1    0    0    0
4     0    0    0    4   36   45    9    2    1    0    0    0
5     0    0    0    0    3   22    0    0    0    0    0    1
6     0    0    0    0    0    1    1    0    0    1    0    0
7     0    0    0    0    0    0    0    0    0    1    0    0
8     0    0    0    0    0    0    0    0    0    1    0    0
9     0    0    0    0    0    0    0    0    0    0    1    0
chisq.test(HousePrice$Bathroom, HousePrice$Bedroom2)

    Pearson's Chi-squared test

data:  HousePrice$Bathroom and HousePrice$Bedroom2
X-squared = 20915, df = 88, p-value < 2.2e-16

Note that \(\chi^2\) test is sometimes used in EDA.

4.2.3 One Numeric Variable and One Categorical Variable

From the modeling point of view, there are two different ways to assess the relationship between a categorical variable and a numerical variable. For example, a ridge plot can be used to visualize the distribution of house prices across the types of houses.

ggplot(HousePrice, aes(x=Price/10000,y=Type,fill=Type))+
  geom_density_ridges_gradient(scale = 4) + theme_ridges() +
  scale_y_discrete(expand = c(0.01, 0)) +
  scale_x_continuous(expand = c(0.08, 0)) +
  labs(x = "Prices",y = "Type") +
  ggtitle("Density estimation of prices given Type") +
  theme(plot.title = element_text(hjust = 0.5))
Ridge plot of density distributions house prices.

Ridge plot of density distributions house prices.

The ridge plot is a visual representation of ANOVA.


4.3 Three or More Variables

Visualizing the relationship between three or more variables can be challenging. One has to use visual design elements such as line, shape, negative/white space, volume, value, color, and texture — to represent the values of variables.


4.3.1 Use of Colors, Movement, and Point-size

In the following example, color, movement, and point size represent continent, time, and population size, respectively. Therefore, it represents the complete relationship of 5 variables.

knitr::include_url("https://flo.uri.sh/visualisation/11871870/embed?auto=1")


4.3.2 Pairewised Relationship Between Variables

The pair-wise scatter plot numerical variables is the most commonly used in practice. We use the Iris data set as an example to show the pair-wise plot in the following.

#library(GGally)
ggpairs(iris, columns = 1:4, aes(color = Species, alpha = 0.5),
        lower = list(continuous = "smooth"))
Pair-wise scatter plot of the numerical variables in the iris data set.

Pair-wise scatter plot of the numerical variables in the iris data set.

The above enhanced pair-wise scatter plot provides a pair-wise comparison between the four numerical variables across the three species (categorical variable).


5 Roles of Visualization in EDA

Information visualization displays information in a visual format that makes insights easier to understand for human users. The information in data is usually visualized in a pictorial or graphical form such as charts, graphs, lists, maps, and comprehensive dashboards that combine these multiple formats.

5.1 Data Visualization

The primary objective of data visualization is to clearly communicate what the data says, help explain trends and statistics, and show patterns that would otherwise be impossible to see. Data visualization is used to make consuming, interpreting, and understanding data as simple as possible, and to make it easier to derive insights from data.

5.2 Visual Analytics

Visual analytics is an emerging area in analytics. It is more than visualization. Interactive exploration and automatic visual manipulation play a central role in visual analytics.

Visual analytics does the heavy lifting with data, by using a variety of tools and technologies — machine learning and mathematical algorithms, statistical models, cutting-edge software programs, etc — to identify and reveal patterns and trends. It prepares the data for the process of data visualization, thereby enabling users to examine data, understand what it means, interpret the patterns it highlights, and help them find meaning and gain useful insights from complex data sets.

In other words, using visual analytic methods and techniques can enhance (data) visualization and improve the performance of analysis and modeling. Interactive visualization technology enables the exploration of data via the manipulation of chart images, with the color, brightness, size, shape, and motion of visual objects representing aspects of the data set being analyzed. The following is such an example (https://vizhub.healthdata.org/cod/).

knitr::include_app("https://vizhub.healthdata.org/cod/")

6 Applications of EDA

EDA is the process of dissecting data, and uncovering its hidden patterns, anomalies, and insights. By visualizing and summarizing data, data scientists can grasp its structure, distribution, and characteristics. This step is vital to understand the context and potential of the data.

6.1 Data Cleaning and Preprocessing

During EDA, analysts detect missing values, outliers, and inconsistencies in the data set. Identifying and addressing these issues is crucial for accurate modeling. The post-EDA procedures usually involve significant data processing that may need advanced algorithms or statistical models.

6.2 Model Assumptions and Validation

Before building any statistical models, EDA allows us to validate assumptions. They can check whether the data meets the model’s assumptions, such as linearity or normality.

6.3 EDA for Variable Selection

EDA aids in selecting the most relevant variables for modeling. By exploring relationships between variables and their significance in predicting outcomes, one can make informed decisions about feature selection and engineering.

6.4 EDA for Variable Creation and Redefinition

This is probably the most important application of EDA in creating analytic data sets. * Discretization of Continuous Variables - Sometimes we may have continuous variables that have multi-modal skewed distributions, we may want to discretize these types of variables to prove model performance and interpretability. For example, in many clinical studies, the age variable is usually defined as age groups for ease of interpretation.

  • Regrouping Categorical Variables - When a categorical variable has homogeneous categories or sparse categories, we need to combine some of these categories in a meaningful way.

  • Clustering - Clustering is the task of dividing data points into a number of groups such that data points in the same groups are more similar to other data points in the same group and dissimilar to the data points in other groups. This

age1 = rnorm(70,16,1.5)
age2 = rnorm(700, 25,3)
age3 = rnorm(150,40,2)
age=c(age1,age2, age3)
salary=c(20000+1000*age1 + rnorm(70,  0, 4000), 
         45000+2000*age2 + rnorm(700, 0, 6000), 
         70000+3000*age3 + rnorm(150, 0, 8000))

grp=c(rep(1,70), rep(2,700), rep(3,150))
plot(density(age))
The distribution of age.

The distribution of age.

plot(age, salary)
The scatter plot of salary vs age.

The scatter plot of salary vs age.

m0=lm(salary~age)
par(mfrow=c(2,2))
plot(m0)
The diagnostic plot of model 1: single predictor age.

The diagnostic plot of model 1: single predictor age.

summary(m0)

Call:
lm(formula = salary ~ age)

Residuals:
   Min     1Q Median     3Q    Max 
-46601  -9159   -229   9221  39100 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -44887.11    1681.83  -26.69   <2e-16 ***
age           5651.85      61.05   92.58   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 12920 on 918 degrees of freedom
Multiple R-squared:  0.9033,    Adjusted R-squared:  0.9032 
F-statistic:  8571 on 1 and 918 DF,  p-value: < 2.2e-16
m1=lm(salary~factor(grp))
par(mfrow=c(2,2))
plot(m1)
The diagnostic plot of model 2: single predictor group.

The diagnostic plot of model 2: single predictor group.

summary(m1)

Call:
lm(formula = salary ~ factor(grp))

Residuals:
     Min       1Q   Median       3Q      Max 
-27305.1  -5003.8      7.1   5440.4  29427.3 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   35179.6      973.2   36.15   <2e-16 ***
factor(grp)2  59362.0     1020.7   58.16   <2e-16 ***
factor(grp)3 155727.6     1178.6  132.12   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 8143 on 917 degrees of freedom
Multiple R-squared:  0.9616,    Adjusted R-squared:  0.9616 
F-statistic: 1.15e+04 on 2 and 917 DF,  p-value: < 2.2e-16
m2=lm(salary~factor(grp)+ age)
par(mfrow=c(2,2))
plot(m2)
The diagnostic plot of model 2: Both group predictor age.

The diagnostic plot of model 2: Both group predictor age.

summary(m2)

Call:
lm(formula = salary ~ factor(grp) + age)

Residuals:
     Min       1Q   Median       3Q      Max 
-19102.8  -4196.6    -94.1   3995.9  23784.6 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)    4954.40    1366.57   3.625 0.000304 ***
factor(grp)2  42031.39    1015.57  41.387  < 2e-16 ***
factor(grp)3 109194.57    1984.28  55.030  < 2e-16 ***
age            1913.61      72.91  26.245  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 6155 on 916 degrees of freedom
Multiple R-squared:  0.9781,    Adjusted R-squared:  0.978 
F-statistic: 1.364e+04 on 3 and 916 DF,  p-value: < 2.2e-16
LS0tDQp0aXRsZTogJ0V4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMnDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIiAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8NCiAgZm9udC1zaXplOiAyMHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgeyAvKiBIZWFkZXIgMSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDEgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KPC9zdHlsZT4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKQ0KICAgbGlicmFyeShsZWFmbGV0KQ0KfQ0KaWYgKCFyZXF1aXJlKCJmYWN0b2V4dHJhIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQ0KICAgbGlicmFyeShmYWN0b2V4dHJhKQ0KfQ0KaWYgKCFyZXF1aXJlKCJUU3N0dWRpbyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJUU3N0dWRpbyIpDQogICBsaWJyYXJ5KFRTc3R1ZGlvKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90cml4IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RyaXgiKQ0KbGlicmFyeShwbG90cml4KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3JpZGdlcyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpDQpsaWJyYXJ5KGdncmlkZ2VzKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikNCmxpYnJhcnkoR0dhbGx5KQ0KfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQoNCg0KXA0KDQoNCiMgSW50cm9kdWN0aW9uDQoNCg0KVGhlIFVTIE5hdGlvbmFsIEluc3RpdHV0ZSBvZiBTdGFuZGFyZHMgYW5kIFRlY2hub2xvZ3kgKE5JU1QpIGRlZmluZXMgRURBIGFzOg0KDQo+QW4gYXBwcm9hY2gvcGhpbG9zb3BoeSBmb3IgZGF0YSBhbmFseXNpcyB0aGF0IGVtcGxveXMgYSB2YXJpZXR5IG9mIHRlY2huaXF1ZXMgKG1vc3RseSBncmFwaGljYWwpIHRvIG1heGltaXplIGluc2lnaHQgaW50byBhIGRhdGEgc2V0LCB1bmNvdmVyIHVuZGVybHlpbmcgc3RydWN0dXJlLCBleHRyYWN0IGltcG9ydGFudCB2YXJpYWJsZXMsIGRldGVjdCBvdXRsaWVycyBhbmQgYW5vbWFsaWVzLCB0ZXN0IHVuZGVybHlpbmcgYXNzdW1wdGlvbnMsIGRldmVsb3AgcGFyc2ltb25pb3VzIG1vZGVscywgYW5kIGRldGVybWluZSBvcHRpbWFsIGZhY3RvciBzZXR0aW5ncy4NCg0KVGhlIHRlcm0gRURBIHdhcyBjb2luZWQgYnkgSm9obiBUdWtleSBpbiB0aGUgMTk3MHMuIEFjY29yZGluZyB0byBUdWtleTog4oCcSXQgKEVEQSkgaXMgaW1wb3J0YW50IHRvIHVuZGVyc3RhbmQgd2hhdCB5b3UgQ0FOIERPIGJlZm9yZSB5b3UgbGVhcm4gdG8gbWVhc3VyZSBob3cgV0VMTCB5b3Ugc2VlbSB0byBoYXZlIERPTkUgaXTigKYgRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBjYW4gbmV2ZXIgYmUgdGhlIHdob2xlIHN0b3J5LCBidXQgbm90aGluZyBlbHNlIGNhbiBzZXJ2ZSBhcyB0aGUgZm91bmRhdGlvbiBzdG9uZSDigJMgYXMgdGhlIGZpcnN0IHN0ZXAuDQoNCg0KVHVrZXkgY2xlYXJseSBleHBsYWlucyB0aGUgcHVycG9zZSBvZiBFREEuIEluIGNsYXNzaWNhbCBzdGF0aXN0aWNzLCBFREEgaGFzIGJlZW4gcHJpbWFyaWx5IHVzZWQgdG8gaW5zcGVjdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHZhcmlhYmxlcyBhbmQgb2JzZXJ2ZSBwYXR0ZXJucyB0byBtYWtlIGh5cG90aGVzZXMgYW5kIHRlc3QgKHZhbGlkYXRpbmcpLiBUbyBiZSBtb3JlIHNwZWNpZmljLCBFREEgaXMgZm9yDQoNCjEuIGluc3BlY3RpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YXJpYWJsZXMsDQoNCjIuIGRldGVjdGluZyAoYW5kL29yIHJlbW92aW5nKSBvdXRsaWVycywNCg0KMy4gZXhhbWluaW5nIHRoZSB0cmVuZCBvZiB2YXJpYWJsZXMNCg0KNC4gYXNzZXNzIHRoZSBhc3NvY2lhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMgDQoNClRoZSBnZW5lcmFsIHRvb2xzIHVzZWQgZm9yIEVEQSBpbiBjbGFzc2ljYWwgc3RhdGlzdGljcyBhcmUgbnVtZXJpY2FsIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgd2l0aCBiYXNpYyBncmFwaGljcyBzdWNoIGFzIGhpc3RvZ3JhbXMgYW5kIHNjYXR0ZXIgcGxvdHMsIGV0Yy4gQSBjYXV0aW9uYXJ5IG5vdGUgYWJvdXQgRURBIGlzIGl0cyBkZXNjcmlwdGl2ZSBuYXR1cmUuIEVEQSBpcyBOT1QgYW4gaW5mZXJlbnRpYWwgbWV0aG9kLg0KDQpJbiBEYXRhIFNjaWVuY2UsIG1vcmUgRURBIHRvb2xzIHdpbGwgYmUgdXNlZCBmb3IgZmVhdHVyZSBlbmdpbmVlcmluZyBpbiBvcmRlciB0byBpbXByb3ZlIHRoZSBwZXJmb3JtYW5jZSBvZiB1bmRlcmx5aW5nIG1vZGVscyBhbmQgYWxnb3JpdGhtcy4gVGhpcyBub3RlIHdpbGwgc3lzdGVtYXRpY2FsbHkgb3V0bGluZSBFREEgdG9vbHMgYW5kIHRoZWlyIGFwcGxpY2F0aW9ucyBpbiBib3RoIGNsYXNzaWNhbCBzdGF0aXN0aWNzIGFuZCBkYXRhIHNjaWVuY2UuDQoNCg0KKipXb3JraW5nIERhdGEgU2V0KioNCg0KDQpGb3IgY29udmVuaWVuY2UsIHdlIHVzZSBhIGRhdGEgc2V0IHRvIGlsbHVzdHJhdGUgdGhlIGNvbmNlcHRzIGFuZCBtZXRob2RzIGFzIHdlIHByb2NlZWQuIFRoZSBkYXRhIHNldCBjYW4gYmUgZm91bmQgYXQgPGh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL01lbGJvdXJuZUhvdXNpbmdNYXJrZXQvTWVsYm91cm5lSG91c2luZy5jc3Y+DQoNCmBgYHtyfQ0KTWVsYm91cm5lSG91c2VQcmljZSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9NZWxib3VybmVIb3VzaW5nTWFya2V0L01lbGJvdXJuZUhvdXNpbmcuY3N2IikNCmBgYA0KDQpcDQoNCiMgVGhlIEVEQSBwcm9jZXNzDQoNCkNvbmR1Y3RpbmcgRURBIHJlcXVpcmVzIGV4cGVydGlzZSBpbiBtdWx0aXBsZSB0b29scyBhbmQgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLiBUaGUgRURBIHByb2Nlc3MgY2FuIGJlIHN1bW1lZCB1cCBpbiB0aHJlZSBtYWpvciBzdGVwczoNCg0KKiBVbmRlcnN0YW5kaW5nIHRoZSBkYXRhDQoqIENsZWFuaW5nIHRoZSBkYXRhDQoqIFBlcmZvcm1pbmcgZGVzY3JpcHRpdmUgYW5hbHlzaXMgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcw0KDQojIyBVbmRlcnN0YW5kaW5nIHRoZSBkYXRhDQoNClRoZSBmaXJzdCBzdGVwIGlzIHRvIGltcG9ydCB0aGUgcmVxdWlyZWQgbGlicmFyaWVzIGFuZCBsb2FkIGRhdGEgdG8geW91ciBjb21wdXRlciBzeXN0ZW0gYXBwcm9wcmlhdGVseS4gVGhlIGluaXRpYWwgaW5zcGVjdGlvbiBpbmNsdWRlcw0KDQoqIENoZWNrIHdoZXRoZXIgYWxsIHJlY29yZHMgd2VyZSBsb2FkZWQgdG8gdGhlIHN5c3RlbS4NCiogY2hlY2sgdGhlIGRhdGEgZGljdGlvbmFyeSBtYXAgdmFyaWFibGUgbmFtZXMgd2l0aCBjb3JyZXNwb25kaW5nIGNvbHVtbiBuYW1lcyBhbmQgdW5kZXJzdGFuZCB0aGUgdHlwZSBvZiBpbmZvcm1hdGlvbiB0aGF0IGlzIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSBzZXQuDQoqIENoZWNrIHRoZSB2YXJpYWJsZSB0eXBlcywgZm9ybWF0cywgYWJub3JtYWxpdGllcywgZXRjLiBieSBwcmludGluZyBvdXQgc2VnbWVudHMgb2YgdGhlIGRhdGEgc2V0Lg0KDQoNCiMjIENsZWFuaW5nIHRoZSBEYXRhDQoNCk9uY2UgdGhlIGRhdGEgaXMgc3VjY2Vzc2Z1bGx5IGxvYWRlZCwgdGhlIG5leHQgc3RlcCBpcyB0byBwZXJmb3JtIGluaXRpYWwgY2xlYW5pbmcgZm9yIHRoZSBkYXRhIHNldCBzdWNoIGFzIHJlbmFtaW5nIHRoZSBjb2x1bW5zIG9yIHRoZSByb3dzIHVzaW5nIG5hbWluZyBjb252ZW50aW9ucy4gUGxlYXNlIGtlZXAgaW4gbWluZCB0aGF0IGNoYW5naW5nIHRoZSB2YWx1ZXMgb2YgYSB2YXJpYWJsZSBicmluZ3Mgd3JvbmcgaW5mb3JtYXRpb24gdG8gdGhlIGRhdGEuIFdoZW4gcG9zc2libGUsIHdlIGRvbid0IGNoYW5nZSB0aGUgdmFsdWVzIG9mIGluZGl2aWR1YWwgdmFyaWFibGVzIHVubGVzcyB0aGUgY2hhbmdlIGlzIHN1cHBvcnRlZCBieSB0aGVvcnkuIFRoZSBtb3N0IGNvbW1vbiBpbml0aWFsIGNsZWFuaW5nIHN0ZXBzIGluY2x1ZGUgDQoNCiogKipDaGVjayBmb3IgbnVsbCB2YWx1ZXMqKiBDaGVjayBmb3IgYW55IG51bGwgdmFsdWVzIGluIHRoZSB2YXJpYWJsZXMuDQogICsgSWYgYW55IG9mIHRoZSB2YXJpYWJsZXMgaW4gYSBkYXRhIHNldCBoYXZlIG51bGwgdmFsdWVzLCBpdCBjYW4gYWZmZWN0IHRoZSBhbmFseXNpcyByZXN1bHRzLiANCiAgKyBJZiB5b3VyIGRhdGEgc2V0IGhhcyBtaXNzaW5nIGRhdGEsIGhhbmRsZSB0aGVtIHRocm91Z2ggYXBwcm9hY2hlcyBsaWtlIGltcHV0YXRpb24sIGRlbGV0aW9uIG9mIG9ic2VydmF0aW9ucyBvciB2YXJpYWJsZXMsIG9yIHVzaW5nIG1vZGVscyB0aGF0IGNhbiBoYW5kbGUgbWlzc2luZyBkYXRhLg0KDQoqICoqRHJvcHBpbmcgdGhlIHJlZHVuZGFudCBkYXRhIGFuZCByZW1vdmluZyBvdXRsaWVycyoqIElmIGFueSByZWR1bmRhbnQgZGF0YSBpbiB0aGUgZGF0YSBzZXQgZG9lcyBub3QgYWRkIHZhbHVlIHRvIHRoZSBvdXRwdXQsIHdlIGNhbiByZW1vdmUgdGhlbSBmcm9tIHRoZSBkYXRhIHNldC4gDQoNCiMjIEFuYWx5c2lzIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYWJsZXMNCg0KVGhlIGZpbmFsIHN0ZXAgaW4gdGhlIHByb2Nlc3Mgb2YgRURBIGlzIHRvIGFuYWx5emUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcy4gSXQgaW52b2x2ZXMgdGhlIGZvbGxvd2luZzoNCg0KKiAqKkNvcnJlbGF0aW9uIGFuYWx5c2lzKio6IFdlIGNhbiB1c2UgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBiZXR3ZWVuIHZhcmlhYmxlcyB0byBpZGVudGlmeSB3aGljaCB2YXJpYWJsZXMgYXJlIHN0cm9uZ2x5IGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLg0KDQoqICoqVmlzdWFsaXphdGlvbioqOiBWaXN1YWxpemF0aW9ucyBjYW4gYmUgdXNlZCB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYWJsZXMuIFRoaXMgaW5jbHVkZXMgc2NhdHRlciBwbG90cywgaGVhdG1hcHMsIGV0Yy4NCg0KKiAqKkh5cG90aGVzaXMgdGVzdGluZyoqOiBXZSBjYW4gcGVyZm9ybSBzdGF0aXN0aWNhbCB0ZXN0cyB0byB0ZXN0IGh5cG90aGVzZXMgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcy4NCg0KDQojIFRvb2xzIG9mIEVEQSBhbmQgQXBwbGljYXRpb25zDQoNClRoaXMgc2VjdGlvbiBzdW1tYXJpemVzIHRoZSB0b29scyBvZiBFREEgYW5kIHRoZWlyIGFwcGxpY2F0aW9ucyBpbiBib3RoIGNsYXNzaWNhbCBzdGF0aXN0aWNzIGFuZCBkYXRhIHNjaWVuY2UuIA0KDQojIyBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIEFwcHJvYWNoDQoNClRoaXMgYXBwcm9hY2ggdXNlcyB0YWJsZXMgYW5kIHN1bW1hcml6ZWQgc3RhdGlzdGljcyB0byB1bmNvdmVyIHRoZSBwYXR0ZXJuIGluIHRoZSBkYXRhLiBUaGVzZSBwYXR0ZXJucyBpbmNsdWRlIHRoZSBkaXN0cmlidXRpb24gb2YgZmVhdHVyZSB2YXJpYWJsZXMsIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHZhcmlhYmxlcywgbWlzc2luZyB2YWx1ZXMgcHJvcG9ydGlvbnMsIG91dGxpZXJzLCBldGMuIE1lYXN1cmVzIHN1Y2ggZml2ZSBudW1iZXIgc3VtbWFyeSwgcXVhcnRpbGVzLCBJUVIsIGFuZCBzdGFuZGFyZGl6YXRpb24gb2YgbnVtZXJpY2FsIHZhcmlhYmxlcy4NCg0KUiBoYXMgYSBwb3dlcmZ1bCBmdW5jdGlvbiBgc3VtbWFyeSgpYCB0aGF0IHByb2R1Y2VzIHN1bW1hcml6ZWQgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgZXZlcnkgdmFyaWFibGUgaW4gdGhlIGRhdGEgc2V0Lg0KDQpgYGB7cn0NCnN1bW1hcnkoTWVsYm91cm5lSG91c2VQcmljZSkNCmBgYA0KDQpXZSBvYnNlcnZlIGZyb20gdGhlIGFib3ZlIHN1bW1hcnkgdGFibGVzIHRoYXQgKDEpIG1vc3Qgb2YgdGhlIG51bWVyaWMgdmFyaWFibGVzIGhhdmUgbWlzc2luZyB2YWx1ZXM7ICgyKSBUaGUgZGlzdHJpYnV0aW9uIG9mIHNvbWUgb2YgdGhlc2UgbnVtZXJpYyB2YXJpYWJsZXMgaXMgc2tld2VkLiBXZSB3aWxsIGRpc2N1c3MgaG93IHRvIHVzZSB0aGVzZSBvYnNlcnZhdGlvbnMgaW4gZmVhdHVyZSBlbmdpbmVlcmluZyBsYXRlci4NCg0KDQoqKlJlbWFya3MqKjogSGFuZGxpbmcgbWlzc2luZyB2YWx1ZXMgaW4gY2xhc3NpY2FsIHN0YXRpc3RpY3MgaXMgY3J1Y2lhbCBwYXJ0aWN1bGFybHkgd2hlbiB0aGUgc2FtcGxlIHNpemUgaXMgc21hbGwuIEluIGRhdGEgc2NpZW5jZSwgbW9zdCBvZiB0aGUgcHJvamVjdHMgYXJlIGJhc2VkIG9uIGxhcmdlIGRhdGEgc2V0cy4gRnVydGhlcm1vcmUsIHRoZSBzYW1wbGUgaXMgdXN1YWxseSBub3QgdGhlIHJhbnNvbSBzYW1wbGUgdGFrZW4gZnJvbSBhIHdlbGwtZGVmaW5lZCBwb3B1bGF0aW9uLiBUaGVyZWZvcmUsIGltcHV0aW5nIG1pc3NpbmcgdmFsdWVzIGlzIGxlc3MgaW1wb3J0YW50IGluIG1hbnkgZGF0YSBzY2llbmNlIHByb2plY3RzIGFyZSBsZXNzIGltcG9ydGFudCAodXN1YWxseSBhc3N1bWVkIG1pc3NpbmcgYXQgcmFuZG9tKS4gTmV4dCwgd2UgZGVsZXRlIGFsbCByZWNvcmRzIHdpdGggbWlzc2luZyBjb21wb25lbnRzLg0KDQoNCg0KYGBge3J9DQpIb3VzZVByaWNlID0gbmEub21pdChNZWxib3VybmVIb3VzZVByaWNlKQ0KYGBgDQoNCg0KRm9yIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUsIHdlIGNhbiB1c2UgYSBmcmVxdWVuY3kgdGFibGUgdG8gZGlzcGxheSBpdHMgZGlzdHJpYnV0aW9uLiBGb3IgZXhhbXBsZSwNCg0KYGBge3J9DQp0YWJsZShIb3VzZVByaWNlJEJlZHJvb20yKQ0KYGBgDQoNCg0KDQojIyBHcmFwaGljYWwgQXBwcm9hY2gNCg0KVGhpcyBhcHByb2FjaCB1c2VzIGJhc2ljIHN0YXRpc3RpY2FsIGdyYXBoaWNzIHRvIHZpc3VhbGl6ZSB0aGUgc2hhcGUgb2YgdGhlIGRhdGEgdG8gZGlzY292ZXIgdGhlIGRpc3RyaWJ1dGlvbmFsIGluZm9ybWF0aW9uIG9mIHZhcmlhYmxlcyBmcm9tIHRoZSBkYXRhIGFuZCB0aGUgcG90ZW50aWFsIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuIEdyYXBoaWNzIHRoYXQgYXJlIGNvbW1vbmx5IHVzZWQgYXJlIGhpc3RvZ3JhbXMsIGJveCBwbG90cywgc2VyaWFsIHBsb3RzLCBldGMuICANCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD02fQ0KcGFyKG1mcm93ID0gYygyLDIpKQ0KaGlzdChIb3VzZVByaWNlJFByaWNlLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBIb3VzZSBQcmljZSIpDQpTdWJ1cmIgPSB0YWJsZShIb3VzZVByaWNlJFN1YnVyYikNCmJhcnBsb3QoU3VidXJiLCBtYWluPSJTdWJ1cmIgSW5mb3JtYXRpb24iKQ0KVHlwZSA9IHRhYmxlKEhvdXNlUHJpY2UkVHlwZSkNCnBpZShUeXBlLCBtYWluPSJEaXN0cmlidXRpb24gb2YgSG91c2UgVHlwZSIpDQpkZW4gPC0gZGVuc2l0eShIb3VzZVByaWNlJFByaWNlKQ0KcGxvdChkZW4sIGZyYW1lID0gRkFMU0UsIGNvbCA9ICJibHVlIixtYWluID0gIkRlbnNpdHkgSG91c2UgUHJpY2VzIikNCmBgYA0KDQpXZSBjYW4gc2VlIFdlIHdpbGwgZGlzY3VzcyBob3cgdG8gdXNlIHRoZXNlIG9ic2VydmVkIHBhdHRlcm5zIGluIGZlYXR1cmUgZW5naW5lZXJpbmcgdG8geWllbGQgYmV0dGVyIHJlc3VsdHMgbGF0ZXIuDQoNCg0KDQojIyBBbGdvcml0aG0tYmFzZWQgTWV0aG9kDQoNCklmIHRoZXJlIGV4aXN0IHNvbWUgZ3JvdXBzIChkYXRhIHBvaW50cyBjbHVzdGVyZWQpLCB3ZSBtYXkgd2FudCB0byBhc3NpZ24gYW4gSUQgZm9yIGVhY2ggZ3JvdXAgdG8gcmVkdWNlIHRoZSBvdmVyYWxsIHZhcmlhdGlvbnMgb2YgdGhlIGRhdGEuIEluY2x1ZGluZyB0aGlzIGNsdXN0ZXIgSUQgd2lsbCBpbXByb3ZlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgdW5kZXJseWluZyBtb2RlbC4gVGhlIGNsdXN0ZXJpbmcgYWxnb3JpdGhtIHVzZXMgYSBsb3Qgb2YgY29tcHV0aW5nIHJlc291cmNlcy4gQXMgYW4gZXhhbXBsZSwgd2UgdXNlIHRoZSB3ZWxsLWtub3duIGlyaXMgZGF0YSBzZXQgYmFzZWQgb24gdGhlIDQgbnVtZXJpY2FsIHZhcmlhYmxlcy4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInfQ0KbGlicmFyeShjbHVzdGVyKQ0KZ2dwbG90KGlyaXMsIGFlcyhQZXRhbC5MZW5ndGgsIFBldGFsLldpZHRoKSkgKyBnZW9tX3BvaW50KGFlcyhjb2w9U3BlY2llcyksIHNpemU9NCkNCmBgYA0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9DQppcmlzMCA9IGlyaXNbLC01XQ0KcmVzLmhjIDwtIGVjbHVzdChpcmlzMCwgImhjbHVzdCIsIGsgPSAzKQ0KI2Z2aXpfZGVuZChyZXMuaGMpICAgICAgICAgICAgICAjIGRlbmRyb2dhbQ0KYGBgDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInfQ0KIGZ2aXpfY2x1c3RlcihyZXMuaGMpICAgICAgICMgc2NhdHRlciBwbG90DQpgYGANCg0KYGBge3J9DQpOZXdJcmlzID0gaXJpcw0KTmV3SXJpcyRDbHVzdGVyID0gcmVzLmhjJGNsdXN0ZXINCmthYmxlKE5ld0lyaXNbc2FtcGxlKDE6MTUwLDI1LCByZXBsYWNlID0gRkFMU0UpLF0sIGNhcHRpb24gPSAiSXJpcyB3aXRoIGNsdXN0ZXIgSUQgYmVpbmcgaW5jbHVkZWQuIikNCmBgYA0KDQoNCg0KIyBWaXN1YWwgVGVjaG5pcXVlcyBvZiBFREENCg0KRURBIGlzIHBhcnRpY3VsYXJseSBlZmZlY3RpdmUgZm9yIGxvdy1kaW1lbnNpb25hbCBkYXRhLiBUaGUgZm9sbG93aW5nIGRpc2N1c3Npb24gd2lsbCBiZSBiYXNlZCBvbiB0aGUgbnVtYmVyIGFuZCB0eXBlIG9mIHZhcmlhYmxlcy4gIA0KDQojIyBVbml2YXJpYXRlIEVEQSANCg0KIyMjIE51bWVyaWNhbCBWYXJpYWJsZQ0KDQpUaGUgY29tbW9ubHkgdXNlZCB2aXN1YWwgdGVjaG5pcXVlcyBmb3IgbnVtZXJpY2FsIHZhcmlhYmxlcyBhcmUgaGlzdG9ncmFtcywgZGVuc2l0eSBjdXJ2ZXMsIGJveCBwbG90cywgc2VyaWFsIHBsb3RzLCBldGMuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0NCnBhcihtZnJvdyA9IGMoMiwyKSkNCmhpc3QoSG91c2VQcmljZSRQcmljZSwgeGxhYiA9ICJQcmljZSIsIHlsYWIgPSAiY291bnQiLCBtYWluID0gIkhvdXNlIFByaWNlcyIpDQpkZW49ZGVuc2l0eShIb3VzZVByaWNlJFByaWNlKQ0KcGxvdChkZW4sIHhsYWIgPSAiUHJpY2UiLCB5bGFiID0gImNvdW50IiwgbWFpbiA9ICJIb3VzZSBQcmljZXMiKQ0KIyMNCmJveHBsb3QoSG91c2VQcmljZSRQcmljZSwgeGxhYiA9ICJQcmljZSIsIHlsYWIgPSAiY291bnQiLCBtYWluID0gIkhvdXNlIFByaWNlcyIpDQojIw0KIyBHZXQgdGhlIGRhdGEgcG9pbnRzIGluIHRoZSBmb3JtIG9mIGFuIFIgdmVjdG9yLg0KcmFpbmZhbGwgPC0gYyg3OTksMTE3NC44LDg2NS4xLDEzMzQuNiw2MzUuNCw5MTguNSw2ODUuNSw5OTguNiw3ODQuMiw5ODUsODgyLjgsMTA3MSkNCiMgQ29udmVydCBpdCB0byBhIHRpbWUgc2VyaWVzIG9iamVjdC4NCnJhaW5mYWxsLnRpbWVzZXJpZXMgPC0gdHMocmFpbmZhbGwsc3RhcnQgPSBjKDIwMTIsMSksZnJlcXVlbmN5ID0gMTIpDQojIFBsb3QgYSBncmFwaCBvZiB0aGUgdGltZSBzZXJpZXMuDQpwbG90KHJhaW5mYWxsLnRpbWVzZXJpZXMsIHlsYWIgPSAiUmFpbmZhbGwiLCBtYWluID0gIlJhaW5mYWxsIFRyZW5kIikNCmBgYA0KDQpPbmUgY2FuIGFsc28gY3JlYXRlIGEgZnJlcXVlbmN5IHRhYmxlIHRvIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbi4NCg0KYGBge3J9DQpvcHRpb25zKGRpZ2l0cyA9IDcpDQpib3VuZCA9IHJvdW5kKHNlcSgxMDAwMDAsOTAwMDAwMCwgbGVuZ3RoPTE1KSwxKQ0KYXMuZGF0YS5mcmFtZSh0YWJsZShjdXQoSG91c2VQcmljZSRQcmljZSwgYnJlYWtzPWJvdW5kKSkpDQpgYGANClRoZSBhYm92ZSBmcmVxdWVuY3kgdGFibGUgZ2l2ZXMgYSBzaW1pbGFyIGRpc3RyaWJ1dGlvbiBhcyBzaG93biBpbiB0aGUgaGlzdG9ncmFtIGFuZCB0aGUgZGVuc2l0eSBjdXJ2ZS4NCg0KDQoNCiMjIyBDYXRlZ29yaWNhbCBWYXJpYWJsZQ0KDQpUaGUgY29tbW9ubHkgdXNlZCB2aXN1YWwgdGVjaG5pcXVlcyBmb3IgbnVtZXJpY2FsIHZhcmlhYmxlcyBhcmUgYmFyIGNoYXJ0cyBhbmQgcGllIGNoYXJ0cy4NCg0KYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0NCnBhcihtZnJvdz1jKDEsMikpDQpmcmVxLnRibCA9IHRhYmxlKEhvdXNlUHJpY2UkQmVkcm9vbTIpDQpiYXJwbG90KGZyZXEudGJsLCB4bGFiPSJOdW1iZXIgb2YgQmVkcm9vbXMiLCB5bGFiID0gIkNvdW50cyIsIG1haW49IkRpc3RyaWJ1dGlvbiBvZiBudW1iZXIgb2YgQmVkcm9vbXMiKQ0KcGllKGZyZXEudGJsLCB4bGFiPSJOdW1iZXIgb2YgQmVkcm9vbXMiLCB5bGFiID0gIkNvdW50cyIsIG1haW49IkRpc3RyaWJ1dGlvbiBvZiBudW1iZXIgb2YgQmVkcm9vbXMiKQ0KDQpgYGANCg0KYGBge3J9DQprYWJsZShhcy5kYXRhLmZyYW1lKHRhYmxlKEhvdXNlUHJpY2UkQmVkcm9vbTIpKSkNCmBgYA0KDQoNCg0KDQoNCiMjIFR3byBWYXJpYWJsZXMNCg0KVGhyZWUgZGlmZmVyZW50IGNhc2VzIGludm9sdmUgdHdvIHZhcmlhYmxlcy4NCg0KIyMjIFR3byBOdW1lcmljIFZhcmlhYmxlcw0KDQpJbiB0aGUgY2FzZSBvZiB0d28gbnVtZXJpYyB2YXJpYWJsZXMsIHRoZSBrZXkgaW50ZXJlc3QgaXMgdG8gbG9vayBhdCB0aGUgcG90ZW50aWFsIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIHR3by4gVGhlIG1vc3QgZWZmZWN0aXZlIHZpc3VhbCByZXByZXNlbnRhdGlvbiBpcyBhIHNjYXR0ZXIgcGxvdC4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInfQ0KcGxvdChIb3VzZVByaWNlJFByaWNlLCBIb3VzZVByaWNlJEJ1aWxkaW5nQXJlYSkNCmBgYA0KDQpUaGUgYWJvdmUgc2NhdHRlciBwbG90IGluZGljYXRlcyBhIGxpbmVhciB0cmVuZCBiZXR3ZWVuIHRoZSBob3VzZSBwcmljZSBhbmQgdGhlIGJ1aWxkaW5nIGFyZWEuDQoNCg0KIyMjIFR3byBDYXRlZ29yaWNhbCBWYXJpYWJsZQ0KDQpGb3IgZ2l2ZW4gdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgd2UgbWF5IGJlIGludGVyZXN0ZWQgaW4gZXhwbG9yaW5nIHdoZXRoZXIgdGhleSBhcmUgaW5kZXBlbmRlbnQuIFRoZSB0d28td2F5IHRhYmxlIGFuZCBiZSB1c2VkIHRvIHZpc3VhbGl6ZSB0aGUgcG90ZW50aWFsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzLg0KDQpgYGB7cn0NCmZ0YWJsZShIb3VzZVByaWNlJEJhdGhyb29tLCBIb3VzZVByaWNlJEJlZHJvb20yKQ0KYGBgDQpgYGB7cn0NCmNoaXNxLnRlc3QoSG91c2VQcmljZSRCYXRocm9vbSwgSG91c2VQcmljZSRCZWRyb29tMikNCmBgYA0KTm90ZSB0aGF0ICRcY2hpXjIkIHRlc3QgaXMgc29tZXRpbWVzIHVzZWQgaW4gRURBLg0KDQoNCiMjIyBPbmUgTnVtZXJpYyBWYXJpYWJsZSBhbmQgT25lIENhdGVnb3JpY2FsIFZhcmlhYmxlDQoNCkZyb20gdGhlIG1vZGVsaW5nIHBvaW50IG9mIHZpZXcsIHRoZXJlIGFyZSB0d28gZGlmZmVyZW50IHdheXMgdG8gYXNzZXNzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGFuZCBhIG51bWVyaWNhbCB2YXJpYWJsZS4gRm9yIGV4YW1wbGUsIGEgcmlkZ2UgcGxvdCBjYW4gYmUgdXNlZCB0byB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBob3VzZSBwcmljZXMgYWNyb3NzIHRoZSB0eXBlcyBvZiBob3VzZXMuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0iUmlkZ2UgcGxvdCBvZiBkZW5zaXR5IGRpc3RyaWJ1dGlvbnMgaG91c2UgcHJpY2VzLiJ9DQpnZ3Bsb3QoSG91c2VQcmljZSwgYWVzKHg9UHJpY2UvMTAwMDAseT1UeXBlLGZpbGw9VHlwZSkpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzX2dyYWRpZW50KHNjYWxlID0gNCkgKyB0aGVtZV9yaWRnZXMoKSArDQogIHNjYWxlX3lfZGlzY3JldGUoZXhwYW5kID0gYygwLjAxLCAwKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjA4LCAwKSkgKw0KICBsYWJzKHggPSAiUHJpY2VzIix5ID0gIlR5cGUiKSArDQogIGdndGl0bGUoIkRlbnNpdHkgZXN0aW1hdGlvbiBvZiBwcmljZXMgZ2l2ZW4gVHlwZSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KDQpUaGUgcmlkZ2UgcGxvdCBpcyBhIHZpc3VhbCByZXByZXNlbnRhdGlvbiBvZiBBTk9WQS4NCg0KXA0KDQojIyBUaHJlZSBvciBNb3JlIFZhcmlhYmxlcw0KDQpWaXN1YWxpemluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhyZWUgb3IgbW9yZSB2YXJpYWJsZXMgY2FuIGJlIGNoYWxsZW5naW5nLiBPbmUgaGFzIHRvIHVzZSB2aXN1YWwgZGVzaWduIGVsZW1lbnRzIHN1Y2ggYXMgbGluZSwgc2hhcGUsIG5lZ2F0aXZlL3doaXRlIHNwYWNlLCB2b2x1bWUsIHZhbHVlLCBjb2xvciwgYW5kIHRleHR1cmUg4oCUIHRvIHJlcHJlc2VudCB0aGUgdmFsdWVzIG9mIHZhcmlhYmxlcy4gDQoNClwNCg0KDQoNCiMjIyBVc2Ugb2YgQ29sb3JzLCBNb3ZlbWVudCwgYW5kIFBvaW50LXNpemUNCg0KSW4gdGhlIGZvbGxvd2luZyBleGFtcGxlLCBjb2xvciwgbW92ZW1lbnQsIGFuZCBwb2ludCBzaXplIHJlcHJlc2VudCBgY29udGluZW50YCwgYHRpbWVgLCBhbmQgYHBvcHVsYXRpb24gc2l6ZWAsIHJlc3BlY3RpdmVseS4gVGhlcmVmb3JlLCBpdCByZXByZXNlbnRzIHRoZSBjb21wbGV0ZSByZWxhdGlvbnNoaXAgb2YgNSB2YXJpYWJsZXMuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLG91dC5oZWlnaHQ9IjcwJSIsIG91dC53aWR0aD0iMTAwJSJ9DQprbml0cjo6aW5jbHVkZV91cmwoImh0dHBzOi8vZmxvLnVyaS5zaC92aXN1YWxpc2F0aW9uLzExODcxODcwL2VtYmVkP2F1dG89MSIpDQpgYGANCg0KXA0KDQojIyMgUGFpcmV3aXNlZCBSZWxhdGlvbnNoaXAgQmV0d2VlbiBWYXJpYWJsZXMNCg0KVGhlIHBhaXItd2lzZSBzY2F0dGVyIHBsb3QgKipudW1lcmljYWwgdmFyaWFibGVzKiogaXMgdGhlIG1vc3QgY29tbW9ubHkgdXNlZCBpbiBwcmFjdGljZS4gV2UgdXNlIHRoZSBgSXJpc2AgZGF0YSBzZXQgYXMgYW4gZXhhbXBsZSB0byBzaG93IHRoZSBwYWlyLXdpc2UgcGxvdCBpbiB0aGUgZm9sbG93aW5nLg0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NywgZmlnLmNhcD0iUGFpci13aXNlIHNjYXR0ZXIgcGxvdCBvZiB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiB0aGUgaXJpcyBkYXRhIHNldC4ifQ0KI2xpYnJhcnkoR0dhbGx5KQ0KZ2dwYWlycyhpcmlzLCBjb2x1bW5zID0gMTo0LCBhZXMoY29sb3IgPSBTcGVjaWVzLCBhbHBoYSA9IDAuNSksDQogICAgICAgIGxvd2VyID0gbGlzdChjb250aW51b3VzID0gInNtb290aCIpKQ0KYGBgDQoNClRoZSBhYm92ZSBlbmhhbmNlZCBwYWlyLXdpc2Ugc2NhdHRlciBwbG90IHByb3ZpZGVzIGEgcGFpci13aXNlIGNvbXBhcmlzb24gYmV0d2VlbiB0aGUgZm91ciBudW1lcmljYWwgdmFyaWFibGVzIGFjcm9zcyB0aGUgdGhyZWUgc3BlY2llcyAoY2F0ZWdvcmljYWwgdmFyaWFibGUpLg0KDQpcDQoNCiMgUm9sZXMgb2YgVmlzdWFsaXphdGlvbiBpbiBFREENCg0KKipJbmZvcm1hdGlvbiB2aXN1YWxpemF0aW9uKiogZGlzcGxheXMgaW5mb3JtYXRpb24gaW4gYSB2aXN1YWwgZm9ybWF0IHRoYXQgbWFrZXMgaW5zaWdodHMgZWFzaWVyIHRvIHVuZGVyc3RhbmQgZm9yIGh1bWFuIHVzZXJzLiBUaGUgaW5mb3JtYXRpb24gaW4gZGF0YSBpcyB1c3VhbGx5IHZpc3VhbGl6ZWQgaW4gYSBwaWN0b3JpYWwgb3IgZ3JhcGhpY2FsIGZvcm0gc3VjaCBhcyBjaGFydHMsIGdyYXBocywgbGlzdHMsIG1hcHMsIGFuZCBjb21wcmVoZW5zaXZlIGRhc2hib2FyZHMgdGhhdCBjb21iaW5lIHRoZXNlIG11bHRpcGxlIGZvcm1hdHMuDQoNCiMjIERhdGEgVmlzdWFsaXphdGlvbg0KDQpUaGUgcHJpbWFyeSBvYmplY3RpdmUgb2YgKipkYXRhIHZpc3VhbGl6YXRpb24qKiBpcyB0byBjbGVhcmx5IGNvbW11bmljYXRlIHdoYXQgdGhlIGRhdGEgc2F5cywgaGVscCBleHBsYWluIHRyZW5kcyBhbmQgc3RhdGlzdGljcywgYW5kIHNob3cgcGF0dGVybnMgdGhhdCB3b3VsZCBvdGhlcndpc2UgYmUgaW1wb3NzaWJsZSB0byBzZWUuICoqRGF0YSB2aXN1YWxpemF0aW9uKiogaXMgdXNlZCB0byBtYWtlIGNvbnN1bWluZywgaW50ZXJwcmV0aW5nLCBhbmQgdW5kZXJzdGFuZGluZyBkYXRhIGFzIHNpbXBsZSBhcyBwb3NzaWJsZSwgYW5kIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGRlcml2ZSBpbnNpZ2h0cyBmcm9tIGRhdGEuIA0KDQoNCg0KIyMgVmlzdWFsIEFuYWx5dGljcw0KDQpWaXN1YWwgYW5hbHl0aWNzIGlzIGFuIGVtZXJnaW5nIGFyZWEgaW4gYW5hbHl0aWNzLiBJdCBpcyBtb3JlIHRoYW4gdmlzdWFsaXphdGlvbi4gKipJbnRlcmFjdGl2ZSoqIGV4cGxvcmF0aW9uIGFuZCAqKmF1dG9tYXRpYyoqIHZpc3VhbCBtYW5pcHVsYXRpb24gcGxheSBhIGNlbnRyYWwgcm9sZSBpbiB2aXN1YWwgYW5hbHl0aWNzLiANCg0KVmlzdWFsIGFuYWx5dGljcyBkb2VzIHRoZSAqKmhlYXZ5IGxpZnRpbmcqKiB3aXRoIGRhdGEsIGJ5IHVzaW5nIGEgdmFyaWV0eSBvZiB0b29scyBhbmQgdGVjaG5vbG9naWVzIOKAlCBtYWNoaW5lIGxlYXJuaW5nIGFuZCBtYXRoZW1hdGljYWwgYWxnb3JpdGhtcywgc3RhdGlzdGljYWwgbW9kZWxzLCBjdXR0aW5nLWVkZ2Ugc29mdHdhcmUgcHJvZ3JhbXMsIGV0YyDigJQgdG8gaWRlbnRpZnkgYW5kIHJldmVhbCBwYXR0ZXJucyBhbmQgdHJlbmRzLiBJdCBwcmVwYXJlcyB0aGUgZGF0YSBmb3IgdGhlIHByb2Nlc3Mgb2YgZGF0YSB2aXN1YWxpemF0aW9uLCB0aGVyZWJ5IGVuYWJsaW5nIHVzZXJzIHRvIGV4YW1pbmUgZGF0YSwgdW5kZXJzdGFuZCB3aGF0IGl0IG1lYW5zLCBpbnRlcnByZXQgdGhlIHBhdHRlcm5zIGl0IGhpZ2hsaWdodHMsIGFuZCBoZWxwIHRoZW0gZmluZCBtZWFuaW5nIGFuZCBnYWluIHVzZWZ1bCBpbnNpZ2h0cyBmcm9tIGNvbXBsZXggZGF0YSBzZXRzLg0KDQpJbiBvdGhlciB3b3JkcywgdXNpbmcgdmlzdWFsIGFuYWx5dGljIG1ldGhvZHMgYW5kIHRlY2huaXF1ZXMgY2FuIGVuaGFuY2UgKGRhdGEpIHZpc3VhbGl6YXRpb24gYW5kIGltcHJvdmUgdGhlIHBlcmZvcm1hbmNlIG9mIGFuYWx5c2lzIGFuZCBtb2RlbGluZy4gSW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiB0ZWNobm9sb2d5IGVuYWJsZXMgdGhlIGV4cGxvcmF0aW9uIG9mIGRhdGEgdmlhIHRoZSBtYW5pcHVsYXRpb24gb2YgY2hhcnQgaW1hZ2VzLCB3aXRoIHRoZSBjb2xvciwgYnJpZ2h0bmVzcywgc2l6ZSwgc2hhcGUsIGFuZCBtb3Rpb24gb2YgdmlzdWFsIG9iamVjdHMgcmVwcmVzZW50aW5nIGFzcGVjdHMgb2YgdGhlIGRhdGEgc2V0IGJlaW5nIGFuYWx5emVkLiBUaGUgZm9sbG93aW5nIGlzIHN1Y2ggYW4gZXhhbXBsZSAoPGh0dHBzOi8vdml6aHViLmhlYWx0aGRhdGEub3JnL2NvZC8+KS4NCg0KDQpgYGB7ciBvdXQuaGVpZ2h0PSIxMDAlIiwgb3V0LndpZHRoPSIxMDAlIn0NCmtuaXRyOjppbmNsdWRlX2FwcCgiaHR0cHM6Ly92aXpodWIuaGVhbHRoZGF0YS5vcmcvY29kLyIpDQpgYGANCg0KIyBBcHBsaWNhdGlvbnMgb2YgRURBDQoNCkVEQSBpcyB0aGUgcHJvY2VzcyBvZiBkaXNzZWN0aW5nIGRhdGEsIGFuZCB1bmNvdmVyaW5nIGl0cyBoaWRkZW4gcGF0dGVybnMsIGFub21hbGllcywgYW5kIGluc2lnaHRzLiBCeSB2aXN1YWxpemluZyBhbmQgc3VtbWFyaXppbmcgZGF0YSwgZGF0YSBzY2llbnRpc3RzIGNhbiBncmFzcCBpdHMgc3RydWN0dXJlLCBkaXN0cmlidXRpb24sIGFuZCBjaGFyYWN0ZXJpc3RpY3MuIFRoaXMgc3RlcCBpcyB2aXRhbCB0byB1bmRlcnN0YW5kIHRoZSBjb250ZXh0IGFuZCBwb3RlbnRpYWwgb2YgdGhlIGRhdGEuDQoNCiMjIERhdGEgQ2xlYW5pbmcgYW5kIFByZXByb2Nlc3NpbmcNCg0KRHVyaW5nIEVEQSwgYW5hbHlzdHMgZGV0ZWN0IG1pc3NpbmcgdmFsdWVzLCBvdXRsaWVycywgYW5kIGluY29uc2lzdGVuY2llcyBpbiB0aGUgZGF0YSBzZXQuIElkZW50aWZ5aW5nIGFuZCBhZGRyZXNzaW5nIHRoZXNlIGlzc3VlcyBpcyBjcnVjaWFsIGZvciBhY2N1cmF0ZSBtb2RlbGluZy4gVGhlIHBvc3QtRURBIHByb2NlZHVyZXMgdXN1YWxseSBpbnZvbHZlIHNpZ25pZmljYW50IGRhdGEgcHJvY2Vzc2luZyB0aGF0IG1heSBuZWVkIGFkdmFuY2VkIGFsZ29yaXRobXMgb3Igc3RhdGlzdGljYWwgbW9kZWxzLg0KDQojIyBNb2RlbCBBc3N1bXB0aW9ucyBhbmQgVmFsaWRhdGlvbg0KDQpCZWZvcmUgYnVpbGRpbmcgYW55IHN0YXRpc3RpY2FsIG1vZGVscywgRURBIGFsbG93cyB1cyB0byB2YWxpZGF0ZSBhc3N1bXB0aW9ucy4gVGhleSBjYW4gY2hlY2sgd2hldGhlciB0aGUgZGF0YSBtZWV0cyB0aGUgbW9kZWzigJlzIGFzc3VtcHRpb25zLCBzdWNoIGFzIGxpbmVhcml0eSBvciBub3JtYWxpdHkuIA0KDQoNCiMjIEVEQSBmb3IgVmFyaWFibGUgU2VsZWN0aW9uDQoNCkVEQSBhaWRzIGluIHNlbGVjdGluZyB0aGUgbW9zdCByZWxldmFudCB2YXJpYWJsZXMgZm9yIG1vZGVsaW5nLiBCeSBleHBsb3JpbmcgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcyBhbmQgdGhlaXIgc2lnbmlmaWNhbmNlIGluIHByZWRpY3Rpbmcgb3V0Y29tZXMsIG9uZSBjYW4gbWFrZSBpbmZvcm1lZCBkZWNpc2lvbnMgYWJvdXQgZmVhdHVyZSBzZWxlY3Rpb24gYW5kIGVuZ2luZWVyaW5nLiANCg0KIyMgRURBIGZvciBWYXJpYWJsZSBDcmVhdGlvbiBhbmQgUmVkZWZpbml0aW9uDQoNClRoaXMgaXMgcHJvYmFibHkgdGhlIG1vc3QgaW1wb3J0YW50IGFwcGxpY2F0aW9uIG9mIEVEQSBpbiBjcmVhdGluZyBhbmFseXRpYyBkYXRhIHNldHMuIA0KKiAqKkRpc2NyZXRpemF0aW9uIG9mIENvbnRpbnVvdXMgVmFyaWFibGVzKiogLSBTb21ldGltZXMgd2UgbWF5IGhhdmUgY29udGludW91cyB2YXJpYWJsZXMgdGhhdCBoYXZlIG11bHRpLW1vZGFsIHNrZXdlZCBkaXN0cmlidXRpb25zLCB3ZSBtYXkgd2FudCB0byBkaXNjcmV0aXplIHRoZXNlIHR5cGVzIG9mIHZhcmlhYmxlcyB0byBwcm92ZSBtb2RlbCBwZXJmb3JtYW5jZSBhbmQgaW50ZXJwcmV0YWJpbGl0eS4gRm9yIGV4YW1wbGUsIGluIG1hbnkgY2xpbmljYWwgc3R1ZGllcywgdGhlIGFnZSB2YXJpYWJsZSBpcyB1c3VhbGx5IGRlZmluZWQgYXMgYWdlIGdyb3VwcyBmb3IgZWFzZSBvZiBpbnRlcnByZXRhdGlvbi4NCg0KDQoqICoqUmVncm91cGluZyBDYXRlZ29yaWNhbCBWYXJpYWJsZXMqKiAtIFdoZW4gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBoYXMgaG9tb2dlbmVvdXMgY2F0ZWdvcmllcyBvciBzcGFyc2UgY2F0ZWdvcmllcywgd2UgbmVlZCB0byBjb21iaW5lIHNvbWUgb2YgdGhlc2UgY2F0ZWdvcmllcyBpbiBhIG1lYW5pbmdmdWwgd2F5Lg0KDQoNCiogKipDbHVzdGVyaW5nKiogLSBDbHVzdGVyaW5nIGlzIHRoZSB0YXNrIG9mIGRpdmlkaW5nIGRhdGEgcG9pbnRzIGludG8gYSBudW1iZXIgb2YgZ3JvdXBzIHN1Y2ggdGhhdCBkYXRhIHBvaW50cyBpbiB0aGUgc2FtZSBncm91cHMgYXJlIG1vcmUgc2ltaWxhciB0byBvdGhlciBkYXRhIHBvaW50cyBpbiB0aGUgc2FtZSBncm91cCBhbmQgZGlzc2ltaWxhciB0byB0aGUgZGF0YSBwb2ludHMgaW4gb3RoZXIgZ3JvdXBzLiBUaGlzIA0KDQpgYGB7cn0NCmFnZTEgPSBybm9ybSg3MCwxNiwxLjUpDQphZ2UyID0gcm5vcm0oNzAwLCAyNSwzKQ0KYWdlMyA9IHJub3JtKDE1MCw0MCwyKQ0KYWdlPWMoYWdlMSxhZ2UyLCBhZ2UzKQ0Kc2FsYXJ5PWMoMjAwMDArMTAwMCphZ2UxICsgcm5vcm0oNzAsICAwLCA0MDAwKSwgDQogICAgICAgICA0NTAwMCsyMDAwKmFnZTIgKyBybm9ybSg3MDAsIDAsIDYwMDApLCANCiAgICAgICAgIDcwMDAwKzMwMDAqYWdlMyArIHJub3JtKDE1MCwgMCwgODAwMCkpDQoNCmdycD1jKHJlcCgxLDcwKSwgcmVwKDIsNzAwKSwgcmVwKDMsMTUwKSkNCmBgYA0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0iVGhlIGRpc3RyaWJ1dGlvbiBvZiBhZ2UuIn0NCnBsb3QoZGVuc2l0eShhZ2UpKQ0KYGBgDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01LCBmaWcuY2FwPSJUaGUgc2NhdHRlciBwbG90IG9mIHNhbGFyeSB2cyBhZ2UuIn0NCnBsb3QoYWdlLCBzYWxhcnkpDQpgYGANCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTcsIGZpZy5jYXA9IlRoZSBkaWFnbm9zdGljIHBsb3Qgb2YgbW9kZWwgMTogc2luZ2xlIHByZWRpY3RvciBhZ2UuIn0NCm0wPWxtKHNhbGFyeX5hZ2UpDQpwYXIobWZyb3c9YygyLDIpKQ0KcGxvdChtMCkNCnN1bW1hcnkobTApDQpgYGANCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTcsIGZpZy5jYXA9IlRoZSBkaWFnbm9zdGljIHBsb3Qgb2YgbW9kZWwgMjogc2luZ2xlIHByZWRpY3RvciBncm91cC4ifQ0KbTE9bG0oc2FsYXJ5fmZhY3RvcihncnApKQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QobTEpDQpzdW1tYXJ5KG0xKQ0KYGBgDQoNCg0KYGBge3IgIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NywgZmlnLmNhcD0iVGhlIGRpYWdub3N0aWMgcGxvdCBvZiBtb2RlbCAyOiBCb3RoIGdyb3VwIHByZWRpY3RvciBhZ2UuIn0NCm0yPWxtKHNhbGFyeX5mYWN0b3IoZ3JwKSsgYWdlKQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QobTIpDQpzdW1tYXJ5KG0yKQ0KYGBgDQo=