Homework: Predicting House Prices in King County Using Multiple Linear Regression

Exercise 1: Collecting and Understanding Data

In this homework, you will analyze house sales in King County, Washington State, using multiple linear regression to predict house prices. Understanding the dataset structure is essential before building a predictive model.

Here is the revised version with improved grammar:

The aim of this homework is to predict house sales in King County, Washington State, USA, using Multiple Linear Regression (MLR). The dataset consists of historical data on houses sold between May 2014 and May 2015.

We aim to predict house sales in King County with an accuracy of at least 75–80% and to identify the factors responsible for higher property values, particularly those priced at $650K and above.

This dataset contains house sale prices for King County, including Seattle. It includes data on homes sold between May 2014 and May 2015. The dataset contains 21 variables and 21,613 observations.

Meaning of abbreviations in the dataset:

Variable Description
id A notation for a house
date Date house was sold
price Price is prediction target
bedrooms Number of bedrooms
bathrooms Number of bathrooms
sqft_living Square footage of the home
sqft_lot Square footage of the lot
floors Total floors (levels) in house
waterfront House which has a view to a waterfront
view Has been viewed
condition How good the condition is overall
grade Overall grade given to the housing unit, based on King County grading system
sqft_above Square footage of house apart from basement
sqft_basement Square footage of the basement
yr_built Built Year
yr_renovated Year when house was renovated
zipcode Zip code
lat Latitude coordinate
long Longitude coordinate
sqft_living15 Living room area in 2015 (implies some renovations) This might or might not have affected the lot size area
sqft_lot15 LotSize area in 2015 (implies some renovations)

Instructions

  1. Load the dataset:
    • Use read.csv() to load the dataset from the file kc_house_data.csv.
  2. Inspect the data structure:
    • Use str() to display variable names, types, and sample values.
    • Confirm the dataset contains 21 variables and 21,613 observations.
  3. Explore the response variable (price):
    • Use summary() to view statistics like the minimum, mean, and maximum price.
    • Note the range and average price of houses.
  4. Visualize the response variable:
    • Create a histogram using hist() to examine the distribution of prices.
    • Adjust the breaks parameter to provide a detailed view.
  5. Understand the dataset features:
    • Use summary() and head() to explore predictor variables (e.g., bedrooms, sqft_living, condition).
    • Identify categorical variables such as waterfront, view, and grade.
# Load the dataset
houses <- read.csv("kc_house_data.csv")

