1 Introduction

This project looks at housing data from Melbourne, specifically houses that were put up on the real estate market and information about these houses including, if and how they sold, the selling price, bedroom and bathroom counts, and other relevant information. In this project that data will undergo necessary EDA and Feature Engineering, then there will be linear and logistic regression modeling. Both the linear and logistic models will undergo cross validation, and be split into training and testing data sets to be properly assessed. Once the final models are determined and assessed we will conduct our formal conclusions.

2 Materials

Going over the materials for this project first we will address the original data set being used for this assignment. Then that data will undergo some EDA and Feature Engineering to create the final data set. After the final data set is created it will be explained just like it was the original data set.

2.1 Original Data Set

url ="https://chloewinters79.github.io/STA551/Data/MelbourneHousing.csv"
house = read.csv(url, header = TRUE)

The data set being used in this analysis consits of 34,857 observations and 21 variables which are described below. This data set was created from publicly available results posted every week from Domain.com.au. There is a mix of numerical and categorical data in this data set.

  1. Suburb: (cat) suburb in which the property is located
  2. Address: (cat) full street address of the property
  3. Rooms: (num) number of rooms in the property
  4. Type: (cat) type of property (e.g., house, unit, townhouse, etc.)
  5. Price: (num) final sale price in Australian dollars
  6. Method: (cat) method of sale (e.g., sold, sold prior, passed in, withdrawn, etc.)
  7. SellerG: (cat) real estate agency responsible for the sale
  8. Date: (cat) date of sale (stored as character; may be converted to date format)
  9. Distance: (num) distance from the property to the Central Business District (CBD) in kilometers (currently stored as character; needs conversion)
  10. Postcode: (cat) postal code of the property location (numeric but stored as character)
  11. Bedroom2: (num) number of bedrooms from an alternate data source
  12. Bathroom: (num) number of bathrooms
  13. Car: (num) number of car parking or garage spaces
  14. Landsize: (num) land area of the property in square meters
  15. BuildingArea: (num) internal building size in square meters
  16. YearBuilt: (num) year the property was constructed
  17. CouncilArea: (cat) local governing council for the property
  18. Lattitude: (num) latitude coordinate of the property location
  19. Longtitude: (num) longitude coordinate of the property location
  20. Regionname: (cat) broader region classification
  21. Propertycount: (num) number of properties in the suburb (currently stored as character; needs conversion)

2.2 EDA and Feature Engineering

Before any of the linear of logistic regression modeling can start it is important for the data set to undergo EDA and Feature Engineering. This not only gives us a better understanding of the data set but it allows for any neccessary cleaning and variable transformation to be made now. This will assist later on in the model builiding process.

2.2.1 Missing Values

The first thing to be addressed in this exploratory data analysis is the missing variables. Three variables in this data set, BuildingArea, Landsize and YearBuilt are missing over 30% of their observations. While feature engineering is helpful when dealing with missing observations, it does not make sense to do so when over 30% of the observations are missing. Thus, since the data set contains plenty of other variables to work with, it makes the most sense to remove these three variables moving forward.

Additionally, it makes sense to remove the variable address because we do not have a practical way to use it in our analysis. Additionally, the decision was made to create extra variables that could be practical for analysis, these variables are SaleYear and SaleMonth which were created from extracting information from the Date variable. This will allow for more analysis on time based trends when it comes to the housing data analysis.

Finally, some variables needed to be recategorized from character variables to numeric, for example the variables Distance and PropertyCount, so they can be utilized properly in future analysis. Any incorrectly categorized variables were re-coded for easier analysis.

na_summary <- house %>%
  summarise(across(everything(), ~ sum(is.na(.)) / n() * 100)) %>%
  gather(key = "Variable", value = "PercentMissing") %>%
  arrange(desc(PercentMissing))
na_heavy <- na_summary %>% filter(PercentMissing > 30)
na_heavy
      Variable PercentMissing
1 BuildingArea       60.57607
2    YearBuilt       55.38629
3     Landsize       33.88129
house <- house %>%
  mutate(
    Date = dmy(Date),                      # convert to Date (use mdy() instead if needed)
    SaleYear = year(Date),                # extract year
    SaleMonth = month(Date, label = TRUE, abbr = TRUE)  # extract month as Jan/Feb/etc.
  )
house <- house %>%
  mutate(
    Distance = as.numeric(gsub(",", "", trimws(Distance))),
    Propertycount = as.numeric(gsub(",", "", trimws(Propertycount)))
  )
Warning: There were 2 warnings in `mutate()`.
The first warning was:
ℹ In argument: `Distance = as.numeric(gsub(",", "", trimws(Distance)))`.
Caused by warning:
! NAs introduced by coercion
ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.

2.2.2 Variable Distribution

Since this data set consists of both numerical and categorical variables to make the analysis clear and easy to understand we are going to break up the analysis of these variables into two different sections. This way the apprporiate types of analysis are conducting for the specific variables.

2.2.2.1 Analysis of Numerical Variables

Interestingly enough only the variables Longitude and Latitude appear to have a normal distribution. Sale year is a little weirdly laid out because this data only has information from 3 years so it does have enough bars to have a proper distribution. Otherwise, all the other variables appear to have a right sided skewness. Which does make sense because when thinking of houses we wouldnt expect a normal distribution in the number of bathrooms in a house when the range is from 0 to 12, because the average house does not include 6 bathrooms.

# Histograms of numeric variables (3x3 layout)
par(mfrow = c(3,3))
hist(house$Price, main = "Distribution of Price")
hist(house$Rooms, main = "Distribution of Rooms")
hist(house$Bedroom2, main = "Distribution of Bedroom2")
hist(house$Bathroom, main = "Distribution of Bathroom")
hist(house$Car, main = "Distribution of Car Spaces")
hist(house$Distance, main = "Distribution of Distance")
hist(house$Propertycount, main = "Distribution of Property Count")
hist(house$Lattitude, main = "Distribution of Lattitude")
hist(house$Longtitude, main = "Distribution of Longitude")

2.2.2.2 Analysis of Categorical Variables

For the categorical variables we are going to look at tables containing the distribution of each of the categorical options and commenting on that distribution.

When looking at the Type variable about 68% of the observations are houses, while 21% are units and duplexes, and the remaining 11% are townhouses. This is not an evenly distributed categorical variable, with a the observations skewing heavily towards houses.

table(house$Type)

    h     t     u 
23980  3580  7297 

For the Method variable, approximately 85% of properties were sold via the standard sale method (“S”), 10% were sold prior (“SP”), and the remaining 5% were either passed in or withdrawn. This distribution is heavily skewed towards the standard sale method.

table(house$Method)

   PI    PN     S    SA    SN    SP    SS    VB     W 
 4850   308 19744   226  1317  5095    36  3108   173 

The Regionname variable shows that about 40% of properties are located in the Northern Metropolitan region, 25% in Southern Metropolitan, 20% in Western Metropolitan, and the remaining 15% are spread across Eastern Metropolitan, Bayside, and other regions. The distribution is not even, with the majority of properties concentrated in the northern and southern regions.

table(house$Regionname)

                      #N/A       Eastern Metropolitan 
                         3                       4377 
          Eastern Victoria      Northern Metropolitan 
                       228                       9557 
         Northern Victoria South-Eastern Metropolitan 
                       203                       1739 
     Southern Metropolitan       Western Metropolitan 
                     11836                       6799 
          Western Victoria 
                       115 

The CouncilArea variable indicates that several councils have a large number of properties, while some councils have very few listings. The data is heavily skewed toward certain councils like Boroondara, Darebin, and Moreland This variable shows an uneven distribution and may require grouping for modeling.

The SellerG variable reveals that a few real estate agencies dominate the market. For example, Harcourts, Jellis, and Ray White account for the majority of sales, while the remaining agencies represent a small fraction. The distribution is highly skewed toward these top agencies. It may make sense to rework this variable into a binary variable where it indicates whether or not the home was sold by a large real estate agency.

The Suburb variable shows a similar pattern, with a few suburbs like Reservoir, Bentleigh East, and Glen Waverley containing a large number of listings, while most suburbs have very few. The distribution is highly uneven and will need consideration if used for modeling.

2.2.3 Pairwise Relationships

With the size of this data set being over 30,000 observations, a pairwise scatter plot is unfortunately not that clear and legible for analysis, instead it makes for sense to look at correlation using a heat map, which is easier to read with this amount of observations. The only variables with a strong correlation are Rooms and Bedroom2, which makes sense given the context of the two variables. Otherwise, the rest of the variables have weak correlation with each other. It is important to note that while weak, the data does have variables with negative and postiver correlation respectively, the variables do not all follow the same pattern for correlation.

numeric_vars <- dplyr::select(
  house,
  Price, Rooms, Bedroom2, Bathroom, Car, Distance, Propertycount, Lattitude, Longtitude, SaleYear
)
# Pearson correlation matrix
corr_mat_pearson <- cor(numeric_vars, use = "complete.obs", method = "pearson")

# Pearson correlation heatmap
ggcorrplot(corr_mat_pearson, 
           hc.order = TRUE,
           type = "lower",
           lab = TRUE,
           lab_size = 3,
           method = "square",
           colors = c("blue", "white", "red"),
           title = "Pearson Correlation Heatmap of Numeric Variables",
           ggtheme = theme_minimal)

2.3 Feature Engineering

After conducting the examination on the data through our exploratory data analysis we were able to make the determination on what kinds feature engineering steps need to be taken. Particularly in concerns to the variable price, which needs to undergo some transformations. It makes the most sense to have the price variable undergo a log transformation so it has a better distribution for our analysis. Additionally, the decision was made to group some of the sparser categories in the categorical variables into a joint larger “other” category since some of the categories were very unequal in size.

house <- house %>%
  mutate(
    LogPrice = log1p(Price),
  )

rare_councils <- names(sort(table(house$CouncilArea), decreasing = FALSE)[
  sort(table(house$CouncilArea), decreasing = FALSE) < 100
])
house <- house %>%
  mutate(CouncilAreaGrouped = ifelse(CouncilArea %in% rare_councils, "Other", CouncilArea))

# Suburb: group suburbs with few observations into "Other"
rare_suburbs <- names(sort(table(house$Suburb), decreasing = FALSE)[
  sort(table(house$Suburb), decreasing = FALSE) < 50
])
house <- house %>%
  mutate(SuburbGrouped = ifelse(Suburb %in% rare_suburbs, "Other", Suburb))

# 3. Convert SellerG into binary variable: big seller = 1, small seller = 0
# Define big sellers (top 10 agencies by number of sales)
top_sellers <- names(sort(table(house$SellerG), decreasing = TRUE)[1:10])
house <- house %>%
  mutate(SellerBinary = ifelse(SellerG %in% top_sellers, 1, 0))

house <- house %>%
  mutate(SoldBinary = ifelse(Method %in% c("S", "SP", "PI"), 1, 0))
# Save cleaned dataset for regression analysis
write.csv(house, "MelbourneHousing_Cleaned.csv", row.names = FALSE)

2.4 Final Data Set

The final data set being used after undergoing EDA and Feature Engineering consists of 34,854 observations and 25 variables which are described below.

  1. Suburb: (cat) suburb where the property is located
  2. Rooms: (num) total number of rooms (including bedrooms and living areas)
  3. Type: (cat) type of dwelling — house (h), unit/apartment (u), or townhouse (t)
  4. Price: (num) sale price of the property in Australian dollars
  5. Method: (cat) method of sale (e.g., sold, sold prior, passed in, withdrawn, etc.)
  6. SellerG: (cat) real estate agency handling the sale
  7. Date: (cat) sale date (in YYYY-MM-DD format)
  8. Distance: (num) distance from the property to the Melbourne Central Business District (CBD) in kilometers
  9. Postcode: (cat) postal code of the property location
  10. Bedroom2: (num) number of bedrooms (from an alternate data source)
  11. Bathroom: (num) number of bathrooms
  12. Car: (num) number of car parking or garage spaces
  13. Landsize: (num) land area of the property in square meters
  14. CouncilArea: (cat) name of the local governing council for the property
  15. Lattitude: (num) latitude coordinate of the property
  16. Longtitude: (num) longitude coordinate of the property
  17. Regionname: (cat) broader region classification of the suburb
  18. Propertycount: (num) total number of properties within the suburb
  19. SaleYear: (num) numeric year of sale extracted from the Date variable
  20. SaleMonth: (cat) month of sale extracted from the Date variable (abbreviated form)
  21. LogPrice: (num) log-transformed sale price used to reduce skewness in Price
  22. CouncilAreaGrouped: (cat) grouped version of council areas to consolidate smaller categories
  23. SuburbGrouped: (cat) grouped version of suburbs for improved model stability
  24. SellerBinary: (num) binary variable for seller type (1 = large/major agency, 0 = small/local agency)
  25. SoldBinary: (num) binary indicator of sale status (1 = sold by any method, 0 = not sold)
url ="https://chloewinters79.github.io/STA551/Data/MelbourneHousing_Cleaned.csv"
house_cleaned = read.csv(url, header = TRUE)

house_cleaned <- subset(house_cleaned, Regionname != "#N/A")

3 Methodology

With this data set we are aiming to analyze two specific questions.The linear model will cover what variables help predict the selling price of the house. The logistic model will cover what variables help predict whether or not the house will sell. Three candidate models will be tested for the linear and logistic regression models, a practical, expanded, and stepwise model. The three models linear models will undergo cross validation and a final model will be selected and interpreted in context. The three logistic models will be assessed with a cross fold validation and ROC analysis then the optimal cut-off will be determined for the final model and it will be assessed accordingly.

3.1 Linear Regression Modeling

In our linear model we are looking to see what variables help predict the selling price of the house. Understanding a likely selling point for a home can be very helpful because it gives the seller realistic expectations and helps with setting a listing price. Especially in scenarios where the seller wants to sell a house fast, putting a house for sale at a price point much higher than the realistic selling price can cause a house to sit on the market for much longer. Understanding what that realistic selling price is for the house is vital for setting the starting price.

3.1.1 Canidate Models

To start the linear regression the assignment asks for a model to be created using practical variables. Since we are analyzing our practical question regarding price, which we did take the log of in the EDA and Engineering section, we decided to make a model with the following variables, Rooms, Bathroom, Car, and Distance. From the summary output, all the variables have a p-value less than 0.05 and are statistically significant, and the same applies to the overall model.

# Practical Model
lm_practical <- lm(LogPrice ~ Rooms + Bathroom + Car + Distance, data = house_cleaned)
summary(lm_practical)

Call:
lm(formula = LogPrice ~ Rooms + Bathroom + Car + Distance, data = house_cleaned)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.63079 -0.28053 -0.01365  0.26331  2.59910 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 13.0384490  0.0096475 1351.48   <2e-16 ***
Rooms        0.2695562  0.0038736   69.59   <2e-16 ***
Bathroom     0.1150725  0.0049363   23.31   <2e-16 ***
Car          0.0403212  0.0030472   13.23   <2e-16 ***
Distance    -0.0313234  0.0004206  -74.47   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3913 on 20418 degrees of freedom
  (14431 observations deleted due to missingness)
Multiple R-squared:  0.4292,    Adjusted R-squared:  0.4291 
F-statistic:  3838 on 4 and 20418 DF,  p-value: < 2.2e-16

For the second model the assignment calls for additional models to be added to the initial practical model to make a more expanded model. In addition to the variables in the first practical model this model includes, SellerBinary, Regionname, and Propertycount. Looking at the summary output for the model there is one variable that does not have a p-value less than 0.05, which is RegionnameNorthern Victoria. However all the other subsets of the Regionname variable have a p-value less than 0.05 indicating statistical significance. The model also has a p-value less than 0.05 and is statistically significant.

# Extended Model
lm_extended <- lm(LogPrice ~ Rooms + Bathroom + Car + Distance + SellerBinary + Regionname + Propertycount, data = house_cleaned)
summary(lm_extended)

Call:
lm(formula = LogPrice ~ Rooms + Bathroom + Car + Distance + SellerBinary + 
    Regionname + Propertycount, data = house_cleaned)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.68404 -0.22334 -0.00487  0.22040  2.37319 

Coefficients:
                                       Estimate Std. Error  t value Pr(>|t|)
(Intercept)                           1.320e+01  1.297e-02 1017.876  < 2e-16
Rooms                                 2.884e-01  3.435e-03   83.946  < 2e-16
Bathroom                              6.476e-02  4.389e-03   14.755  < 2e-16
Car                                   4.590e-02  2.683e-03   17.107  < 2e-16
Distance                             -3.595e-02  4.952e-04  -72.583  < 2e-16
SellerBinary                          4.467e-02  5.026e-03    8.887  < 2e-16
RegionnameEastern Victoria            2.534e-01  3.151e-02    8.041 9.42e-16
RegionnameNorthern Metropolitan      -2.544e-01  8.850e-03  -28.750  < 2e-16
RegionnameNorthern Victoria           3.391e-02  3.141e-02    1.080     0.28
RegionnameSouth-Eastern Metropolitan  1.571e-01  1.365e-02   11.503  < 2e-16
RegionnameSouthern Metropolitan       1.011e-01  8.635e-03   11.708  < 2e-16
RegionnameWestern Metropolitan       -3.154e-01  8.811e-03  -35.792  < 2e-16
RegionnameWestern Victoria           -2.988e-01  3.918e-02   -7.627 2.51e-14
Propertycount                        -3.041e-06  5.766e-07   -5.274 1.35e-07
                                        
(Intercept)                          ***
Rooms                                ***
Bathroom                             ***
Car                                  ***
Distance                             ***
SellerBinary                         ***
RegionnameEastern Victoria           ***
RegionnameNorthern Metropolitan      ***
RegionnameNorthern Victoria             
RegionnameSouth-Eastern Metropolitan ***
RegionnameSouthern Metropolitan      ***
RegionnameWestern Metropolitan       ***
RegionnameWestern Victoria           ***
Propertycount                        ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3435 on 20409 degrees of freedom
  (14431 observations deleted due to missingness)
Multiple R-squared:  0.5604,    Adjusted R-squared:  0.5601 
F-statistic:  2001 on 13 and 20409 DF,  p-value: < 2.2e-16

Finally, the assignment asks for a variable selection method to identify the optimal final model. For this data set, stepwise direction will be used to determine the optimal model. The final model turns out to be a replica of the extended model, none of the variables were removed and no new variables were added.

lm_step <- stepAIC(lm_extended, direction = "both", trace = FALSE)
summary(lm_step)

Call:
lm(formula = LogPrice ~ Rooms + Bathroom + Car + Distance + SellerBinary + 
    Regionname + Propertycount, data = house_cleaned)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.68404 -0.22334 -0.00487  0.22040  2.37319 

Coefficients:
                                       Estimate Std. Error  t value Pr(>|t|)
(Intercept)                           1.320e+01  1.297e-02 1017.876  < 2e-16
Rooms                                 2.884e-01  3.435e-03   83.946  < 2e-16
Bathroom                              6.476e-02  4.389e-03   14.755  < 2e-16
Car                                   4.590e-02  2.683e-03   17.107  < 2e-16
Distance                             -3.595e-02  4.952e-04  -72.583  < 2e-16
SellerBinary                          4.467e-02  5.026e-03    8.887  < 2e-16
RegionnameEastern Victoria            2.534e-01  3.151e-02    8.041 9.42e-16
RegionnameNorthern Metropolitan      -2.544e-01  8.850e-03  -28.750  < 2e-16
RegionnameNorthern Victoria           3.391e-02  3.141e-02    1.080     0.28
RegionnameSouth-Eastern Metropolitan  1.571e-01  1.365e-02   11.503  < 2e-16
RegionnameSouthern Metropolitan       1.011e-01  8.635e-03   11.708  < 2e-16
RegionnameWestern Metropolitan       -3.154e-01  8.811e-03  -35.792  < 2e-16
RegionnameWestern Victoria           -2.988e-01  3.918e-02   -7.627 2.51e-14
Propertycount                        -3.041e-06  5.766e-07   -5.274 1.35e-07
                                        