# Inspect the data structure
str(houses)
## 'data.frame':    21613 obs. of  21 variables:
##  $ id           : num  7.13e+09 6.41e+09 5.63e+09 2.49e+09 1.95e+09 ...
##  $ date         : chr  "20141013T000000" "20141209T000000" "20150225T000000" "20141209T000000" ...
##  $ price        : num  221900 538000 180000 604000 510000 ...
##  $ bedrooms     : int  3 3 2 4 3 4 3 3 3 3 ...
##  $ bathrooms    : num  1 2.25 1 3 2 4.5 2.25 1.5 1 2.5 ...
##  $ sqft_living  : int  1180 2570 770 1960 1680 5420 1715 1060 1780 1890 ...
##  $ sqft_lot     : int  5650 7242 10000 5000 8080 101930 6819 9711 7470 6560 ...
##  $ floors       : num  1 2 1 1 1 1 2 1 1 2 ...
##  $ waterfront   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ view         : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ condition    : int  3 3 3 5 3 3 3 3 3 3 ...
##  $ grade        : int  7 7 6 7 8 11 7 7 7 7 ...
##  $ sqft_above   : int  1180 2170 770 1050 1680 3890 1715 1060 1050 1890 ...
##  $ sqft_basement: int  0 400 0 910 0 1530 0 0 730 0 ...
##  $ yr_built     : int  1955 1951 1933 1965 1987 2001 1995 1963 1960 2003 ...
##  $ yr_renovated : int  0 1991 0 0 0 0 0 0 0 0 ...
##  $ zipcode      : int  98178 98125 98028 98136 98074 98053 98003 98198 98146 98038 ...
##  $ lat          : num  47.5 47.7 47.7 47.5 47.6 ...
##  $ long         : num  -122 -122 -122 -122 -122 ...
##  $ sqft_living15: int  1340 1690 2720 1360 1800 4760 2238 1650 1780 2390 ...
##  $ sqft_lot15   : int  5650 7639 8062 5000 7503 101930 6819 9711 8113 7570 ...
# Explore the response variable
summary(houses$price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   75000  321950  450000  540088  645000 7700000
# Visualize the response variable
hist(houses$price, breaks = 50, main = "Distribution of House Prices", xlab = "House Prices")

# Understand the dataset features
summary(houses[, c("bedrooms", "bathrooms", "sqft_living", "condition", "grade", "waterfront", "view")])
##     bedrooms        bathrooms      sqft_living      condition    
##  Min.   : 0.000   Min.   :0.000   Min.   :  290   Min.   :1.000  
##  1st Qu.: 3.000   1st Qu.:1.750   1st Qu.: 1427   1st Qu.:3.000  
##  Median : 3.000   Median :2.250   Median : 1910   Median :3.000  
##  Mean   : 3.371   Mean   :2.115   Mean   : 2080   Mean   :3.409  
##  3rd Qu.: 4.000   3rd Qu.:2.500   3rd Qu.: 2550   3rd Qu.:4.000  
##  Max.   :33.000   Max.   :8.000   Max.   :13540   Max.   :5.000  
##      grade          waterfront            view       
##  Min.   : 1.000   Min.   :0.000000   Min.   :0.0000  
##  1st Qu.: 7.000   1st Qu.:0.000000   1st Qu.:0.0000  
##  Median : 7.000   Median :0.000000   Median :0.0000  
##  Mean   : 7.657   Mean   :0.007542   Mean   :0.2343  
##  3rd Qu.: 8.000   3rd Qu.:0.000000   3rd Qu.:0.0000  
##  Max.   :13.000   Max.   :1.000000   Max.   :4.0000

Exercise 2: Exploring Relationships Between Variables

Examining relationships between predictors and the target variable is a critical step before building a regression model.

Instructions

  1. Compute a correlation matrix:
    • Use cor() with numeric variables (e.g., price, sqft_living, sqft_lot, bedrooms, bathrooms).
  2. Create scatterplots:
    • Use plot() to visualize relationships between price and predictors like sqft_living, bedrooms, and bathrooms.
  3. Include categorical variables:
    • Use boxplots to visualize the relationship between price and categorical variables like waterfront and grade.
  4. Interpret the results:
    • Identify predictors showing strong positive or negative correlations with price.
# Compute the correlation matrix
numeric_vars <- c("price", "sqft_living", "sqft_lot", "bedrooms", "bathrooms", "sqft_above", "sqft_basement")
cor_matrix <- cor(houses[, numeric_vars], use = "complete.obs")
print(cor_matrix)
##                    price sqft_living   sqft_lot   bedrooms  bathrooms
## price         1.00000000   0.7020554 0.08966148 0.30836580 0.52514986
## sqft_living   0.70205535   1.0000000 0.17284073 0.57676330 0.75468405
## sqft_lot      0.08966148   0.1728407 1.00000000 0.03170956 0.08773009
## bedrooms      0.30836580   0.5767633 0.03170956 1.00000000 0.51597353
## bathrooms     0.52514986   0.7546840 0.08773009 0.51597353 1.00000000
## sqft_above    0.60556709   0.8766441 0.18351066 0.47761635 0.68536337
## sqft_basement 0.32384249   0.4349249 0.01530090 0.30325114 0.28373700
##                sqft_above sqft_basement
## price          0.60556709    0.32384249
## sqft_living    0.87664406    0.43492490
## sqft_lot       0.18351066    0.01530090
## bedrooms       0.47761635    0.30325114
## bathrooms      0.68536337    0.28373700
## sqft_above     1.00000000   -0.05197575
## sqft_basement -0.05197575    1.00000000
# Create scatterplots
plot(houses$sqft_living, houses$price, main = "Price vs. Sqft Living", xlab = "Sqft Living", ylab = "Price")

plot(houses$bathrooms, houses$price, main = "Price vs. Bathrooms", xlab = "Bathrooms", ylab = "Price")

# Boxplots for categorical variables
boxplot(price ~ waterfront, data = houses, main = "Price by Waterfront", xlab = "Waterfront (0 = No, 1 = Yes)", ylab = "Price")

boxplot(price ~ grade, data = houses, main = "Price by Grade", xlab = "Grade", ylab = "Price")


Exercise 3: Building the Initial Regression Model

Build an initial regression model using key predictors, including categorical variables, to understand their impact on house prices.

Instructions

  1. Convert categorical variables to factors:
    • Ensure variables like waterfront, view, and grade are treated as factors.
  2. Fit the regression model:
    • Use lm() with price as the dependent variable and predictors such as sqft_living, bedrooms, bathrooms, grade, and waterfront.
  3. View model coefficients:
    • Examine the model output for coefficients and intercept.
  4. Summarize the model:
    • Use summary() to review R-squared, p-values, and residual statistics.
# Convert categorical variables to factors
houses$waterfront <- as.factor(houses$waterfront)
houses$view <- as.factor(houses$view)
houses$grade <- as.factor(houses$grade)

# Fit the regression model
house_model <- lm(price ~ sqft_living + bedrooms + bathrooms + grade + waterfront, data = houses)

# View coefficients
coef(house_model)
##  (Intercept)  sqft_living     bedrooms    bathrooms       grade3       grade4 
##   93480.0383     167.3102  -15512.6019   -6546.5970   29507.4525   39322.7284 
##       grade5       grade6       grade7       grade8       grade9      grade10 
##   22191.8670   54371.7825   86971.7646  148142.7057  268809.1699  450673.6551 
##      grade11      grade12      grade13  waterfront1 
##  716990.9940 1180137.7116 2472679.0735  766704.2185
# Summarize the model
summary(house_model)
## 
## Call:
## lm(formula = price ~ sqft_living + bedrooms + bathrooms + grade + 
##     waterfront, data = houses)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1520979  -125123   -25017    92399  3912553 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  9.348e+04  2.277e+05   0.411  0.68140    
## sqft_living  1.673e+02  3.475e+00  48.143  < 2e-16 ***
## bedrooms    -1.551e+04  2.154e+03  -7.201 6.17e-13 ***
## bathrooms   -6.547e+03  3.258e+03  -2.009  0.04453 *  
## grade3       2.951e+04  2.629e+05   0.112  0.91064    
## grade4       3.932e+04  2.316e+05   0.170  0.86518    
## grade5       2.219e+04  2.282e+05   0.097  0.92253    
## grade6       5.437e+04  2.278e+05   0.239  0.81135    
## grade7       8.697e+04  2.278e+05   0.382  0.70261    
## grade8       1.481e+05  2.278e+05   0.650  0.51555    
## grade9       2.688e+05  2.279e+05   1.180  0.23819    
## grade10      4.507e+05  2.280e+05   1.977  0.04809 *  
## grade11      7.170e+05  2.283e+05   3.141  0.00169 ** 
## grade12      1.180e+06  2.294e+05   5.144 2.71e-07 ***
## grade13      2.473e+06  2.371e+05  10.428  < 2e-16 ***
## waterfront1  7.667e+05  1.811e+04  42.339  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 227700 on 21597 degrees of freedom
## Multiple R-squared:  0.6156, Adjusted R-squared:  0.6154 
## F-statistic:  2306 on 15 and 21597 DF,  p-value: < 2.2e-16

Exercise 4: Diagnosing and Improving the Model

Refine your model to improve its fit, include more variables, and interpret the results.

Instructions

  1. Evaluate residuals:
    • Plot residuals using plot() and check for patterns.
  2. Add more predictors:
    • Include additional variables (e.g., sqft_lot, condition, yr_built, view) to improve the model.
  3. Include interaction terms and nonlinear effects:
    • Identify a variable likely to have a nonlinear effect on price (e.g., sqft_living).
    • Add a squared term for sqft_living to capture the nonlinear relationship.
    • Add an interaction term between two variables (e.g., bathrooms and sqft_living).
  4. Fit the updated model:
    • Update the model to include the new terms.
  5. Compare models:
    • Compare R-squared and adjusted R-squared values to determine model improvements.
# Add squared term for sqft_living
houses$sqft_living_sq <- houses$sqft_living^2

# Add interaction term between bathrooms and sqft_living
houses$bath_sqft_interaction <- houses$bathrooms * houses$sqft_living

# Fit the updated model
house_model_improved <- lm(price ~ sqft_living + sqft_living_sq + bedrooms + bathrooms + bath_sqft_interaction + grade + waterfront + view + sqft_lot + yr_built, data = houses)

# Summarize the improved model
summary(house_model_improved)
## 
## Call:
## lm(formula = price ~ sqft_living + sqft_living_sq + bedrooms + 
##     bathrooms + bath_sqft_interaction + grade + waterfront + 
##     view + sqft_lot + yr_built, data = houses)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3812754  -105948   -11763    84257  3032377 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            6.632e+06  2.364e+05  28.054  < 2e-16 ***
## sqft_living           -6.037e+00  6.227e+00  -0.970 0.332294    
## sqft_living_sq         2.001e-02  1.681e-03  11.905  < 2e-16 ***
## bedrooms              -1.559e+04  1.989e+03  -7.840 4.70e-15 ***
## bathrooms              4.154e+04  6.745e+03   6.159 7.44e-10 ***
## bath_sqft_interaction  9.356e+00  2.568e+00   3.643 0.000270 ***
## grade3                 7.455e+03  2.364e+05   0.032 0.974847    
## grade4                -4.252e+04  2.083e+05  -0.204 0.838273    
## grade5                -3.469e+04  2.053e+05  -0.169 0.865804    
## grade6                 3.342e+04  2.049e+05   0.163 0.870462    
## grade7                 1.461e+05  2.050e+05   0.713 0.475981    
## grade8                 2.600e+05  2.050e+05   1.268 0.204814    
## grade9                 4.103e+05  2.051e+05   2.001 0.045444 *  
## grade10                5.736e+05  2.051e+05   2.796 0.005175 ** 
## grade11                7.749e+05  2.054e+05   3.774 0.000161 ***
## grade12                1.085e+06  2.064e+05   5.259 1.46e-07 ***
## grade13                1.851e+06  2.141e+05   8.645  < 2e-16 ***
## waterfront1            4.966e+05  2.002e+04  24.800  < 2e-16 ***
## view1                  1.227e+05  1.142e+04  10.749  < 2e-16 ***
## view2                  5.760e+04  6.914e+03   8.331  < 2e-16 ***
## view3                  1.066e+05  9.445e+03  11.287  < 2e-16 ***
## view4                  2.468e+05  1.461e+04  16.888  < 2e-16 ***
## sqft_lot              -2.983e-01  3.445e-02  -8.658  < 2e-16 ***
## yr_built              -3.303e+03  6.013e+01 -54.930  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 204800 on 21589 degrees of freedom
## Multiple R-squared:  0.6893, Adjusted R-squared:  0.6889 
## F-statistic:  2082 on 23 and 21589 DF,  p-value: < 2.2e-16
#Plotting the residuals a extra line
plot(house_model_improved$residuals, main = "Residual Plot", xlab = "Fitted Values", ylab = "Residuals", pch = 20)
abline(h = 0, col = "red")


Exercise 5: Evaluating Model Performance

Assess the performance of your improved model and interpret the significance of predictors.

Instructions

  1. Review model summary:
    • Examine the coefficients, p-values, R-squared, and adjusted R-squared values.
  2. Interpret coefficients:
    • Identify significant predictors based on p-values.
  3. Analyze the effect of nonlinear and interaction terms:
    • Interpret the coefficients of sqft_living_sq and bath_sqft_interaction.
# Review model summary
summary(house_model_improved)
## 
## Call:
## lm(formula = price ~ sqft_living + sqft_living_sq + bedrooms + 
##     bathrooms + bath_sqft_interaction + grade + waterfront + 
##     view + sqft_lot + yr_built, data = houses)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -3812754  -105948   -11763    84257  3032377 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            6.632e+06  2.364e+05  28.054  < 2e-16 ***
## sqft_living           -6.037e+00  6.227e+00  -0.970 0.332294    
## sqft_living_sq         2.001e-02  1.681e-03  11.905  < 2e-16 ***
## bedrooms              -1.559e+04  1.989e+03  -7.840 4.70e-15 ***
## bathrooms              4.154e+04  6.745e+03   6.159 7.44e-10 ***
## bath_sqft_interaction  9.356e+00  2.568e+00   3.643 0.000270 ***
## grade3                 7.455e+03  2.364e+05   0.032 0.974847    
## grade4                -4.252e+04  2.083e+05  -0.204 0.838273    
## grade5                -3.469e+04  2.053e+05  -0.169 0.865804    
## grade6                 3.342e+04  2.049e+05   0.163 0.870462    
## grade7                 1.461e+05  2.050e+05   0.713 0.475981    
## grade8                 2.600e+05  2.050e+05   1.268 0.204814    
## grade9                 4.103e+05  2.051e+05   2.001 0.045444 *  
## grade10                5.736e+05  2.051e+05   2.796 0.005175 ** 
## grade11                7.749e+05  2.054e+05   3.774 0.000161 ***
## grade12                1.085e+06  2.064e+05   5.259 1.46e-07 ***
## grade13                1.851e+06  2.141e+05   8.645  < 2e-16 ***
## waterfront1            4.966e+05  2.002e+04  24.800  < 2e-16 ***
## view1                  1.227e+05  1.142e+04  10.749  < 2e-16 ***
## view2                  5.760e+04  6.914e+03   8.331  < 2e-16 ***
## view3                  1.066e+05  9.445e+03  11.287  < 2e-16 ***
## view4                  2.468e+05  1.461e+04  16.888  < 2e-16 ***
## sqft_lot              -2.983e-01  3.445e-02  -8.658  < 2e-16 ***
## yr_built              -3.303e+03  6.013e+01 -54.930  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 204800 on 21589 degrees of freedom
## Multiple R-squared:  0.6893, Adjusted R-squared:  0.6889 
## F-statistic:  2082 on 23 and 21589 DF,  p-value: < 2.2e-16

Exercise 6: Predicting House Prices

Use the improved model to predict house prices and evaluate its performance.

Instructions

  1. Generate predictions:
    • Use predict() on the dataset to compute predicted prices.
  2. Visualize predictions:
    • Create a scatterplot of actual vs. predicted prices.
  3. Evaluate accuracy:
    • Compute the correlation between actual and predicted prices.
  4. Predict for a new house:
    • Create a new data frame with values for all predictors, including squared and interaction terms.
    • Use predict() to estimate the price of this hypothetical house.
# Generate predictions
houses$predicted_price <- predict(house_model_improved, newdata = houses)

# Visualize predicted vs. actual prices
plot(houses$price, houses$predicted_price, 
     main = "Actual vs. Predicted House Prices", 
     xlab = "Actual Prices", 
     ylab = "Predicted Prices", 
     pch = 16, col = "blue")
abline(a = 0, b = 1, col = "red", lwd = 2)

# Compute correlation between actual and predicted prices
cor(houses$price, houses$predicted_price)
## [1] 0.8302244
# Predict for a new house
new_house <- data.frame(
  sqft_living = 2500,  # Example value for sqft_living
  sqft_living_sq = 2500^2,  # Squared value for sqft_living
  bedrooms = 3,  # Example value for bedrooms
  bathrooms = 3,  # Example value for bathrooms
  bath_sqft_interaction = 2500 * 3,  # Interaction term between bathrooms and sqft_living
  grade = factor(8, levels = levels(houses$grade)),  # Example grade, as a factor
  waterfront = factor(0, levels = levels(houses$waterfront)),  # Waterfront as factor (0 for no)
  view = factor(0, levels = levels(houses$view)),  # View as factor (0 for no view)
  condition = factor(3, levels = levels(houses$condition)),  # Condition as factor (3 is an example)
  yr_built = 2000,  # Example for year built
  sqft_lot = 5000  # Example sqft_lot (ensure it's included)
)

# Predict price for the new house using the improved model
predicted_price_new <- predict(house_model_improved, newdata = new_house)

# Print predicted price for the new house
print(predicted_price_new)
##        1 
## 542527.1

Exercise 7: Interpreting the Impact of Nonlinear and Interaction Effects

Understanding how nonlinear transformations and interaction terms influence the model is crucial for interpreting the results accurately.

Instructions

  1. Interpret the coefficient of the squared term (sqft_living_sq):
    • Discuss how the square of living area affects the price.
    • Explain whether this suggests a diminishing or increasing return on additional square footage.

Answer = The squared term for sqft_living_sq (the square of living area) is added to the model to account for a potential nonlinear relationship between living space and house price. The coefficient for this squared term indicates the rate of change in the house price as the square footage increases.

If the coefficient of sqft_living_sq is positive, it means that as the square footage increases, the rate of price increase becomes larger. This would suggest an increasing return on additional square footage, meaning that larger houses increase in price more steeply than smaller ones.

If the coefficient of sqft_living_sq is negative, it suggests a diminishing return on additional square footage, meaning that after a certain point, additional square footage increases the house price at a slower rate.

In conclusion our case, if the coefficient is positive, it shows that larger houses tend to be more valuable at an accelerating rate.

  1. Interpret the interaction term (bath_sqft_interaction):
    • Explain how the interaction between bathrooms and living area influences the price.
    • Discuss scenarios where this interaction could significantly impact the house price.

Answer = The interaction term between bathrooms and sqft_living captures how the effect of one variable depends on the value of the other. Specifically, this term explains how the combination of additional bathrooms and living area size jointly impacts the price of a house.

Positive coefficient for interaction: If the coefficient for bath_sqft_interaction is positive, this means that having more bathrooms amplifies the price impact of having more living space. In other words, larger homes with more bathrooms tend to be priced significantly higher than larger homes with fewer bathrooms. This could be the case in luxury homes or family-sized homes where more bathrooms are expected to accommodate larger living areas.

Negative coefficient for interaction: If the coefficient is negative, it would suggest that more bathrooms have less of a price impact on larger homes, possibly indicating that for homes with very large square footage, adding additional bathrooms doesn’t significantly increase value.

This interaction term is particularly relevant in larger homes, where the number of bathrooms might matter more in terms of functionality and perceived luxury, which directly influences pricing.

  1. Summarize the overall model improvement:
    • Compare the adjusted R-squared of the initial and improved models.
    • Discuss how adding nonlinear and interaction terms has affected model performance.

Answer = When comparing the adjusted R-squared between the initial and improved models: Initial Model: The adjusted R-squared value provides a baseline for how well the model explains the variation in house prices. This might be moderate if only linear terms are included.

Improved Model: After adding the squared and interaction terms, you should see an improvement in the adjusted R-squared value. A higher adjusted R-squared means that the improved model is explaining more of the variation in the house prices. This improvement suggests that the added complexity of capturing nonlinear relationships and interactions between predictors is helping the model make more accurate predictions.

The addition of nonlinear and interaction terms typically increases model performance by better fitting the underlying data structure, especially when relationships between variables are more complex than simple linear patterns. However, it’s important to also evaluate the significance of each added term to ensure that the increase in performance is not just due to overfitting or unnecessary complexity.

In conclusion, adding these terms should ideally improve the model’s ability to capture important nuances in how different factors interact to influence house prices, and the model’s performance (as measured by R-squared) should reflect this improvement.

LS0tCnRpdGxlOiAiSG91c2luZyBQcmljZSBQcmVkaWN0aW9uIHVzaW5nIE11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIgphdXRob3I6ICJTYXR5YSBOYXJheWFuYSBQYW5kYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gVFJVRSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkob3BlbmludHJvKQpgYGAKCiMjIyBIb21ld29yazogUHJlZGljdGluZyBIb3VzZSBQcmljZXMgaW4gS2luZyBDb3VudHkgVXNpbmcgTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24KCiMjIyBFeGVyY2lzZSAxOiBDb2xsZWN0aW5nIGFuZCBVbmRlcnN0YW5kaW5nIERhdGEKCkluIHRoaXMgaG9tZXdvcmssIHlvdSB3aWxsIGFuYWx5emUgaG91c2Ugc2FsZXMgaW4gS2luZyBDb3VudHksIFdhc2hpbmd0b24gU3RhdGUsIHVzaW5nIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIHRvIHByZWRpY3QgaG91c2UgcHJpY2VzLiBVbmRlcnN0YW5kaW5nIHRoZSBkYXRhc2V0IHN0cnVjdHVyZSBpcyBlc3NlbnRpYWwgYmVmb3JlIGJ1aWxkaW5nIGEgcHJlZGljdGl2ZSBtb2RlbC4KCkhlcmUgaXMgdGhlIHJldmlzZWQgdmVyc2lvbiB3aXRoIGltcHJvdmVkIGdyYW1tYXI6CgpUaGUgYWltIG9mIHRoaXMgaG9tZXdvcmsgaXMgdG8gcHJlZGljdCBob3VzZSBzYWxlcyBpbiBLaW5nIENvdW50eSwgV2FzaGluZ3RvbiBTdGF0ZSwgVVNBLCB1c2luZyBNdWx0aXBsZSBMaW5lYXIgUmVncmVzc2lvbiAoTUxSKS4gVGhlIGRhdGFzZXQgY29uc2lzdHMgb2YgaGlzdG9yaWNhbCBkYXRhIG9uIGhvdXNlcyBzb2xkIGJldHdlZW4gTWF5IDIwMTQgYW5kIE1heSAyMDE1LiAKCldlIGFpbSB0byBwcmVkaWN0IGhvdXNlIHNhbGVzIGluIEtpbmcgQ291bnR5IHdpdGggYW4gYWNjdXJhY3kgb2YgYXQgbGVhc3QgNzXigJM4MCUgYW5kIHRvIGlkZW50aWZ5IHRoZSBmYWN0b3JzIHJlc3BvbnNpYmxlIGZvciBoaWdoZXIgcHJvcGVydHkgdmFsdWVzLCBwYXJ0aWN1bGFybHkgdGhvc2UgcHJpY2VkIGF0ICQ2NTBLIGFuZCBhYm92ZS4KClRoaXMgZGF0YXNldCBjb250YWlucyBob3VzZSBzYWxlIHByaWNlcyBmb3IgS2luZyBDb3VudHksIGluY2x1ZGluZyBTZWF0dGxlLiBJdCBpbmNsdWRlcyBkYXRhIG9uIGhvbWVzIHNvbGQgYmV0d2VlbiBNYXkgMjAxNCBhbmQgTWF5IDIwMTUuIFRoZSBkYXRhc2V0IGNvbnRhaW5zIDIxIHZhcmlhYmxlcyBhbmQgMjEsNjEzIG9ic2VydmF0aW9ucy4KCioqTWVhbmluZyBvZiBhYmJyZXZpYXRpb25zIGluIHRoZSBkYXRhc2V0OioqCgp8ICoqVmFyaWFibGUqKiAgICAgICB8ICoqRGVzY3JpcHRpb24qKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBpZCAgICAgICAgICAgICAgICAgfCBBIG5vdGF0aW9uIGZvciBhIGhvdXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGRhdGUgICAgICAgICAgICAgICB8IERhdGUgaG91c2Ugd2FzIHNvbGQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgcHJpY2UgICAgICAgICAgICAgIHwgUHJpY2UgaXMgcHJlZGljdGlvbiB0YXJnZXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBiZWRyb29tcyAgICAgICAgICAgfCBOdW1iZXIgb2YgYmVkcm9vbXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGJhdGhyb29tcyAgICAgICAgICB8IE51bWJlciBvZiBiYXRocm9vbXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8Cnwgc3FmdF9saXZpbmcgICAgICAgIHwgU3F1YXJlIGZvb3RhZ2Ugb2YgdGhlIGhvbWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBzcWZ0X2xvdCAgICAgICAgICAgfCBTcXVhcmUgZm9vdGFnZSBvZiB0aGUgbG90ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGZsb29ycyAgICAgICAgICAgICB8IFRvdGFsIGZsb29ycyAobGV2ZWxzKSBpbiBob3VzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8Cnwgd2F0ZXJmcm9udCAgICAgICAgIHwgSG91c2Ugd2hpY2ggaGFzIGEgdmlldyB0byBhIHdhdGVyZnJvbnQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCB2aWV3ICAgICAgICAgICAgICAgfCBIYXMgYmVlbiB2aWV3ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGNvbmRpdGlvbiAgICAgICAgICB8IEhvdyBnb29kIHRoZSBjb25kaXRpb24gaXMgb3ZlcmFsbCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgZ3JhZGUgICAgICAgICAgICAgIHwgT3ZlcmFsbCBncmFkZSBnaXZlbiB0byB0aGUgaG91c2luZyB1bml0LCBiYXNlZCBvbiBLaW5nIENvdW50eSBncmFkaW5nIHN5c3RlbSAgIHwKfCBzcWZ0X2Fib3ZlICAgICAgICAgfCBTcXVhcmUgZm9vdGFnZSBvZiBob3VzZSBhcGFydCBmcm9tIGJhc2VtZW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IHNxZnRfYmFzZW1lbnQgICAgICB8IFNxdWFyZSBmb290YWdlIG9mIHRoZSBiYXNlbWVudCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgeXJfYnVpbHQgICAgICAgICAgIHwgQnVpbHQgWWVhciAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCB5cl9yZW5vdmF0ZWQgICAgICAgfCBZZWFyIHdoZW4gaG91c2Ugd2FzIHJlbm92YXRlZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IHppcGNvZGUgICAgICAgICAgICB8IFppcCBjb2RlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgbGF0ICAgICAgICAgICAgICAgIHwgTGF0aXR1ZGUgY29vcmRpbmF0ZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBsb25nICAgICAgICAgICAgICAgfCBMb25naXR1ZGUgY29vcmRpbmF0ZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IHNxZnRfbGl2aW5nMTUgICAgICB8IExpdmluZyByb29tIGFyZWEgaW4gMjAxNSAoaW1wbGllcyBzb21lIHJlbm92YXRpb25zKSBUaGlzIG1pZ2h0IG9yIG1pZ2h0IG5vdCBoYXZlIGFmZmVjdGVkIHRoZSBsb3Qgc2l6ZSBhcmVhIHwKfCBzcWZ0X2xvdDE1ICAgICAgICAgfCBMb3RTaXplIGFyZWEgaW4gMjAxNSAoaW1wbGllcyBzb21lIHJlbm92YXRpb25zKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAoKIyMjIyBJbnN0cnVjdGlvbnMKCjEuICoqTG9hZCB0aGUgZGF0YXNldDoqKgogICAtIFVzZSBgcmVhZC5jc3YoKWAgdG8gbG9hZCB0aGUgZGF0YXNldCBmcm9tIHRoZSBmaWxlIGBrY19ob3VzZV9kYXRhLmNzdmAuCgoyLiAqKkluc3BlY3QgdGhlIGRhdGEgc3RydWN0dXJlOioqCiAgIC0gVXNlIGBzdHIoKWAgdG8gZGlzcGxheSB2YXJpYWJsZSBuYW1lcywgdHlwZXMsIGFuZCBzYW1wbGUgdmFsdWVzLgogICAtIENvbmZpcm0gdGhlIGRhdGFzZXQgY29udGFpbnMgMjEgdmFyaWFibGVzIGFuZCAyMSw2MTMgb2JzZXJ2YXRpb25zLgoKMy4gKipFeHBsb3JlIHRoZSByZXNwb25zZSB2YXJpYWJsZSAocHJpY2UpOioqCiAgIC0gVXNlIGBzdW1tYXJ5KClgIHRvIHZpZXcgc3RhdGlzdGljcyBsaWtlIHRoZSBtaW5pbXVtLCBtZWFuLCBhbmQgbWF4aW11bSBwcmljZS4KICAgLSBOb3RlIHRoZSByYW5nZSBhbmQgYXZlcmFnZSBwcmljZSBvZiBob3VzZXMuCgo0LiAqKlZpc3VhbGl6ZSB0aGUgcmVzcG9uc2UgdmFyaWFibGU6KioKICAgLSBDcmVhdGUgYSBoaXN0b2dyYW0gdXNpbmcgYGhpc3QoKWAgdG8gZXhhbWluZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHByaWNlcy4KICAgLSBBZGp1c3QgdGhlIGBicmVha3NgIHBhcmFtZXRlciB0byBwcm92aWRlIGEgZGV0YWlsZWQgdmlldy4KCjUuICoqVW5kZXJzdGFuZCB0aGUgZGF0YXNldCBmZWF0dXJlczoqKgogICAtIFVzZSBgc3VtbWFyeSgpYCBhbmQgYGhlYWQoKWAgdG8gZXhwbG9yZSBwcmVkaWN0b3IgdmFyaWFibGVzIChlLmcuLCBgYmVkcm9vbXNgLCBgc3FmdF9saXZpbmdgLCBgY29uZGl0aW9uYCkuCiAgIC0gSWRlbnRpZnkgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHN1Y2ggYXMgYHdhdGVyZnJvbnRgLCBgdmlld2AsIGFuZCBgZ3JhZGVgLgoKYGBge3IgRXhlcmNpc2VfMX0KIyBMb2FkIHRoZSBkYXRhc2V0CmhvdXNlcyA8LSByZWFkLmNzdigia2NfaG91c2VfZGF0YS5jc3YiKQoKIyBJbnNwZWN0IHRoZSBkYXRhIHN0cnVjdHVyZQpzdHIoaG91c2VzKQoKIyBFeHBsb3JlIHRoZSByZXNwb25zZSB2YXJpYWJsZQpzdW1tYXJ5KGhvdXNlcyRwcmljZSkKCiMgVmlzdWFsaXplIHRoZSByZXNwb25zZSB2YXJpYWJsZQpoaXN0KGhvdXNlcyRwcmljZSwgYnJlYWtzID0gNTAsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEhvdXNlIFByaWNlcyIsIHhsYWIgPSAiSG91c2UgUHJpY2VzIikKCiMgVW5kZXJzdGFuZCB0aGUgZGF0YXNldCBmZWF0dXJlcwpzdW1tYXJ5KGhvdXNlc1ssIGMoImJlZHJvb21zIiwgImJhdGhyb29tcyIsICJzcWZ0X2xpdmluZyIsICJjb25kaXRpb24iLCAiZ3JhZGUiLCAid2F0ZXJmcm9udCIsICJ2aWV3IildKQpgYGAKCi0tLQoKIyMjIEV4ZXJjaXNlIDI6IEV4cGxvcmluZyBSZWxhdGlvbnNoaXBzIEJldHdlZW4gVmFyaWFibGVzCgpFeGFtaW5pbmcgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHByZWRpY3RvcnMgYW5kIHRoZSB0YXJnZXQgdmFyaWFibGUgaXMgYSBjcml0aWNhbCBzdGVwIGJlZm9yZSBidWlsZGluZyBhIHJlZ3Jlc3Npb24gbW9kZWwuCgojIyMjIEluc3RydWN0aW9ucwoKMS4gKipDb21wdXRlIGEgY29ycmVsYXRpb24gbWF0cml4OioqCiAgIC0gVXNlIGBjb3IoKWAgd2l0aCBudW1lcmljIHZhcmlhYmxlcyAoZS5nLiwgYHByaWNlYCwgYHNxZnRfbGl2aW5nYCwgYHNxZnRfbG90YCwgYGJlZHJvb21zYCwgYGJhdGhyb29tc2ApLgoKMi4gKipDcmVhdGUgc2NhdHRlcnBsb3RzOioqCiAgIC0gVXNlIGBwbG90KClgIHRvIHZpc3VhbGl6ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gYHByaWNlYCBhbmQgcHJlZGljdG9ycyBsaWtlIGBzcWZ0X2xpdmluZ2AsIGBiZWRyb29tc2AsIGFuZCBgYmF0aHJvb21zYC4KCjMuICoqSW5jbHVkZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXM6KioKICAgLSBVc2UgYm94cGxvdHMgdG8gdmlzdWFsaXplIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBgcHJpY2VgIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgbGlrZSBgd2F0ZXJmcm9udGAgYW5kIGBncmFkZWAuCgo0LiAqKkludGVycHJldCB0aGUgcmVzdWx0czoqKgogICAtIElkZW50aWZ5IHByZWRpY3RvcnMgc2hvd2luZyBzdHJvbmcgcG9zaXRpdmUgb3IgbmVnYXRpdmUgY29ycmVsYXRpb25zIHdpdGggcHJpY2UuCgpgYGB7ciBFeGVyY2lzZV8yfQojIENvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApudW1lcmljX3ZhcnMgPC0gYygicHJpY2UiLCAic3FmdF9saXZpbmciLCAic3FmdF9sb3QiLCAiYmVkcm9vbXMiLCAiYmF0aHJvb21zIiwgInNxZnRfYWJvdmUiLCAic3FmdF9iYXNlbWVudCIpCmNvcl9tYXRyaXggPC0gY29yKGhvdXNlc1ssIG51bWVyaWNfdmFyc10sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQpwcmludChjb3JfbWF0cml4KQoKIyBDcmVhdGUgc2NhdHRlcnBsb3RzCnBsb3QoaG91c2VzJHNxZnRfbGl2aW5nLCBob3VzZXMkcHJpY2UsIG1haW4gPSAiUHJpY2UgdnMuIFNxZnQgTGl2aW5nIiwgeGxhYiA9ICJTcWZ0IExpdmluZyIsIHlsYWIgPSAiUHJpY2UiKQpwbG90KGhvdXNlcyRiYXRocm9vbXMsIGhvdXNlcyRwcmljZSwgbWFpbiA9ICJQcmljZSB2cy4gQmF0aHJvb21zIiwgeGxhYiA9ICJCYXRocm9vbXMiLCB5bGFiID0gIlByaWNlIikKCiMgQm94cGxvdHMgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcwpib3hwbG90KHByaWNlIH4gd2F0ZXJmcm9udCwgZGF0YSA9IGhvdXNlcywgbWFpbiA9ICJQcmljZSBieSBXYXRlcmZyb250IiwgeGxhYiA9ICJXYXRlcmZyb250ICgwID0gTm8sIDEgPSBZZXMpIiwgeWxhYiA9ICJQcmljZSIpCmJveHBsb3QocHJpY2UgfiBncmFkZSwgZGF0YSA9IGhvdXNlcywgbWFpbiA9ICJQcmljZSBieSBHcmFkZSIsIHhsYWIgPSAiR3JhZGUiLCB5bGFiID0gIlByaWNlIikKYGBgCgotLS0KCiMjIyBFeGVyY2lzZSAzOiBCdWlsZGluZyB0aGUgSW5pdGlhbCBSZWdyZXNzaW9uIE1vZGVsCgpCdWlsZCBhbiBpbml0aWFsIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcga2V5IHByZWRpY3RvcnMsIGluY2x1ZGluZyBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIHRvIHVuZGVyc3RhbmQgdGhlaXIgaW1wYWN0IG9uIGhvdXNlIHByaWNlcy4KCiMjIyMgSW5zdHJ1Y3Rpb25zCgoxLiAqKkNvbnZlcnQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRvIGZhY3RvcnM6KioKICAgLSBFbnN1cmUgdmFyaWFibGVzIGxpa2UgYHdhdGVyZnJvbnRgLCBgdmlld2AsIGFuZCBgZ3JhZGVgIGFyZSB0cmVhdGVkIGFzIGZhY3RvcnMuCgoyLiAqKkZpdCB0aGUgcmVncmVzc2lvbiBtb2RlbDoqKgogICAtIFVzZSBgbG0oKWAgd2l0aCBgcHJpY2VgIGFzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHByZWRpY3RvcnMgc3VjaCBhcyBgc3FmdF9saXZpbmdgLCBgYmVkcm9vbXNgLCBgYmF0aHJvb21zYCwgYGdyYWRlYCwgYW5kIGB3YXRlcmZyb250YC4KCjMuICoqVmlldyBtb2RlbCBjb2VmZmljaWVudHM6KioKICAgLSBFeGFtaW5lIHRoZSBtb2RlbCBvdXRwdXQgZm9yIGNvZWZmaWNpZW50cyBhbmQgaW50ZXJjZXB0LgoKNC4gKipTdW1tYXJpemUgdGhlIG1vZGVsOioqCiAgIC0gVXNlIGBzdW1tYXJ5KClgIHRvIHJldmlldyBSLXNxdWFyZWQsIHAtdmFsdWVzLCBhbmQgcmVzaWR1YWwgc3RhdGlzdGljcy4KCmBgYHtyIEV4ZXJjaXNlXzN9CiMgQ29udmVydCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgdG8gZmFjdG9ycwpob3VzZXMkd2F0ZXJmcm9udCA8LSBhcy5mYWN0b3IoaG91c2VzJHdhdGVyZnJvbnQpCmhvdXNlcyR2aWV3IDwtIGFzLmZhY3Rvcihob3VzZXMkdmlldykKaG91c2VzJGdyYWRlIDwtIGFzLmZhY3Rvcihob3VzZXMkZ3JhZGUpCgojIEZpdCB0aGUgcmVncmVzc2lvbiBtb2RlbApob3VzZV9tb2RlbCA8LSBsbShwcmljZSB+IHNxZnRfbGl2aW5nICsgYmVkcm9vbXMgKyBiYXRocm9vbXMgKyBncmFkZSArIHdhdGVyZnJvbnQsIGRhdGEgPSBob3VzZXMpCgojIFZpZXcgY29lZmZpY2llbnRzCmNvZWYoaG91c2VfbW9kZWwpCgojIFN1bW1hcml6ZSB0aGUgbW9kZWwKc3VtbWFyeShob3VzZV9tb2RlbCkKYGBgCgotLS0KCiMjIyBFeGVyY2lzZSA0OiBEaWFnbm9zaW5nIGFuZCBJbXByb3ZpbmcgdGhlIE1vZGVsCgpSZWZpbmUgeW91ciBtb2RlbCB0byBpbXByb3ZlIGl0cyBmaXQsIGluY2x1ZGUgbW9yZSB2YXJpYWJsZXMsIGFuZCBpbnRlcnByZXQgdGhlIHJlc3VsdHMuCgojIyMjIEluc3RydWN0aW9ucwoKMS4gKipFdmFsdWF0ZSByZXNpZHVhbHM6KioKICAgLSBQbG90IHJlc2lkdWFscyB1c2luZyBgcGxvdCgpYCBhbmQgY2hlY2sgZm9yIHBhdHRlcm5zLgoKMi4gKipBZGQgbW9yZSBwcmVkaWN0b3JzOioqCiAgIC0gSW5jbHVkZSBhZGRpdGlvbmFsIHZhcmlhYmxlcyAoZS5nLiwgYHNxZnRfbG90YCwgYGNvbmRpdGlvbmAsIGB5cl9idWlsdGAsIGB2aWV3YCkgdG8gaW1wcm92ZSB0aGUgbW9kZWwuCgozLiAqKkluY2x1ZGUgaW50ZXJhY3Rpb24gdGVybXMgYW5kIG5vbmxpbmVhciBlZmZlY3RzOioqCiAgIC0gSWRlbnRpZnkgYSB2YXJpYWJsZSBsaWtlbHkgdG8gaGF2ZSBhIG5vbmxpbmVhciBlZmZlY3Qgb24gcHJpY2UgKGUuZy4sIGBzcWZ0X2xpdmluZ2ApLgogICAtIEFkZCBhIHNxdWFyZWQgdGVybSBmb3IgYHNxZnRfbGl2aW5nYCB0byBjYXB0dXJlIHRoZSBub25saW5lYXIgcmVsYXRpb25zaGlwLgogICAtIEFkZCBhbiBpbnRlcmFjdGlvbiB0ZXJtIGJldHdlZW4gdHdvIHZhcmlhYmxlcyAoZS5nLiwgYGJhdGhyb29tc2AgYW5kIGBzcWZ0X2xpdmluZ2ApLgoKNC4gKipGaXQgdGhlIHVwZGF0ZWQgbW9kZWw6KioKICAgLSBVcGRhdGUgdGhlIG1vZGVsIHRvIGluY2x1ZGUgdGhlIG5ldyB0ZXJtcy4KCjUuICoqQ29tcGFyZSBtb2RlbHM6KioKICAgLSBDb21wYXJlIFItc3F1YXJlZCBhbmQgYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlcyB0byBkZXRlcm1pbmUgbW9kZWwgaW1wcm92ZW1lbnRzLgoKYGBge3IgRXhlcmNpc2VfNH0KIyBBZGQgc3F1YXJlZCB0ZXJtIGZvciBzcWZ0X2xpdmluZwpob3VzZXMkc3FmdF9saXZpbmdfc3EgPC0gaG91c2VzJHNxZnRfbGl2aW5nXjIKCiMgQWRkIGludGVyYWN0aW9uIHRlcm0gYmV0d2VlbiBiYXRocm9vbXMgYW5kIHNxZnRfbGl2aW5nCmhvdXNlcyRiYXRoX3NxZnRfaW50ZXJhY3Rpb24gPC0gaG91c2VzJGJhdGhyb29tcyAqIGhvdXNlcyRzcWZ0X2xpdmluZwoKIyBGaXQgdGhlIHVwZGF0ZWQgbW9kZWwKaG91c2VfbW9kZWxfaW1wcm92ZWQgPC0gbG0ocHJpY2UgfiBzcWZ0X2xpdmluZyArIHNxZnRfbGl2aW5nX3NxICsgYmVkcm9vbXMgKyBiYXRocm9vbXMgKyBiYXRoX3NxZnRfaW50ZXJhY3Rpb24gKyBncmFkZSArIHdhdGVyZnJvbnQgKyB2aWV3ICsgc3FmdF9sb3QgKyB5cl9idWlsdCwgZGF0YSA9IGhvdXNlcykKCiMgU3VtbWFyaXplIHRoZSBpbXByb3ZlZCBtb2RlbApzdW1tYXJ5KGhvdXNlX21vZGVsX2ltcHJvdmVkKQoKI1Bsb3R0aW5nIHRoZSByZXNpZHVhbHMgYSBleHRyYSBsaW5lCnBsb3QoaG91c2VfbW9kZWxfaW1wcm92ZWQkcmVzaWR1YWxzLCBtYWluID0gIlJlc2lkdWFsIFBsb3QiLCB4bGFiID0gIkZpdHRlZCBWYWx1ZXMiLCB5bGFiID0gIlJlc2lkdWFscyIsIHBjaCA9IDIwKQphYmxpbmUoaCA9IDAsIGNvbCA9ICJyZWQiKQoKYGBgCgotLS0KCiMjIyBFeGVyY2lzZSA1OiBFdmFsdWF0aW5nIE1vZGVsIFBlcmZvcm1hbmNlCgpBc3Nlc3MgdGhlIHBlcmZvcm1hbmNlIG9mIHlvdXIgaW1wcm92ZWQgbW9kZWwgYW5kIGludGVycHJldCB0aGUgc2lnbmlmaWNhbmNlIG9mIHByZWRpY3RvcnMuCgojIyMjIEluc3RydWN0aW9ucwoKMS4gKipSZXZpZXcgbW9kZWwgc3VtbWFyeToqKgogICAtIEV4YW1pbmUgdGhlIGNvZWZmaWNpZW50cywgcC12YWx1ZXMsIFItc3F1YXJlZCwgYW5kIGFkanVzdGVkIFItc3F1YXJlZCB2YWx1ZXMuCgoyLiAqKkludGVycHJldCBjb2VmZmljaWVudHM6KioKICAgLSBJZGVudGlmeSBzaWduaWZpY2FudCBwcmVkaWN0b3JzIGJhc2VkIG9uIHAtdmFsdWVzLgoKMy4gKipBbmFseXplIHRoZSBlZmZlY3Qgb2Ygbm9ubGluZWFyIGFuZCBpbnRlcmFjdGlvbiB0ZXJtczoqKgogICAtIEludGVycHJldCB0aGUgY29lZmZpY2llbnRzIG9mIGBzcWZ0X2xpdmluZ19zcWAgYW5kIGBiYXRoX3NxZnRfaW50ZXJhY3Rpb25gLgoKYGBge3IgRXhlcmNpc2VfNX0KIyBSZXZpZXcgbW9kZWwgc3VtbWFyeQpzdW1tYXJ5KGhvdXNlX21vZGVsX2ltcHJvdmVkKQoKCmBgYAoKLS0tCgojIyMgRXhlcmNpc2UgNjogUHJlZGljdGluZyBIb3VzZSBQcmljZXMKClVzZSB0aGUgaW1wcm92ZWQgbW9kZWwgdG8gcHJlZGljdCBob3VzZSBwcmljZXMgYW5kIGV2YWx1YXRlIGl0cyBwZXJmb3JtYW5jZS4KCiMjIyMgSW5zdHJ1Y3Rpb25zCgoxLiAqKkdlbmVyYXRlIHByZWRpY3Rpb25zOioqCiAgIC0gVXNlIGBwcmVkaWN0KClgIG9uIHRoZSBkYXRhc2V0IHRvIGNvbXB1dGUgcHJlZGljdGVkIHByaWNlcy4KCjIuICoqVmlzdWFsaXplIHByZWRpY3Rpb25zOioqCiAgIC0gQ3JlYXRlIGEgc2NhdHRlcnBsb3Qgb2YgYWN0dWFsIHZzLiBwcmVkaWN0ZWQgcHJpY2VzLgoKMy4gKipFdmFsdWF0ZSBhY2N1cmFjeToqKgogICAtIENvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYWN0dWFsIGFuZCBwcmVkaWN0ZWQgcHJpY2VzLgoKNC4gKipQcmVkaWN0IGZvciBhIG5ldyBob3VzZToqKgogICAtIENyZWF0ZSBhIG5ldyBkYXRhIGZyYW1lIHdpdGggdmFsdWVzIGZvciBhbGwgcHJlZGljdG9ycywgaW5jbHVkaW5nIHNxdWFyZWQgYW5kIGludGVyYWN0aW9uIHRlcm1zLgogICAtIFVzZSBgcHJlZGljdCgpYCB0byBlc3RpbWF0ZSB0aGUgcHJpY2Ugb2YgdGhpcyBoeXBvdGhldGljYWwgaG91c2UuCgoKYGBge3IgRXhlcmNpc2VfNn0KIyBHZW5lcmF0ZSBwcmVkaWN0aW9ucwpob3VzZXMkcHJlZGljdGVkX3ByaWNlIDwtIHByZWRpY3QoaG91c2VfbW9kZWxfaW1wcm92ZWQsIG5ld2RhdGEgPSBob3VzZXMpCgojIFZpc3VhbGl6ZSBwcmVkaWN0ZWQgdnMuIGFjdHVhbCBwcmljZXMKcGxvdChob3VzZXMkcHJpY2UsIGhvdXNlcyRwcmVkaWN0ZWRfcHJpY2UsIAogICAgIG1haW4gPSAiQWN0dWFsIHZzLiBQcmVkaWN0ZWQgSG91c2UgUHJpY2VzIiwgCiAgICAgeGxhYiA9ICJBY3R1YWwgUHJpY2VzIiwgCiAgICAgeWxhYiA9ICJQcmVkaWN0ZWQgUHJpY2VzIiwgCiAgICAgcGNoID0gMTYsIGNvbCA9ICJibHVlIikKYWJsaW5lKGEgPSAwLCBiID0gMSwgY29sID0gInJlZCIsIGx3ZCA9IDIpCgojIENvbXB1dGUgY29ycmVsYXRpb24gYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCBwcmljZXMKY29yKGhvdXNlcyRwcmljZSwgaG91c2VzJHByZWRpY3RlZF9wcmljZSkKCiMgUHJlZGljdCBmb3IgYSBuZXcgaG91c2UKbmV3X2hvdXNlIDwtIGRhdGEuZnJhbWUoCiAgc3FmdF9saXZpbmcgPSAyNTAwLCAgIyBFeGFtcGxlIHZhbHVlIGZvciBzcWZ0X2xpdmluZwogIHNxZnRfbGl2aW5nX3NxID0gMjUwMF4yLCAgIyBTcXVhcmVkIHZhbHVlIGZvciBzcWZ0X2xpdmluZwogIGJlZHJvb21zID0gMywgICMgRXhhbXBsZSB2YWx1ZSBmb3IgYmVkcm9vbXMKICBiYXRocm9vbXMgPSAzLCAgIyBFeGFtcGxlIHZhbHVlIGZvciBiYXRocm9vbXMKICBiYXRoX3NxZnRfaW50ZXJhY3Rpb24gPSAyNTAwICogMywgICMgSW50ZXJhY3Rpb24gdGVybSBiZXR3ZWVuIGJhdGhyb29tcyBhbmQgc3FmdF9saXZpbmcKICBncmFkZSA9IGZhY3Rvcig4LCBsZXZlbHMgPSBsZXZlbHMoaG91c2VzJGdyYWRlKSksICAjIEV4YW1wbGUgZ3JhZGUsIGFzIGEgZmFjdG9yCiAgd2F0ZXJmcm9udCA9IGZhY3RvcigwLCBsZXZlbHMgPSBsZXZlbHMoaG91c2VzJHdhdGVyZnJvbnQpKSwgICMgV2F0ZXJmcm9udCBhcyBmYWN0b3IgKDAgZm9yIG5vKQogIHZpZXcgPSBmYWN0b3IoMCwgbGV2ZWxzID0gbGV2ZWxzKGhvdXNlcyR2aWV3KSksICAjIFZpZXcgYXMgZmFjdG9yICgwIGZvciBubyB2aWV3KQogIGNvbmRpdGlvbiA9IGZhY3RvcigzLCBsZXZlbHMgPSBsZXZlbHMoaG91c2VzJGNvbmRpdGlvbikpLCAgIyBDb25kaXRpb24gYXMgZmFjdG9yICgzIGlzIGFuIGV4YW1wbGUpCiAgeXJfYnVpbHQgPSAyMDAwLCAgIyBFeGFtcGxlIGZvciB5ZWFyIGJ1aWx0CiAgc3FmdF9sb3QgPSA1MDAwICAjIEV4YW1wbGUgc3FmdF9sb3QgKGVuc3VyZSBpdCdzIGluY2x1ZGVkKQopCgojIFByZWRpY3QgcHJpY2UgZm9yIHRoZSBuZXcgaG91c2UgdXNpbmcgdGhlIGltcHJvdmVkIG1vZGVsCnByZWRpY3RlZF9wcmljZV9uZXcgPC0gcHJlZGljdChob3VzZV9tb2RlbF9pbXByb3ZlZCwgbmV3ZGF0YSA9IG5ld19ob3VzZSkKCiMgUHJpbnQgcHJlZGljdGVkIHByaWNlIGZvciB0aGUgbmV3IGhvdXNlCnByaW50KHByZWRpY3RlZF9wcmljZV9uZXcpCgpgYGAKCi0tLQoKIyMjIEV4ZXJjaXNlIDc6IEludGVycHJldGluZyB0aGUgSW1wYWN0IG9mIE5vbmxpbmVhciBhbmQgSW50ZXJhY3Rpb24gRWZmZWN0cwoKVW5kZXJzdGFuZGluZyBob3cgbm9ubGluZWFyIHRyYW5zZm9ybWF0aW9ucyBhbmQgaW50ZXJhY3Rpb24gdGVybXMgaW5mbHVlbmNlIHRoZSBtb2RlbCBpcyBjcnVjaWFsIGZvciBpbnRlcnByZXRpbmcgdGhlIHJlc3VsdHMgYWNjdXJhdGVseS4KCiMjIyMgSW5zdHJ1Y3Rpb25zCgoxLiAqKkludGVycHJldCB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHNxdWFyZWQgdGVybSAoYHNxZnRfbGl2aW5nX3NxYCk6KioKICAgLSBEaXNjdXNzIGhvdyB0aGUgc3F1YXJlIG9mIGxpdmluZyBhcmVhIGFmZmVjdHMgdGhlIHByaWNlLgogICAtIEV4cGxhaW4gd2hldGhlciB0aGlzIHN1Z2dlc3RzIGEgZGltaW5pc2hpbmcgb3IgaW5jcmVhc2luZyByZXR1cm4gb24gYWRkaXRpb25hbCBzcXVhcmUgZm9vdGFnZS4KICAgCkFuc3dlciA9IFRoZSBzcXVhcmVkIHRlcm0gZm9yIHNxZnRfbGl2aW5nX3NxICh0aGUgc3F1YXJlIG9mIGxpdmluZyBhcmVhKSBpcyBhZGRlZCB0byB0aGUgbW9kZWwgdG8gYWNjb3VudCBmb3IgYSBwb3RlbnRpYWwgbm9ubGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxpdmluZyBzcGFjZSBhbmQgaG91c2UgcHJpY2UuIFRoZSBjb2VmZmljaWVudCBmb3IgdGhpcyBzcXVhcmVkIHRlcm0gaW5kaWNhdGVzIHRoZSByYXRlIG9mIGNoYW5nZSBpbiB0aGUgaG91c2UgcHJpY2UgYXMgdGhlIHNxdWFyZSBmb290YWdlIGluY3JlYXNlcy4KCklmIHRoZSBjb2VmZmljaWVudCBvZiBzcWZ0X2xpdmluZ19zcSBpcyBwb3NpdGl2ZSwgaXQgbWVhbnMgdGhhdCBhcyB0aGUgc3F1YXJlIGZvb3RhZ2UgaW5jcmVhc2VzLCB0aGUgcmF0ZSBvZiBwcmljZSBpbmNyZWFzZSBiZWNvbWVzIGxhcmdlci4gVGhpcyB3b3VsZCBzdWdnZXN0IGFuIGluY3JlYXNpbmcgcmV0dXJuIG9uIGFkZGl0aW9uYWwgc3F1YXJlIGZvb3RhZ2UsIG1lYW5pbmcgdGhhdCBsYXJnZXIgaG91c2VzIGluY3JlYXNlIGluIHByaWNlIG1vcmUgc3RlZXBseSB0aGFuIHNtYWxsZXIgb25lcy4KCklmIHRoZSBjb2VmZmljaWVudCBvZiBzcWZ0X2xpdmluZ19zcSBpcyBuZWdhdGl2ZSwgaXQgc3VnZ2VzdHMgYSBkaW1pbmlzaGluZyByZXR1cm4gb24gYWRkaXRpb25hbCBzcXVhcmUgZm9vdGFnZSwgbWVhbmluZyB0aGF0IGFmdGVyIGEgY2VydGFpbiBwb2ludCwgYWRkaXRpb25hbCBzcXVhcmUgZm9vdGFnZSBpbmNyZWFzZXMgdGhlIGhvdXNlIHByaWNlIGF0IGEgc2xvd2VyIHJhdGUuCgpJbiBjb25jbHVzaW9uIG91ciBjYXNlLCBpZiB0aGUgY29lZmZpY2llbnQgaXMgcG9zaXRpdmUsIGl0IHNob3dzIHRoYXQgbGFyZ2VyIGhvdXNlcyB0ZW5kIHRvIGJlIG1vcmUgdmFsdWFibGUgYXQgYW4gYWNjZWxlcmF0aW5nIHJhdGUuCgoyLiAqKkludGVycHJldCB0aGUgaW50ZXJhY3Rpb24gdGVybSAoYGJhdGhfc3FmdF9pbnRlcmFjdGlvbmApOioqCiAgIC0gRXhwbGFpbiBob3cgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gYmF0aHJvb21zIGFuZCBsaXZpbmcgYXJlYSBpbmZsdWVuY2VzIHRoZSBwcmljZS4KICAgLSBEaXNjdXNzIHNjZW5hcmlvcyB3aGVyZSB0aGlzIGludGVyYWN0aW9uIGNvdWxkIHNpZ25pZmljYW50bHkgaW1wYWN0IHRoZSBob3VzZSBwcmljZS4KICAgCkFuc3dlciA9IFRoZSBpbnRlcmFjdGlvbiB0ZXJtIGJldHdlZW4gYmF0aHJvb21zIGFuZCBzcWZ0X2xpdmluZyBjYXB0dXJlcyBob3cgdGhlIGVmZmVjdCBvZiBvbmUgdmFyaWFibGUgZGVwZW5kcyBvbiB0aGUgdmFsdWUgb2YgdGhlIG90aGVyLiBTcGVjaWZpY2FsbHksIHRoaXMgdGVybSBleHBsYWlucyBob3cgdGhlIGNvbWJpbmF0aW9uIG9mIGFkZGl0aW9uYWwgYmF0aHJvb21zIGFuZCBsaXZpbmcgYXJlYSBzaXplIGpvaW50bHkgaW1wYWN0cyB0aGUgcHJpY2Ugb2YgYSBob3VzZS4KClBvc2l0aXZlIGNvZWZmaWNpZW50IGZvciBpbnRlcmFjdGlvbjogSWYgdGhlIGNvZWZmaWNpZW50IGZvciBiYXRoX3NxZnRfaW50ZXJhY3Rpb24gaXMgcG9zaXRpdmUsIHRoaXMgbWVhbnMgdGhhdCBoYXZpbmcgbW9yZSBiYXRocm9vbXMgYW1wbGlmaWVzIHRoZSBwcmljZSBpbXBhY3Qgb2YgaGF2aW5nIG1vcmUgbGl2aW5nIHNwYWNlLiBJbiBvdGhlciB3b3JkcywgbGFyZ2VyIGhvbWVzIHdpdGggbW9yZSBiYXRocm9vbXMgdGVuZCB0byBiZSBwcmljZWQgc2lnbmlmaWNhbnRseSBoaWdoZXIgdGhhbiBsYXJnZXIgaG9tZXMgd2l0aCBmZXdlciBiYXRocm9vbXMuIFRoaXMgY291bGQgYmUgdGhlIGNhc2UgaW4gbHV4dXJ5IGhvbWVzIG9yIGZhbWlseS1zaXplZCBob21lcyB3aGVyZSBtb3JlIGJhdGhyb29tcyBhcmUgZXhwZWN0ZWQgdG8gYWNjb21tb2RhdGUgbGFyZ2VyIGxpdmluZyBhcmVhcy4KCk5lZ2F0aXZlIGNvZWZmaWNpZW50IGZvciBpbnRlcmFjdGlvbjogSWYgdGhlIGNvZWZmaWNpZW50IGlzIG5lZ2F0aXZlLCBpdCB3b3VsZCBzdWdnZXN0IHRoYXQgbW9yZSBiYXRocm9vbXMgaGF2ZSBsZXNzIG9mIGEgcHJpY2UgaW1wYWN0IG9uIGxhcmdlciBob21lcywgcG9zc2libHkgaW5kaWNhdGluZyB0aGF0IGZvciBob21lcyB3aXRoIHZlcnkgbGFyZ2Ugc3F1YXJlIGZvb3RhZ2UsIGFkZGluZyBhZGRpdGlvbmFsIGJhdGhyb29tcyBkb2Vzbid0IHNpZ25pZmljYW50bHkgaW5jcmVhc2UgdmFsdWUuCgpUaGlzIGludGVyYWN0aW9uIHRlcm0gaXMgcGFydGljdWxhcmx5IHJlbGV2YW50IGluIGxhcmdlciBob21lcywgd2hlcmUgdGhlIG51bWJlciBvZiBiYXRocm9vbXMgbWlnaHQgbWF0dGVyIG1vcmUgaW4gdGVybXMgb2YgZnVuY3Rpb25hbGl0eSBhbmQgcGVyY2VpdmVkIGx1eHVyeSwgd2hpY2ggZGlyZWN0bHkgaW5mbHVlbmNlcyBwcmljaW5nLgoKMy4gKipTdW1tYXJpemUgdGhlIG92ZXJhbGwgbW9kZWwgaW1wcm92ZW1lbnQ6KioKICAgLSBDb21wYXJlIHRoZSBhZGp1c3RlZCBSLXNxdWFyZWQgb2YgdGhlIGluaXRpYWwgYW5kIGltcHJvdmVkIG1vZGVscy4KICAgLSBEaXNjdXNzIGhvdyBhZGRpbmcgbm9ubGluZWFyIGFuZCBpbnRlcmFjdGlvbiB0ZXJtcyBoYXMgYWZmZWN0ZWQgbW9kZWwgcGVyZm9ybWFuY2UuCgoKQW5zd2VyID0gV2hlbiBjb21wYXJpbmcgdGhlIGFkanVzdGVkIFItc3F1YXJlZCBiZXR3ZWVuIHRoZSBpbml0aWFsIGFuZCBpbXByb3ZlZCBtb2RlbHM6CkluaXRpYWwgTW9kZWw6IFRoZSBhZGp1c3RlZCBSLXNxdWFyZWQgdmFsdWUgcHJvdmlkZXMgYSBiYXNlbGluZSBmb3IgaG93IHdlbGwgdGhlIG1vZGVsIGV4cGxhaW5zIHRoZSB2YXJpYXRpb24gaW4gaG91c2UgcHJpY2VzLiBUaGlzIG1pZ2h0IGJlIG1vZGVyYXRlIGlmIG9ubHkgbGluZWFyIHRlcm1zIGFyZSBpbmNsdWRlZC4KCkltcHJvdmVkIE1vZGVsOiBBZnRlciBhZGRpbmcgdGhlIHNxdWFyZWQgYW5kIGludGVyYWN0aW9uIHRlcm1zLCB5b3Ugc2hvdWxkIHNlZSBhbiBpbXByb3ZlbWVudCBpbiB0aGUgYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlLiBBIGhpZ2hlciBhZGp1c3RlZCBSLXNxdWFyZWQgbWVhbnMgdGhhdCB0aGUgaW1wcm92ZWQgbW9kZWwgaXMgZXhwbGFpbmluZyBtb3JlIG9mIHRoZSB2YXJpYXRpb24gaW4gdGhlIGhvdXNlIHByaWNlcy4gVGhpcyBpbXByb3ZlbWVudCBzdWdnZXN0cyB0aGF0IHRoZSBhZGRlZCBjb21wbGV4aXR5IG9mIGNhcHR1cmluZyBub25saW5lYXIgcmVsYXRpb25zaGlwcyBhbmQgaW50ZXJhY3Rpb25zIGJldHdlZW4gcHJlZGljdG9ycyBpcyBoZWxwaW5nIHRoZSBtb2RlbCBtYWtlIG1vcmUgYWNjdXJhdGUgcHJlZGljdGlvbnMuCgpUaGUgYWRkaXRpb24gb2Ygbm9ubGluZWFyIGFuZCBpbnRlcmFjdGlvbiB0ZXJtcyB0eXBpY2FsbHkgaW5jcmVhc2VzIG1vZGVsIHBlcmZvcm1hbmNlIGJ5IGJldHRlciBmaXR0aW5nIHRoZSB1bmRlcmx5aW5nIGRhdGEgc3RydWN0dXJlLCBlc3BlY2lhbGx5IHdoZW4gcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcyBhcmUgbW9yZSBjb21wbGV4IHRoYW4gc2ltcGxlIGxpbmVhciBwYXR0ZXJucy4gSG93ZXZlciwgaXQncyBpbXBvcnRhbnQgdG8gYWxzbyBldmFsdWF0ZSB0aGUgc2lnbmlmaWNhbmNlIG9mIGVhY2ggYWRkZWQgdGVybSB0byBlbnN1cmUgdGhhdCB0aGUgaW5jcmVhc2UgaW4gcGVyZm9ybWFuY2UgaXMgbm90IGp1c3QgZHVlIHRvIG92ZXJmaXR0aW5nIG9yIHVubmVjZXNzYXJ5IGNvbXBsZXhpdHkuCgpJbiBjb25jbHVzaW9uLCBhZGRpbmcgdGhlc2UgdGVybXMgc2hvdWxkIGlkZWFsbHkgaW1wcm92ZSB0aGUgbW9kZWwncyBhYmlsaXR5IHRvIGNhcHR1cmUgaW1wb3J0YW50IG51YW5jZXMgaW4gaG93IGRpZmZlcmVudCBmYWN0b3JzIGludGVyYWN0IHRvIGluZmx1ZW5jZSBob3VzZSBwcmljZXMsIGFuZCB0aGUgbW9kZWwncyBwZXJmb3JtYW5jZSAoYXMgbWVhc3VyZWQgYnkgUi1zcXVhcmVkKSBzaG91bGQgcmVmbGVjdCB0aGlzIGltcHJvdmVtZW50LgoKCgoKCgoKCgoKCg==