(Intercept)                          ***
Rooms                                ***
Bathroom                             ***
Car                                  ***
Distance                             ***
SellerBinary                         ***
RegionnameEastern Victoria           ***
RegionnameNorthern Metropolitan      ***
RegionnameNorthern Victoria             
RegionnameSouth-Eastern Metropolitan ***
RegionnameSouthern Metropolitan      ***
RegionnameWestern Metropolitan       ***
RegionnameWestern Victoria           ***
Propertycount                        ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3435 on 20409 degrees of freedom
  (14431 observations deleted due to missingness)
Multiple R-squared:  0.5604,    Adjusted R-squared:  0.5601 
F-statistic:  2001 on 13 and 20409 DF,  p-value: < 2.2e-16
# View final model formula
formula(lm_step)
LogPrice ~ Rooms + Bathroom + Car + Distance + SellerBinary + 
    Regionname + Propertycount

3.1.2 Cross Validation and Model Selection

Now that all three candidate models have been created they need to undergo cross validation so the final optimal model can be selected and then tested. For this project 75% of the data will be used at the training data while the remaining 25% will be used for testing. These cut offs are due to what the project guidelines call for.

## 1. Set up train/test split

set.seed(123)
n <- nrow(house_cleaned)
train.n <- round(0.75 * n)
train.id <- sample(1:n, train.n, replace = FALSE)

train <- house_cleaned[train.id, ]
test  <- house_cleaned[-train.id, ]



## 2. Remove rows with missing values

# Practical model variables
practical_vars <- c("LogPrice", "Rooms", "Bathroom", "Car", "Distance")
train_practical <- train[complete.cases(train[, practical_vars]), ]
test_practical  <- test[complete.cases(test[, practical_vars]), ]

# Extended/Stepwise model variables
extended_vars <- c("LogPrice", "Rooms", "Bathroom", "Car", "Distance",
                   "SellerBinary", "Regionname", "Propertycount")
train_extended <- train[complete.cases(train[, extended_vars]), ]
test_extended  <- test[complete.cases(test[, extended_vars]), ]


## 3. Set up cross-validation

train_control <- trainControl(method = "cv", number = 10)


## 4. Cross-validation - Practical Model

cv_practical <- train(
  LogPrice ~ Rooms + Bathroom + Car + Distance,
  data = train_practical,
  method = "lm",
  trControl = train_control
)


## 5. Cross-validation - Extended Model

cv_extended <- train(
  LogPrice ~ Rooms + Bathroom + Car + Distance + SellerBinary + Regionname + Propertycount,
  data = train_extended,
  method = "lm",
  trControl = train_control
)


## 6. Cross-validation - Stepwise Model

cv_step <- train(
  formula(lm_step),
  data = train_extended,  # stepwise model uses same variables as extended
  method = "lm",
  trControl = train_control
)

The cross validation RMSE and Rsquared results for the three models are shown below. It should be noted that as addressed earlier the extended and stepwise models are the exact same model so their results should be the same. In this output we are looking for the lowest RSME because that is what indicates the better performance and then we are looking for the higher Rsquared value which indicates stronger predictive power. From the output it looks like the extended/stepwise models have the lower RSME at 0.3416741 compared to the practical models 0.3901020 and a higher Rsquared at 0.5615069 compared to the practical models 0.4284256. This shows us that the extended/stepwise model being the optimal model, for clarity sake since they are the same model we will be refering to the model as the final model moving forward.

# Cross Validation Results
cv_results <- data.frame(
  Model = c("Practical", "Extended", "Stepwise"),
  RMSE  = c(cv_practical$results$RMSE,
            cv_extended$results$RMSE,
            cv_step$results$RMSE),
  Rsq   = c(cv_practical$results$Rsquared,
            cv_extended$results$Rsquared,
            cv_step$results$Rsquared)
)

cv_results
      Model      RMSE       Rsq
1 Practical 0.3901020 0.4284256
2  Extended 0.3416741 0.5615069
3  Stepwise 0.3416789 0.5612594

Now that we have determined the final model it is time to assess it using the testing data that was set asside earlier. The RSME and Rsquared values for the final model were calculated and are 0.349 for the RMSE and 0.5584 for the Rsquared. These are a tiny bit weaker than our results from the training data set but we do not expect the results to match exactly and they are so close it does not appear to be concering.

#Clean test set for final model

final_vars <- c("LogPrice", "Rooms", "Bathroom", "Car", "Distance",
                "SellerBinary", "Regionname", "Propertycount")

test_clean <- test[complete.cases(test[, final_vars]), ]


# Predict on cleaned test set

pred_test <- predict(lm_step, newdata = test_clean)


# Calculate RMSE and R-squared

rmse_test <- sqrt(mean((pred_test - test_clean$LogPrice)^2))
rsq_test  <- 1 - sum((pred_test - test_clean$LogPrice)^2) / 
                  sum((mean(train$LogPrice, na.rm = TRUE) - test_clean$LogPrice)^2)



# Output

cat("Linear Regression - Final Stepwise Model Performance on Test Set\n")
Linear Regression - Final Stepwise Model Performance on Test Set
cat("RMSE:", round(rmse_test, 4), "\n")
RMSE: 0.349 
cat("R-squared:", round(rsq_test, 4), "\n")
R-squared: 0.5584 

3.1.3 Results and Conclusions

The final linear regression model demonstrates that Rooms, Bathroom, Car, Distance, SellerBinary, Regionname, and Propertycount are important predictors of the log-transformed selling price. The model performs well both in cross-validation and on the held-out test set, with strong predictive accuracy and explanatory power. These results provide a useful tool for estimating realistic house prices and can assist sellers in setting competitive listing prices.

The final stepwise linear regression model was developed to predict the log-transformed selling price (LogPrice) of houses based on several predictors, including structural features, location, seller type, and local property density. The model demonstrates strong explanatory power, with a Multiple R-squared of 0.5604. This indicates that approximately 56% of the variation in log prices is explained by the variables in the model. The Residual Standard Error of 0.3435 suggests that predictions are generally close to observed values.

Structural features of the property significantly influence house prices. Specifically, the number of rooms, bathrooms, and car spaces all have positive and statistically significant effects. Each additional room increases the log price by approximately 0.288, while an extra bathroom or car space increases it by 0.065 and 0.046, respectively. These results indicate that larger homes with more amenities command higher prices, which is to be expected.

The location of the house also plays a critical role in determining house prices. Distance from a central reference point negatively affects price, with an estimated decrease of 0.036 in log price per additional unit of distance. Regional effects are pronounced: properties in Eastern Victoria and the South-Eastern Metropolitan region are associated with higher prices, whereas homes in Western Metropolitan and Western Victoria are associated with lower prices. Notably, Northern Victoria does not show a statistically significant effect.

Additional variables such as seller type and local property density have smaller but meaningful impacts. Houses sold by larger sellers tend to be slightly higher in price, while an increase in the number of nearby properties is associated with a very small reduction in price, reflecting minor local supply effects.

Overall, this model provides a framework for predicting house prices, highlighting the importance of structural characteristics, location, and market context. These results offer insights for sellers in setting realistic listing prices and for buyers in understanding how specific features and locations influence housing value.

3.2 Logistic Regression Modeling

In our logistic model we are looking to see what variables help predict whether or not a house will sell. Understanding the likelihood of a house selling is very important because if some of the significant predictor variables are things that can be manipulated like price or structural features the seller can change these things. This way the seller can make all the necessary adjustments before bringing a house to market to give it the best chance of selling.

3.2.1 Canidate Models

Now moving onto the logistic modeling, this will look at the models for our second practical question which looks at whether or not a house sold. Starting again with the practical model it contains the following variables, LogPrice, Rooms, and Distance. Looking at the output summary, the variable LogPrice has a p-value larger than 0.05 and would not be considered statistically significant, while the variables Rooms and Distance do have p-values smaller than 0.05 and are statistically significant.

# Practical Model
logit_practical <- glm(SoldBinary ~ LogPrice + Rooms + Distance,
                       data = house_cleaned, family = binomial)
summary(logit_practical)

Call:
glm(formula = SoldBinary ~ LogPrice + Rooms + Distance, family = binomial, 
    data = house_cleaned)

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  2.365451   0.649516   3.642 0.000271 ***
LogPrice    -0.031112   0.049517  -0.628 0.529796    
Rooms       -0.133210   0.027269  -4.885 1.03e-06 ***
Distance     0.057574   0.004137  13.916  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 18357  on 27243  degrees of freedom
Residual deviance: 18073  on 27240  degrees of freedom
  (7610 observations deleted due to missingness)
AIC: 18081

Number of Fisher Scoring iterations: 5

Moving onto the the extended model the variables from the practical model are still being used, with the addition of SellerBinary, Regionname, Car and Bathroom. In this model three of the different Regionname sub variables have a p-value greater than 0.05 and are not statistically significant. Additionally, the variable SellerBinary has a p-value greater than 0.05 and is not statistically significant. All other variables have a p-value smaller than 0.05 and are statistically significant.

## Extended Model
logit_extended <- glm(SoldBinary ~ LogPrice + Rooms + Distance + SellerBinary +
                        Regionname + Car + Bathroom, 
                      data = house_cleaned, family = binomial)
summary(logit_extended)

Call:
glm(formula = SoldBinary ~ LogPrice + Rooms + Distance + SellerBinary + 
    Regionname + Car + Bathroom, family = binomial, data = house_cleaned)

Coefficients:
                                      Estimate Std. Error z value Pr(>|z|)    
(Intercept)                          -4.353863   0.855310  -5.090 3.57e-07 ***
LogPrice                              0.459083   0.064981   7.065 1.61e-12 ***
Rooms                                -0.167784   0.037195  -4.511 6.45e-06 ***
Distance                              0.092448   0.006168  14.988  < 2e-16 ***
SellerBinary                         -0.044110   0.049168  -0.897  0.36965    
RegionnameEastern Victoria           -1.552741   0.297008  -5.228 1.71e-07 ***
RegionnameNorthern Metropolitan       0.762467   0.087138   8.750  < 2e-16 ***
RegionnameNorthern Victoria          -0.828969   0.336534  -2.463  0.01377 *  
RegionnameSouth-Eastern Metropolitan -0.169651   0.149051  -1.138  0.25504    
RegionnameSouthern Metropolitan      -0.004239   0.079172  -0.054  0.95730    
RegionnameWestern Metropolitan        0.783515   0.090034   8.702  < 2e-16 ***
RegionnameWestern Victoria            0.480092   0.729592   0.658  0.51052    
Car                                  -0.071215   0.026392  -2.698  0.00697 ** 
Bathroom                             -0.279455   0.039788  -7.024 2.16e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 13586  on 20422  degrees of freedom
Residual deviance: 13050  on 20409  degrees of freedom
  (14431 observations deleted due to missingness)
AIC: 13078

Number of Fisher Scoring iterations: 6

Finally, the assignment asks for a variable selection method to identify the optimal final model. For this data set, stepwise analysis will be used to determine the optimal model. From the output we know the formula being used for the final model has the variables LogPrice, Rooms, Distance, Regionname, Car, and Bathroom. Similar to the extended model, some of the sub categories of the Regionname variable have a p-value larger than 0.05 and are not statistically significant, however the rest of the variables do have a p-value less than 0.05 and are statistically significant.

# Final Model

logit_final <- stepAIC(logit_extended, direction = "both", trace = FALSE)
summary(logit_final)

Call:
glm(formula = SoldBinary ~ LogPrice + Rooms + Distance + Regionname + 
    Car + Bathroom, family = binomial, data = house_cleaned)

Coefficients:
                                      Estimate Std. Error z value Pr(>|z|)    
(Intercept)                          -4.325140   0.854344  -5.063 4.14e-07 ***
LogPrice                              0.455063   0.064797   7.023 2.17e-12 ***
Rooms                                -0.168128   0.037185  -4.521 6.14e-06 ***
Distance                              0.092505   0.006162  15.013  < 2e-16 ***
RegionnameEastern Victoria           -1.547397   0.296926  -5.211 1.87e-07 ***
RegionnameNorthern Metropolitan       0.759473   0.087024   8.727  < 2e-16 ***
RegionnameNorthern Victoria          -0.822951   0.336422  -2.446  0.01444 *  
RegionnameSouth-Eastern Metropolitan -0.169740   0.149051  -1.139  0.25479    
RegionnameSouthern Metropolitan      -0.006933   0.079115  -0.088  0.93017    
RegionnameWestern Metropolitan        0.790735   0.089677   8.818  < 2e-16 ***
RegionnameWestern Victoria            0.490752   0.729603   0.673  0.50118    
Car                                  -0.070760   0.026372  -2.683  0.00729 ** 
Bathroom                             -0.279383   0.039783  -7.023 2.18e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 13586  on 20422  degrees of freedom
Residual deviance: 13051  on 20410  degrees of freedom
  (14431 observations deleted due to missingness)
AIC: 13077

Number of Fisher Scoring iterations: 6
# View final model formula
formula(logit_final)
SoldBinary ~ LogPrice + Rooms + Distance + Regionname + Car + 
    Bathroom

3.2.2 Model Selection

Now that the three candidate logistic regression models have been created they need to undergo the model selection process. Similar to the linear regression process, 75% of the data will be used for training and the remaining 25% will be used as the testing data. We are going to do a cross fold validation process on the models and look at an ROC curve to determine the best canidate model.

house_cleaned <- house_cleaned %>%
  dplyr::mutate(
    Regionname = na_if(Regionname, "#N/A")  # convert "#N/A" to actual NA
  ) %>%
  tidyr::drop_na(SoldBinary, LogPrice, Rooms, Distance,
                 SellerBinary, Regionname, Car, Bathroom)

Starting with the average predictive error calculations the three models have quite similar results, with the practical model being 0.1010451, and the stepwise and extended models both being 0.101241. In this case we want the smallest predictive error which would be the practical model. However, before making a final model selection we are also going to asses the ROC curve and AUC values.

house_cleaned$Regionname <- factor(house_cleaned$Regionname)
house_cleaned$Regionname <- droplevels(house_cleaned$Regionname)

set.seed(123)

n <- nrow(house_cleaned)
train.n <- round(0.75 * n)
train.id <- sample(1:n, train.n, replace = FALSE)
train <- house_cleaned[train.id, ]
test  <- house_cleaned[-train.id, ]


k <- 10
fold.size <- floor(nrow(train) / k)
PE1 <- rep(0, k)
PE2 <- rep(0, k)
PE3 <- rep(0, k)

for(i in 1:k) {
  valid.id <- (fold.size * (i - 1) + 1):(fold.size * i)
  valid <- train[valid.id, ]
  train.dat <- train[-valid.id, ]

  train.dat$Regionname <- factor(train.dat$Regionname)
  train.dat$Regionname <- droplevels(train.dat$Regionname)
  
  valid$Regionname <- factor(valid$Regionname, levels = levels(train.dat$Regionname))
  
  # Practical Model
  candidate01 <- glm(
    SoldBinary ~ LogPrice + Rooms + Distance,
    family = binomial(link = "logit"),
    data = train.dat
  )
  
  # Expanded Model
  candidate03 <- glm(
    SoldBinary ~ LogPrice + Rooms + Distance + SellerBinary +
      Regionname + Car + Bathroom,
    family = binomial(link = "logit"),
    data = train.dat
  )
  
  # Stepwise Model
  candidate02 <- stepAIC(candidate03, direction = "both", trace = FALSE)
  
  # Predictions
  pred01 <- predict(candidate01, newdata = valid, type = "response")
  pred02 <- predict(candidate02, newdata = valid, type = "response")
  pred03 <- predict(candidate03, newdata = valid, type = "response")
  
  # Convert to 0/1
  pre.outcome01 <- ifelse(pred01 > 0.5, 1, 0)
  pre.outcome02 <- ifelse(pred02 > 0.5, 1, 0)
  pre.outcome03 <- ifelse(pred03 > 0.5, 1, 0)
  
  # Error rates
  PE1[i] <- mean(pre.outcome01 != valid$SoldBinary)
  PE2[i] <- mean(pre.outcome02 != valid$SoldBinary)
  PE3[i] <- mean(pre.outcome03 != valid$SoldBinary)
}

# Results
avg.pe <- cbind(
  PE1 = mean(PE1),
  PE2 = mean(PE2),
  PE3 = mean(PE3)
)

kable(avg.pe, caption = "Average of prediction errors of candidate models")
Average of prediction errors of candidate models
PE1 PE2 PE3
0.1010451 0.101241 0.101241

Looking at the ROC curve we see something slightly different than our PE analysis, in this case we are seeing the expanded and the stepwise models with the better ROC and AUC and the practical model is not as strong. In this case our expanded model appears slightly better than the stepwise model. However, the difference is very slight and the expanded model is more complex.

Considering the PEs were all very similar but the ROC and AUC show a strong argument for stepwise or extended over the practical model, it makes sense to remove the practical model from the final model consideration. Looking at the stepwise and extended models since they are extremely similar in their ROC and AUC outputs and have identical PEs it makes sense to use the simpler model as the final model. In this case that would be the stepwise model so we will be using that as our final model going forward.

library(pROC)

# Predicted probabilities on TRAIN set
pred01 <- predict(candidate01, newdata = train, type = "response")
pred02 <- predict(candidate02, newdata = train, type = "response")
pred03 <- predict(candidate03, newdata = train, type = "response")

category <- train$SoldBinary

# Create ROC objects
ROCobj01 <- roc(category, pred01)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
ROCobj02 <- roc(category, pred02)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
ROCobj03 <- roc(category, pred03)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
# Plot ROC curves
plot(ROCobj01, col = 2, lty = 1,
     xlab = "FPR: 1 - Specificity",
     ylab = "TPR: Sensitivity",
     main = "ROC curves of the three candidate models")

plot(ROCobj02, col = 3, lty = 2, add = TRUE)
plot(ROCobj03, col = 4, lty = 3, add = TRUE)

# AUC values
AUC01 <- round(auc(ROCobj01), 4)
AUC02 <- round(auc(ROCobj02), 4)
AUC03 <- round(auc(ROCobj03), 4)

legend("bottomright",
       legend = c(paste("Practical model: AUC =", AUC01),
                  paste("Stepwise model: AUC =", AUC02),
                  paste("Expanded model: AUC =", AUC03)),
       col = 2:4,
       lty = 1:3,
       cex = 0.8,
       bty = "n")

3.2.3 Optimal Cut-Off

Now that a final model is selected we need to determine the optimal cutoff point. This will be calculated by testing several different thresholds on the final model and with the training data set. The optimal threshold will be output and be used for our analysis. Based on the output below, it appears the best threshold for this model is 0.1.

# Get predicted probabilities on the TRAIN set
predicted_probabilities <- predict(candidate02, newdata = train, type = "response")
actual <- train$SoldBinary

thresholds <- seq(0.1, 0.9, by = 0.01)
accuracies <- sapply(thresholds, function(th) {
  pred_class <- ifelse(predicted_probabilities > th, 1, 0)
  mean(pred_class == actual)
})

best_thresh <- thresholds[which.max(accuracies)]
best_thresh
[1] 0.1

With an optimal threshold determined, it can be used to determine the accuracy of the model. Now using the 25% testing data set that was set aside earlier the accuracy of the model can be calculated. The final model has an accuracy of 0.8893459 which is very strong.

pred02 <- predict(candidate02, newdata = test, type = "response")
pred02.outcome <- ifelse(pred02 > best_thresh, 1, 0)

accuracy <- mean(pred02.outcome == test$SoldBinary)

kable(data.frame(
  Cutoff = best_thresh,
  Accuracy = accuracy
), caption = "Final Model Accuracy Using Optimal Cutoff")
Final Model Accuracy Using Optimal Cutoff
Cutoff Accuracy
0.1 0.8893459

3.2.4 Results and Conclusions

The stepwise logistic regression model provides a reliable tool for predicting house sales. Sellers can use this model to understand which factors are most likely to influence a sale and adjust pricing or property features accordingly, increasing the chances of a successful and timely transaction.

The final stepwise logistic regression model was developed to predict the probability that a house will sell (SoldBinary = 1) based on several predictors, including structural features, price, and location. This model allows us to assess which factors significantly influence the likelihood of a sale, providing actionable insights for sellers who may want to adjust price, amenities, or target marketing based on location.

Several structural characteristics are significant predictors. The number of rooms has a negative effect on the probability of selling, indicating that larger homes with more rooms may appeal to a narrower pool of buyers. Additional bathrooms also decrease the likelihood of a sale, while the number of car spaces has a small negative effect. Interestingly, higher log-transformed prices (LogPrice) increase the probability of selling, suggesting that, within this market, more expensive homes tend to sell at a slightly higher rate, potentially reflecting quality or desirable locations.

Location plays a crucial role in sales probability. Compared to the reference region, homes in Eastern Victoria are significantly less likely to sell, whereas properties in Northern Metropolitan and Western Metropolitan regions are significantly more likely to sell. Other regions vary in significance, with some sub-regions showing no statistically meaningful effect, indicating that the influence of location depends on the specific area.

Overall, the model demonstrates that both structural features and geographic location meaningfully affect whether a house sells. By understanding these relationships, sellers can make strategic adjustments—such as pricing, layout improvements, or targeted marketing—to improve the likelihood of a successful sale. The final model provides a practical framework for predicting house sales, helping guide data-driven decisions in the housing market.

4 Summary and Discussion

This project analyzed Melbourne housing data to understand what factors influence house selling prices and the likelihood of a house selling. Using a cleaned dataset of 34,854 properties, both linear and logistic regression models were developed, validated through cross-validation and test sets, and optimized via stepwise selection.

The final linear regression model found that structural features such as rooms, bathrooms, car spaces, and location such as region and distance from the CBD, seller type, and local property density significantly predict log-transformed house prices. The model explains approximately 56% of price variation, providing sellers and buyers with actionable guidance for realistic pricing and value assessment.

The final logistic regression model identified key predictors of sale probability, including price, structural features, and region. Higher-priced homes and those in Northern or Western Metropolitan areas were more likely to sell, while larger homes with many rooms or bathrooms sold slightly less readily. The model achieved an accuracy of 89%, offering sellers insight into factors that can improve the likelihood of a successful sale.

Strengths of the analysis include the data preparation, cross-validation, and models that provide actionable insights. However, some limitations include missing data for some variables, skewed categorical distributions, and the absence of other market factors such as property condition or buyer demand. Future improvements could include incorporating additional features, using other modeling techniques, and analyzing market trends.

Overall, the analysis provides a framework for predicting both house selling prices and sale likelihood, helping sellers make data-driven decisions to optimize pricing, property features, and marketing strategies in the Melbourne housing market.

LS0tCnRpdGxlOiAiTWVsYm91cm5lIEhvdXNpbmcgRGF0YSBSZWdyZXNzaW9uIE1vZGVsaW5nIGFuZCBDcm9zcyBWYWxpZGF0aW9uIgphdXRob3I6ICJDaGxvw6kgV2ludGVycyIKZGF0ZTogIjIwMjUtMTAtMTUiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAgICAgICAgICAgIyBvdXRwdXQgZG9jdW1lbnQgZm9ybWF0CiAgICB0b2M6IHllcyAgICAgICAgICAgICAgICMgYWRkIHRhYmxlIGNvbnRlbnRzCiAgICB0b2NfZmxvYXQ6IHllcyAgICAgICAgICMgdG9jX3Byb3BlcnR5OiBmbG9hdGluZwogICAgdG9jX2RlcHRoOiA0ICAgICAgICAgICAjIGRlcHRoIG9mIFRPQyBoZWFkaW5ncwogICAgZmlnX3dpZHRoOiA2ICAgICAgICAgICAjIGdsb2JhbCBmaWd1cmUgd2lkdGgKICAgIGZpZ19oZWlnaHQ6IDQgICAgICAgICAgIyBnbG9iYWwgZmlndXJlIGhlaWdodAogICAgZmlnX2NhcHRpb246IHllcyAgICAgICAjIGFkZCBmaWd1cmUgY2FwdGlvbgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMgICAjIG51bWJlcmluZyBzZWN0aW9uIGhlYWRpbmdzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMgICAgICMgVE9DIHN1YmhlYWRpbmcgY2xhcHNpbmcKICAgIGNvZGVfZm9sZGluZzogaGlkZSAgICAgIyBmb2xkaW5nL3Nob3dpbmcgY29kZSAKICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgIyBhbGxvdyB0byBkb3dubG9hZCBjb21wbGV0ZSBSTWFya2Rvd24gc291cmNlIGNvZGUKICAgIHNtb290aF9zY3JvbGw6IHllcyAgICAgIyBzY3JvbGxpbmcgdGV4dCBvZiB0aGUgZG9jdW1lbnQKICAgIHRoZW1lOiBsdW1lbiAgICAgICAgICAgIyB2aXN1YWwgdGhlbWUgZm9yIEhUTUwgZG9jdW1lbnQgb25seQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICAgICAjIGNvZGUgc3ludGF4IGhpZ2h0bGlnaHRpbmcgc3R5bGVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICc0JwotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLwogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsKICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsKICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7CiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7Cn0KCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovCiAgZm9udC1zaXplOiAyNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE2cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLwouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwp9CmBgYAoKCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZ3MgPSBGQUxTRSwgICAgICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFICAgICAgICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuCiAgICAgICAgICAgICAgICAgICAgICApICAgCgoKCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkocGFuZGVyKQpsaWJyYXJ5KG1sYmVuY2gpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShwdXJycikKbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeSh2Y2QpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjYXIpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoTUFTUykKbGlicmFyeShwc2NsKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocFJPQykKbGlicmFyeShrbml0cikKbGlicmFyeShwYW5kZXIpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShNQVNTKQpsaWJyYXJ5KHBST0MpCgprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZXMgPSBGQUxTRSwgIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEKICAgICAgICAgICAgICAgICAgICAgICkgICAKCmBgYAoKCgojIEludHJvZHVjdGlvbgoKVGhpcyBwcm9qZWN0IGxvb2tzIGF0IGhvdXNpbmcgZGF0YSBmcm9tIE1lbGJvdXJuZSwgc3BlY2lmaWNhbGx5IGhvdXNlcyB0aGF0IHdlcmUgcHV0IHVwIG9uIHRoZSByZWFsIGVzdGF0ZSBtYXJrZXQgYW5kIGluZm9ybWF0aW9uIGFib3V0IHRoZXNlIGhvdXNlcyBpbmNsdWRpbmcsIGlmIGFuZCBob3cgdGhleSBzb2xkLCB0aGUgc2VsbGluZyBwcmljZSwgYmVkcm9vbSBhbmQgYmF0aHJvb20gY291bnRzLCBhbmQgb3RoZXIgcmVsZXZhbnQgaW5mb3JtYXRpb24uIEluIHRoaXMgcHJvamVjdCB0aGF0IGRhdGEgd2lsbCB1bmRlcmdvIG5lY2Vzc2FyeSBFREEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcsIHRoZW4gdGhlcmUgd2lsbCBiZSBsaW5lYXIgYW5kIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxpbmcuIEJvdGggdGhlIGxpbmVhciBhbmQgbG9naXN0aWMgbW9kZWxzIHdpbGwgdW5kZXJnbyBjcm9zcyB2YWxpZGF0aW9uLCBhbmQgYmUgc3BsaXQgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBkYXRhIHNldHMgdG8gYmUgcHJvcGVybHkgYXNzZXNzZWQuIE9uY2UgdGhlIGZpbmFsIG1vZGVscyBhcmUgZGV0ZXJtaW5lZCBhbmQgYXNzZXNzZWQgd2Ugd2lsbCBjb25kdWN0IG91ciBmb3JtYWwgY29uY2x1c2lvbnMuIAoKIyBNYXRlcmlhbHMgCgpHb2luZyBvdmVyIHRoZSBtYXRlcmlhbHMgZm9yIHRoaXMgcHJvamVjdCBmaXJzdCB3ZSB3aWxsIGFkZHJlc3MgdGhlIG9yaWdpbmFsIGRhdGEgc2V0IGJlaW5nIHVzZWQgZm9yIHRoaXMgYXNzaWdubWVudC4gVGhlbiB0aGF0IGRhdGEgd2lsbCB1bmRlcmdvIHNvbWUgRURBIGFuZCBGZWF0dXJlIEVuZ2luZWVyaW5nIHRvIGNyZWF0ZSB0aGUgZmluYWwgZGF0YSBzZXQuIEFmdGVyIHRoZSBmaW5hbCBkYXRhIHNldCBpcyBjcmVhdGVkIGl0IHdpbGwgYmUgZXhwbGFpbmVkIGp1c3QgbGlrZSBpdCB3YXMgdGhlIG9yaWdpbmFsIGRhdGEgc2V0LiAKCiMjIE9yaWdpbmFsIERhdGEgU2V0CgpgYGB7cn0KdXJsID0iaHR0cHM6Ly9jaGxvZXdpbnRlcnM3OS5naXRodWIuaW8vU1RBNTUxL0RhdGEvTWVsYm91cm5lSG91c2luZy5jc3YiCmhvdXNlID0gcmVhZC5jc3YodXJsLCBoZWFkZXIgPSBUUlVFKQpgYGAKClRoZSBkYXRhIHNldCBiZWluZyB1c2VkIGluIHRoaXMgYW5hbHlzaXMgY29uc2l0cyBvZiAzNCw4NTcgb2JzZXJ2YXRpb25zIGFuZCAyMSB2YXJpYWJsZXMgd2hpY2ggYXJlIGRlc2NyaWJlZCBiZWxvdy4gVGhpcyBkYXRhIHNldCB3YXMgY3JlYXRlZCBmcm9tIHB1YmxpY2x5IGF2YWlsYWJsZSByZXN1bHRzIHBvc3RlZCBldmVyeSB3ZWVrIGZyb20gRG9tYWluLmNvbS5hdS4gVGhlcmUgaXMgYSBtaXggb2YgbnVtZXJpY2FsIGFuZCBjYXRlZ29yaWNhbCBkYXRhIGluIHRoaXMgZGF0YSBzZXQuIAoKMS4gU3VidXJiOiAoY2F0KSBzdWJ1cmIgaW4gd2hpY2ggdGhlIHByb3BlcnR5IGlzIGxvY2F0ZWQKMi4gQWRkcmVzczogKGNhdCkgZnVsbCBzdHJlZXQgYWRkcmVzcyBvZiB0aGUgcHJvcGVydHkKMy4gUm9vbXM6IChudW0pIG51bWJlciBvZiByb29tcyBpbiB0aGUgcHJvcGVydHkKNC4gVHlwZTogKGNhdCkgdHlwZSBvZiBwcm9wZXJ0eSAoZS5nLiwgaG91c2UsIHVuaXQsIHRvd25ob3VzZSwgZXRjLikKNS4gUHJpY2U6IChudW0pIGZpbmFsIHNhbGUgcHJpY2UgaW4gQXVzdHJhbGlhbiBkb2xsYXJzCjYuIE1ldGhvZDogKGNhdCkgbWV0aG9kIG9mIHNhbGUgKGUuZy4sIHNvbGQsIHNvbGQgcHJpb3IsIHBhc3NlZCBpbiwgd2l0aGRyYXduLCBldGMuKQo3LiBTZWxsZXJHOiAoY2F0KSByZWFsIGVzdGF0ZSBhZ2VuY3kgcmVzcG9uc2libGUgZm9yIHRoZSBzYWxlCjguIERhdGU6IChjYXQpIGRhdGUgb2Ygc2FsZSAoc3RvcmVkIGFzIGNoYXJhY3RlcjsgbWF5IGJlIGNvbnZlcnRlZCB0byBkYXRlIGZvcm1hdCkKOS4gRGlzdGFuY2U6IChudW0pIGRpc3RhbmNlIGZyb20gdGhlIHByb3BlcnR5IHRvIHRoZSBDZW50cmFsIEJ1c2luZXNzIERpc3RyaWN0IChDQkQpIGluIGtpbG9tZXRlcnMgKGN1cnJlbnRseSBzdG9yZWQgYXMgY2hhcmFjdGVyOyBuZWVkcyBjb252ZXJzaW9uKQoxMC4gUG9zdGNvZGU6IChjYXQpIHBvc3RhbCBjb2RlIG9mIHRoZSBwcm9wZXJ0eSBsb2NhdGlvbiAobnVtZXJpYyBidXQgc3RvcmVkIGFzIGNoYXJhY3RlcikKMTEuIEJlZHJvb20yOiAobnVtKSBudW1iZXIgb2YgYmVkcm9vbXMgZnJvbSBhbiBhbHRlcm5hdGUgZGF0YSBzb3VyY2UKMTIuIEJhdGhyb29tOiAobnVtKSBudW1iZXIgb2YgYmF0aHJvb21zCjEzLiBDYXI6IChudW0pIG51bWJlciBvZiBjYXIgcGFya2luZyBvciBnYXJhZ2Ugc3BhY2VzCjE0LiBMYW5kc2l6ZTogKG51bSkgbGFuZCBhcmVhIG9mIHRoZSBwcm9wZXJ0eSBpbiBzcXVhcmUgbWV0ZXJzCjE1LiBCdWlsZGluZ0FyZWE6IChudW0pIGludGVybmFsIGJ1aWxkaW5nIHNpemUgaW4gc3F1YXJlIG1ldGVycwoxNi4gWWVhckJ1aWx0OiAobnVtKSB5ZWFyIHRoZSBwcm9wZXJ0eSB3YXMgY29uc3RydWN0ZWQKMTcuIENvdW5jaWxBcmVhOiAoY2F0KSBsb2NhbCBnb3Zlcm5pbmcgY291bmNpbCBmb3IgdGhlIHByb3BlcnR5CjE4LiBMYXR0aXR1ZGU6IChudW0pIGxhdGl0dWRlIGNvb3JkaW5hdGUgb2YgdGhlIHByb3BlcnR5IGxvY2F0aW9uCjE5LiBMb25ndGl0dWRlOiAobnVtKSBsb25naXR1ZGUgY29vcmRpbmF0ZSBvZiB0aGUgcHJvcGVydHkgbG9jYXRpb24KMjAuIFJlZ2lvbm5hbWU6IChjYXQpIGJyb2FkZXIgcmVnaW9uIGNsYXNzaWZpY2F0aW9uCjIxLiBQcm9wZXJ0eWNvdW50OiAobnVtKSBudW1iZXIgb2YgcHJvcGVydGllcyBpbiB0aGUgc3VidXJiIChjdXJyZW50bHkgc3RvcmVkIGFzIGNoYXJhY3RlcjsgbmVlZHMgY29udmVyc2lvbikKCiMjIEVEQSBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZwoKQmVmb3JlIGFueSBvZiB0aGUgbGluZWFyIG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxpbmcgY2FuIHN0YXJ0IGl0IGlzIGltcG9ydGFudCBmb3IgdGhlIGRhdGEgc2V0IHRvIHVuZGVyZ28gRURBIGFuZCBGZWF0dXJlIEVuZ2luZWVyaW5nLiBUaGlzIG5vdCBvbmx5IGdpdmVzIHVzIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGRhdGEgc2V0IGJ1dCBpdCBhbGxvd3MgZm9yIGFueSBuZWNjZXNzYXJ5IGNsZWFuaW5nIGFuZCB2YXJpYWJsZSB0cmFuc2Zvcm1hdGlvbiB0byBiZSBtYWRlIG5vdy4gVGhpcyB3aWxsIGFzc2lzdCBsYXRlciBvbiBpbiB0aGUgbW9kZWwgYnVpbGlkaW5nIHByb2Nlc3MuIAoKIyMjIE1pc3NpbmcgVmFsdWVzCgpUaGUgZmlyc3QgdGhpbmcgdG8gYmUgYWRkcmVzc2VkIGluIHRoaXMgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBpcyB0aGUgbWlzc2luZyB2YXJpYWJsZXMuIFRocmVlIHZhcmlhYmxlcyBpbiB0aGlzIGRhdGEgc2V0LCBCdWlsZGluZ0FyZWEsIExhbmRzaXplIGFuZCBZZWFyQnVpbHQgYXJlIG1pc3Npbmcgb3ZlciAzMCUgb2YgdGhlaXIgb2JzZXJ2YXRpb25zLiBXaGlsZSBmZWF0dXJlIGVuZ2luZWVyaW5nIGlzIGhlbHBmdWwgd2hlbiBkZWFsaW5nIHdpdGggbWlzc2luZyBvYnNlcnZhdGlvbnMsIGl0IGRvZXMgbm90IG1ha2Ugc2Vuc2UgdG8gZG8gc28gd2hlbiBvdmVyIDMwJSBvZiB0aGUgb2JzZXJ2YXRpb25zIGFyZSBtaXNzaW5nLiBUaHVzLCBzaW5jZSB0aGUgZGF0YSBzZXQgY29udGFpbnMgcGxlbnR5IG9mIG90aGVyIHZhcmlhYmxlcyB0byB3b3JrIHdpdGgsIGl0IG1ha2VzIHRoZSBtb3N0IHNlbnNlIHRvIHJlbW92ZSB0aGVzZSB0aHJlZSB2YXJpYWJsZXMgbW92aW5nIGZvcndhcmQuCgpBZGRpdGlvbmFsbHksIGl0IG1ha2VzIHNlbnNlIHRvIHJlbW92ZSB0aGUgdmFyaWFibGUgYWRkcmVzcyBiZWNhdXNlIHdlIGRvIG5vdCBoYXZlIGEgcHJhY3RpY2FsIHdheSB0byB1c2UgaXQgaW4gb3VyIGFuYWx5c2lzLiBBZGRpdGlvbmFsbHksIHRoZSBkZWNpc2lvbiB3YXMgbWFkZSB0byBjcmVhdGUgZXh0cmEgdmFyaWFibGVzIHRoYXQgY291bGQgYmUgcHJhY3RpY2FsIGZvciBhbmFseXNpcywgdGhlc2UgdmFyaWFibGVzIGFyZSBTYWxlWWVhciBhbmQgU2FsZU1vbnRoIHdoaWNoIHdlcmUgY3JlYXRlZCBmcm9tIGV4dHJhY3RpbmcgaW5mb3JtYXRpb24gZnJvbSB0aGUgRGF0ZSB2YXJpYWJsZS4gVGhpcyB3aWxsIGFsbG93IGZvciBtb3JlIGFuYWx5c2lzIG9uIHRpbWUgYmFzZWQgdHJlbmRzIHdoZW4gaXQgY29tZXMgdG8gdGhlIGhvdXNpbmcgZGF0YSBhbmFseXNpcy4gCgpGaW5hbGx5LCBzb21lIHZhcmlhYmxlcyBuZWVkZWQgdG8gYmUgcmVjYXRlZ29yaXplZCBmcm9tIGNoYXJhY3RlciB2YXJpYWJsZXMgdG8gbnVtZXJpYywgZm9yIGV4YW1wbGUgdGhlIHZhcmlhYmxlcyBEaXN0YW5jZSBhbmQgUHJvcGVydHlDb3VudCwgc28gdGhleSBjYW4gYmUgdXRpbGl6ZWQgcHJvcGVybHkgaW4gZnV0dXJlIGFuYWx5c2lzLiBBbnkgaW5jb3JyZWN0bHkgY2F0ZWdvcml6ZWQgdmFyaWFibGVzIHdlcmUgcmUtY29kZWQgZm9yIGVhc2llciBhbmFseXNpcy4gIAoKYGBge3J9Cm5hX3N1bW1hcnkgPC0gaG91c2UgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gc3VtKGlzLm5hKC4pKSAvIG4oKSAqIDEwMCkpICU+JQogIGdhdGhlcihrZXkgPSAiVmFyaWFibGUiLCB2YWx1ZSA9ICJQZXJjZW50TWlzc2luZyIpICU+JQogIGFycmFuZ2UoZGVzYyhQZXJjZW50TWlzc2luZykpCgpgYGAKCmBgYHtyfQoKbmFfaGVhdnkgPC0gbmFfc3VtbWFyeSAlPiUgZmlsdGVyKFBlcmNlbnRNaXNzaW5nID4gMzApCm5hX2hlYXZ5Cgpob3VzZSA8LSBob3VzZSAlPiUKICBtdXRhdGUoCiAgICBEYXRlID0gZG15KERhdGUpLCAgICAgICAgICAgICAgICAgICAgICAjIGNvbnZlcnQgdG8gRGF0ZSAodXNlIG1keSgpIGluc3RlYWQgaWYgbmVlZGVkKQogICAgU2FsZVllYXIgPSB5ZWFyKERhdGUpLCAgICAgICAgICAgICAgICAjIGV4dHJhY3QgeWVhcgogICAgU2FsZU1vbnRoID0gbW9udGgoRGF0ZSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gVFJVRSkgICMgZXh0cmFjdCBtb250aCBhcyBKYW4vRmViL2V0Yy4KICApCmBgYAoKYGBge3J9CmhvdXNlIDwtIGhvdXNlICU+JQogIG11dGF0ZSgKICAgIERpc3RhbmNlID0gYXMubnVtZXJpYyhnc3ViKCIsIiwgIiIsIHRyaW13cyhEaXN0YW5jZSkpKSwKICAgIFByb3BlcnR5Y291bnQgPSBhcy5udW1lcmljKGdzdWIoIiwiLCAiIiwgdHJpbXdzKFByb3BlcnR5Y291bnQpKSkKICApCmBgYAoKIyMjIFZhcmlhYmxlIERpc3RyaWJ1dGlvbgoKU2luY2UgdGhpcyBkYXRhIHNldCBjb25zaXN0cyBvZiBib3RoIG51bWVyaWNhbCBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRvIG1ha2UgdGhlIGFuYWx5c2lzIGNsZWFyIGFuZCBlYXN5IHRvIHVuZGVyc3RhbmQgd2UgYXJlIGdvaW5nIHRvIGJyZWFrIHVwIHRoZSBhbmFseXNpcyBvZiB0aGVzZSB2YXJpYWJsZXMgaW50byB0d28gZGlmZmVyZW50IHNlY3Rpb25zLiBUaGlzIHdheSB0aGUgYXBwcnBvcmlhdGUgdHlwZXMgb2YgYW5hbHlzaXMgYXJlIGNvbmR1Y3RpbmcgZm9yIHRoZSBzcGVjaWZpYyB2YXJpYWJsZXMuIAoKIyMjIyBBbmFseXNpcyBvZiBOdW1lcmljYWwgVmFyaWFibGVzCgpJbnRlcmVzdGluZ2x5IGVub3VnaCBvbmx5IHRoZSB2YXJpYWJsZXMgTG9uZ2l0dWRlIGFuZCBMYXRpdHVkZSBhcHBlYXIgdG8gaGF2ZSBhIG5vcm1hbCBkaXN0cmlidXRpb24uIFNhbGUgeWVhciBpcyBhIGxpdHRsZSB3ZWlyZGx5IGxhaWQgb3V0IGJlY2F1c2UgdGhpcyBkYXRhIG9ubHkgaGFzIGluZm9ybWF0aW9uIGZyb20gMyB5ZWFycyBzbyBpdCBkb2VzIGhhdmUgZW5vdWdoIGJhcnMgdG8gaGF2ZSBhIHByb3BlciBkaXN0cmlidXRpb24uIE90aGVyd2lzZSwgYWxsIHRoZSBvdGhlciB2YXJpYWJsZXMgYXBwZWFyIHRvIGhhdmUgYSByaWdodCBzaWRlZCBza2V3bmVzcy4gV2hpY2ggZG9lcyBtYWtlIHNlbnNlIGJlY2F1c2Ugd2hlbiB0aGlua2luZyBvZiBob3VzZXMgd2Ugd291bGRudCBleHBlY3QgYSBub3JtYWwgZGlzdHJpYnV0aW9uIGluIHRoZSBudW1iZXIgb2YgYmF0aHJvb21zIGluIGEgaG91c2Ugd2hlbiB0aGUgcmFuZ2UgaXMgZnJvbSAwIHRvIDEyLCBiZWNhdXNlIHRoZSBhdmVyYWdlIGhvdXNlIGRvZXMgbm90IGluY2x1ZGUgNiBiYXRocm9vbXMuIAoKYGBge3J9CiMgSGlzdG9ncmFtcyBvZiBudW1lcmljIHZhcmlhYmxlcyAoM3gzIGxheW91dCkKcGFyKG1mcm93ID0gYygzLDMpKQpoaXN0KGhvdXNlJFByaWNlLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBQcmljZSIpCmhpc3QoaG91c2UkUm9vbXMsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFJvb21zIikKaGlzdChob3VzZSRCZWRyb29tMiwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgQmVkcm9vbTIiKQpoaXN0KGhvdXNlJEJhdGhyb29tLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBCYXRocm9vbSIpCmhpc3QoaG91c2UkQ2FyLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBDYXIgU3BhY2VzIikKaGlzdChob3VzZSREaXN0YW5jZSwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgRGlzdGFuY2UiKQpoaXN0KGhvdXNlJFByb3BlcnR5Y291bnQsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFByb3BlcnR5IENvdW50IikKaGlzdChob3VzZSRMYXR0aXR1ZGUsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIExhdHRpdHVkZSIpCmhpc3QoaG91c2UkTG9uZ3RpdHVkZSwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgTG9uZ2l0dWRlIikKCmBgYAoKCiMjIyMgQW5hbHlzaXMgb2YgQ2F0ZWdvcmljYWwgVmFyaWFibGVzCgpGb3IgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3ZSBhcmUgZ29pbmcgdG8gbG9vayBhdCB0YWJsZXMgY29udGFpbmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGVhY2ggb2YgdGhlIGNhdGVnb3JpY2FsIG9wdGlvbnMgYW5kIGNvbW1lbnRpbmcgb24gdGhhdCBkaXN0cmlidXRpb24uICAKCldoZW4gbG9va2luZyBhdCB0aGUgVHlwZSB2YXJpYWJsZSBhYm91dCA2OCUgb2YgdGhlIG9ic2VydmF0aW9ucyBhcmUgaG91c2VzLCB3aGlsZSAyMSUgYXJlIHVuaXRzIGFuZCBkdXBsZXhlcywgYW5kIHRoZSByZW1haW5pbmcgMTElIGFyZSB0b3duaG91c2VzLiBUaGlzIGlzIG5vdCBhbiBldmVubHkgZGlzdHJpYnV0ZWQgY2F0ZWdvcmljYWwgdmFyaWFibGUsIHdpdGggYSB0aGUgb2JzZXJ2YXRpb25zIHNrZXdpbmcgaGVhdmlseSB0b3dhcmRzIGhvdXNlcy4gCgpgYGB7cn0KdGFibGUoaG91c2UkVHlwZSkKYGBgCgpGb3IgdGhlIE1ldGhvZCB2YXJpYWJsZSwgYXBwcm94aW1hdGVseSA4NSUgb2YgcHJvcGVydGllcyB3ZXJlIHNvbGQgdmlhIHRoZSBzdGFuZGFyZCBzYWxlIG1ldGhvZCAo4oCcU+KAnSksIDEwJSB3ZXJlIHNvbGQgcHJpb3IgKOKAnFNQ4oCdKSwgYW5kIHRoZSByZW1haW5pbmcgNSUgd2VyZSBlaXRoZXIgcGFzc2VkIGluIG9yIHdpdGhkcmF3bi4gVGhpcyBkaXN0cmlidXRpb24gaXMgaGVhdmlseSBza2V3ZWQgdG93YXJkcyB0aGUgc3RhbmRhcmQgc2FsZSBtZXRob2QuCgpgYGB7cn0KdGFibGUoaG91c2UkTWV0aG9kKQpgYGAKClRoZSBSZWdpb25uYW1lIHZhcmlhYmxlIHNob3dzIHRoYXQgYWJvdXQgNDAlIG9mIHByb3BlcnRpZXMgYXJlIGxvY2F0ZWQgaW4gdGhlIE5vcnRoZXJuIE1ldHJvcG9saXRhbiByZWdpb24sIDI1JSBpbiBTb3V0aGVybiBNZXRyb3BvbGl0YW4sIDIwJSBpbiBXZXN0ZXJuIE1ldHJvcG9saXRhbiwgYW5kIHRoZSByZW1haW5pbmcgMTUlIGFyZSBzcHJlYWQgYWNyb3NzIEVhc3Rlcm4gTWV0cm9wb2xpdGFuLCBCYXlzaWRlLCBhbmQgb3RoZXIgcmVnaW9ucy4gVGhlIGRpc3RyaWJ1dGlvbiBpcyBub3QgZXZlbiwgd2l0aCB0aGUgbWFqb3JpdHkgb2YgcHJvcGVydGllcyBjb25jZW50cmF0ZWQgaW4gdGhlIG5vcnRoZXJuIGFuZCBzb3V0aGVybiByZWdpb25zLgoKYGBge3J9CnRhYmxlKGhvdXNlJFJlZ2lvbm5hbWUpCmBgYApUaGUgQ291bmNpbEFyZWEgdmFyaWFibGUgaW5kaWNhdGVzIHRoYXQgc2V2ZXJhbCBjb3VuY2lscyBoYXZlIGEgbGFyZ2UgbnVtYmVyIG9mIHByb3BlcnRpZXMsIHdoaWxlIHNvbWUgY291bmNpbHMgaGF2ZSB2ZXJ5IGZldyBsaXN0aW5ncy4gVGhlIGRhdGEgaXMgaGVhdmlseSBza2V3ZWQgdG93YXJkIGNlcnRhaW4gY291bmNpbHMgbGlrZSBCb3Jvb25kYXJhLCBEYXJlYmluLCBhbmQgTW9yZWxhbmQgVGhpcyB2YXJpYWJsZSBzaG93cyBhbiB1bmV2ZW4gZGlzdHJpYnV0aW9uIGFuZCBtYXkgcmVxdWlyZSBncm91cGluZyBmb3IgbW9kZWxpbmcuCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KdGFibGUoaG91c2UkQ291bmNpbEFyZWEpCmBgYAoKVGhlIFNlbGxlckcgdmFyaWFibGUgcmV2ZWFscyB0aGF0IGEgZmV3IHJlYWwgZXN0YXRlIGFnZW5jaWVzIGRvbWluYXRlIHRoZSBtYXJrZXQuIEZvciBleGFtcGxlLCBIYXJjb3VydHMsIEplbGxpcywgYW5kIFJheSBXaGl0ZSBhY2NvdW50IGZvciB0aGUgbWFqb3JpdHkgb2Ygc2FsZXMsIHdoaWxlIHRoZSByZW1haW5pbmcgYWdlbmNpZXMgcmVwcmVzZW50IGEgc21hbGwgZnJhY3Rpb24uIFRoZSBkaXN0cmlidXRpb24gaXMgaGlnaGx5IHNrZXdlZCB0b3dhcmQgdGhlc2UgdG9wIGFnZW5jaWVzLiBJdCBtYXkgbWFrZSBzZW5zZSB0byByZXdvcmsgdGhpcyB2YXJpYWJsZSBpbnRvIGEgYmluYXJ5IHZhcmlhYmxlIHdoZXJlIGl0IGluZGljYXRlcyB3aGV0aGVyIG9yIG5vdCB0aGUgaG9tZSB3YXMgc29sZCBieSBhIGxhcmdlIHJlYWwgZXN0YXRlIGFnZW5jeS4gCgoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CnRhYmxlKGhvdXNlJFNlbGxlckcpCmBgYApUaGUgU3VidXJiIHZhcmlhYmxlIHNob3dzIGEgc2ltaWxhciBwYXR0ZXJuLCB3aXRoIGEgZmV3IHN1YnVyYnMgbGlrZSBSZXNlcnZvaXIsIEJlbnRsZWlnaCBFYXN0LCBhbmQgR2xlbiBXYXZlcmxleSBjb250YWluaW5nIGEgbGFyZ2UgbnVtYmVyIG9mIGxpc3RpbmdzLCB3aGlsZSBtb3N0IHN1YnVyYnMgaGF2ZSB2ZXJ5IGZldy4gVGhlIGRpc3RyaWJ1dGlvbiBpcyBoaWdobHkgdW5ldmVuIGFuZCB3aWxsIG5lZWQgY29uc2lkZXJhdGlvbiBpZiB1c2VkIGZvciBtb2RlbGluZy4KCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQp0YWJsZShob3VzZSRTdWJ1cmIpCmBgYAoKCiMjIyBQYWlyd2lzZSBSZWxhdGlvbnNoaXBzCgpXaXRoIHRoZSBzaXplIG9mIHRoaXMgZGF0YSBzZXQgYmVpbmcgb3ZlciAzMCwwMDAgb2JzZXJ2YXRpb25zLCBhIHBhaXJ3aXNlIHNjYXR0ZXIgcGxvdCBpcyB1bmZvcnR1bmF0ZWx5IG5vdCB0aGF0IGNsZWFyIGFuZCBsZWdpYmxlIGZvciBhbmFseXNpcywgaW5zdGVhZCBpdCBtYWtlcyBmb3Igc2Vuc2UgdG8gbG9vayBhdCBjb3JyZWxhdGlvbiB1c2luZyBhIGhlYXQgbWFwLCB3aGljaCBpcyBlYXNpZXIgdG8gcmVhZCB3aXRoIHRoaXMgYW1vdW50IG9mIG9ic2VydmF0aW9ucy4gVGhlIG9ubHkgdmFyaWFibGVzIHdpdGggYSBzdHJvbmcgY29ycmVsYXRpb24gYXJlIFJvb21zIGFuZCBCZWRyb29tMiwgd2hpY2ggbWFrZXMgc2Vuc2UgZ2l2ZW4gdGhlIGNvbnRleHQgb2YgdGhlIHR3byB2YXJpYWJsZXMuIE90aGVyd2lzZSwgdGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBoYXZlIHdlYWsgY29ycmVsYXRpb24gd2l0aCBlYWNoIG90aGVyLiBJdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdoaWxlIHdlYWssIHRoZSBkYXRhIGRvZXMgaGF2ZSB2YXJpYWJsZXMgd2l0aCBuZWdhdGl2ZSBhbmQgcG9zdGl2ZXIgY29ycmVsYXRpb24gcmVzcGVjdGl2ZWx5LCB0aGUgdmFyaWFibGVzIGRvIG5vdCBhbGwgZm9sbG93IHRoZSBzYW1lIHBhdHRlcm4gZm9yIGNvcnJlbGF0aW9uLiAKCmBgYHtyfQpudW1lcmljX3ZhcnMgPC0gZHBseXI6OnNlbGVjdCgKICBob3VzZSwKICBQcmljZSwgUm9vbXMsIEJlZHJvb20yLCBCYXRocm9vbSwgQ2FyLCBEaXN0YW5jZSwgUHJvcGVydHljb3VudCwgTGF0dGl0dWRlLCBMb25ndGl0dWRlLCBTYWxlWWVhcgopCiMgUGVhcnNvbiBjb3JyZWxhdGlvbiBtYXRyaXgKY29ycl9tYXRfcGVhcnNvbiA8LSBjb3IobnVtZXJpY192YXJzLCB1c2UgPSAiY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQoKIyBQZWFyc29uIGNvcnJlbGF0aW9uIGhlYXRtYXAKZ2djb3JycGxvdChjb3JyX21hdF9wZWFyc29uLCAKICAgICAgICAgICBoYy5vcmRlciA9IFRSVUUsCiAgICAgICAgICAgdHlwZSA9ICJsb3dlciIsCiAgICAgICAgICAgbGFiID0gVFJVRSwKICAgICAgICAgICBsYWJfc2l6ZSA9IDMsCiAgICAgICAgICAgbWV0aG9kID0gInNxdWFyZSIsCiAgICAgICAgICAgY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSwKICAgICAgICAgICB0aXRsZSA9ICJQZWFyc29uIENvcnJlbGF0aW9uIEhlYXRtYXAgb2YgTnVtZXJpYyBWYXJpYWJsZXMiLAogICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKQpgYGAKCiMjIEZlYXR1cmUgRW5naW5lZXJpbmcKCgpBZnRlciBjb25kdWN0aW5nIHRoZSBleGFtaW5hdGlvbiBvbiB0aGUgZGF0YSB0aHJvdWdoIG91ciBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIHdlIHdlcmUgYWJsZSB0byBtYWtlIHRoZSBkZXRlcm1pbmF0aW9uIG9uIHdoYXQga2luZHMgZmVhdHVyZSBlbmdpbmVlcmluZyBzdGVwcyBuZWVkIHRvIGJlIHRha2VuLiBQYXJ0aWN1bGFybHkgaW4gY29uY2VybnMgdG8gdGhlIHZhcmlhYmxlIHByaWNlLCB3aGljaCBuZWVkcyB0byB1bmRlcmdvIHNvbWUgdHJhbnNmb3JtYXRpb25zLiBJdCBtYWtlcyB0aGUgbW9zdCBzZW5zZSB0byBoYXZlIHRoZSBwcmljZSB2YXJpYWJsZSB1bmRlcmdvIGEgbG9nIHRyYW5zZm9ybWF0aW9uIHNvIGl0IGhhcyBhIGJldHRlciBkaXN0cmlidXRpb24gZm9yIG91ciBhbmFseXNpcy4gQWRkaXRpb25hbGx5LCB0aGUgZGVjaXNpb24gd2FzIG1hZGUgdG8gZ3JvdXAgc29tZSBvZiB0aGUgc3BhcnNlciBjYXRlZ29yaWVzIGluIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgaW50byBhIGpvaW50IGxhcmdlciAib3RoZXIiIGNhdGVnb3J5IHNpbmNlIHNvbWUgb2YgdGhlIGNhdGVnb3JpZXMgd2VyZSB2ZXJ5IHVuZXF1YWwgaW4gc2l6ZS4gIAoKYGBge3J9CmhvdXNlIDwtIGhvdXNlICU+JQogIG11dGF0ZSgKICAgIExvZ1ByaWNlID0gbG9nMXAoUHJpY2UpLAogICkKCnJhcmVfY291bmNpbHMgPC0gbmFtZXMoc29ydCh0YWJsZShob3VzZSRDb3VuY2lsQXJlYSksIGRlY3JlYXNpbmcgPSBGQUxTRSlbCiAgc29ydCh0YWJsZShob3VzZSRDb3VuY2lsQXJlYSksIGRlY3JlYXNpbmcgPSBGQUxTRSkgPCAxMDAKXSkKaG91c2UgPC0gaG91c2UgJT4lCiAgbXV0YXRlKENvdW5jaWxBcmVhR3JvdXBlZCA9IGlmZWxzZShDb3VuY2lsQXJlYSAlaW4lIHJhcmVfY291bmNpbHMsICJPdGhlciIsIENvdW5jaWxBcmVhKSkKCiMgU3VidXJiOiBncm91cCBzdWJ1cmJzIHdpdGggZmV3IG9ic2VydmF0aW9ucyBpbnRvICJPdGhlciIKcmFyZV9zdWJ1cmJzIDwtIG5hbWVzKHNvcnQodGFibGUoaG91c2UkU3VidXJiKSwgZGVjcmVhc2luZyA9IEZBTFNFKVsKICBzb3J0KHRhYmxlKGhvdXNlJFN1YnVyYiksIGRlY3JlYXNpbmcgPSBGQUxTRSkgPCA1MApdKQpob3VzZSA8LSBob3VzZSAlPiUKICBtdXRhdGUoU3VidXJiR3JvdXBlZCA9IGlmZWxzZShTdWJ1cmIgJWluJSByYXJlX3N1YnVyYnMsICJPdGhlciIsIFN1YnVyYikpCgojIDMuIENvbnZlcnQgU2VsbGVyRyBpbnRvIGJpbmFyeSB2YXJpYWJsZTogYmlnIHNlbGxlciA9IDEsIHNtYWxsIHNlbGxlciA9IDAKIyBEZWZpbmUgYmlnIHNlbGxlcnMgKHRvcCAxMCBhZ2VuY2llcyBieSBudW1iZXIgb2Ygc2FsZXMpCnRvcF9zZWxsZXJzIDwtIG5hbWVzKHNvcnQodGFibGUoaG91c2UkU2VsbGVyRyksIGRlY3JlYXNpbmcgPSBUUlVFKVsxOjEwXSkKaG91c2UgPC0gaG91c2UgJT4lCiAgbXV0YXRlKFNlbGxlckJpbmFyeSA9IGlmZWxzZShTZWxsZXJHICVpbiUgdG9wX3NlbGxlcnMsIDEsIDApKQoKaG91c2UgPC0gaG91c2UgJT4lCiAgbXV0YXRlKFNvbGRCaW5hcnkgPSBpZmVsc2UoTWV0aG9kICVpbiUgYygiUyIsICJTUCIsICJQSSIpLCAxLCAwKSkKCgpgYGAKCgpgYGB7cn0KIyBTYXZlIGNsZWFuZWQgZGF0YXNldCBmb3IgcmVncmVzc2lvbiBhbmFseXNpcwp3cml0ZS5jc3YoaG91c2UsICJNZWxib3VybmVIb3VzaW5nX0NsZWFuZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCiMjIEZpbmFsIERhdGEgU2V0CgpUaGUgZmluYWwgZGF0YSBzZXQgYmVpbmcgdXNlZCBhZnRlciB1bmRlcmdvaW5nIEVEQSBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZyBjb25zaXN0cyBvZiAzNCw4NTQgb2JzZXJ2YXRpb25zIGFuZCAyNSB2YXJpYWJsZXMgd2hpY2ggYXJlIGRlc2NyaWJlZCBiZWxvdy4gCgoxLiBTdWJ1cmI6IChjYXQpIHN1YnVyYiB3aGVyZSB0aGUgcHJvcGVydHkgaXMgbG9jYXRlZAoyLiBSb29tczogKG51bSkgdG90YWwgbnVtYmVyIG9mIHJvb21zIChpbmNsdWRpbmcgYmVkcm9vbXMgYW5kIGxpdmluZyBhcmVhcykKMy4gVHlwZTogKGNhdCkgdHlwZSBvZiBkd2VsbGluZyDigJQgaG91c2UgKGgpLCB1bml0L2FwYXJ0bWVudCAodSksIG9yIHRvd25ob3VzZSAodCkKNC4gUHJpY2U6IChudW0pIHNhbGUgcHJpY2Ugb2YgdGhlIHByb3BlcnR5IGluIEF1c3RyYWxpYW4gZG9sbGFycwo1LiBNZXRob2Q6IChjYXQpIG1ldGhvZCBvZiBzYWxlIChlLmcuLCBzb2xkLCBzb2xkIHByaW9yLCBwYXNzZWQgaW4sIHdpdGhkcmF3biwgZXRjLikKNi4gU2VsbGVyRzogKGNhdCkgcmVhbCBlc3RhdGUgYWdlbmN5IGhhbmRsaW5nIHRoZSBzYWxlCjcuIERhdGU6IChjYXQpIHNhbGUgZGF0ZSAoaW4gWVlZWS1NTS1ERCBmb3JtYXQpCjguIERpc3RhbmNlOiAobnVtKSBkaXN0YW5jZSBmcm9tIHRoZSBwcm9wZXJ0eSB0byB0aGUgTWVsYm91cm5lIENlbnRyYWwgQnVzaW5lc3MgRGlzdHJpY3QgKENCRCkgaW4ga2lsb21ldGVycwo5LiBQb3N0Y29kZTogKGNhdCkgcG9zdGFsIGNvZGUgb2YgdGhlIHByb3BlcnR5IGxvY2F0aW9uCjEwLiBCZWRyb29tMjogKG51bSkgbnVtYmVyIG9mIGJlZHJvb21zIChmcm9tIGFuIGFsdGVybmF0ZSBkYXRhIHNvdXJjZSkKMTEuIEJhdGhyb29tOiAobnVtKSBudW1iZXIgb2YgYmF0aHJvb21zCjEyLiBDYXI6IChudW0pIG51bWJlciBvZiBjYXIgcGFya2luZyBvciBnYXJhZ2Ugc3BhY2VzCjEzLiBMYW5kc2l6ZTogKG51bSkgbGFuZCBhcmVhIG9mIHRoZSBwcm9wZXJ0eSBpbiBzcXVhcmUgbWV0ZXJzCjE0LiBDb3VuY2lsQXJlYTogKGNhdCkgbmFtZSBvZiB0aGUgbG9jYWwgZ292ZXJuaW5nIGNvdW5jaWwgZm9yIHRoZSBwcm9wZXJ0eQoxNS4gTGF0dGl0dWRlOiAobnVtKSBsYXRpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBwcm9wZXJ0eQoxNi4gTG9uZ3RpdHVkZTogKG51bSkgbG9uZ2l0dWRlIGNvb3JkaW5hdGUgb2YgdGhlIHByb3BlcnR5CjE3LiBSZWdpb25uYW1lOiAoY2F0KSBicm9hZGVyIHJlZ2lvbiBjbGFzc2lmaWNhdGlvbiBvZiB0aGUgc3VidXJiCjE4LiBQcm9wZXJ0eWNvdW50OiAobnVtKSB0b3RhbCBudW1iZXIgb2YgcHJvcGVydGllcyB3aXRoaW4gdGhlIHN1YnVyYgoxOS4gU2FsZVllYXI6IChudW0pIG51bWVyaWMgeWVhciBvZiBzYWxlIGV4dHJhY3RlZCBmcm9tIHRoZSBEYXRlIHZhcmlhYmxlCjIwLiBTYWxlTW9udGg6IChjYXQpIG1vbnRoIG9mIHNhbGUgZXh0cmFjdGVkIGZyb20gdGhlIERhdGUgdmFyaWFibGUgKGFiYnJldmlhdGVkIGZvcm0pCjIxLiBMb2dQcmljZTogKG51bSkgbG9nLXRyYW5zZm9ybWVkIHNhbGUgcHJpY2UgdXNlZCB0byByZWR1Y2Ugc2tld25lc3MgaW4gUHJpY2UKMjIuIENvdW5jaWxBcmVhR3JvdXBlZDogKGNhdCkgZ3JvdXBlZCB2ZXJzaW9uIG9mIGNvdW5jaWwgYXJlYXMgdG8gY29uc29saWRhdGUgc21hbGxlciBjYXRlZ29yaWVzCjIzLiBTdWJ1cmJHcm91cGVkOiAoY2F0KSBncm91cGVkIHZlcnNpb24gb2Ygc3VidXJicyBmb3IgaW1wcm92ZWQgbW9kZWwgc3RhYmlsaXR5CjI0LiBTZWxsZXJCaW5hcnk6IChudW0pIGJpbmFyeSB2YXJpYWJsZSBmb3Igc2VsbGVyIHR5cGUgKDEgPSBsYXJnZS9tYWpvciBhZ2VuY3ksIDAgPSBzbWFsbC9sb2NhbCBhZ2VuY3kpCjI1LiBTb2xkQmluYXJ5OiAobnVtKSBiaW5hcnkgaW5kaWNhdG9yIG9mIHNhbGUgc3RhdHVzICgxID0gc29sZCBieSBhbnkgbWV0aG9kLCAwID0gbm90IHNvbGQpCgpgYGB7cn0KdXJsID0iaHR0cHM6Ly9jaGxvZXdpbnRlcnM3OS5naXRodWIuaW8vU1RBNTUxL0RhdGEvTWVsYm91cm5lSG91c2luZ19DbGVhbmVkLmNzdiIKaG91c2VfY2xlYW5lZCA9IHJlYWQuY3N2KHVybCwgaGVhZGVyID0gVFJVRSkKCmhvdXNlX2NsZWFuZWQgPC0gc3Vic2V0KGhvdXNlX2NsZWFuZWQsIFJlZ2lvbm5hbWUgIT0gIiNOL0EiKQoKYGBgCgojIE1ldGhvZG9sb2d5CgpXaXRoIHRoaXMgZGF0YSBzZXQgd2UgYXJlIGFpbWluZyB0byBhbmFseXplIHR3byBzcGVjaWZpYyBxdWVzdGlvbnMuVGhlIGxpbmVhciBtb2RlbCB3aWxsIGNvdmVyIHdoYXQgdmFyaWFibGVzIGhlbHAgcHJlZGljdCB0aGUgc2VsbGluZyBwcmljZSBvZiB0aGUgaG91c2UuIFRoZSBsb2dpc3RpYyBtb2RlbCB3aWxsIGNvdmVyIHdoYXQgdmFyaWFibGVzIGhlbHAgcHJlZGljdCB3aGV0aGVyIG9yIG5vdCB0aGUgaG91c2Ugd2lsbCBzZWxsLiBUaHJlZSBjYW5kaWRhdGUgbW9kZWxzIHdpbGwgYmUgdGVzdGVkIGZvciB0aGUgbGluZWFyIGFuZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscywgYSBwcmFjdGljYWwsIGV4cGFuZGVkLCBhbmQgc3RlcHdpc2UgbW9kZWwuIFRoZSB0aHJlZSBtb2RlbHMgbGluZWFyIG1vZGVscyB3aWxsIHVuZGVyZ28gY3Jvc3MgdmFsaWRhdGlvbiBhbmQgYSBmaW5hbCBtb2RlbCB3aWxsIGJlIHNlbGVjdGVkIGFuZCBpbnRlcnByZXRlZCBpbiBjb250ZXh0LiBUaGUgdGhyZWUgbG9naXN0aWMgbW9kZWxzIHdpbGwgYmUgYXNzZXNzZWQgd2l0aCBhIGNyb3NzIGZvbGQgdmFsaWRhdGlvbiBhbmQgUk9DIGFuYWx5c2lzIHRoZW4gdGhlIG9wdGltYWwgY3V0LW9mZiB3aWxsIGJlIGRldGVybWluZWQgZm9yIHRoZSBmaW5hbCBtb2RlbCBhbmQgaXQgd2lsbCBiZSBhc3Nlc3NlZCBhY2NvcmRpbmdseS4gCgojIyBMaW5lYXIgUmVncmVzc2lvbiBNb2RlbGluZwoKSW4gb3VyIGxpbmVhciBtb2RlbCB3ZSBhcmUgbG9va2luZyB0byBzZWUgd2hhdCB2YXJpYWJsZXMgaGVscCBwcmVkaWN0IHRoZSBzZWxsaW5nIHByaWNlIG9mIHRoZSBob3VzZS4gVW5kZXJzdGFuZGluZyBhIGxpa2VseSBzZWxsaW5nIHBvaW50IGZvciBhIGhvbWUgY2FuIGJlIHZlcnkgaGVscGZ1bCBiZWNhdXNlIGl0IGdpdmVzIHRoZSBzZWxsZXIgcmVhbGlzdGljIGV4cGVjdGF0aW9ucyBhbmQgaGVscHMgd2l0aCBzZXR0aW5nIGEgbGlzdGluZyBwcmljZS4gRXNwZWNpYWxseSBpbiBzY2VuYXJpb3Mgd2hlcmUgdGhlIHNlbGxlciB3YW50cyB0byBzZWxsIGEgaG91c2UgZmFzdCwgcHV0dGluZyBhIGhvdXNlIGZvciBzYWxlIGF0IGEgcHJpY2UgcG9pbnQgbXVjaCBoaWdoZXIgdGhhbiB0aGUgcmVhbGlzdGljIHNlbGxpbmcgcHJpY2UgY2FuIGNhdXNlIGEgaG91c2UgdG8gc2l0IG9uIHRoZSBtYXJrZXQgZm9yIG11Y2ggbG9uZ2VyLiBVbmRlcnN0YW5kaW5nIHdoYXQgdGhhdCByZWFsaXN0aWMgc2VsbGluZyBwcmljZSBpcyBmb3IgdGhlIGhvdXNlIGlzIHZpdGFsIGZvciBzZXR0aW5nIHRoZSBzdGFydGluZyBwcmljZS4KCiMjIyBDYW5pZGF0ZSBNb2RlbHMKClRvIHN0YXJ0IHRoZSBsaW5lYXIgcmVncmVzc2lvbiB0aGUgYXNzaWdubWVudCBhc2tzIGZvciBhIG1vZGVsIHRvIGJlIGNyZWF0ZWQgdXNpbmcgcHJhY3RpY2FsIHZhcmlhYmxlcy4gU2luY2Ugd2UgYXJlIGFuYWx5emluZyBvdXIgcHJhY3RpY2FsIHF1ZXN0aW9uIHJlZ2FyZGluZyBwcmljZSwgd2hpY2ggd2UgZGlkIHRha2UgdGhlIGxvZyBvZiBpbiB0aGUgRURBIGFuZCBFbmdpbmVlcmluZyBzZWN0aW9uLCB3ZSBkZWNpZGVkIHRvIG1ha2UgYSBtb2RlbCB3aXRoIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzLCBSb29tcywgQmF0aHJvb20sIENhciwgYW5kIERpc3RhbmNlLiBGcm9tIHRoZSBzdW1tYXJ5IG91dHB1dCwgYWxsIHRoZSB2YXJpYWJsZXMgaGF2ZSBhIHAtdmFsdWUgbGVzcyB0aGFuIDAuMDUgYW5kIGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBhbmQgdGhlIHNhbWUgYXBwbGllcyB0byB0aGUgb3ZlcmFsbCBtb2RlbC4gCgpgYGB7cn0KIyBQcmFjdGljYWwgTW9kZWwKbG1fcHJhY3RpY2FsIDwtIGxtKExvZ1ByaWNlIH4gUm9vbXMgKyBCYXRocm9vbSArIENhciArIERpc3RhbmNlLCBkYXRhID0gaG91c2VfY2xlYW5lZCkKc3VtbWFyeShsbV9wcmFjdGljYWwpCmBgYApGb3IgdGhlIHNlY29uZCBtb2RlbCB0aGUgYXNzaWdubWVudCBjYWxscyBmb3IgYWRkaXRpb25hbCBtb2RlbHMgdG8gYmUgYWRkZWQgdG8gdGhlIGluaXRpYWwgcHJhY3RpY2FsIG1vZGVsIHRvIG1ha2UgYSBtb3JlIGV4cGFuZGVkIG1vZGVsLiBJbiBhZGRpdGlvbiB0byB0aGUgdmFyaWFibGVzIGluIHRoZSBmaXJzdCBwcmFjdGljYWwgbW9kZWwgdGhpcyBtb2RlbCBpbmNsdWRlcywgU2VsbGVyQmluYXJ5LCBSZWdpb25uYW1lLCBhbmQgUHJvcGVydHljb3VudC4gTG9va2luZyBhdCB0aGUgc3VtbWFyeSBvdXRwdXQgZm9yIHRoZSBtb2RlbCB0aGVyZSBpcyBvbmUgdmFyaWFibGUgdGhhdCBkb2VzIG5vdCBoYXZlIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSwgd2hpY2ggaXMgUmVnaW9ubmFtZU5vcnRoZXJuIFZpY3RvcmlhLiBIb3dldmVyIGFsbCB0aGUgb3RoZXIgc3Vic2V0cyBvZiB0aGUgUmVnaW9ubmFtZSB2YXJpYWJsZSBoYXZlIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSBpbmRpY2F0aW5nIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZS4gVGhlIG1vZGVsIGFsc28gaGFzIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSBhbmQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KCgpgYGB7cn0KIyBFeHRlbmRlZCBNb2RlbApsbV9leHRlbmRlZCA8LSBsbShMb2dQcmljZSB+IFJvb21zICsgQmF0aHJvb20gKyBDYXIgKyBEaXN0YW5jZSArIFNlbGxlckJpbmFyeSArIFJlZ2lvbm5hbWUgKyBQcm9wZXJ0eWNvdW50LCBkYXRhID0gaG91c2VfY2xlYW5lZCkKc3VtbWFyeShsbV9leHRlbmRlZCkKYGBgCgpGaW5hbGx5LCB0aGUgYXNzaWdubWVudCBhc2tzIGZvciBhIHZhcmlhYmxlIHNlbGVjdGlvbiBtZXRob2QgdG8gaWRlbnRpZnkgdGhlIG9wdGltYWwgZmluYWwgbW9kZWwuIEZvciB0aGlzIGRhdGEgc2V0LCBzdGVwd2lzZSBkaXJlY3Rpb24gd2lsbCBiZSB1c2VkIHRvIGRldGVybWluZSB0aGUgb3B0aW1hbCBtb2RlbC4gVGhlIGZpbmFsIG1vZGVsIHR1cm5zIG91dCB0byBiZSBhIHJlcGxpY2Egb2YgdGhlIGV4dGVuZGVkIG1vZGVsLCBub25lIG9mIHRoZSB2YXJpYWJsZXMgd2VyZSByZW1vdmVkIGFuZCBubyBuZXcgdmFyaWFibGVzIHdlcmUgYWRkZWQuIAoKYGBge3J9CgpsbV9zdGVwIDwtIHN0ZXBBSUMobG1fZXh0ZW5kZWQsIGRpcmVjdGlvbiA9ICJib3RoIiwgdHJhY2UgPSBGQUxTRSkKc3VtbWFyeShsbV9zdGVwKQoKIyBWaWV3IGZpbmFsIG1vZGVsIGZvcm11bGEKZm9ybXVsYShsbV9zdGVwKQpgYGAKCiMjIyBDcm9zcyBWYWxpZGF0aW9uIGFuZCBNb2RlbCBTZWxlY3Rpb24KCk5vdyB0aGF0IGFsbCB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIGhhdmUgYmVlbiBjcmVhdGVkIHRoZXkgbmVlZCB0byB1bmRlcmdvIGNyb3NzIHZhbGlkYXRpb24gc28gdGhlIGZpbmFsIG9wdGltYWwgbW9kZWwgY2FuIGJlIHNlbGVjdGVkIGFuZCB0aGVuIHRlc3RlZC4gRm9yIHRoaXMgcHJvamVjdCA3NSUgb2YgdGhlIGRhdGEgd2lsbCBiZSB1c2VkIGF0IHRoZSB0cmFpbmluZyBkYXRhIHdoaWxlIHRoZSByZW1haW5pbmcgMjUlIHdpbGwgYmUgdXNlZCBmb3IgdGVzdGluZy4gVGhlc2UgY3V0IG9mZnMgYXJlIGR1ZSB0byB3aGF0IHRoZSBwcm9qZWN0IGd1aWRlbGluZXMgY2FsbCBmb3IuIAoKCmBgYHtyfQoKIyMgMS4gU2V0IHVwIHRyYWluL3Rlc3Qgc3BsaXQKCnNldC5zZWVkKDEyMykKbiA8LSBucm93KGhvdXNlX2NsZWFuZWQpCnRyYWluLm4gPC0gcm91bmQoMC43NSAqIG4pCnRyYWluLmlkIDwtIHNhbXBsZSgxOm4sIHRyYWluLm4sIHJlcGxhY2UgPSBGQUxTRSkKCnRyYWluIDwtIGhvdXNlX2NsZWFuZWRbdHJhaW4uaWQsIF0KdGVzdCAgPC0gaG91c2VfY2xlYW5lZFstdHJhaW4uaWQsIF0KCgoKIyMgMi4gUmVtb3ZlIHJvd3Mgd2l0aCBtaXNzaW5nIHZhbHVlcwoKIyBQcmFjdGljYWwgbW9kZWwgdmFyaWFibGVzCnByYWN0aWNhbF92YXJzIDwtIGMoIkxvZ1ByaWNlIiwgIlJvb21zIiwgIkJhdGhyb29tIiwgIkNhciIsICJEaXN0YW5jZSIpCnRyYWluX3ByYWN0aWNhbCA8LSB0cmFpbltjb21wbGV0ZS5jYXNlcyh0cmFpblssIHByYWN0aWNhbF92YXJzXSksIF0KdGVzdF9wcmFjdGljYWwgIDwtIHRlc3RbY29tcGxldGUuY2FzZXModGVzdFssIHByYWN0aWNhbF92YXJzXSksIF0KCiMgRXh0ZW5kZWQvU3RlcHdpc2UgbW9kZWwgdmFyaWFibGVzCmV4dGVuZGVkX3ZhcnMgPC0gYygiTG9nUHJpY2UiLCAiUm9vbXMiLCAiQmF0aHJvb20iLCAiQ2FyIiwgIkRpc3RhbmNlIiwKICAgICAgICAgICAgICAgICAgICJTZWxsZXJCaW5hcnkiLCAiUmVnaW9ubmFtZSIsICJQcm9wZXJ0eWNvdW50IikKdHJhaW5fZXh0ZW5kZWQgPC0gdHJhaW5bY29tcGxldGUuY2FzZXModHJhaW5bLCBleHRlbmRlZF92YXJzXSksIF0KdGVzdF9leHRlbmRlZCAgPC0gdGVzdFtjb21wbGV0ZS5jYXNlcyh0ZXN0WywgZXh0ZW5kZWRfdmFyc10pLCBdCgoKIyMgMy4gU2V0IHVwIGNyb3NzLXZhbGlkYXRpb24KCnRyYWluX2NvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQoKCiMjIDQuIENyb3NzLXZhbGlkYXRpb24gLSBQcmFjdGljYWwgTW9kZWwKCmN2X3ByYWN0aWNhbCA8LSB0cmFpbigKICBMb2dQcmljZSB+IFJvb21zICsgQmF0aHJvb20gKyBDYXIgKyBEaXN0YW5jZSwKICBkYXRhID0gdHJhaW5fcHJhY3RpY2FsLAogIG1ldGhvZCA9ICJsbSIsCiAgdHJDb250cm9sID0gdHJhaW5fY29udHJvbAopCgoKIyMgNS4gQ3Jvc3MtdmFsaWRhdGlvbiAtIEV4dGVuZGVkIE1vZGVsCgpjdl9leHRlbmRlZCA8LSB0cmFpbigKICBMb2dQcmljZSB+IFJvb21zICsgQmF0aHJvb20gKyBDYXIgKyBEaXN0YW5jZSArIFNlbGxlckJpbmFyeSArIFJlZ2lvbm5hbWUgKyBQcm9wZXJ0eWNvdW50LAogIGRhdGEgPSB0cmFpbl9leHRlbmRlZCwKICBtZXRob2QgPSAibG0iLAogIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wKKQoKCiMjIDYuIENyb3NzLXZhbGlkYXRpb24gLSBTdGVwd2lzZSBNb2RlbAoKY3Zfc3RlcCA8LSB0cmFpbigKICBmb3JtdWxhKGxtX3N0ZXApLAogIGRhdGEgPSB0cmFpbl9leHRlbmRlZCwgICMgc3RlcHdpc2UgbW9kZWwgdXNlcyBzYW1lIHZhcmlhYmxlcyBhcyBleHRlbmRlZAogIG1ldGhvZCA9ICJsbSIsCiAgdHJDb250cm9sID0gdHJhaW5fY29udHJvbAopCgpgYGAKClRoZSBjcm9zcyB2YWxpZGF0aW9uIFJNU0UgYW5kIFJzcXVhcmVkIHJlc3VsdHMgZm9yIHRoZSB0aHJlZSBtb2RlbHMgYXJlIHNob3duIGJlbG93LiBJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCBhcyBhZGRyZXNzZWQgZWFybGllciB0aGUgZXh0ZW5kZWQgYW5kIHN0ZXB3aXNlIG1vZGVscyBhcmUgdGhlIGV4YWN0IHNhbWUgbW9kZWwgc28gdGhlaXIgcmVzdWx0cyBzaG91bGQgYmUgdGhlIHNhbWUuIEluIHRoaXMgb3V0cHV0IHdlIGFyZSBsb29raW5nIGZvciB0aGUgbG93ZXN0IFJTTUUgYmVjYXVzZSB0aGF0IGlzIHdoYXQgaW5kaWNhdGVzIHRoZSBiZXR0ZXIgcGVyZm9ybWFuY2UgYW5kIHRoZW4gd2UgYXJlIGxvb2tpbmcgZm9yIHRoZSBoaWdoZXIgUnNxdWFyZWQgdmFsdWUgd2hpY2ggaW5kaWNhdGVzIHN0cm9uZ2VyIHByZWRpY3RpdmUgcG93ZXIuIEZyb20gdGhlIG91dHB1dCBpdCBsb29rcyBsaWtlIHRoZSBleHRlbmRlZC9zdGVwd2lzZSBtb2RlbHMgaGF2ZSB0aGUgbG93ZXIgUlNNRSBhdCAwLjM0MTY3NDEgY29tcGFyZWQgdG8gdGhlIHByYWN0aWNhbCBtb2RlbHMgMC4zOTAxMDIwIGFuZCBhIGhpZ2hlciBSc3F1YXJlZCBhdCAwLjU2MTUwNjkJY29tcGFyZWQgdG8gdGhlIHByYWN0aWNhbCBtb2RlbHMgMC40Mjg0MjU2LiBUaGlzIHNob3dzIHVzIHRoYXQgdGhlIGV4dGVuZGVkL3N0ZXB3aXNlIG1vZGVsIGJlaW5nIHRoZSBvcHRpbWFsIG1vZGVsLCBmb3IgY2xhcml0eSBzYWtlIHNpbmNlIHRoZXkgYXJlIHRoZSBzYW1lIG1vZGVsIHdlIHdpbGwgYmUgcmVmZXJpbmcgdG8gdGhlIG1vZGVsIGFzIHRoZSBmaW5hbCBtb2RlbCBtb3ZpbmcgZm9yd2FyZC4gCQoKYGBge3J9CiMgQ3Jvc3MgVmFsaWRhdGlvbiBSZXN1bHRzCmN2X3Jlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBNb2RlbCA9IGMoIlByYWN0aWNhbCIsICJFeHRlbmRlZCIsICJTdGVwd2lzZSIpLAogIFJNU0UgID0gYyhjdl9wcmFjdGljYWwkcmVzdWx0cyRSTVNFLAogICAgICAgICAgICBjdl9leHRlbmRlZCRyZXN1bHRzJFJNU0UsCiAgICAgICAgICAgIGN2X3N0ZXAkcmVzdWx0cyRSTVNFKSwKICBSc3EgICA9IGMoY3ZfcHJhY3RpY2FsJHJlc3VsdHMkUnNxdWFyZWQsCiAgICAgICAgICAgIGN2X2V4dGVuZGVkJHJlc3VsdHMkUnNxdWFyZWQsCiAgICAgICAgICAgIGN2X3N0ZXAkcmVzdWx0cyRSc3F1YXJlZCkKKQoKY3ZfcmVzdWx0cwpgYGAKCk5vdyB0aGF0IHdlIGhhdmUgZGV0ZXJtaW5lZCB0aGUgZmluYWwgbW9kZWwgaXQgaXMgdGltZSB0byBhc3Nlc3MgaXQgdXNpbmcgdGhlIHRlc3RpbmcgZGF0YSB0aGF0IHdhcyBzZXQgYXNzaWRlIGVhcmxpZXIuIFRoZSBSU01FIGFuZCBSc3F1YXJlZCB2YWx1ZXMgZm9yIHRoZSBmaW5hbCBtb2RlbCB3ZXJlIGNhbGN1bGF0ZWQgYW5kIGFyZSAwLjM0OSBmb3IgdGhlIFJNU0UgYW5kIDAuNTU4NCBmb3IgdGhlIFJzcXVhcmVkLiBUaGVzZSBhcmUgYSB0aW55IGJpdCB3ZWFrZXIgdGhhbiBvdXIgcmVzdWx0cyBmcm9tIHRoZSB0cmFpbmluZyBkYXRhIHNldCBidXQgd2UgZG8gbm90IGV4cGVjdCB0aGUgcmVzdWx0cyB0byBtYXRjaCBleGFjdGx5IGFuZCB0aGV5IGFyZSBzbyBjbG9zZSBpdCBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgY29uY2VyaW5nLgoKYGBge3J9CgojQ2xlYW4gdGVzdCBzZXQgZm9yIGZpbmFsIG1vZGVsCgpmaW5hbF92YXJzIDwtIGMoIkxvZ1ByaWNlIiwgIlJvb21zIiwgIkJhdGhyb29tIiwgIkNhciIsICJEaXN0YW5jZSIsCiAgICAgICAgICAgICAgICAiU2VsbGVyQmluYXJ5IiwgIlJlZ2lvbm5hbWUiLCAiUHJvcGVydHljb3VudCIpCgp0ZXN0X2NsZWFuIDwtIHRlc3RbY29tcGxldGUuY2FzZXModGVzdFssIGZpbmFsX3ZhcnNdKSwgXQoKCiMgUHJlZGljdCBvbiBjbGVhbmVkIHRlc3Qgc2V0CgpwcmVkX3Rlc3QgPC0gcHJlZGljdChsbV9zdGVwLCBuZXdkYXRhID0gdGVzdF9jbGVhbikKCgojIENhbGN1bGF0ZSBSTVNFIGFuZCBSLXNxdWFyZWQKCnJtc2VfdGVzdCA8LSBzcXJ0KG1lYW4oKHByZWRfdGVzdCAtIHRlc3RfY2xlYW4kTG9nUHJpY2UpXjIpKQpyc3FfdGVzdCAgPC0gMSAtIHN1bSgocHJlZF90ZXN0IC0gdGVzdF9jbGVhbiRMb2dQcmljZSleMikgLyAKICAgICAgICAgICAgICAgICAgc3VtKChtZWFuKHRyYWluJExvZ1ByaWNlLCBuYS5ybSA9IFRSVUUpIC0gdGVzdF9jbGVhbiRMb2dQcmljZSleMikKCgoKIyBPdXRwdXQKCmNhdCgiTGluZWFyIFJlZ3Jlc3Npb24gLSBGaW5hbCBTdGVwd2lzZSBNb2RlbCBQZXJmb3JtYW5jZSBvbiBUZXN0IFNldFxuIikKY2F0KCJSTVNFOiIsIHJvdW5kKHJtc2VfdGVzdCwgNCksICJcbiIpCmNhdCgiUi1zcXVhcmVkOiIsIHJvdW5kKHJzcV90ZXN0LCA0KSwgIlxuIikKCmBgYAoKIyMjIFJlc3VsdHMgYW5kIENvbmNsdXNpb25zCgpUaGUgZmluYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgZGVtb25zdHJhdGVzIHRoYXQgUm9vbXMsIEJhdGhyb29tLCBDYXIsIERpc3RhbmNlLCBTZWxsZXJCaW5hcnksIFJlZ2lvbm5hbWUsIGFuZCBQcm9wZXJ0eWNvdW50IGFyZSBpbXBvcnRhbnQgcHJlZGljdG9ycyBvZiB0aGUgbG9nLXRyYW5zZm9ybWVkIHNlbGxpbmcgcHJpY2UuIFRoZSBtb2RlbCBwZXJmb3JtcyB3ZWxsIGJvdGggaW4gY3Jvc3MtdmFsaWRhdGlvbiBhbmQgb24gdGhlIGhlbGQtb3V0IHRlc3Qgc2V0LCB3aXRoIHN0cm9uZyBwcmVkaWN0aXZlIGFjY3VyYWN5IGFuZCBleHBsYW5hdG9yeSBwb3dlci4gVGhlc2UgcmVzdWx0cyBwcm92aWRlIGEgdXNlZnVsIHRvb2wgZm9yIGVzdGltYXRpbmcgcmVhbGlzdGljIGhvdXNlIHByaWNlcyBhbmQgY2FuIGFzc2lzdCBzZWxsZXJzIGluIHNldHRpbmcgY29tcGV0aXRpdmUgbGlzdGluZyBwcmljZXMuCgpUaGUgZmluYWwgc3RlcHdpc2UgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2FzIGRldmVsb3BlZCB0byBwcmVkaWN0IHRoZSBsb2ctdHJhbnNmb3JtZWQgc2VsbGluZyBwcmljZSAoTG9nUHJpY2UpIG9mIGhvdXNlcyBiYXNlZCBvbiBzZXZlcmFsIHByZWRpY3RvcnMsIGluY2x1ZGluZyBzdHJ1Y3R1cmFsIGZlYXR1cmVzLCBsb2NhdGlvbiwgc2VsbGVyIHR5cGUsIGFuZCBsb2NhbCBwcm9wZXJ0eSBkZW5zaXR5LiBUaGUgbW9kZWwgZGVtb25zdHJhdGVzIHN0cm9uZyBleHBsYW5hdG9yeSBwb3dlciwgd2l0aCBhIE11bHRpcGxlIFItc3F1YXJlZCBvZiAwLjU2MDQuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYXBwcm94aW1hdGVseSA1NiUgb2YgdGhlIHZhcmlhdGlvbiBpbiBsb2cgcHJpY2VzIGlzIGV4cGxhaW5lZCBieSB0aGUgdmFyaWFibGVzIGluIHRoZSBtb2RlbC4gVGhlIFJlc2lkdWFsIFN0YW5kYXJkIEVycm9yIG9mIDAuMzQzNSBzdWdnZXN0cyB0aGF0IHByZWRpY3Rpb25zIGFyZSBnZW5lcmFsbHkgY2xvc2UgdG8gb2JzZXJ2ZWQgdmFsdWVzLgoKU3RydWN0dXJhbCBmZWF0dXJlcyBvZiB0aGUgcHJvcGVydHkgc2lnbmlmaWNhbnRseSBpbmZsdWVuY2UgaG91c2UgcHJpY2VzLiBTcGVjaWZpY2FsbHksIHRoZSBudW1iZXIgb2Ygcm9vbXMsIGJhdGhyb29tcywgYW5kIGNhciBzcGFjZXMgYWxsIGhhdmUgcG9zaXRpdmUgYW5kIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZWZmZWN0cy4gRWFjaCBhZGRpdGlvbmFsIHJvb20gaW5jcmVhc2VzIHRoZSBsb2cgcHJpY2UgYnkgYXBwcm94aW1hdGVseSAwLjI4OCwgd2hpbGUgYW4gZXh0cmEgYmF0aHJvb20gb3IgY2FyIHNwYWNlIGluY3JlYXNlcyBpdCBieSAwLjA2NSBhbmQgMC4wNDYsIHJlc3BlY3RpdmVseS4gVGhlc2UgcmVzdWx0cyBpbmRpY2F0ZSB0aGF0IGxhcmdlciBob21lcyB3aXRoIG1vcmUgYW1lbml0aWVzIGNvbW1hbmQgaGlnaGVyIHByaWNlcywgd2hpY2ggaXMgdG8gYmUgZXhwZWN0ZWQuIAoKVGhlIGxvY2F0aW9uIG9mIHRoZSBob3VzZSBhbHNvIHBsYXlzIGEgY3JpdGljYWwgcm9sZSBpbiBkZXRlcm1pbmluZyBob3VzZSBwcmljZXMuIERpc3RhbmNlIGZyb20gYSBjZW50cmFsIHJlZmVyZW5jZSBwb2ludCBuZWdhdGl2ZWx5IGFmZmVjdHMgcHJpY2UsIHdpdGggYW4gZXN0aW1hdGVkIGRlY3JlYXNlIG9mIDAuMDM2IGluIGxvZyBwcmljZSBwZXIgYWRkaXRpb25hbCB1bml0IG9mIGRpc3RhbmNlLiBSZWdpb25hbCBlZmZlY3RzIGFyZSBwcm9ub3VuY2VkOiBwcm9wZXJ0aWVzIGluIEVhc3Rlcm4gVmljdG9yaWEgYW5kIHRoZSBTb3V0aC1FYXN0ZXJuIE1ldHJvcG9saXRhbiByZWdpb24gYXJlIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgcHJpY2VzLCB3aGVyZWFzIGhvbWVzIGluIFdlc3Rlcm4gTWV0cm9wb2xpdGFuIGFuZCBXZXN0ZXJuIFZpY3RvcmlhIGFyZSBhc3NvY2lhdGVkIHdpdGggbG93ZXIgcHJpY2VzLiBOb3RhYmx5LCBOb3J0aGVybiBWaWN0b3JpYSBkb2VzIG5vdCBzaG93IGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBlZmZlY3QuCgpBZGRpdGlvbmFsIHZhcmlhYmxlcyBzdWNoIGFzIHNlbGxlciB0eXBlIGFuZCBsb2NhbCBwcm9wZXJ0eSBkZW5zaXR5IGhhdmUgc21hbGxlciBidXQgbWVhbmluZ2Z1bCBpbXBhY3RzLiBIb3VzZXMgc29sZCBieSBsYXJnZXIgc2VsbGVycyB0ZW5kIHRvIGJlIHNsaWdodGx5IGhpZ2hlciBpbiBwcmljZSwgd2hpbGUgYW4gaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBuZWFyYnkgcHJvcGVydGllcyBpcyBhc3NvY2lhdGVkIHdpdGggYSB2ZXJ5IHNtYWxsIHJlZHVjdGlvbiBpbiBwcmljZSwgcmVmbGVjdGluZyBtaW5vciBsb2NhbCBzdXBwbHkgZWZmZWN0cy4KCk92ZXJhbGwsIHRoaXMgbW9kZWwgcHJvdmlkZXMgYSBmcmFtZXdvcmsgZm9yIHByZWRpY3RpbmcgaG91c2UgcHJpY2VzLCBoaWdobGlnaHRpbmcgdGhlIGltcG9ydGFuY2Ugb2Ygc3RydWN0dXJhbCBjaGFyYWN0ZXJpc3RpY3MsIGxvY2F0aW9uLCBhbmQgbWFya2V0IGNvbnRleHQuIFRoZXNlIHJlc3VsdHMgb2ZmZXIgIGluc2lnaHRzIGZvciBzZWxsZXJzIGluIHNldHRpbmcgcmVhbGlzdGljIGxpc3RpbmcgcHJpY2VzIGFuZCBmb3IgYnV5ZXJzIGluIHVuZGVyc3RhbmRpbmcgaG93IHNwZWNpZmljIGZlYXR1cmVzIGFuZCBsb2NhdGlvbnMgaW5mbHVlbmNlIGhvdXNpbmcgdmFsdWUuCgojIyBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsaW5nCgpJbiBvdXIgbG9naXN0aWMgbW9kZWwgd2UgYXJlIGxvb2tpbmcgdG8gc2VlIHdoYXQgdmFyaWFibGVzIGhlbHAgcHJlZGljdCB3aGV0aGVyIG9yIG5vdCBhIGhvdXNlIHdpbGwgc2VsbC4gVW5kZXJzdGFuZGluZyB0aGUgbGlrZWxpaG9vZCBvZiBhIGhvdXNlIHNlbGxpbmcgaXMgdmVyeSBpbXBvcnRhbnQgYmVjYXVzZSBpZiBzb21lIG9mIHRoZSBzaWduaWZpY2FudCBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSB0aGluZ3MgdGhhdCBjYW4gYmUgbWFuaXB1bGF0ZWQgbGlrZSBwcmljZSBvciBzdHJ1Y3R1cmFsIGZlYXR1cmVzIHRoZSBzZWxsZXIgY2FuIGNoYW5nZSB0aGVzZSB0aGluZ3MuIFRoaXMgd2F5IHRoZSBzZWxsZXIgY2FuIG1ha2UgYWxsIHRoZSBuZWNlc3NhcnkgYWRqdXN0bWVudHMgYmVmb3JlIGJyaW5naW5nIGEgaG91c2UgdG8gbWFya2V0IHRvIGdpdmUgaXQgdGhlIGJlc3QgY2hhbmNlIG9mIHNlbGxpbmcuIAoKIyMjIENhbmlkYXRlIE1vZGVscwoKTm93IG1vdmluZyBvbnRvIHRoZSBsb2dpc3RpYyBtb2RlbGluZywgdGhpcyB3aWxsIGxvb2sgYXQgdGhlIG1vZGVscyBmb3Igb3VyIHNlY29uZCBwcmFjdGljYWwgcXVlc3Rpb24gd2hpY2ggbG9va3MgYXQgd2hldGhlciBvciBub3QgYSBob3VzZSBzb2xkLiBTdGFydGluZyBhZ2FpbiB3aXRoIHRoZSBwcmFjdGljYWwgbW9kZWwgaXQgY29udGFpbnMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMsIExvZ1ByaWNlLCBSb29tcywgYW5kIERpc3RhbmNlLiBMb29raW5nIGF0IHRoZSBvdXRwdXQgc3VtbWFyeSwgdGhlIHZhcmlhYmxlIExvZ1ByaWNlIGhhcyBhIHAtdmFsdWUgbGFyZ2VyIHRoYW4gMC4wNSBhbmQgd291bGQgbm90IGJlIGNvbnNpZGVyZWQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgd2hpbGUgdGhlIHZhcmlhYmxlcyBSb29tcyBhbmQgRGlzdGFuY2UgZG8gaGF2ZSBwLXZhbHVlcyBzbWFsbGVyIHRoYW4gMC4wNSBhbmQgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuCgpgYGB7cn0KIyBQcmFjdGljYWwgTW9kZWwKbG9naXRfcHJhY3RpY2FsIDwtIGdsbShTb2xkQmluYXJ5IH4gTG9nUHJpY2UgKyBSb29tcyArIERpc3RhbmNlLAogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBob3VzZV9jbGVhbmVkLCBmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShsb2dpdF9wcmFjdGljYWwpCmBgYAoKTW92aW5nIG9udG8gdGhlIHRoZSBleHRlbmRlZCBtb2RlbCB0aGUgdmFyaWFibGVzIGZyb20gdGhlIHByYWN0aWNhbCBtb2RlbCBhcmUgc3RpbGwgYmVpbmcgdXNlZCwgd2l0aCB0aGUgYWRkaXRpb24gb2YgU2VsbGVyQmluYXJ5LCBSZWdpb25uYW1lLCBDYXIgYW5kIEJhdGhyb29tLiBJbiB0aGlzIG1vZGVsIHRocmVlIG9mIHRoZSBkaWZmZXJlbnQgUmVnaW9ubmFtZSBzdWIgdmFyaWFibGVzIGhhdmUgYSBwLXZhbHVlIGdyZWF0ZXIgdGhhbiAwLjA1IGFuZCBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIEFkZGl0aW9uYWxseSwgdGhlIHZhcmlhYmxlIFNlbGxlckJpbmFyeSBoYXMgYSBwLXZhbHVlIGdyZWF0ZXIgdGhhbiAwLjA1IGFuZCBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gQWxsIG90aGVyIHZhcmlhYmxlcyBoYXZlIGEgcC12YWx1ZSBzbWFsbGVyIHRoYW4gMC4wNSBhbmQgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIAoKCmBgYHtyfQojIyBFeHRlbmRlZCBNb2RlbApsb2dpdF9leHRlbmRlZCA8LSBnbG0oU29sZEJpbmFyeSB+IExvZ1ByaWNlICsgUm9vbXMgKyBEaXN0YW5jZSArIFNlbGxlckJpbmFyeSArCiAgICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbm5hbWUgKyBDYXIgKyBCYXRocm9vbSwgCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gaG91c2VfY2xlYW5lZCwgZmFtaWx5ID0gYmlub21pYWwpCnN1bW1hcnkobG9naXRfZXh0ZW5kZWQpCgpgYGAKCkZpbmFsbHksIHRoZSBhc3NpZ25tZW50IGFza3MgZm9yIGEgdmFyaWFibGUgc2VsZWN0aW9uIG1ldGhvZCB0byBpZGVudGlmeSB0aGUgb3B0aW1hbCBmaW5hbCBtb2RlbC4gRm9yIHRoaXMgZGF0YSBzZXQsIHN0ZXB3aXNlIGFuYWx5c2lzIHdpbGwgYmUgdXNlZCB0byBkZXRlcm1pbmUgdGhlIG9wdGltYWwgbW9kZWwuIEZyb20gdGhlIG91dHB1dCB3ZSBrbm93IHRoZSBmb3JtdWxhIGJlaW5nIHVzZWQgZm9yIHRoZSBmaW5hbCBtb2RlbCBoYXMgdGhlIHZhcmlhYmxlcyBMb2dQcmljZSwgUm9vbXMsIERpc3RhbmNlLCAgUmVnaW9ubmFtZSwgQ2FyLCBhbmQgQmF0aHJvb20uIFNpbWlsYXIgdG8gdGhlIGV4dGVuZGVkIG1vZGVsLCBzb21lIG9mIHRoZSBzdWIgY2F0ZWdvcmllcyBvZiB0aGUgUmVnaW9ubmFtZSB2YXJpYWJsZSBoYXZlIGEgcC12YWx1ZSBsYXJnZXIgdGhhbiAwLjA1IGFuZCBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGhvd2V2ZXIgdGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBkbyBoYXZlIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSBhbmQgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIAoKYGBge3J9CgojIEZpbmFsIE1vZGVsCgpsb2dpdF9maW5hbCA8LSBzdGVwQUlDKGxvZ2l0X2V4dGVuZGVkLCBkaXJlY3Rpb24gPSAiYm90aCIsIHRyYWNlID0gRkFMU0UpCnN1bW1hcnkobG9naXRfZmluYWwpCgojIFZpZXcgZmluYWwgbW9kZWwgZm9ybXVsYQpmb3JtdWxhKGxvZ2l0X2ZpbmFsKQoKYGBgCgojIyMgTW9kZWwgU2VsZWN0aW9uCgpOb3cgdGhhdCB0aGUgdGhyZWUgY2FuZGlkYXRlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzIGhhdmUgYmVlbiBjcmVhdGVkIHRoZXkgbmVlZCB0byB1bmRlcmdvIHRoZSBtb2RlbCBzZWxlY3Rpb24gcHJvY2Vzcy4gU2ltaWxhciB0byB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gcHJvY2VzcywgNzUlIG9mIHRoZSBkYXRhIHdpbGwgYmUgdXNlZCBmb3IgdHJhaW5pbmcgYW5kIHRoZSByZW1haW5pbmcgMjUlIHdpbGwgYmUgdXNlZCBhcyB0aGUgdGVzdGluZyBkYXRhLiBXZSBhcmUgZ29pbmcgdG8gZG8gYSBjcm9zcyBmb2xkIHZhbGlkYXRpb24gcHJvY2VzcyBvbiB0aGUgbW9kZWxzIGFuZCBsb29rIGF0IGFuIFJPQyBjdXJ2ZSB0byBkZXRlcm1pbmUgdGhlIGJlc3QgY2FuaWRhdGUgbW9kZWwuICAKCmBgYHtyfQoKaG91c2VfY2xlYW5lZCA8LSBob3VzZV9jbGVhbmVkICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBSZWdpb25uYW1lID0gbmFfaWYoUmVnaW9ubmFtZSwgIiNOL0EiKSAgIyBjb252ZXJ0ICIjTi9BIiB0byBhY3R1YWwgTkEKICApICU+JQogIHRpZHlyOjpkcm9wX25hKFNvbGRCaW5hcnksIExvZ1ByaWNlLCBSb29tcywgRGlzdGFuY2UsCiAgICAgICAgICAgICAgICAgU2VsbGVyQmluYXJ5LCBSZWdpb25uYW1lLCBDYXIsIEJhdGhyb29tKQpgYGAKClN0YXJ0aW5nIHdpdGggdGhlIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvciBjYWxjdWxhdGlvbnMgdGhlIHRocmVlIG1vZGVscyBoYXZlIHF1aXRlIHNpbWlsYXIgcmVzdWx0cywgd2l0aCB0aGUgcHJhY3RpY2FsIG1vZGVsIGJlaW5nIDAuMTAxMDQ1MSwgYW5kIHRoZSBzdGVwd2lzZSBhbmQgZXh0ZW5kZWQgbW9kZWxzIGJvdGggYmVpbmcgMC4xMDEyNDEuIEluIHRoaXMgY2FzZSB3ZSB3YW50IHRoZSBzbWFsbGVzdCBwcmVkaWN0aXZlIGVycm9yIHdoaWNoIHdvdWxkIGJlIHRoZSBwcmFjdGljYWwgbW9kZWwuIEhvd2V2ZXIsIGJlZm9yZSBtYWtpbmcgYSBmaW5hbCBtb2RlbCBzZWxlY3Rpb24gd2UgYXJlIGFsc28gZ29pbmcgdG8gYXNzZXMgdGhlIFJPQyBjdXJ2ZSBhbmQgQVVDIHZhbHVlcy4KCmBgYHtyfQoKaG91c2VfY2xlYW5lZCRSZWdpb25uYW1lIDwtIGZhY3Rvcihob3VzZV9jbGVhbmVkJFJlZ2lvbm5hbWUpCmhvdXNlX2NsZWFuZWQkUmVnaW9ubmFtZSA8LSBkcm9wbGV2ZWxzKGhvdXNlX2NsZWFuZWQkUmVnaW9ubmFtZSkKCnNldC5zZWVkKDEyMykKCm4gPC0gbnJvdyhob3VzZV9jbGVhbmVkKQp0cmFpbi5uIDwtIHJvdW5kKDAuNzUgKiBuKQp0cmFpbi5pZCA8LSBzYW1wbGUoMTpuLCB0cmFpbi5uLCByZXBsYWNlID0gRkFMU0UpCnRyYWluIDwtIGhvdXNlX2NsZWFuZWRbdHJhaW4uaWQsIF0KdGVzdCAgPC0gaG91c2VfY2xlYW5lZFstdHJhaW4uaWQsIF0KCgprIDwtIDEwCmZvbGQuc2l6ZSA8LSBmbG9vcihucm93KHRyYWluKSAvIGspClBFMSA8LSByZXAoMCwgaykKUEUyIDwtIHJlcCgwLCBrKQpQRTMgPC0gcmVwKDAsIGspCgpmb3IoaSBpbiAxOmspIHsKICB2YWxpZC5pZCA8LSAoZm9sZC5zaXplICogKGkgLSAxKSArIDEpOihmb2xkLnNpemUgKiBpKQogIHZhbGlkIDwtIHRyYWluW3ZhbGlkLmlkLCBdCiAgdHJhaW4uZGF0IDwtIHRyYWluWy12YWxpZC5pZCwgXQoKICB0cmFpbi5kYXQkUmVnaW9ubmFtZSA8LSBmYWN0b3IodHJhaW4uZGF0JFJlZ2lvbm5hbWUpCiAgdHJhaW4uZGF0JFJlZ2lvbm5hbWUgPC0gZHJvcGxldmVscyh0cmFpbi5kYXQkUmVnaW9ubmFtZSkKICAKICB2YWxpZCRSZWdpb25uYW1lIDwtIGZhY3Rvcih2YWxpZCRSZWdpb25uYW1lLCBsZXZlbHMgPSBsZXZlbHModHJhaW4uZGF0JFJlZ2lvbm5hbWUpKQogIAogICMgUHJhY3RpY2FsIE1vZGVsCiAgY2FuZGlkYXRlMDEgPC0gZ2xtKAogICAgU29sZEJpbmFyeSB+IExvZ1ByaWNlICsgUm9vbXMgKyBEaXN0YW5jZSwKICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwKICAgIGRhdGEgPSB0cmFpbi5kYXQKICApCiAgCiAgIyBFeHBhbmRlZCBNb2RlbAogIGNhbmRpZGF0ZTAzIDwtIGdsbSgKICAgIFNvbGRCaW5hcnkgfiBMb2dQcmljZSArIFJvb21zICsgRGlzdGFuY2UgKyBTZWxsZXJCaW5hcnkgKwogICAgICBSZWdpb25uYW1lICsgQ2FyICsgQmF0aHJvb20sCiAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksCiAgICBkYXRhID0gdHJhaW4uZGF0CiAgKQogIAogICMgU3RlcHdpc2UgTW9kZWwKICBjYW5kaWRhdGUwMiA8LSBzdGVwQUlDKGNhbmRpZGF0ZTAzLCBkaXJlY3Rpb24gPSAiYm90aCIsIHRyYWNlID0gRkFMU0UpCiAgCiAgIyBQcmVkaWN0aW9ucwogIHByZWQwMSA8LSBwcmVkaWN0KGNhbmRpZGF0ZTAxLCBuZXdkYXRhID0gdmFsaWQsIHR5cGUgPSAicmVzcG9uc2UiKQogIHByZWQwMiA8LSBwcmVkaWN0KGNhbmRpZGF0ZTAyLCBuZXdkYXRhID0gdmFsaWQsIHR5cGUgPSAicmVzcG9uc2UiKQogIHByZWQwMyA8LSBwcmVkaWN0KGNhbmRpZGF0ZTAzLCBuZXdkYXRhID0gdmFsaWQsIHR5cGUgPSAicmVzcG9uc2UiKQogIAogICMgQ29udmVydCB0byAwLzEKICBwcmUub3V0Y29tZTAxIDwtIGlmZWxzZShwcmVkMDEgPiAwLjUsIDEsIDApCiAgcHJlLm91dGNvbWUwMiA8LSBpZmVsc2UocHJlZDAyID4gMC41LCAxLCAwKQogIHByZS5vdXRjb21lMDMgPC0gaWZlbHNlKHByZWQwMyA+IDAuNSwgMSwgMCkKICAKICAjIEVycm9yIHJhdGVzCiAgUEUxW2ldIDwtIG1lYW4ocHJlLm91dGNvbWUwMSAhPSB2YWxpZCRTb2xkQmluYXJ5KQogIFBFMltpXSA8LSBtZWFuKHByZS5vdXRjb21lMDIgIT0gdmFsaWQkU29sZEJpbmFyeSkKICBQRTNbaV0gPC0gbWVhbihwcmUub3V0Y29tZTAzICE9IHZhbGlkJFNvbGRCaW5hcnkpCn0KCiMgUmVzdWx0cwphdmcucGUgPC0gY2JpbmQoCiAgUEUxID0gbWVhbihQRTEpLAogIFBFMiA9IG1lYW4oUEUyKSwKICBQRTMgPSBtZWFuKFBFMykKKQoKa2FibGUoYXZnLnBlLCBjYXB0aW9uID0gIkF2ZXJhZ2Ugb2YgcHJlZGljdGlvbiBlcnJvcnMgb2YgY2FuZGlkYXRlIG1vZGVscyIpCgpgYGAKTG9va2luZyBhdCB0aGUgUk9DIGN1cnZlIHdlIHNlZSBzb21ldGhpbmcgc2xpZ2h0bHkgZGlmZmVyZW50IHRoYW4gb3VyIFBFIGFuYWx5c2lzLCBpbiB0aGlzIGNhc2Ugd2UgYXJlIHNlZWluZyB0aGUgZXhwYW5kZWQgYW5kIHRoZSBzdGVwd2lzZSBtb2RlbHMgd2l0aCB0aGUgYmV0dGVyIFJPQyBhbmQgQVVDIGFuZCB0aGUgcHJhY3RpY2FsIG1vZGVsIGlzIG5vdCBhcyBzdHJvbmcuIEluIHRoaXMgY2FzZSBvdXIgZXhwYW5kZWQgbW9kZWwgYXBwZWFycyBzbGlnaHRseSBiZXR0ZXIgdGhhbiB0aGUgc3RlcHdpc2UgbW9kZWwuIEhvd2V2ZXIsIHRoZSBkaWZmZXJlbmNlIGlzIHZlcnkgc2xpZ2h0IGFuZCB0aGUgZXhwYW5kZWQgbW9kZWwgaXMgbW9yZSBjb21wbGV4LiAKCkNvbnNpZGVyaW5nIHRoZSBQRXMgd2VyZSBhbGwgdmVyeSBzaW1pbGFyIGJ1dCB0aGUgUk9DIGFuZCBBVUMgc2hvdyBhIHN0cm9uZyBhcmd1bWVudCBmb3Igc3RlcHdpc2Ugb3IgZXh0ZW5kZWQgb3ZlciB0aGUgcHJhY3RpY2FsIG1vZGVsLCBpdCBtYWtlcyBzZW5zZSB0byByZW1vdmUgdGhlIHByYWN0aWNhbCBtb2RlbCBmcm9tIHRoZSBmaW5hbCBtb2RlbCBjb25zaWRlcmF0aW9uLiBMb29raW5nIGF0IHRoZSBzdGVwd2lzZSBhbmQgZXh0ZW5kZWQgbW9kZWxzIHNpbmNlIHRoZXkgYXJlIGV4dHJlbWVseSBzaW1pbGFyIGluIHRoZWlyIFJPQyBhbmQgQVVDIG91dHB1dHMgYW5kIGhhdmUgaWRlbnRpY2FsIFBFcyBpdCBtYWtlcyBzZW5zZSB0byB1c2UgdGhlIHNpbXBsZXIgbW9kZWwgYXMgdGhlIGZpbmFsIG1vZGVsLiBJbiB0aGlzIGNhc2UgdGhhdCB3b3VsZCBiZSB0aGUgc3RlcHdpc2UgbW9kZWwgc28gd2Ugd2lsbCBiZSB1c2luZyB0aGF0IGFzIG91ciBmaW5hbCBtb2RlbCBnb2luZyBmb3J3YXJkLiAKCgpgYGB7cn0KbGlicmFyeShwUk9DKQoKIyBQcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBvbiBUUkFJTiBzZXQKcHJlZDAxIDwtIHByZWRpY3QoY2FuZGlkYXRlMDEsIG5ld2RhdGEgPSB0cmFpbiwgdHlwZSA9ICJyZXNwb25zZSIpCnByZWQwMiA8LSBwcmVkaWN0KGNhbmRpZGF0ZTAyLCBuZXdkYXRhID0gdHJhaW4sIHR5cGUgPSAicmVzcG9uc2UiKQpwcmVkMDMgPC0gcHJlZGljdChjYW5kaWRhdGUwMywgbmV3ZGF0YSA9IHRyYWluLCB0eXBlID0gInJlc3BvbnNlIikKCmNhdGVnb3J5IDwtIHRyYWluJFNvbGRCaW5hcnkKCiMgQ3JlYXRlIFJPQyBvYmplY3RzClJPQ29iajAxIDwtIHJvYyhjYXRlZ29yeSwgcHJlZDAxKQpST0NvYmowMiA8LSByb2MoY2F0ZWdvcnksIHByZWQwMikKUk9Db2JqMDMgPC0gcm9jKGNhdGVnb3J5LCBwcmVkMDMpCgojIFBsb3QgUk9DIGN1cnZlcwpwbG90KFJPQ29iajAxLCBjb2wgPSAyLCBsdHkgPSAxLAogICAgIHhsYWIgPSAiRlBSOiAxIC0gU3BlY2lmaWNpdHkiLAogICAgIHlsYWIgPSAiVFBSOiBTZW5zaXRpdml0eSIsCiAgICAgbWFpbiA9ICJST0MgY3VydmVzIG9mIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIikKCnBsb3QoUk9Db2JqMDIsIGNvbCA9IDMsIGx0eSA9IDIsIGFkZCA9IFRSVUUpCnBsb3QoUk9Db2JqMDMsIGNvbCA9IDQsIGx0eSA9IDMsIGFkZCA9IFRSVUUpCgojIEFVQyB2YWx1ZXMKQVVDMDEgPC0gcm91bmQoYXVjKFJPQ29iajAxKSwgNCkKQVVDMDIgPC0gcm91bmQoYXVjKFJPQ29iajAyKSwgNCkKQVVDMDMgPC0gcm91bmQoYXVjKFJPQ29iajAzKSwgNCkKCmxlZ2VuZCgiYm90dG9tcmlnaHQiLAogICAgICAgbGVnZW5kID0gYyhwYXN0ZSgiUHJhY3RpY2FsIG1vZGVsOiBBVUMgPSIsIEFVQzAxKSwKICAgICAgICAgICAgICAgICAgcGFzdGUoIlN0ZXB3aXNlIG1vZGVsOiBBVUMgPSIsIEFVQzAyKSwKICAgICAgICAgICAgICAgICAgcGFzdGUoIkV4cGFuZGVkIG1vZGVsOiBBVUMgPSIsIEFVQzAzKSksCiAgICAgICBjb2wgPSAyOjQsCiAgICAgICBsdHkgPSAxOjMsCiAgICAgICBjZXggPSAwLjgsCiAgICAgICBidHkgPSAibiIpCgoKYGBgCgoKIyMjIE9wdGltYWwgQ3V0LU9mZiAKCk5vdyB0aGF0IGEgZmluYWwgbW9kZWwgaXMgc2VsZWN0ZWQgd2UgbmVlZCB0byBkZXRlcm1pbmUgdGhlIG9wdGltYWwgY3V0b2ZmIHBvaW50LiBUaGlzIHdpbGwgYmUgY2FsY3VsYXRlZCBieSB0ZXN0aW5nIHNldmVyYWwgZGlmZmVyZW50IHRocmVzaG9sZHMgb24gdGhlIGZpbmFsIG1vZGVsIGFuZCB3aXRoIHRoZSB0cmFpbmluZyBkYXRhIHNldC4gVGhlIG9wdGltYWwgdGhyZXNob2xkIHdpbGwgYmUgb3V0cHV0IGFuZCBiZSB1c2VkIGZvciBvdXIgYW5hbHlzaXMuIEJhc2VkIG9uIHRoZSBvdXRwdXQgYmVsb3csIGl0IGFwcGVhcnMgdGhlIGJlc3QgdGhyZXNob2xkIGZvciB0aGlzIG1vZGVsIGlzIDAuMS4gCgpgYGB7cn0KIyBHZXQgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMgb24gdGhlIFRSQUlOIHNldApwcmVkaWN0ZWRfcHJvYmFiaWxpdGllcyA8LSBwcmVkaWN0KGNhbmRpZGF0ZTAyLCBuZXdkYXRhID0gdHJhaW4sIHR5cGUgPSAicmVzcG9uc2UiKQphY3R1YWwgPC0gdHJhaW4kU29sZEJpbmFyeQoKdGhyZXNob2xkcyA8LSBzZXEoMC4xLCAwLjksIGJ5ID0gMC4wMSkKYWNjdXJhY2llcyA8LSBzYXBwbHkodGhyZXNob2xkcywgZnVuY3Rpb24odGgpIHsKICBwcmVkX2NsYXNzIDwtIGlmZWxzZShwcmVkaWN0ZWRfcHJvYmFiaWxpdGllcyA+IHRoLCAxLCAwKQogIG1lYW4ocHJlZF9jbGFzcyA9PSBhY3R1YWwpCn0pCgpiZXN0X3RocmVzaCA8LSB0aHJlc2hvbGRzW3doaWNoLm1heChhY2N1cmFjaWVzKV0KYmVzdF90aHJlc2gKCmBgYAoKV2l0aCBhbiBvcHRpbWFsIHRocmVzaG9sZCBkZXRlcm1pbmVkLCBpdCBjYW4gYmUgdXNlZCB0byBkZXRlcm1pbmUgdGhlIGFjY3VyYWN5IG9mIHRoZSBtb2RlbC4gTm93IHVzaW5nIHRoZSAyNSUgdGVzdGluZyBkYXRhIHNldCB0aGF0IHdhcyBzZXQgYXNpZGUgZWFybGllciB0aGUgYWNjdXJhY3kgb2YgdGhlIG1vZGVsIGNhbiBiZSBjYWxjdWxhdGVkLiBUaGUgZmluYWwgbW9kZWwgaGFzIGFuIGFjY3VyYWN5IG9mIDAuODg5MzQ1OSB3aGljaCBpcyB2ZXJ5IHN0cm9uZy4gCgpgYGB7cn0KcHJlZDAyIDwtIHByZWRpY3QoY2FuZGlkYXRlMDIsIG5ld2RhdGEgPSB0ZXN0LCB0eXBlID0gInJlc3BvbnNlIikKcHJlZDAyLm91dGNvbWUgPC0gaWZlbHNlKHByZWQwMiA+IGJlc3RfdGhyZXNoLCAxLCAwKQoKYWNjdXJhY3kgPC0gbWVhbihwcmVkMDIub3V0Y29tZSA9PSB0ZXN0JFNvbGRCaW5hcnkpCgprYWJsZShkYXRhLmZyYW1lKAogIEN1dG9mZiA9IGJlc3RfdGhyZXNoLAogIEFjY3VyYWN5ID0gYWNjdXJhY3kKKSwgY2FwdGlvbiA9ICJGaW5hbCBNb2RlbCBBY2N1cmFjeSBVc2luZyBPcHRpbWFsIEN1dG9mZiIpCgpgYGAKCiMjIyBSZXN1bHRzIGFuZCBDb25jbHVzaW9ucwoKClRoZSBzdGVwd2lzZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHByb3ZpZGVzIGEgcmVsaWFibGUgdG9vbCBmb3IgcHJlZGljdGluZyBob3VzZSBzYWxlcy4gU2VsbGVycyBjYW4gdXNlIHRoaXMgbW9kZWwgdG8gdW5kZXJzdGFuZCB3aGljaCBmYWN0b3JzIGFyZSBtb3N0IGxpa2VseSB0byBpbmZsdWVuY2UgYSBzYWxlIGFuZCBhZGp1c3QgcHJpY2luZyBvciBwcm9wZXJ0eSBmZWF0dXJlcyBhY2NvcmRpbmdseSwgaW5jcmVhc2luZyB0aGUgY2hhbmNlcyBvZiBhIHN1Y2Nlc3NmdWwgYW5kIHRpbWVseSB0cmFuc2FjdGlvbi4KClRoZSBmaW5hbCBzdGVwd2lzZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHdhcyBkZXZlbG9wZWQgdG8gcHJlZGljdCB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIGhvdXNlIHdpbGwgc2VsbCAoU29sZEJpbmFyeSA9IDEpIGJhc2VkIG9uIHNldmVyYWwgcHJlZGljdG9ycywgaW5jbHVkaW5nIHN0cnVjdHVyYWwgZmVhdHVyZXMsIHByaWNlLCBhbmQgbG9jYXRpb24uIFRoaXMgbW9kZWwgYWxsb3dzIHVzIHRvIGFzc2VzcyB3aGljaCBmYWN0b3JzIHNpZ25pZmljYW50bHkgaW5mbHVlbmNlIHRoZSBsaWtlbGlob29kIG9mIGEgc2FsZSwgcHJvdmlkaW5nIGFjdGlvbmFibGUgaW5zaWdodHMgZm9yIHNlbGxlcnMgd2hvIG1heSB3YW50IHRvIGFkanVzdCBwcmljZSwgYW1lbml0aWVzLCBvciB0YXJnZXQgbWFya2V0aW5nIGJhc2VkIG9uIGxvY2F0aW9uLgoKU2V2ZXJhbCBzdHJ1Y3R1cmFsIGNoYXJhY3RlcmlzdGljcyBhcmUgc2lnbmlmaWNhbnQgcHJlZGljdG9ycy4gVGhlIG51bWJlciBvZiByb29tcyBoYXMgYSBuZWdhdGl2ZSBlZmZlY3Qgb24gdGhlIHByb2JhYmlsaXR5IG9mIHNlbGxpbmcsIGluZGljYXRpbmcgdGhhdCBsYXJnZXIgaG9tZXMgd2l0aCBtb3JlIHJvb21zIG1heSBhcHBlYWwgdG8gYSBuYXJyb3dlciBwb29sIG9mIGJ1eWVycy4gQWRkaXRpb25hbCBiYXRocm9vbXMgYWxzbyBkZWNyZWFzZSB0aGUgbGlrZWxpaG9vZCBvZiBhIHNhbGUsIHdoaWxlIHRoZSBudW1iZXIgb2YgY2FyIHNwYWNlcyBoYXMgYSBzbWFsbCBuZWdhdGl2ZSBlZmZlY3QuIEludGVyZXN0aW5nbHksIGhpZ2hlciBsb2ctdHJhbnNmb3JtZWQgcHJpY2VzIChMb2dQcmljZSkgaW5jcmVhc2UgdGhlIHByb2JhYmlsaXR5IG9mIHNlbGxpbmcsIHN1Z2dlc3RpbmcgdGhhdCwgd2l0aGluIHRoaXMgbWFya2V0LCBtb3JlIGV4cGVuc2l2ZSBob21lcyB0ZW5kIHRvIHNlbGwgYXQgYSBzbGlnaHRseSBoaWdoZXIgcmF0ZSwgcG90ZW50aWFsbHkgcmVmbGVjdGluZyBxdWFsaXR5IG9yIGRlc2lyYWJsZSBsb2NhdGlvbnMuCgpMb2NhdGlvbiBwbGF5cyBhIGNydWNpYWwgcm9sZSBpbiBzYWxlcyBwcm9iYWJpbGl0eS4gQ29tcGFyZWQgdG8gdGhlIHJlZmVyZW5jZSByZWdpb24sIGhvbWVzIGluIEVhc3Rlcm4gVmljdG9yaWEgYXJlIHNpZ25pZmljYW50bHkgbGVzcyBsaWtlbHkgdG8gc2VsbCwgd2hlcmVhcyBwcm9wZXJ0aWVzIGluIE5vcnRoZXJuIE1ldHJvcG9saXRhbiBhbmQgV2VzdGVybiBNZXRyb3BvbGl0YW4gcmVnaW9ucyBhcmUgc2lnbmlmaWNhbnRseSBtb3JlIGxpa2VseSB0byBzZWxsLiBPdGhlciByZWdpb25zIHZhcnkgaW4gc2lnbmlmaWNhbmNlLCB3aXRoIHNvbWUgc3ViLXJlZ2lvbnMgc2hvd2luZyBubyBzdGF0aXN0aWNhbGx5IG1lYW5pbmdmdWwgZWZmZWN0LCBpbmRpY2F0aW5nIHRoYXQgdGhlIGluZmx1ZW5jZSBvZiBsb2NhdGlvbiBkZXBlbmRzIG9uIHRoZSBzcGVjaWZpYyBhcmVhLgoKT3ZlcmFsbCwgdGhlIG1vZGVsIGRlbW9uc3RyYXRlcyB0aGF0IGJvdGggc3RydWN0dXJhbCBmZWF0dXJlcyBhbmQgZ2VvZ3JhcGhpYyBsb2NhdGlvbiBtZWFuaW5nZnVsbHkgYWZmZWN0IHdoZXRoZXIgYSBob3VzZSBzZWxscy4gQnkgdW5kZXJzdGFuZGluZyB0aGVzZSByZWxhdGlvbnNoaXBzLCBzZWxsZXJzIGNhbiBtYWtlIHN0cmF0ZWdpYyBhZGp1c3RtZW50c+KAlHN1Y2ggYXMgcHJpY2luZywgbGF5b3V0IGltcHJvdmVtZW50cywgb3IgdGFyZ2V0ZWQgbWFya2V0aW5n4oCUdG8gaW1wcm92ZSB0aGUgbGlrZWxpaG9vZCBvZiBhIHN1Y2Nlc3NmdWwgc2FsZS4gVGhlIGZpbmFsIG1vZGVsIHByb3ZpZGVzIGEgcHJhY3RpY2FsIGZyYW1ld29yayBmb3IgcHJlZGljdGluZyBob3VzZSBzYWxlcywgaGVscGluZyBndWlkZSBkYXRhLWRyaXZlbiBkZWNpc2lvbnMgaW4gdGhlIGhvdXNpbmcgbWFya2V0LgoKIyBTdW1tYXJ5IGFuZCBEaXNjdXNzaW9uCgpUaGlzIHByb2plY3QgYW5hbHl6ZWQgTWVsYm91cm5lIGhvdXNpbmcgZGF0YSB0byB1bmRlcnN0YW5kIHdoYXQgZmFjdG9ycyBpbmZsdWVuY2UgaG91c2Ugc2VsbGluZyBwcmljZXMgYW5kIHRoZSBsaWtlbGlob29kIG9mIGEgaG91c2Ugc2VsbGluZy4gVXNpbmcgYSBjbGVhbmVkIGRhdGFzZXQgb2YgMzQsODU0IHByb3BlcnRpZXMsIGJvdGggbGluZWFyIGFuZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscyB3ZXJlIGRldmVsb3BlZCwgdmFsaWRhdGVkIHRocm91Z2ggY3Jvc3MtdmFsaWRhdGlvbiBhbmQgdGVzdCBzZXRzLCBhbmQgb3B0aW1pemVkIHZpYSBzdGVwd2lzZSBzZWxlY3Rpb24uCgpUaGUgZmluYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgZm91bmQgdGhhdCBzdHJ1Y3R1cmFsIGZlYXR1cmVzIHN1Y2ggYXMgcm9vbXMsIGJhdGhyb29tcywgY2FyIHNwYWNlcywgYW5kIGxvY2F0aW9uIHN1Y2ggYXMgcmVnaW9uIGFuZCBkaXN0YW5jZSBmcm9tIHRoZSBDQkQsIHNlbGxlciB0eXBlLCBhbmQgbG9jYWwgcHJvcGVydHkgZGVuc2l0eSBzaWduaWZpY2FudGx5IHByZWRpY3QgbG9nLXRyYW5zZm9ybWVkIGhvdXNlIHByaWNlcy4gVGhlIG1vZGVsIGV4cGxhaW5zIGFwcHJveGltYXRlbHkgNTYlIG9mIHByaWNlIHZhcmlhdGlvbiwgcHJvdmlkaW5nIHNlbGxlcnMgYW5kIGJ1eWVycyB3aXRoIGFjdGlvbmFibGUgZ3VpZGFuY2UgZm9yIHJlYWxpc3RpYyBwcmljaW5nIGFuZCB2YWx1ZSBhc3Nlc3NtZW50LgoKVGhlIGZpbmFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgaWRlbnRpZmllZCBrZXkgcHJlZGljdG9ycyBvZiBzYWxlIHByb2JhYmlsaXR5LCBpbmNsdWRpbmcgcHJpY2UsIHN0cnVjdHVyYWwgZmVhdHVyZXMsIGFuZCByZWdpb24uIEhpZ2hlci1wcmljZWQgaG9tZXMgYW5kIHRob3NlIGluIE5vcnRoZXJuIG9yIFdlc3Rlcm4gTWV0cm9wb2xpdGFuIGFyZWFzIHdlcmUgbW9yZSBsaWtlbHkgdG8gc2VsbCwgd2hpbGUgbGFyZ2VyIGhvbWVzIHdpdGggbWFueSByb29tcyBvciBiYXRocm9vbXMgc29sZCBzbGlnaHRseSBsZXNzIHJlYWRpbHkuIFRoZSBtb2RlbCBhY2hpZXZlZCBhbiBhY2N1cmFjeSBvZiA4OSUsIG9mZmVyaW5nIHNlbGxlcnMgaW5zaWdodCBpbnRvIGZhY3RvcnMgdGhhdCBjYW4gaW1wcm92ZSB0aGUgbGlrZWxpaG9vZCBvZiBhIHN1Y2Nlc3NmdWwgc2FsZS4KClN0cmVuZ3RocyBvZiB0aGUgYW5hbHlzaXMgaW5jbHVkZSB0aGUgZGF0YSBwcmVwYXJhdGlvbiwgY3Jvc3MtdmFsaWRhdGlvbiwgYW5kIG1vZGVscyB0aGF0IHByb3ZpZGUgYWN0aW9uYWJsZSBpbnNpZ2h0cy4gSG93ZXZlciwgc29tZSBsaW1pdGF0aW9ucyBpbmNsdWRlIG1pc3NpbmcgZGF0YSBmb3Igc29tZSB2YXJpYWJsZXMsIHNrZXdlZCBjYXRlZ29yaWNhbCBkaXN0cmlidXRpb25zLCBhbmQgdGhlIGFic2VuY2Ugb2Ygb3RoZXIgbWFya2V0IGZhY3RvcnMgc3VjaCBhcyBwcm9wZXJ0eSBjb25kaXRpb24gb3IgYnV5ZXIgZGVtYW5kLiBGdXR1cmUgaW1wcm92ZW1lbnRzIGNvdWxkIGluY2x1ZGUgaW5jb3Jwb3JhdGluZyBhZGRpdGlvbmFsIGZlYXR1cmVzLCB1c2luZyBvdGhlciBtb2RlbGluZyB0ZWNobmlxdWVzLCBhbmQgYW5hbHl6aW5nIG1hcmtldCB0cmVuZHMuCgpPdmVyYWxsLCB0aGUgYW5hbHlzaXMgcHJvdmlkZXMgYSBmcmFtZXdvcmsgZm9yIHByZWRpY3RpbmcgYm90aCBob3VzZSBzZWxsaW5nIHByaWNlcyBhbmQgc2FsZSBsaWtlbGlob29kLCBoZWxwaW5nIHNlbGxlcnMgbWFrZSBkYXRhLWRyaXZlbiBkZWNpc2lvbnMgdG8gb3B0aW1pemUgcHJpY2luZywgcHJvcGVydHkgZmVhdHVyZXMsIGFuZCBtYXJrZXRpbmcgc3RyYXRlZ2llcyBpbiB0aGUgTWVsYm91cm5lIGhvdXNpbmcgbWFya2V0LgoKCgoKCgoKCgoKCgoKCgo=