Name: Ruowei Fischer

UCID: M14820974

Part 1: Practice of modeling the landing distance using linear regression.

Initial exploration of the data

Step 1. Read the two files ‘FAA-1.xls’ (800 flights) and ‘FAA-2.xls’ into your R system. Please search “Read Excel files from R” in Google in case you do not know how to do that.
FAA1 <- read.csv("FAA1.csv", header = TRUE)
FAA2 <- read.csv("FAA2.csv", header = TRUE)
FAA2 <- FAA2[-c(151:200), ]

I used the read.csv function to load both csv files. I have previously saved the xls file downloaded from Canvas into csv files so it’s easier to load. Also, there were 50 rows of data with NA values, I have removed them.

Step 2. Check the structure of each data set using the “str” function. For each dataset, what is the sample size and how many variables? Is there any differencebetween the two data sets?
str(FAA1)
'data.frame':   800 obs. of  8 variables:
 $ aircraft    : chr  "boeing" "boeing" "boeing" "boeing" ...
 $ duration    : num  98.5 125.7 112 196.8 90.1 ...
 $ no_pasg     : int  53 69 61 56 70 55 54 57 61 56 ...
 $ speed_ground: num  107.9 101.7 71.1 85.8 59.9 ...
 $ speed_air   : num  109 103 NA NA NA ...
 $ height      : num  27.4 27.8 18.6 30.7 32.4 ...
 $ pitch       : num  4.04 4.12 4.43 3.88 4.03 ...
 $ distance    : num  3370 2988 1145 1664 1050 ...
str(FAA2)
'data.frame':   150 obs. of  7 variables:
 $ aircraft    : chr  "boeing" "boeing" "boeing" "boeing" ...
 $ no_pasg     : int  53 69 61 56 70 55 54 57 61 56 ...
 $ speed_ground: num  107.9 101.7 71.1 85.8 59.9 ...
 $ speed_air   : num  109 103 NA NA NA ...
 $ height      : num  27.4 27.8 18.6 30.7 32.4 ...
 $ pitch       : num  4.04 4.12 4.43 3.88 4.03 ...
 $ distance    : num  3370 2988 1145 1664 1050 ...

Sample size of FAA1 is 800, FAA2 is 150. FAA1 has 8 different variables and FAA2 only has 7, FAA2 does not have the duration variable.

Step 3. Merge the two data sets. Are there any duplications? Search “check duplicates in r” if you do not know how to check duplications. If the answer is “Yes”, what action you would take?
#outerjoin both FAA1 and FAA2
merged_data_outer <- merge(FAA1, FAA2, by = c("aircraft","no_pasg", "speed_ground","speed_air","height", "pitch", "distance"), all = TRUE)

#count the number of duplicates
num_duplicates <- sum(duplicated(merged_data_outer))
print(num_duplicates)
[1] 0
FAA <- merged_data_outer
attach(FAA)

I chose to use outer join so I can keep all unique data from both data sets. The outer join got rid of 100 rows of duplicate data, with duration values being NA. I used “duplicated” function to get a count of the duplicated data to verify there is no longer duplicate values, and it was zero.

Step 4. Check the structure of the combined data set. What is the sample size and how many variables? Provide summary statistics for each variable.
str(FAA)
'data.frame':   850 obs. of  8 variables:
 $ aircraft    : chr  "airbus" "airbus" "airbus" "airbus" ...
 $ no_pasg     : int  36 38 40 41 43 44 45 45 45 45 ...
 $ speed_ground: num  47.5 85.2 80.6 97.6 82.5 ...
 $ speed_air   : num  NA NA NA 97 NA ...
 $ height      : num  14 37 28.6 38.4 30.1 ...
 $ pitch       : num  4.3 4.12 3.62 3.53 4.09 ...
 $ distance    : num  251 1257 1021 2168 1321 ...
 $ duration    : num  172 188 93.5 123.3 109.2 ...
summary(FAA)
   aircraft            no_pasg      speed_ground      speed_air          height           pitch      
 Length:850         Min.   :29.0   Min.   : 27.74   Min.   : 90.00   Min.   :-3.546   Min.   :2.284  
 Class :character   1st Qu.:55.0   1st Qu.: 65.90   1st Qu.: 96.25   1st Qu.:23.314   1st Qu.:3.642  
 Mode  :character   Median :60.0   Median : 79.64   Median :101.15   Median :30.093   Median :4.008  
                    Mean   :60.1   Mean   : 79.45   Mean   :103.80   Mean   :30.144   Mean   :4.009  
                    3rd Qu.:65.0   3rd Qu.: 92.06   3rd Qu.:109.40   3rd Qu.:36.993   3rd Qu.:4.377  
                    Max.   :87.0   Max.   :141.22   Max.   :141.72   Max.   :59.946   Max.   :5.927  
                                                    NA's   :642                                      
    distance          duration     
 Min.   :  34.08   Min.   : 14.76  
 1st Qu.: 883.79   1st Qu.:119.49  
 Median :1258.09   Median :153.95  
 Mean   :1526.02   Mean   :154.01  
 3rd Qu.:1936.95   3rd Qu.:188.91  
 Max.   :6533.05   Max.   :305.62  
                   NA's   :50      

The new data set FAA has a sample size of 850 and 8 variables.

Step 5. By now, if you are asked to prepare ONE presentation slide to summarize your findings, what observations will you bring to the attention of FAA agents? Please list no more than five using “bullet statements”, from the most important to the least important.
  1. The total observation of the data has a sample size of 850. There are 8 variables in the dataset, and 7 are predictor variables, and one is the response variable.

  2. There is a binary variable - Aircraft, has two values, Boeing and Airbus.

  3. There are 50 missing values in the variable “duration”.

  4. The average landing distance is 1526, however, there are extreme values such as a minimum of 34 and a maximum of 6533. These are not normal which may need further analysis.

  5. There is a negative amount in the height variable, which is not normal.

Data Cleaning and further exploration

Step 6. Are there abnormal values in the data set? Please refer to the variable dictionary for criteria defining “normal/abnormal” values. Remove the rows that contain any “abnormal values” and report how many rows you have removed
#remove duration not greater than 40
FAA_new <- subset(FAA, duration > 40)

#remove speed_ground that's less than 30 or greater than 140
FAA_new <- subset(FAA_new, speed_ground >=30 & speed_ground <=140)

#remove speed_air that's less than 30 or greater than 140
FAA_new <- subset(FAA_new, speed_air >=30 & speed_ground <=140)

#remove height that's less than 6 meters
FAA_new <- subset(FAA_new, height >=6)

#remove distance that's over 6000 feet
FAA_new <- subset(FAA_new, distance < 6000)

Yes, there were abnormal values in the data set. Based on the variable dictionary, I have removed abnormal values, and now I have the sample size of 195.

Step 7. Repeat Step 4.
str(FAA_new)
'data.frame':   195 obs. of  8 variables:
 $ aircraft    : chr  "airbus" "airbus" "airbus" "airbus" ...
 $ no_pasg     : int  41 44 47 48 48 48 49 49 49 51 ...
 $ speed_ground: num  97.6 99.6 92.9 101.8 109.3 ...
 $ speed_air   : num  97 99.2 95.8 103.6 109.6 ...
 $ height      : num  38.4 35.2 23.8 23 33.1 ...
 $ pitch       : num  3.53 3.84 3.91 4.94 4.04 ...
 $ distance    : num  2168 2116 1955 2525 3177 ...
 $ duration    : num  123 139 169 157 200 ...
summary(FAA_new)
   aircraft            no_pasg       speed_ground      speed_air          height           pitch      
 Length:195         Min.   :41.00   Min.   : 88.69   Min.   : 90.00   Min.   : 9.697   Min.   :2.702  
 Class :character   1st Qu.:56.00   1st Qu.: 95.28   1st Qu.: 96.15   1st Qu.:23.365   1st Qu.:3.636  
 Mode  :character   Median :60.00   Median :100.75   Median :100.89   Median :29.837   Median :4.070  
                    Mean   :59.83   Mean   :103.43   Mean   :103.50   Mean   :30.359   Mean   :4.043  
                    3rd Qu.:65.00   3rd Qu.:109.57   3rd Qu.:109.42   3rd Qu.:36.590   3rd Qu.:4.442  
                    Max.   :80.00   Max.   :132.78   Max.   :132.91   Max.   :58.228   Max.   :5.311  
    distance       duration    
 Min.   :1741   Min.   : 45.5  
 1st Qu.:2161   1st Qu.:115.9  
 Median :2526   Median :149.3  
 Mean   :2784   Mean   :150.9  
 3rd Qu.:3186   3rd Qu.:185.4  
 Max.   :5382   Max.   :287.0  
Step 8. Since you have a small set of variables, you may want to show histograms for all of them.
# Load the tidyverse package
library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     ── Conflicts ───────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
selected_vars <- c("speed_ground", "speed_air", "height","pitch","duration","distance","no_pasg")
#aircraft was not selected as it was a categorical variable.

# Use walk to plot histograms for the selected variables
walk(selected_vars, ~ {
  hist(FAA_new[[.x]], main = paste("Histogram of", .x), 
       xlab = .x, col = "blue", border = "white", prob = TRUE)
  lines(density(FAA_new[[.x]], na.rm = TRUE), col = "red", lwd = 2)
})

We can see that speed_ground, speed_air, and distance are right skewed, and the rest of the variables shows normal distribution.

Step 9. Prepare another presentation slide to summarize your findings drawn from the cleaned data set, using no more than five “bullet statements”.
  1. The new set of data has a sample size of 195, there are 7 numeric variables and one binary variable.

  2. The speed_ground and speed_air value is very similar and both histogram shows skewed to the right. The mean speed is around 100 MPH.

  3. Number of Passengers shows the average number is around 60 passengers per fight.

  4. There are outliers in height, where the average is about 30, we observed that there are height as small as 9.6 and as large as 58.

  5. The average of a flight being in the air is about 150.9.

Initial analysis for identifying important factors that impact the response variable “landing distance”

Step 10. Compute the pairwise correlation between the landing distance and each factor X. Provide a table that ranks the factors based on the size (absolute value) of the correlation. This table contains three columns: the names of variables, the size of the correlation, the direction of the correlation (positive or negative). We call it Table 1, which will be used for comparison with our analysis later.
# Load the knitr package for creating a formatted table.
library(knitr)

# Convert 'aircraft' to numeric: 1 for 'airbus', 0 for 'boeing'
FAA_new$aircraft_numeric <- ifelse(FAA_new$aircraft == "airbus", 1, 0)

# View the updated dataframe to confirm the changes
head(FAA_new)

factors <- c("speed_ground", "speed_air", "height", "pitch", "duration", "no_pasg", "aircraft_numeric")

# Initialize an empty data frame to store the results
correlations <- data.frame(
  Variable = character(),
  SizeOfCorrelation = numeric(),
  DirectionOfCorrelation = character(),
  stringsAsFactors = FALSE
)

# Calculate the pairwise correlations
for (var in factors) {
  corr <- cor(FAA_new$distance, FAA_new[[var]], use = "complete.obs")
  correlations <- rbind(correlations, data.frame(
    Variable = var,
    SizeOfCorrelation = abs(corr),
    DirectionOfCorrelation = ifelse(corr > 0, "Positive", "Negative")
  ))
}

# Sort the data frame by the size of the correlation
correlations <- correlations[order(-correlations$SizeOfCorrelation), ]

# Print the table
cat("Table 1")
Table 1
print(correlations)
Step 11. Show X-Y scatter plots. Do you think the correlation strength observed in these plots is consistent with the values computed in Step 10?
library(ggplot2)
selected_vars <- c("speed_ground", "speed_air", "height", "pitch", "duration", "no_pasg")
#Loop through each variable and create scatter plots
for (var in selected_vars) {
  p <- ggplot(FAA_new, aes_string(x = var, y = "distance", color = "aircraft")) +
    geom_point() +
    ggtitle(paste("Scatter Plot of", var, "vs Landing Distance by Aircraft Type")) +
    xlab(var) +
    ylab("Distance") +
    theme_minimal() +
    scale_color_manual(values = c("blue", "red"))
  print(p)
}
Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
Please use tidy evaluation idioms with `aes()`. 
See also `vignette("ggplot2-in-packages")` for more information.

Yes, the correlation strength observed in these plots is consistent with the values computed. Based on the plots, we can clearly see that the speed_air and speed_ground has strong linear relationship with the distance, when speed_air and speed_ground value increases, distance also increases. The rest of the variables are scattered in the plots.

Step 12. Have you included the airplane make as a possible factor in Steps 10-11? You can code this character variable as 0/1.

I have included aircraft make in step 10. I wanted to include this variable to see if it has any correlation with the distance variable. Since it’s a categorical variable, I needed to transform the variable from a character variable to a numeric variable. In step 11, I decided to show the scatter plot grouped by the aircraft variable to provide better visualization.

Regression using a single factor each time

Step 13. Regress Y (landing distance) on each of the X variables. Provide a table that ranks the factors based on its significance. The smaller the p-value, the more significant the factor. This table contains three columns: the names of variables, the size of the p-value, the direction of the regression coefficient (positive or negative). We call it Table 2.
# Initialize an empty data frame to store the results
regression_results <- data.frame(
  Variable = character(),
  P_Value = numeric(),
  DirectionOfCoefficient = character(),
  stringsAsFactors = FALSE
)

# Loop through each factor to perform regression, factors were created in previous steps
for (var in factors) {
  # Define the regression formula
  formula <- as.formula(paste("distance ~", var))
  
  # Fit the linear model
  model <- lm(formula, data = FAA_new)
  
  # Get the p-value and coefficient for the factor
  p_value <- summary(model)$coefficients[2, 4]
  coefficient <- summary(model)$coefficients[2, 1]
  
  # Determine the direction of the coefficient
  direction <- ifelse(coefficient > 0, "Positive", "Negative")
  
  # Append the results to the data frame
  regression_results <- rbind(regression_results, data.frame(
    Variable = var,
    P_Value = p_value,
    DirectionOfCoefficient = direction
  ))
}

# Sort the data frame by P-Value
regression_results <- regression_results[order(regression_results$P_Value), ]

# Print the final table
cat("Table 2")
Table 2
print(regression_results)
Step 14. Standardize each X variable. In other words, create a new variable X’= {X-mean(X)}/sd(X). The mean of X’ is 0 and its standard deviation is 1. Regress Y (landing distance) on each of the X’ variables. Provide a table that ranks the factors based on the size of the regression coefficient. The larger the size, the more important the factor. This table contains three columns: the names of variables, the size of the regression coefficient, the direction of the regression coefficient (positive or negative). We call it Table 3.
# Standardize each factor
for (var in factors) {
  FAA_new[[paste(var, "standardized", sep = "_")]] <- 
    (FAA_new[[var]] - mean(FAA_new[[var]], na.rm = TRUE)) / sd(FAA_new[[var]], na.rm = TRUE)
}

# Initialize an empty data frame to store results
reg_results <- data.frame(
  Variable = character(),
  SizeOfCoefficient = numeric(),
  Direction = character(),
  stringsAsFactors = FALSE
)

# Loop through each standardized variable to perform regression
for (var in factors) {
  # Define the regression formula using the standardized variable
  formula <- as.formula(paste("distance ~", paste(var, "standardized", sep = "_")))
  
  # Fit the linear model
  model_standardized <- lm(formula, data = FAA_new)
  
  # Get the coefficient for the standardized variable
  coefficient2 <- summary(model_standardized)$coefficients[2, 1]
  
  # Determine the direction of the coefficient
  direction2 <- ifelse(coefficient2 > 0, "Positive", "Negative")
  
  # Append the results to the data frame
  reg_results <- rbind(reg_results, data.frame(
    Variable = var,
    SizeOfCoefficient = abs(coefficient2),
    Direction = direction2
  ))
}

# Sort the data frame by Coefficient_Size in descending order
reg_results <- reg_results[order(reg_results$SizeOfCoefficient, decreasing = TRUE), ]

# Print the final table with a name
cat("Table 3")
Table 3
print(reg_results)
Step 15. Compare Tables 1,2,3. Are the results consistent? At this point, you will meet with a FAA agent again. Please provide a single table than ranks all the factors based on their relative importance in determining the landing distance. We call it Table 0.
# Table 1: correlations (columns: Variable, SizeOfCorrelation, DirectionOfCorrelation)
# Table 2: regression_results (columns: Variable, P_Value, DirectionofCoefficient)
# Table 3: reg_results (columns: Variable, SizeOfCoefficient, Direction)

# Combine the tables into a single data frame
combined_results <- merge(correlations, regression_results, by = "Variable", suffixes = c("_Correlation", "_Significance"))
combined_results <- merge(combined_results, reg_results, by = "Variable")

# Add ranks for each metric
combined_results$Rank_Correlation <- rank(-abs(combined_results$SizeOfCorrelation), ties.method = "min")
combined_results$Rank_Significance <- rank(combined_results$P_Value, ties.method = "min")
combined_results$Rank_Coefficient <- rank(-combined_results$SizeOfCoefficient, ties.method = "min")

# Calculate the overall rank by averaging the ranks
combined_results$Overall_Rank <- rowMeans(combined_results[, c("Rank_Correlation", "Rank_Significance", "Rank_Coefficient")])

# Sort by the overall rank
combined_results <- combined_results[order(combined_results$Overall_Rank), ]

# Select the relevant columns for Table 0
table_0 <- combined_results[, c("Variable", "SizeOfCorrelation", "P_Value", "SizeOfCoefficient", "Overall_Rank")]
colnames(table_0) <- c("Variable", "Correlation", "P_Value", "Coefficient_Size", "Overall_Rank")

# Print Table 0
cat("Table 0")
Table 0
print(table_0)

Check collinearity

Step 16. Compare the regression coefficients of the three models below: Model 1: LD ~ Speed_ground Model 2: LD ~ Speed_air Model 3: LD ~ Speed_ground + Speed_air. Do you observe any significance change and sign change? Check the correlation between Speed_ground and Speed_air. You may want to keep one of them in the model selection. Which one would you pick? Why?
# Fit Model 1: LD ~ Speed_ground
model1 <- lm(distance ~ speed_ground, data = FAA_new)
summary(model1)

Call:
lm(formula = distance ~ speed_ground, data = FAA_new)

Residuals:
    Min      1Q  Median      3Q     Max 
-714.00 -196.07   29.33  238.20  741.40 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -5148.798    228.961  -22.49   <2e-16 ***
speed_ground    76.702      2.203   34.81   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 308.5 on 193 degrees of freedom
Multiple R-squared:  0.8626,    Adjusted R-squared:  0.8619 
F-statistic:  1212 on 1 and 193 DF,  p-value: < 2.2e-16
# Fit Model 2: LD ~ Speed_air
model2 <- lm(distance ~ speed_air, data = FAA_new)
summary(model2)

Call:
lm(formula = distance ~ speed_air, data = FAA_new)

Residuals:
    Min      1Q  Median      3Q     Max 
-783.22 -189.61    2.73  215.76  623.27 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -5417.607    208.860  -25.94   <2e-16 ***
speed_air      79.244      2.009   39.45   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 276.4 on 193 degrees of freedom
Multiple R-squared:  0.8897,    Adjusted R-squared:  0.8891 
F-statistic:  1556 on 1 and 193 DF,  p-value: < 2.2e-16
# Fit Model 3: LD ~ Speed_ground + Speed_air
model3 <- lm(distance ~ speed_ground + speed_air, data = FAA_new)
summary(model3)

Call:
lm(formula = distance ~ speed_ground + speed_air, data = FAA_new)

Residuals:
   Min     1Q Median     3Q    Max 
-820.6 -182.0    7.7  204.2  633.0 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -5425.49     209.08 -25.950  < 2e-16 ***
speed_ground   -12.32      12.98  -0.949    0.344    
speed_air       91.63      13.20   6.941 5.82e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 276.5 on 192 degrees of freedom
Multiple R-squared:  0.8902,    Adjusted R-squared:  0.889 
F-statistic: 778.1 on 2 and 192 DF,  p-value: < 2.2e-16
# Extract coefficients for each model
coeff_model1 <- summary(model1)$coefficients
coeff_model2 <- summary(model2)$coefficients
coeff_model3 <- summary(model3)$coefficients

# Display the coefficients
cat("Model 1 Coefficients:\n")
Model 1 Coefficients:
print(coeff_model1)
                Estimate Std. Error   t value     Pr(>|t|)
(Intercept)  -5148.79756 228.961387 -22.48762 8.139210e-56
speed_ground    76.70237   2.203368  34.81142 3.988133e-85
cat("\nModel 2 Coefficients:\n")

Model 2 Coefficients:
print(coeff_model2)
               Estimate Std. Error   t value     Pr(>|t|)
(Intercept) -5417.60675 208.860347 -25.93890 8.071172e-65
speed_air      79.24368   2.008797  39.44833 2.550801e-94
cat("\nModel 3 Coefficients:\n")

Model 3 Coefficients:
print(coeff_model3)
                Estimate Std. Error     t value     Pr(>|t|)
(Intercept)  -5425.48760  209.07862 -25.9495097 1.093361e-64
speed_ground   -12.31906   12.97593  -0.9493783 3.436217e-01
speed_air       91.62992   13.20051   6.9413917 5.819901e-11
# Check the correlation between Speed_ground and Speed_air
correlation_speed <- cor(FAA_new$speed_ground, FAA_new$speed_air, use = "complete.obs")
cat("\nCorrelation between Speed_ground and Speed_air:", correlation_speed, "\n")

Correlation between Speed_ground and Speed_air: 0.9883475 

The correlation between speed_ground and speed_air is 0.9883475, which is a very high value and close to 1. It indicates a very strong positive linear relationship between the two variables. As speed_ground increases, speed_air also increases almost proportionally. Such a high correlation suggests multicollinearity when both variables are used together, so we need to eliminate one. Both variables have very small P-value which suggests its significant influence. However, the value of adjusted R-squared for speed_air is higher, which indicates that speed_air explains a greater proportion of the variance in distance variable.

Variable selection based on our ranking in Table 0.

Step 17. Suppose in Table 0, the variable ranking is as follows: X1, X2, X3….. Please fit the following six models: Model 1: LD ~ X1 Model 2: LD ~ X1 + X2 Model 3: LD ~ X1 + X2 + X3 ………. Calculate the R-squared for each model. Plot these R-squared values versus the number of variables p. What patterns do you observe?
var_ranked <- c("speed_air", "speed_ground", "aircraft_numeric","height", "duration", "pitch", "no_pasg")

# Initialize a vector to store R-squared values
r_squared_values <- numeric(length(var_ranked))

# Fit models and calculate R-squared values
for (i in seq_along(var_ranked)) {
  # Create the formula dynamically
  formula <- as.formula(paste("distance ~", paste(var_ranked[1:i], collapse = " + ")))
  
  # Fit the model
  model_rank <- lm(formula, data = FAA_new)
  
  # Extract the R-squared value
  r_squared_values[i] <- summary(model_rank)$r.squared
}

# Create a data frame for plotting
r_squared_rank <- data.frame(
  Num_Variables = seq_along(var_ranked),
  R_Squared = r_squared_values
)

# Plot the R-squared values versus the number of variables
ggplot(r_squared_rank, aes(x = Num_Variables, y = R_Squared)) +
  geom_line() +
  geom_point() +
  labs(title = "R-squared vs Number of Variables",
       x = "Number of Variables",
       y = "R-squared") +
  theme_minimal()


# Print the R-squared values for reference
print(r_squared_rank)

It looks like the \(R^2\) value increases when the number of variables increase as well, however, the value is pretty stable when the variable reach four.

Step 18. Repeat Step 17 but use adjusted R-squared values instead.
adj_r_squared_values <- numeric(length(var_ranked))

# Fit models and calculate Adjusted R-squared values
for (i in seq_along(var_ranked)) {
  # Create the formula dynamically
  formula_adj <- as.formula(paste("distance ~", paste(var_ranked[1:i], collapse = " + ")))
  
  # Fit the model
  model_adj <- lm(formula_adj, data = FAA_new)
  
  # Extract the R-squared value
  adj_r_squared_values[i] <- summary(model_adj)$adj.r.squared
}

# Create a data frame for plotting
adj_r_squared <- data.frame(
  Num_Variables = seq_along(var_ranked),
  Adj_R_Squared = adj_r_squared_values
)

# Plot the R-squared values versus the number of variables
ggplot(adj_r_squared, aes(x = Num_Variables, y = Adj_R_Squared)) +
  geom_line() +
  geom_point() +
  labs(title = "Adjusted R-squared vs Number of Variables",
       x = "Number of Variables",
       y = "Adjusted R-squared") +
  theme_minimal()


# Print the R-squared values for reference
print(adj_r_squared)

The value of adjusted R squared looks very similar compared to R squared values. The value increases when the number of variables increase, and became stable once it reaches four variables.

Step 19. Repeat Step 17 but use AIC values instead.
aic_values <- numeric(length(var_ranked))

# Fit models and calculate AIC values
for (i in seq_along(var_ranked)) {
  # Create the formula dynamically
  formula_aic <- as.formula(paste("distance ~", paste(var_ranked[1:i], collapse = " + ")))
  
  # Fit the model
  model_aic <- lm(formula_aic, data = FAA_new)
  
  # Extract the AIC value
  aic_values[i] <- AIC(model_aic)
}

# Create a data frame for plotting
aic_plot <- data.frame(
  Num_Variables = seq_along(var_ranked),
  AIC = aic_values
)

# Plot the R-squared values versus the number of variables
ggplot(aic_plot, aes(x = Num_Variables, y = AIC)) +
  geom_line() +
  geom_point() +
  labs(title = "AIC vs Number of Variables",
       x = "Number of Variables",
       y = "AIC") +
  theme_minimal()


# Print the R-squared values for reference
print(aic_plot)

It appears that the AIC decrease as more variables are added to the model. However, it stops decreasing when variable reaches four, and the lowest AIC value is when the variable number is four. It suggests the optimal model size could be four.

Step 20. Compare the results in Steps 18-19, what variables would you select to build a predictive model for LD?

Based on the results in steps 18, 19, it indicates that four variable is the optimal choice, therefore the variables will be speed_air, speed_ground, aircraft, height. Although, from previous steps, we learned there is multicollinearity between speed_ground and speed_air, so we could eliminate one. Also, aircraft is a categorical variable, instead of including it, maybe have the other variable results grouped by aircraft could also be sufficient.

Variable selection based on automate algorithm.

Step 21. Use the R function “StepAIC” to perform forward variable selection. Compare the result with that in Step 19.
# Load the necessary library for stepAIC
library(MASS)

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select
# Create a full model using all predictors
full_model <- lm(distance ~ ., data = FAA_new[, c("distance", var_ranked)])

# Perform forward selection using stepAIC
step_model <- stepAIC(full_model, direction = "forward", trace = FALSE)

# Summary of the stepwise-selected model
summary(step_model)

Call:
lm(formula = distance ~ speed_air + speed_ground + aircraft_numeric + 
    height + duration + pitch + no_pasg, data = FAA_new[, c("distance", 
    var_ranked)])

Residuals:
    Min      1Q  Median      3Q     Max 
-287.36  -85.69   11.25   83.50  359.85 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)      -5791.6573   163.2346 -35.481   <2e-16 ***
speed_air           85.5469     6.5221  13.117   <2e-16 ***
speed_ground        -3.5464     6.4160  -0.553    0.581    
aircraft_numeric  -437.9428    21.2621 -20.597   <2e-16 ***
height              13.6756     1.0386  13.168   <2e-16 ***
duration             0.1276     0.2039   0.626    0.532    
pitch              -13.4897    18.6077  -0.725    0.469    
no_pasg             -1.9812     1.3780  -1.438    0.152    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 134.5 on 187 degrees of freedom
Multiple R-squared:  0.9747,    Adjusted R-squared:  0.9738 
F-statistic:  1030 on 7 and 187 DF,  p-value: < 2.2e-16
# Print the selected variables
selected_variables <- names(coef(step_model))
print(selected_variables)
[1] "(Intercept)"      "speed_air"        "speed_ground"     "aircraft_numeric" "height"          
[6] "duration"         "pitch"            "no_pasg"         
# Compare the AIC value of the StepAIC selected model with manual AIC values
step_model_aic <- AIC(step_model)
manual_aic <- aic_values

# Print the AIC of the StepAIC selected model
print(paste("StepAIC Selected Model AIC:", step_model_aic))
[1] "StepAIC Selected Model AIC: 2474.69216451066"
# Compare with manual AIC values
print(manual_aic)
[1] 2749.962 2751.048 2597.804 2471.938 2473.334 2474.836 2474.692

From the result of stepAIC function, we can see that the AIC values are very much the same. StepAIC selected 7 variables, however, when looking at the summary of AIC model, there is only three showed significant impact, which is the similar results as the AIC calculation in Step 19 (speed_ground has been eliminated).

LS0tCnRpdGxlOiAiQkFOQSA3MDQyIE1vZHVsZSAxIFByb2plY3QgUGFydCAxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyBOYW1lOiBSdW93ZWkgRmlzY2hlcgoKIyMgVUNJRDogTTE0ODIwOTc0CgojIyBQYXJ0IDE6IFByYWN0aWNlIG9mIG1vZGVsaW5nIHRoZSBsYW5kaW5nIGRpc3RhbmNlIHVzaW5nIGxpbmVhciByZWdyZXNzaW9uLgoKIyMjIEluaXRpYWwgZXhwbG9yYXRpb24gb2YgdGhlIGRhdGEKCiMjIyMjIFN0ZXAgMS4gUmVhZCB0aGUgdHdvIGZpbGVzIOKAmEZBQS0xLnhsc+KAmSAoODAwIGZsaWdodHMpIGFuZCDigJhGQUEtMi54bHPigJkgaW50byB5b3VyIFIgc3lzdGVtLiBQbGVhc2Ugc2VhcmNoIOKAnFJlYWQgRXhjZWwgZmlsZXMgZnJvbSBS4oCdIGluIEdvb2dsZSBpbiBjYXNlIHlvdSBkbyBub3Qga25vdyBob3cgdG8gZG8gdGhhdC4KCmBgYHtyfQpGQUExIDwtIHJlYWQuY3N2KCJGQUExLmNzdiIsIGhlYWRlciA9IFRSVUUpCkZBQTIgPC0gcmVhZC5jc3YoIkZBQTIuY3N2IiwgaGVhZGVyID0gVFJVRSkKRkFBMiA8LSBGQUEyWy1jKDE1MToyMDApLCBdCmBgYAoKSSB1c2VkIHRoZSByZWFkLmNzdiBmdW5jdGlvbiB0byBsb2FkIGJvdGggY3N2IGZpbGVzLiBJIGhhdmUgcHJldmlvdXNseSBzYXZlZCB0aGUgeGxzIGZpbGUgZG93bmxvYWRlZCBmcm9tIENhbnZhcyBpbnRvIGNzdiBmaWxlcyBzbyBpdCdzIGVhc2llciB0byBsb2FkLiBBbHNvLCB0aGVyZSB3ZXJlIDUwIHJvd3Mgb2YgZGF0YSB3aXRoIE5BIHZhbHVlcywgSSBoYXZlIHJlbW92ZWQgdGhlbS4KCiMjIyMjIFN0ZXAgMi4gQ2hlY2sgdGhlIHN0cnVjdHVyZSBvZiBlYWNoIGRhdGEgc2V0IHVzaW5nIHRoZSDigJxzdHLigJ0gZnVuY3Rpb24uIEZvciBlYWNoIGRhdGFzZXQsIHdoYXQgaXMgdGhlIHNhbXBsZSBzaXplIGFuZCBob3cgbWFueSB2YXJpYWJsZXM/IElzIHRoZXJlIGFueSBkaWZmZXJlbmNlYmV0d2VlbiB0aGUgdHdvIGRhdGEgc2V0cz8gCgpgYGB7cn0Kc3RyKEZBQTEpCnN0cihGQUEyKQpgYGAKClNhbXBsZSBzaXplIG9mIEZBQTEgaXMgODAwLCBGQUEyIGlzIDE1MC4gRkFBMSBoYXMgOCBkaWZmZXJlbnQgdmFyaWFibGVzIGFuZCBGQUEyIG9ubHkgaGFzIDcsIEZBQTIgZG9lcyBub3QgaGF2ZSB0aGUgZHVyYXRpb24gdmFyaWFibGUuCgojIyMjIyBTdGVwIDMuIE1lcmdlIHRoZSB0d28gZGF0YSBzZXRzLiBBcmUgdGhlcmUgYW55IGR1cGxpY2F0aW9ucz8gU2VhcmNoIOKAnGNoZWNrIGR1cGxpY2F0ZXMgaW4gcuKAnSBpZiB5b3UgZG8gbm90IGtub3cgaG93IHRvIGNoZWNrIGR1cGxpY2F0aW9ucy4gSWYgdGhlIGFuc3dlciBpcyDigJxZZXPigJ0sIHdoYXQgYWN0aW9uIHlvdSB3b3VsZCB0YWtlPwoKYGBge3J9CiNvdXRlcmpvaW4gYm90aCBGQUExIGFuZCBGQUEyCm1lcmdlZF9kYXRhX291dGVyIDwtIG1lcmdlKEZBQTEsIEZBQTIsIGJ5ID0gYygiYWlyY3JhZnQiLCJub19wYXNnIiwgInNwZWVkX2dyb3VuZCIsInNwZWVkX2FpciIsImhlaWdodCIsICJwaXRjaCIsICJkaXN0YW5jZSIpLCBhbGwgPSBUUlVFKQoKI2NvdW50IHRoZSBudW1iZXIgb2YgZHVwbGljYXRlcwpudW1fZHVwbGljYXRlcyA8LSBzdW0oZHVwbGljYXRlZChtZXJnZWRfZGF0YV9vdXRlcikpCnByaW50KG51bV9kdXBsaWNhdGVzKQoKRkFBIDwtIG1lcmdlZF9kYXRhX291dGVyCmF0dGFjaChGQUEpCmBgYApJIGNob3NlIHRvIHVzZSBvdXRlciBqb2luIHNvIEkgY2FuIGtlZXAgYWxsIHVuaXF1ZSBkYXRhIGZyb20gYm90aCBkYXRhIHNldHMuIFRoZSBvdXRlciBqb2luIGdvdCByaWQgb2YgMTAwIHJvd3Mgb2YgZHVwbGljYXRlIGRhdGEsIHdpdGggZHVyYXRpb24gdmFsdWVzIGJlaW5nIE5BLiBJIHVzZWQgImR1cGxpY2F0ZWQiIGZ1bmN0aW9uIHRvIGdldCBhIGNvdW50IG9mIHRoZSBkdXBsaWNhdGVkIGRhdGEgdG8gdmVyaWZ5IHRoZXJlIGlzIG5vIGxvbmdlciBkdXBsaWNhdGUgdmFsdWVzLCBhbmQgaXQgd2FzIHplcm8uCgojIyMjIyBTdGVwIDQuIENoZWNrIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGNvbWJpbmVkIGRhdGEgc2V0LiBXaGF0IGlzIHRoZSBzYW1wbGUgc2l6ZSBhbmQgaG93IG1hbnkgdmFyaWFibGVzPyBQcm92aWRlIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgZWFjaCB2YXJpYWJsZS4KCmBgYHtyfQpzdHIoRkFBKQoKc3VtbWFyeShGQUEpCmBgYAoKVGhlIG5ldyBkYXRhIHNldCBGQUEgaGFzIGEgc2FtcGxlIHNpemUgb2YgODUwIGFuZCA4IHZhcmlhYmxlcy4KCiMjIyMjIFN0ZXAgNS4gQnkgbm93LCBpZiB5b3UgYXJlIGFza2VkIHRvIHByZXBhcmUgT05FIHByZXNlbnRhdGlvbiBzbGlkZSB0byBzdW1tYXJpemUgeW91ciBmaW5kaW5ncywgd2hhdCBvYnNlcnZhdGlvbnMgd2lsbCB5b3UgYnJpbmcgdG8gdGhlIGF0dGVudGlvbiBvZiBGQUEgYWdlbnRzPyBQbGVhc2UgbGlzdCBubyBtb3JlIHRoYW4gZml2ZSB1c2luZyDigJxidWxsZXQgc3RhdGVtZW50c+KAnSwgZnJvbSB0aGUgbW9zdCBpbXBvcnRhbnQgdG8gdGhlIGxlYXN0IGltcG9ydGFudC4KCjEuIFRoZSB0b3RhbCBvYnNlcnZhdGlvbiBvZiB0aGUgZGF0YSBoYXMgYSBzYW1wbGUgc2l6ZSBvZiA4NTAuIFRoZXJlIGFyZSA4IHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldCwgYW5kIDcgYXJlIHByZWRpY3RvciB2YXJpYWJsZXMsIGFuZCBvbmUgaXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlLgoKMi4gVGhlcmUgaXMgYSBiaW5hcnkgdmFyaWFibGUgLSBBaXJjcmFmdCwgaGFzIHR3byB2YWx1ZXMsIEJvZWluZyBhbmQgQWlyYnVzLgoKMy4gVGhlcmUgYXJlIDUwIG1pc3NpbmcgdmFsdWVzIGluIHRoZSB2YXJpYWJsZSAiZHVyYXRpb24iLgoKNC4gVGhlIGF2ZXJhZ2UgbGFuZGluZyBkaXN0YW5jZSBpcyAxNTI2LCBob3dldmVyLCB0aGVyZSBhcmUgZXh0cmVtZSB2YWx1ZXMgc3VjaCBhcyBhIG1pbmltdW0gb2YgMzQgYW5kIGEgbWF4aW11bSBvZiA2NTMzLiBUaGVzZSBhcmUgbm90IG5vcm1hbCB3aGljaCBtYXkgbmVlZCBmdXJ0aGVyIGFuYWx5c2lzLgoKNS4gVGhlcmUgaXMgYSBuZWdhdGl2ZSBhbW91bnQgaW4gdGhlIGhlaWdodCB2YXJpYWJsZSwgd2hpY2ggaXMgbm90IG5vcm1hbC4KCiMjIyBEYXRhIENsZWFuaW5nIGFuZCBmdXJ0aGVyIGV4cGxvcmF0aW9uCgojIyMjIyBTdGVwIDYuIEFyZSB0aGVyZSBhYm5vcm1hbCB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0PyBQbGVhc2UgcmVmZXIgdG8gdGhlIHZhcmlhYmxlIGRpY3Rpb25hcnkgZm9yIGNyaXRlcmlhIGRlZmluaW5nIOKAnG5vcm1hbC9hYm5vcm1hbOKAnSB2YWx1ZXMuIFJlbW92ZSB0aGUgcm93cyB0aGF0IGNvbnRhaW4gYW55IOKAnGFibm9ybWFsIHZhbHVlc+KAnSBhbmQgcmVwb3J0IGhvdyBtYW55IHJvd3MgeW91IGhhdmUgcmVtb3ZlZAoKYGBge3J9CiNyZW1vdmUgZHVyYXRpb24gbm90IGdyZWF0ZXIgdGhhbiA0MApGQUFfbmV3IDwtIHN1YnNldChGQUEsIGR1cmF0aW9uID4gNDApCgojcmVtb3ZlIHNwZWVkX2dyb3VuZCB0aGF0J3MgbGVzcyB0aGFuIDMwIG9yIGdyZWF0ZXIgdGhhbiAxNDAKRkFBX25ldyA8LSBzdWJzZXQoRkFBX25ldywgc3BlZWRfZ3JvdW5kID49MzAgJiBzcGVlZF9ncm91bmQgPD0xNDApCgojcmVtb3ZlIHNwZWVkX2FpciB0aGF0J3MgbGVzcyB0aGFuIDMwIG9yIGdyZWF0ZXIgdGhhbiAxNDAKRkFBX25ldyA8LSBzdWJzZXQoRkFBX25ldywgc3BlZWRfYWlyID49MzAgJiBzcGVlZF9ncm91bmQgPD0xNDApCgojcmVtb3ZlIGhlaWdodCB0aGF0J3MgbGVzcyB0aGFuIDYgbWV0ZXJzCkZBQV9uZXcgPC0gc3Vic2V0KEZBQV9uZXcsIGhlaWdodCA+PTYpCgojcmVtb3ZlIGRpc3RhbmNlIHRoYXQncyBvdmVyIDYwMDAgZmVldApGQUFfbmV3IDwtIHN1YnNldChGQUFfbmV3LCBkaXN0YW5jZSA8IDYwMDApCmBgYAoKWWVzLCB0aGVyZSB3ZXJlIGFibm9ybWFsIHZhbHVlcyBpbiB0aGUgZGF0YSBzZXQuIEJhc2VkIG9uIHRoZSB2YXJpYWJsZSBkaWN0aW9uYXJ5LCBJIGhhdmUgcmVtb3ZlZCBhYm5vcm1hbCB2YWx1ZXMsIGFuZCBub3cgSSBoYXZlIHRoZSBzYW1wbGUgc2l6ZSBvZiAxOTUuCgojIyMjIyBTdGVwIDcuIFJlcGVhdCBTdGVwIDQuCgpgYGB7cn0Kc3RyKEZBQV9uZXcpCgpzdW1tYXJ5KEZBQV9uZXcpCmBgYAoKIyMjIyMgU3RlcCA4LiBTaW5jZSB5b3UgaGF2ZSBhIHNtYWxsIHNldCBvZiB2YXJpYWJsZXMsIHlvdSBtYXkgd2FudCB0byBzaG93IGhpc3RvZ3JhbXMgZm9yIGFsbCBvZiB0aGVtLgoKYGBge3J9CiMgTG9hZCB0aGUgdGlkeXZlcnNlIHBhY2thZ2UKbGlicmFyeSh0aWR5dmVyc2UpCgpzZWxlY3RlZF92YXJzIDwtIGMoInNwZWVkX2dyb3VuZCIsICJzcGVlZF9haXIiLCAiaGVpZ2h0IiwicGl0Y2giLCJkdXJhdGlvbiIsImRpc3RhbmNlIiwibm9fcGFzZyIpCiNhaXJjcmFmdCB3YXMgbm90IHNlbGVjdGVkIGFzIGl0IHdhcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLgoKIyBVc2Ugd2FsayB0byBwbG90IGhpc3RvZ3JhbXMgZm9yIHRoZSBzZWxlY3RlZCB2YXJpYWJsZXMKd2FsayhzZWxlY3RlZF92YXJzLCB+IHsKICBoaXN0KEZBQV9uZXdbWy54XV0sIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mIiwgLngpLCAKICAgICAgIHhsYWIgPSAueCwgY29sID0gImJsdWUiLCBib3JkZXIgPSAid2hpdGUiLCBwcm9iID0gVFJVRSkKICBsaW5lcyhkZW5zaXR5KEZBQV9uZXdbWy54XV0sIG5hLnJtID0gVFJVRSksIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQp9KQpgYGAKCldlIGNhbiBzZWUgdGhhdCBzcGVlZF9ncm91bmQsIHNwZWVkX2FpciwgYW5kIGRpc3RhbmNlIGFyZSByaWdodCBza2V3ZWQsIGFuZCB0aGUgcmVzdCBvZiB0aGUgdmFyaWFibGVzIHNob3dzIG5vcm1hbCBkaXN0cmlidXRpb24uCgojIyMjIyBTdGVwIDkuIFByZXBhcmUgYW5vdGhlciBwcmVzZW50YXRpb24gc2xpZGUgdG8gc3VtbWFyaXplIHlvdXIgZmluZGluZ3MgZHJhd24gZnJvbSB0aGUgY2xlYW5lZCBkYXRhIHNldCwgdXNpbmcgbm8gbW9yZSB0aGFuIGZpdmUg4oCcYnVsbGV0IHN0YXRlbWVudHPigJ0uIAoKMS4gVGhlIG5ldyBzZXQgb2YgZGF0YSBoYXMgYSBzYW1wbGUgc2l6ZSBvZiAxOTUsIHRoZXJlIGFyZSA3IG51bWVyaWMgdmFyaWFibGVzIGFuZCBvbmUgYmluYXJ5IHZhcmlhYmxlLgoKMi4gVGhlIHNwZWVkX2dyb3VuZCBhbmQgc3BlZWRfYWlyIHZhbHVlIGlzIHZlcnkgc2ltaWxhciBhbmQgYm90aCBoaXN0b2dyYW0gc2hvd3Mgc2tld2VkIHRvIHRoZSByaWdodC4gVGhlIG1lYW4gc3BlZWQgaXMgYXJvdW5kIDEwMCBNUEguCgozLiBOdW1iZXIgb2YgUGFzc2VuZ2VycyBzaG93cyB0aGUgYXZlcmFnZSBudW1iZXIgaXMgYXJvdW5kIDYwIHBhc3NlbmdlcnMgcGVyIGZpZ2h0LgoKNC4gVGhlcmUgYXJlIG91dGxpZXJzIGluIGhlaWdodCwgd2hlcmUgdGhlIGF2ZXJhZ2UgaXMgYWJvdXQgMzAsIHdlIG9ic2VydmVkIHRoYXQgdGhlcmUgYXJlIGhlaWdodCBhcyBzbWFsbCBhcyA5LjYgYW5kIGFzIGxhcmdlIGFzIDU4LgoKNS4gVGhlIGF2ZXJhZ2Ugb2YgYSBmbGlnaHQgYmVpbmcgaW4gdGhlIGFpciBpcyBhYm91dCAxNTAuOS4gCgojIyMgSW5pdGlhbCBhbmFseXNpcyBmb3IgaWRlbnRpZnlpbmcgaW1wb3J0YW50IGZhY3RvcnMgdGhhdCBpbXBhY3QgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIOKAnGxhbmRpbmcgZGlzdGFuY2XigJ0KCiMjIyMjIFN0ZXAgMTAuIENvbXB1dGUgdGhlIHBhaXJ3aXNlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGxhbmRpbmcgZGlzdGFuY2UgYW5kIGVhY2ggZmFjdG9yIFguIFByb3ZpZGUgYSB0YWJsZSB0aGF0IHJhbmtzIHRoZSBmYWN0b3JzIGJhc2VkIG9uIHRoZSBzaXplIChhYnNvbHV0ZSB2YWx1ZSkgb2YgdGhlIGNvcnJlbGF0aW9uLiBUaGlzIHRhYmxlIGNvbnRhaW5zIHRocmVlIGNvbHVtbnM6IHRoZSBuYW1lcyBvZiB2YXJpYWJsZXMsIHRoZSBzaXplIG9mIHRoZSBjb3JyZWxhdGlvbiwgdGhlIGRpcmVjdGlvbiBvZiB0aGUgY29ycmVsYXRpb24gKHBvc2l0aXZlIG9yIG5lZ2F0aXZlKS4gV2UgY2FsbCBpdCBUYWJsZSAxLCB3aGljaCB3aWxsIGJlIHVzZWQgZm9yIGNvbXBhcmlzb24gd2l0aCBvdXIgYW5hbHlzaXMgbGF0ZXIuCgpgYGB7cn0KIyBMb2FkIHRoZSBrbml0ciBwYWNrYWdlIGZvciBjcmVhdGluZyBhIGZvcm1hdHRlZCB0YWJsZS4KbGlicmFyeShrbml0cikKCiMgQ29udmVydCAnYWlyY3JhZnQnIHRvIG51bWVyaWM6IDEgZm9yICdhaXJidXMnLCAwIGZvciAnYm9laW5nJwpGQUFfbmV3JGFpcmNyYWZ0X251bWVyaWMgPC0gaWZlbHNlKEZBQV9uZXckYWlyY3JhZnQgPT0gImFpcmJ1cyIsIDEsIDApCgojIFZpZXcgdGhlIHVwZGF0ZWQgZGF0YWZyYW1lIHRvIGNvbmZpcm0gdGhlIGNoYW5nZXMKaGVhZChGQUFfbmV3KQoKZmFjdG9ycyA8LSBjKCJzcGVlZF9ncm91bmQiLCAic3BlZWRfYWlyIiwgImhlaWdodCIsICJwaXRjaCIsICJkdXJhdGlvbiIsICJub19wYXNnIiwgImFpcmNyYWZ0X251bWVyaWMiKQoKIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgdG8gc3RvcmUgdGhlIHJlc3VsdHMKY29ycmVsYXRpb25zIDwtIGRhdGEuZnJhbWUoCiAgVmFyaWFibGUgPSBjaGFyYWN0ZXIoKSwKICBTaXplT2ZDb3JyZWxhdGlvbiA9IG51bWVyaWMoKSwKICBEaXJlY3Rpb25PZkNvcnJlbGF0aW9uID0gY2hhcmFjdGVyKCksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgQ2FsY3VsYXRlIHRoZSBwYWlyd2lzZSBjb3JyZWxhdGlvbnMKZm9yICh2YXIgaW4gZmFjdG9ycykgewogIGNvcnIgPC0gY29yKEZBQV9uZXckZGlzdGFuY2UsIEZBQV9uZXdbW3Zhcl1dLCB1c2UgPSAiY29tcGxldGUub2JzIikKICBjb3JyZWxhdGlvbnMgPC0gcmJpbmQoY29ycmVsYXRpb25zLCBkYXRhLmZyYW1lKAogICAgVmFyaWFibGUgPSB2YXIsCiAgICBTaXplT2ZDb3JyZWxhdGlvbiA9IGFicyhjb3JyKSwKICAgIERpcmVjdGlvbk9mQ29ycmVsYXRpb24gPSBpZmVsc2UoY29yciA+IDAsICJQb3NpdGl2ZSIsICJOZWdhdGl2ZSIpCiAgKSkKfQoKIyBTb3J0IHRoZSBkYXRhIGZyYW1lIGJ5IHRoZSBzaXplIG9mIHRoZSBjb3JyZWxhdGlvbgpjb3JyZWxhdGlvbnMgPC0gY29ycmVsYXRpb25zW29yZGVyKC1jb3JyZWxhdGlvbnMkU2l6ZU9mQ29ycmVsYXRpb24pLCBdCgojIFByaW50IHRoZSB0YWJsZQpjYXQoIlRhYmxlIDEiKQpwcmludChjb3JyZWxhdGlvbnMpCmBgYAoKIyMjIyMgU3RlcCAxMS4gU2hvdyBYLVkgc2NhdHRlciBwbG90cy4gRG8geW91IHRoaW5rIHRoZSBjb3JyZWxhdGlvbiBzdHJlbmd0aCBvYnNlcnZlZCBpbiB0aGVzZSBwbG90cyBpcyBjb25zaXN0ZW50IHdpdGggdGhlIHZhbHVlcyBjb21wdXRlZCBpbiBTdGVwIDEwPwoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKc2VsZWN0ZWRfdmFycyA8LSBjKCJzcGVlZF9ncm91bmQiLCAic3BlZWRfYWlyIiwgImhlaWdodCIsICJwaXRjaCIsICJkdXJhdGlvbiIsICJub19wYXNnIikKI0xvb3AgdGhyb3VnaCBlYWNoIHZhcmlhYmxlIGFuZCBjcmVhdGUgc2NhdHRlciBwbG90cwpmb3IgKHZhciBpbiBzZWxlY3RlZF92YXJzKSB7CiAgcCA8LSBnZ3Bsb3QoRkFBX25ldywgYWVzX3N0cmluZyh4ID0gdmFyLCB5ID0gImRpc3RhbmNlIiwgY29sb3IgPSAiYWlyY3JhZnQiKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdndGl0bGUocGFzdGUoIlNjYXR0ZXIgUGxvdCBvZiIsIHZhciwgInZzIExhbmRpbmcgRGlzdGFuY2UgYnkgQWlyY3JhZnQgVHlwZSIpKSArCiAgICB4bGFiKHZhcikgKwogICAgeWxhYigiRGlzdGFuY2UiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCAicmVkIikpCiAgcHJpbnQocCkKfQpgYGAKClllcywgdGhlIGNvcnJlbGF0aW9uIHN0cmVuZ3RoIG9ic2VydmVkIGluIHRoZXNlIHBsb3RzIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgdmFsdWVzIGNvbXB1dGVkLiBCYXNlZCBvbiB0aGUgcGxvdHMsIHdlIGNhbiBjbGVhcmx5IHNlZSB0aGF0IHRoZSBzcGVlZF9haXIgYW5kIHNwZWVkX2dyb3VuZCBoYXMgc3Ryb25nIGxpbmVhciByZWxhdGlvbnNoaXAgd2l0aCB0aGUgZGlzdGFuY2UsIHdoZW4gc3BlZWRfYWlyIGFuZCBzcGVlZF9ncm91bmQgdmFsdWUgaW5jcmVhc2VzLCBkaXN0YW5jZSBhbHNvIGluY3JlYXNlcy4gVGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBhcmUgc2NhdHRlcmVkIGluIHRoZSBwbG90cy4KCiMjIyMjIFN0ZXAgMTIuIEhhdmUgeW91IGluY2x1ZGVkIHRoZSBhaXJwbGFuZSBtYWtlIGFzIGEgcG9zc2libGUgZmFjdG9yIGluIFN0ZXBzIDEwLTExPyBZb3UgY2FuIGNvZGUgdGhpcyBjaGFyYWN0ZXIgdmFyaWFibGUgYXMgMC8xLgoKSSBoYXZlIGluY2x1ZGVkIGFpcmNyYWZ0IG1ha2UgaW4gc3RlcCAxMC4gSSB3YW50ZWQgdG8gaW5jbHVkZSB0aGlzIHZhcmlhYmxlIHRvIHNlZSBpZiBpdCBoYXMgYW55IGNvcnJlbGF0aW9uIHdpdGggdGhlIGRpc3RhbmNlIHZhcmlhYmxlLiBTaW5jZSBpdCdzIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUsIEkgbmVlZGVkIHRvIHRyYW5zZm9ybSB0aGUgdmFyaWFibGUgZnJvbSBhIGNoYXJhY3RlciB2YXJpYWJsZSB0byBhIG51bWVyaWMgdmFyaWFibGUuIEluIHN0ZXAgMTEsIEkgZGVjaWRlZCB0byBzaG93IHRoZSBzY2F0dGVyIHBsb3QgZ3JvdXBlZCBieSB0aGUgYWlyY3JhZnQgdmFyaWFibGUgdG8gcHJvdmlkZSBiZXR0ZXIgdmlzdWFsaXphdGlvbi4KCiMjIyBSZWdyZXNzaW9uIHVzaW5nIGEgc2luZ2xlIGZhY3RvciBlYWNoIHRpbWUKCiMjIyMjIFN0ZXAgMTMuIFJlZ3Jlc3MgWSAobGFuZGluZyBkaXN0YW5jZSkgb24gZWFjaCBvZiB0aGUgWCB2YXJpYWJsZXMuIFByb3ZpZGUgYSB0YWJsZSB0aGF0IHJhbmtzIHRoZSBmYWN0b3JzIGJhc2VkIG9uIGl0cyBzaWduaWZpY2FuY2UuIFRoZSBzbWFsbGVyIHRoZSBwLXZhbHVlLCB0aGUgbW9yZSBzaWduaWZpY2FudCB0aGUgZmFjdG9yLiBUaGlzIHRhYmxlIGNvbnRhaW5zIHRocmVlIGNvbHVtbnM6IHRoZSBuYW1lcyBvZiB2YXJpYWJsZXMsIHRoZSBzaXplIG9mIHRoZSBwLXZhbHVlLCB0aGUgZGlyZWN0aW9uIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50IChwb3NpdGl2ZSBvciBuZWdhdGl2ZSkuIFdlIGNhbGwgaXQgVGFibGUgMi4KCmBgYHtyfQojIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSB0byBzdG9yZSB0aGUgcmVzdWx0cwpyZWdyZXNzaW9uX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBWYXJpYWJsZSA9IGNoYXJhY3RlcigpLAogIFBfVmFsdWUgPSBudW1lcmljKCksCiAgRGlyZWN0aW9uT2ZDb2VmZmljaWVudCA9IGNoYXJhY3RlcigpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgojIExvb3AgdGhyb3VnaCBlYWNoIGZhY3RvciB0byBwZXJmb3JtIHJlZ3Jlc3Npb24sIGZhY3RvcnMgd2VyZSBjcmVhdGVkIGluIHByZXZpb3VzIHN0ZXBzCmZvciAodmFyIGluIGZhY3RvcnMpIHsKICAjIERlZmluZSB0aGUgcmVncmVzc2lvbiBmb3JtdWxhCiAgZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJkaXN0YW5jZSB+IiwgdmFyKSkKICAKICAjIEZpdCB0aGUgbGluZWFyIG1vZGVsCiAgbW9kZWwgPC0gbG0oZm9ybXVsYSwgZGF0YSA9IEZBQV9uZXcpCiAgCiAgIyBHZXQgdGhlIHAtdmFsdWUgYW5kIGNvZWZmaWNpZW50IGZvciB0aGUgZmFjdG9yCiAgcF92YWx1ZSA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHNbMiwgNF0KICBjb2VmZmljaWVudCA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHNbMiwgMV0KICAKICAjIERldGVybWluZSB0aGUgZGlyZWN0aW9uIG9mIHRoZSBjb2VmZmljaWVudAogIGRpcmVjdGlvbiA8LSBpZmVsc2UoY29lZmZpY2llbnQgPiAwLCAiUG9zaXRpdmUiLCAiTmVnYXRpdmUiKQogIAogICMgQXBwZW5kIHRoZSByZXN1bHRzIHRvIHRoZSBkYXRhIGZyYW1lCiAgcmVncmVzc2lvbl9yZXN1bHRzIDwtIHJiaW5kKHJlZ3Jlc3Npb25fcmVzdWx0cywgZGF0YS5mcmFtZSgKICAgIFZhcmlhYmxlID0gdmFyLAogICAgUF9WYWx1ZSA9IHBfdmFsdWUsCiAgICBEaXJlY3Rpb25PZkNvZWZmaWNpZW50ID0gZGlyZWN0aW9uCiAgKSkKfQoKIyBTb3J0IHRoZSBkYXRhIGZyYW1lIGJ5IFAtVmFsdWUKcmVncmVzc2lvbl9yZXN1bHRzIDwtIHJlZ3Jlc3Npb25fcmVzdWx0c1tvcmRlcihyZWdyZXNzaW9uX3Jlc3VsdHMkUF9WYWx1ZSksIF0KCiMgUHJpbnQgdGhlIGZpbmFsIHRhYmxlCmNhdCgiVGFibGUgMiIpCnByaW50KHJlZ3Jlc3Npb25fcmVzdWx0cykKYGBgCgoKIyMjIyMgU3RlcCAxNC4gU3RhbmRhcmRpemUgZWFjaCBYIHZhcmlhYmxlLiBJbiBvdGhlciB3b3JkcywgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIFjigJk9IHtYLW1lYW4oWCl9L3NkKFgpLiBUaGUgbWVhbiBvZiBY4oCZIGlzIDAgYW5kIGl0cyBzdGFuZGFyZCBkZXZpYXRpb24gaXMgMS4gUmVncmVzcyBZIChsYW5kaW5nIGRpc3RhbmNlKSBvbiBlYWNoIG9mIHRoZSBY4oCZIHZhcmlhYmxlcy4gUHJvdmlkZSBhIHRhYmxlIHRoYXQgcmFua3MgdGhlIGZhY3RvcnMgYmFzZWQgb24gdGhlIHNpemUgb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQuIFRoZSBsYXJnZXIgdGhlIHNpemUsIHRoZSBtb3JlIGltcG9ydGFudCB0aGUgZmFjdG9yLiBUaGlzIHRhYmxlIGNvbnRhaW5zIHRocmVlIGNvbHVtbnM6IHRoZSBuYW1lcyBvZiB2YXJpYWJsZXMsIHRoZSBzaXplIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50LCB0aGUgZGlyZWN0aW9uIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50IChwb3NpdGl2ZSBvciBuZWdhdGl2ZSkuIFdlIGNhbGwgaXQgVGFibGUgMy4KCmBgYHtyfQojIFN0YW5kYXJkaXplIGVhY2ggZmFjdG9yCmZvciAodmFyIGluIGZhY3RvcnMpIHsKICBGQUFfbmV3W1twYXN0ZSh2YXIsICJzdGFuZGFyZGl6ZWQiLCBzZXAgPSAiXyIpXV0gPC0gCiAgICAoRkFBX25ld1tbdmFyXV0gLSBtZWFuKEZBQV9uZXdbW3Zhcl1dLCBuYS5ybSA9IFRSVUUpKSAvIHNkKEZBQV9uZXdbW3Zhcl1dLCBuYS5ybSA9IFRSVUUpCn0KCiMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIHRvIHN0b3JlIHJlc3VsdHMKcmVnX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBWYXJpYWJsZSA9IGNoYXJhY3RlcigpLAogIFNpemVPZkNvZWZmaWNpZW50ID0gbnVtZXJpYygpLAogIERpcmVjdGlvbiA9IGNoYXJhY3RlcigpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgojIExvb3AgdGhyb3VnaCBlYWNoIHN0YW5kYXJkaXplZCB2YXJpYWJsZSB0byBwZXJmb3JtIHJlZ3Jlc3Npb24KZm9yICh2YXIgaW4gZmFjdG9ycykgewogICMgRGVmaW5lIHRoZSByZWdyZXNzaW9uIGZvcm11bGEgdXNpbmcgdGhlIHN0YW5kYXJkaXplZCB2YXJpYWJsZQogIGZvcm11bGEgPC0gYXMuZm9ybXVsYShwYXN0ZSgiZGlzdGFuY2UgfiIsIHBhc3RlKHZhciwgInN0YW5kYXJkaXplZCIsIHNlcCA9ICJfIikpKQogIAogICMgRml0IHRoZSBsaW5lYXIgbW9kZWwKICBtb2RlbF9zdGFuZGFyZGl6ZWQgPC0gbG0oZm9ybXVsYSwgZGF0YSA9IEZBQV9uZXcpCiAgCiAgIyBHZXQgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgc3RhbmRhcmRpemVkIHZhcmlhYmxlCiAgY29lZmZpY2llbnQyIDwtIHN1bW1hcnkobW9kZWxfc3RhbmRhcmRpemVkKSRjb2VmZmljaWVudHNbMiwgMV0KICAKICAjIERldGVybWluZSB0aGUgZGlyZWN0aW9uIG9mIHRoZSBjb2VmZmljaWVudAogIGRpcmVjdGlvbjIgPC0gaWZlbHNlKGNvZWZmaWNpZW50MiA+IDAsICJQb3NpdGl2ZSIsICJOZWdhdGl2ZSIpCiAgCiAgIyBBcHBlbmQgdGhlIHJlc3VsdHMgdG8gdGhlIGRhdGEgZnJhbWUKICByZWdfcmVzdWx0cyA8LSByYmluZChyZWdfcmVzdWx0cywgZGF0YS5mcmFtZSgKICAgIFZhcmlhYmxlID0gdmFyLAogICAgU2l6ZU9mQ29lZmZpY2llbnQgPSBhYnMoY29lZmZpY2llbnQyKSwKICAgIERpcmVjdGlvbiA9IGRpcmVjdGlvbjIKICApKQp9CgojIFNvcnQgdGhlIGRhdGEgZnJhbWUgYnkgQ29lZmZpY2llbnRfU2l6ZSBpbiBkZXNjZW5kaW5nIG9yZGVyCnJlZ19yZXN1bHRzIDwtIHJlZ19yZXN1bHRzW29yZGVyKHJlZ19yZXN1bHRzJFNpemVPZkNvZWZmaWNpZW50LCBkZWNyZWFzaW5nID0gVFJVRSksIF0KCiMgUHJpbnQgdGhlIGZpbmFsIHRhYmxlIHdpdGggYSBuYW1lCmNhdCgiVGFibGUgMyIpCnByaW50KHJlZ19yZXN1bHRzKQpgYGAKCgojIyMjIyBTdGVwIDE1LiBDb21wYXJlIFRhYmxlcyAxLDIsMy4gQXJlIHRoZSByZXN1bHRzIGNvbnNpc3RlbnQ/IEF0IHRoaXMgcG9pbnQsIHlvdSB3aWxsIG1lZXQgd2l0aCBhIEZBQSBhZ2VudCBhZ2Fpbi4gUGxlYXNlIHByb3ZpZGUgYSBzaW5nbGUgdGFibGUgdGhhbiByYW5rcyBhbGwgdGhlIGZhY3RvcnMgYmFzZWQgb24gdGhlaXIgcmVsYXRpdmUgaW1wb3J0YW5jZSBpbiBkZXRlcm1pbmluZyB0aGUgbGFuZGluZyBkaXN0YW5jZS4gV2UgY2FsbCBpdCBUYWJsZSAwLgoKYGBge3J9CiMgVGFibGUgMTogY29ycmVsYXRpb25zIChjb2x1bW5zOiBWYXJpYWJsZSwgU2l6ZU9mQ29ycmVsYXRpb24sIERpcmVjdGlvbk9mQ29ycmVsYXRpb24pCiMgVGFibGUgMjogcmVncmVzc2lvbl9yZXN1bHRzIChjb2x1bW5zOiBWYXJpYWJsZSwgUF9WYWx1ZSwgRGlyZWN0aW9ub2ZDb2VmZmljaWVudCkKIyBUYWJsZSAzOiByZWdfcmVzdWx0cyAoY29sdW1uczogVmFyaWFibGUsIFNpemVPZkNvZWZmaWNpZW50LCBEaXJlY3Rpb24pCgojIENvbWJpbmUgdGhlIHRhYmxlcyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKY29tYmluZWRfcmVzdWx0cyA8LSBtZXJnZShjb3JyZWxhdGlvbnMsIHJlZ3Jlc3Npb25fcmVzdWx0cywgYnkgPSAiVmFyaWFibGUiLCBzdWZmaXhlcyA9IGMoIl9Db3JyZWxhdGlvbiIsICJfU2lnbmlmaWNhbmNlIikpCmNvbWJpbmVkX3Jlc3VsdHMgPC0gbWVyZ2UoY29tYmluZWRfcmVzdWx0cywgcmVnX3Jlc3VsdHMsIGJ5ID0gIlZhcmlhYmxlIikKCiMgQWRkIHJhbmtzIGZvciBlYWNoIG1ldHJpYwpjb21iaW5lZF9yZXN1bHRzJFJhbmtfQ29ycmVsYXRpb24gPC0gcmFuaygtYWJzKGNvbWJpbmVkX3Jlc3VsdHMkU2l6ZU9mQ29ycmVsYXRpb24pLCB0aWVzLm1ldGhvZCA9ICJtaW4iKQpjb21iaW5lZF9yZXN1bHRzJFJhbmtfU2lnbmlmaWNhbmNlIDwtIHJhbmsoY29tYmluZWRfcmVzdWx0cyRQX1ZhbHVlLCB0aWVzLm1ldGhvZCA9ICJtaW4iKQpjb21iaW5lZF9yZXN1bHRzJFJhbmtfQ29lZmZpY2llbnQgPC0gcmFuaygtY29tYmluZWRfcmVzdWx0cyRTaXplT2ZDb2VmZmljaWVudCwgdGllcy5tZXRob2QgPSAibWluIikKCiMgQ2FsY3VsYXRlIHRoZSBvdmVyYWxsIHJhbmsgYnkgYXZlcmFnaW5nIHRoZSByYW5rcwpjb21iaW5lZF9yZXN1bHRzJE92ZXJhbGxfUmFuayA8LSByb3dNZWFucyhjb21iaW5lZF9yZXN1bHRzWywgYygiUmFua19Db3JyZWxhdGlvbiIsICJSYW5rX1NpZ25pZmljYW5jZSIsICJSYW5rX0NvZWZmaWNpZW50IildKQoKIyBTb3J0IGJ5IHRoZSBvdmVyYWxsIHJhbmsKY29tYmluZWRfcmVzdWx0cyA8LSBjb21iaW5lZF9yZXN1bHRzW29yZGVyKGNvbWJpbmVkX3Jlc3VsdHMkT3ZlcmFsbF9SYW5rKSwgXQoKIyBTZWxlY3QgdGhlIHJlbGV2YW50IGNvbHVtbnMgZm9yIFRhYmxlIDAKdGFibGVfMCA8LSBjb21iaW5lZF9yZXN1bHRzWywgYygiVmFyaWFibGUiLCAiU2l6ZU9mQ29ycmVsYXRpb24iLCAiUF9WYWx1ZSIsICJTaXplT2ZDb2VmZmljaWVudCIsICJPdmVyYWxsX1JhbmsiKV0KY29sbmFtZXModGFibGVfMCkgPC0gYygiVmFyaWFibGUiLCAiQ29ycmVsYXRpb24iLCAiUF9WYWx1ZSIsICJDb2VmZmljaWVudF9TaXplIiwgIk92ZXJhbGxfUmFuayIpCgojIFByaW50IFRhYmxlIDAKY2F0KCJUYWJsZSAwIikKcHJpbnQodGFibGVfMCkKYGBgCgoKIyMjIENoZWNrIGNvbGxpbmVhcml0eQoKIyMjIyMgU3RlcCAxNi4gQ29tcGFyZSB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgb2YgdGhlIHRocmVlIG1vZGVscyBiZWxvdzogTW9kZWwgMTogTEQgfiBTcGVlZF9ncm91bmQgTW9kZWwgMjogTEQgfiBTcGVlZF9haXIgTW9kZWwgMzogTEQgfiBTcGVlZF9ncm91bmQgKyBTcGVlZF9haXIuIERvIHlvdSBvYnNlcnZlIGFueSBzaWduaWZpY2FuY2UgY2hhbmdlIGFuZCBzaWduIGNoYW5nZT8gQ2hlY2sgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gU3BlZWRfZ3JvdW5kIGFuZCBTcGVlZF9haXIuIFlvdSBtYXkgd2FudCB0byBrZWVwIG9uZSBvZiB0aGVtIGluIHRoZSBtb2RlbCBzZWxlY3Rpb24uIFdoaWNoIG9uZSB3b3VsZCB5b3UgcGljaz8gV2h5PyAKCmBgYHtyfQojIEZpdCBNb2RlbCAxOiBMRCB+IFNwZWVkX2dyb3VuZAptb2RlbDEgPC0gbG0oZGlzdGFuY2UgfiBzcGVlZF9ncm91bmQsIGRhdGEgPSBGQUFfbmV3KQpzdW1tYXJ5KG1vZGVsMSkKCiMgRml0IE1vZGVsIDI6IExEIH4gU3BlZWRfYWlyCm1vZGVsMiA8LSBsbShkaXN0YW5jZSB+IHNwZWVkX2FpciwgZGF0YSA9IEZBQV9uZXcpCnN1bW1hcnkobW9kZWwyKQoKIyBGaXQgTW9kZWwgMzogTEQgfiBTcGVlZF9ncm91bmQgKyBTcGVlZF9haXIKbW9kZWwzIDwtIGxtKGRpc3RhbmNlIH4gc3BlZWRfZ3JvdW5kICsgc3BlZWRfYWlyLCBkYXRhID0gRkFBX25ldykKc3VtbWFyeShtb2RlbDMpCgojIEV4dHJhY3QgY29lZmZpY2llbnRzIGZvciBlYWNoIG1vZGVsCmNvZWZmX21vZGVsMSA8LSBzdW1tYXJ5KG1vZGVsMSkkY29lZmZpY2llbnRzCmNvZWZmX21vZGVsMiA8LSBzdW1tYXJ5KG1vZGVsMikkY29lZmZpY2llbnRzCmNvZWZmX21vZGVsMyA8LSBzdW1tYXJ5KG1vZGVsMykkY29lZmZpY2llbnRzCgojIERpc3BsYXkgdGhlIGNvZWZmaWNpZW50cwpjYXQoIk1vZGVsIDEgQ29lZmZpY2llbnRzOlxuIikKcHJpbnQoY29lZmZfbW9kZWwxKQpjYXQoIlxuTW9kZWwgMiBDb2VmZmljaWVudHM6XG4iKQpwcmludChjb2VmZl9tb2RlbDIpCmNhdCgiXG5Nb2RlbCAzIENvZWZmaWNpZW50czpcbiIpCnByaW50KGNvZWZmX21vZGVsMykKCiMgQ2hlY2sgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gU3BlZWRfZ3JvdW5kIGFuZCBTcGVlZF9haXIKY29ycmVsYXRpb25fc3BlZWQgPC0gY29yKEZBQV9uZXckc3BlZWRfZ3JvdW5kLCBGQUFfbmV3JHNwZWVkX2FpciwgdXNlID0gImNvbXBsZXRlLm9icyIpCmNhdCgiXG5Db3JyZWxhdGlvbiBiZXR3ZWVuIFNwZWVkX2dyb3VuZCBhbmQgU3BlZWRfYWlyOiIsIGNvcnJlbGF0aW9uX3NwZWVkLCAiXG4iKQpgYGAKClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNwZWVkX2dyb3VuZCBhbmQgc3BlZWRfYWlyIGlzIDAuOTg4MzQ3NSwgd2hpY2ggaXMgYSB2ZXJ5IGhpZ2ggdmFsdWUgYW5kIGNsb3NlIHRvIDEuIEl0IGluZGljYXRlcyBhIHZlcnkgc3Ryb25nIHBvc2l0aXZlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4gQXMgc3BlZWRfZ3JvdW5kIGluY3JlYXNlcywgc3BlZWRfYWlyIGFsc28gaW5jcmVhc2VzIGFsbW9zdCBwcm9wb3J0aW9uYWxseS4gU3VjaCBhIGhpZ2ggY29ycmVsYXRpb24gc3VnZ2VzdHMgbXVsdGljb2xsaW5lYXJpdHkgd2hlbiBib3RoIHZhcmlhYmxlcyBhcmUgdXNlZCB0b2dldGhlciwgc28gd2UgbmVlZCB0byBlbGltaW5hdGUgb25lLiBCb3RoIHZhcmlhYmxlcyBoYXZlIHZlcnkgc21hbGwgUC12YWx1ZSB3aGljaCBzdWdnZXN0cyBpdHMgc2lnbmlmaWNhbnQgaW5mbHVlbmNlLiBIb3dldmVyLCB0aGUgdmFsdWUgb2YgYWRqdXN0ZWQgUi1zcXVhcmVkIGZvciBzcGVlZF9haXIgaXMgaGlnaGVyLCB3aGljaCBpbmRpY2F0ZXMgdGhhdCBzcGVlZF9haXIgZXhwbGFpbnMgYSBncmVhdGVyIHByb3BvcnRpb24gb2YgdGhlIHZhcmlhbmNlIGluIGRpc3RhbmNlIHZhcmlhYmxlLgoKIyMjIFZhcmlhYmxlIHNlbGVjdGlvbiBiYXNlZCBvbiBvdXIgcmFua2luZyBpbiBUYWJsZSAwLgoKIyMjIyMgU3RlcCAxNy4gU3VwcG9zZSBpbiBUYWJsZSAwLCB0aGUgdmFyaWFibGUgcmFua2luZyBpcyBhcyBmb2xsb3dzOiBYMSwgWDIsIFgz4oCmLi4gUGxlYXNlIGZpdCB0aGUgZm9sbG93aW5nIHNpeCBtb2RlbHM6IE1vZGVsIDE6IExEIH4gWDEgTW9kZWwgMjogTEQgfiBYMSArIFgyIE1vZGVsIDM6IExEIH4gWDEgKyBYMiArIFgzIOKApuKApuKApi4gQ2FsY3VsYXRlIHRoZSBSLXNxdWFyZWQgZm9yIGVhY2ggbW9kZWwuIFBsb3QgdGhlc2UgUi1zcXVhcmVkIHZhbHVlcyB2ZXJzdXMgdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgcC4gV2hhdCBwYXR0ZXJucyBkbyB5b3Ugb2JzZXJ2ZT8KCmBgYHtyfQp2YXJfcmFua2VkIDwtIGMoInNwZWVkX2FpciIsICJzcGVlZF9ncm91bmQiLCAiYWlyY3JhZnRfbnVtZXJpYyIsImhlaWdodCIsICJkdXJhdGlvbiIsICJwaXRjaCIsICJub19wYXNnIikKCiMgSW5pdGlhbGl6ZSBhIHZlY3RvciB0byBzdG9yZSBSLXNxdWFyZWQgdmFsdWVzCnJfc3F1YXJlZF92YWx1ZXMgPC0gbnVtZXJpYyhsZW5ndGgodmFyX3JhbmtlZCkpCgojIEZpdCBtb2RlbHMgYW5kIGNhbGN1bGF0ZSBSLXNxdWFyZWQgdmFsdWVzCmZvciAoaSBpbiBzZXFfYWxvbmcodmFyX3JhbmtlZCkpIHsKICAjIENyZWF0ZSB0aGUgZm9ybXVsYSBkeW5hbWljYWxseQogIGZvcm11bGEgPC0gYXMuZm9ybXVsYShwYXN0ZSgiZGlzdGFuY2UgfiIsIHBhc3RlKHZhcl9yYW5rZWRbMTppXSwgY29sbGFwc2UgPSAiICsgIikpKQogIAogICMgRml0IHRoZSBtb2RlbAogIG1vZGVsX3JhbmsgPC0gbG0oZm9ybXVsYSwgZGF0YSA9IEZBQV9uZXcpCiAgCiAgIyBFeHRyYWN0IHRoZSBSLXNxdWFyZWQgdmFsdWUKICByX3NxdWFyZWRfdmFsdWVzW2ldIDwtIHN1bW1hcnkobW9kZWxfcmFuaykkci5zcXVhcmVkCn0KCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKcl9zcXVhcmVkX3JhbmsgPC0gZGF0YS5mcmFtZSgKICBOdW1fVmFyaWFibGVzID0gc2VxX2Fsb25nKHZhcl9yYW5rZWQpLAogIFJfU3F1YXJlZCA9IHJfc3F1YXJlZF92YWx1ZXMKKQoKIyBQbG90IHRoZSBSLXNxdWFyZWQgdmFsdWVzIHZlcnN1cyB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcwpnZ3Bsb3Qocl9zcXVhcmVkX3JhbmssIGFlcyh4ID0gTnVtX1ZhcmlhYmxlcywgeSA9IFJfU3F1YXJlZCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIlItc3F1YXJlZCB2cyBOdW1iZXIgb2YgVmFyaWFibGVzIiwKICAgICAgIHggPSAiTnVtYmVyIG9mIFZhcmlhYmxlcyIsCiAgICAgICB5ID0gIlItc3F1YXJlZCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgUHJpbnQgdGhlIFItc3F1YXJlZCB2YWx1ZXMgZm9yIHJlZmVyZW5jZQpwcmludChyX3NxdWFyZWRfcmFuaykKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSAkUl4yJCB2YWx1ZSBpbmNyZWFzZXMgd2hlbiB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyBpbmNyZWFzZSBhcyB3ZWxsLCBob3dldmVyLCB0aGUgdmFsdWUgaXMgcHJldHR5IHN0YWJsZSB3aGVuIHRoZSB2YXJpYWJsZSByZWFjaCBmb3VyLgoKIyMjIyMgU3RlcCAxOC4gUmVwZWF0IFN0ZXAgMTcgYnV0IHVzZSBhZGp1c3RlZCBSLXNxdWFyZWQgdmFsdWVzIGluc3RlYWQuCgpgYGB7cn0KYWRqX3Jfc3F1YXJlZF92YWx1ZXMgPC0gbnVtZXJpYyhsZW5ndGgodmFyX3JhbmtlZCkpCgojIEZpdCBtb2RlbHMgYW5kIGNhbGN1bGF0ZSBBZGp1c3RlZCBSLXNxdWFyZWQgdmFsdWVzCmZvciAoaSBpbiBzZXFfYWxvbmcodmFyX3JhbmtlZCkpIHsKICAjIENyZWF0ZSB0aGUgZm9ybXVsYSBkeW5hbWljYWxseQogIGZvcm11bGFfYWRqIDwtIGFzLmZvcm11bGEocGFzdGUoImRpc3RhbmNlIH4iLCBwYXN0ZSh2YXJfcmFua2VkWzE6aV0sIGNvbGxhcHNlID0gIiArICIpKSkKICAKICAjIEZpdCB0aGUgbW9kZWwKICBtb2RlbF9hZGogPC0gbG0oZm9ybXVsYV9hZGosIGRhdGEgPSBGQUFfbmV3KQogIAogICMgRXh0cmFjdCB0aGUgUi1zcXVhcmVkIHZhbHVlCiAgYWRqX3Jfc3F1YXJlZF92YWx1ZXNbaV0gPC0gc3VtbWFyeShtb2RlbF9hZGopJGFkai5yLnNxdWFyZWQKfQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwphZGpfcl9zcXVhcmVkIDwtIGRhdGEuZnJhbWUoCiAgTnVtX1ZhcmlhYmxlcyA9IHNlcV9hbG9uZyh2YXJfcmFua2VkKSwKICBBZGpfUl9TcXVhcmVkID0gYWRqX3Jfc3F1YXJlZF92YWx1ZXMKKQoKIyBQbG90IHRoZSBSLXNxdWFyZWQgdmFsdWVzIHZlcnN1cyB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcwpnZ3Bsb3QoYWRqX3Jfc3F1YXJlZCwgYWVzKHggPSBOdW1fVmFyaWFibGVzLCB5ID0gQWRqX1JfU3F1YXJlZCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIkFkanVzdGVkIFItc3F1YXJlZCB2cyBOdW1iZXIgb2YgVmFyaWFibGVzIiwKICAgICAgIHggPSAiTnVtYmVyIG9mIFZhcmlhYmxlcyIsCiAgICAgICB5ID0gIkFkanVzdGVkIFItc3F1YXJlZCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgUHJpbnQgdGhlIFItc3F1YXJlZCB2YWx1ZXMgZm9yIHJlZmVyZW5jZQpwcmludChhZGpfcl9zcXVhcmVkKQpgYGAKClRoZSB2YWx1ZSBvZiBhZGp1c3RlZCBSIHNxdWFyZWQgbG9va3MgdmVyeSBzaW1pbGFyIGNvbXBhcmVkIHRvIFIgc3F1YXJlZCB2YWx1ZXMuIFRoZSB2YWx1ZSBpbmNyZWFzZXMgd2hlbiB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyBpbmNyZWFzZSwgYW5kIGJlY2FtZSBzdGFibGUgb25jZSBpdCByZWFjaGVzIGZvdXIgdmFyaWFibGVzLgoKIyMjIyMgU3RlcCAxOS4gUmVwZWF0IFN0ZXAgMTcgYnV0IHVzZSBBSUMgdmFsdWVzIGluc3RlYWQuCgpgYGB7cn0KYWljX3ZhbHVlcyA8LSBudW1lcmljKGxlbmd0aCh2YXJfcmFua2VkKSkKCiMgRml0IG1vZGVscyBhbmQgY2FsY3VsYXRlIEFJQyB2YWx1ZXMKZm9yIChpIGluIHNlcV9hbG9uZyh2YXJfcmFua2VkKSkgewogICMgQ3JlYXRlIHRoZSBmb3JtdWxhIGR5bmFtaWNhbGx5CiAgZm9ybXVsYV9haWMgPC0gYXMuZm9ybXVsYShwYXN0ZSgiZGlzdGFuY2UgfiIsIHBhc3RlKHZhcl9yYW5rZWRbMTppXSwgY29sbGFwc2UgPSAiICsgIikpKQogIAogICMgRml0IHRoZSBtb2RlbAogIG1vZGVsX2FpYyA8LSBsbShmb3JtdWxhX2FpYywgZGF0YSA9IEZBQV9uZXcpCiAgCiAgIyBFeHRyYWN0IHRoZSBBSUMgdmFsdWUKICBhaWNfdmFsdWVzW2ldIDwtIEFJQyhtb2RlbF9haWMpCn0KCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKYWljX3Bsb3QgPC0gZGF0YS5mcmFtZSgKICBOdW1fVmFyaWFibGVzID0gc2VxX2Fsb25nKHZhcl9yYW5rZWQpLAogIEFJQyA9IGFpY192YWx1ZXMKKQoKIyBQbG90IHRoZSBSLXNxdWFyZWQgdmFsdWVzIHZlcnN1cyB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcwpnZ3Bsb3QoYWljX3Bsb3QsIGFlcyh4ID0gTnVtX1ZhcmlhYmxlcywgeSA9IEFJQykpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIkFJQyB2cyBOdW1iZXIgb2YgVmFyaWFibGVzIiwKICAgICAgIHggPSAiTnVtYmVyIG9mIFZhcmlhYmxlcyIsCiAgICAgICB5ID0gIkFJQyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgUHJpbnQgdGhlIFItc3F1YXJlZCB2YWx1ZXMgZm9yIHJlZmVyZW5jZQpwcmludChhaWNfcGxvdCkKYGBgCgpJdCBhcHBlYXJzIHRoYXQgdGhlIEFJQyBkZWNyZWFzZSBhcyBtb3JlIHZhcmlhYmxlcyBhcmUgYWRkZWQgdG8gdGhlIG1vZGVsLiBIb3dldmVyLCBpdCBzdG9wcyBkZWNyZWFzaW5nIHdoZW4gdmFyaWFibGUgcmVhY2hlcyBmb3VyLCBhbmQgdGhlIGxvd2VzdCBBSUMgdmFsdWUgaXMgd2hlbiB0aGUgdmFyaWFibGUgbnVtYmVyIGlzIGZvdXIuIEl0IHN1Z2dlc3RzIHRoZSBvcHRpbWFsIG1vZGVsIHNpemUgY291bGQgYmUgZm91ci4gCgojIyMjIyBTdGVwIDIwLiBDb21wYXJlIHRoZSByZXN1bHRzIGluIFN0ZXBzIDE4LTE5LCB3aGF0IHZhcmlhYmxlcyB3b3VsZCB5b3Ugc2VsZWN0IHRvIGJ1aWxkIGEgcHJlZGljdGl2ZSBtb2RlbCBmb3IgTEQ/CgpCYXNlZCBvbiB0aGUgcmVzdWx0cyBpbiBzdGVwcyAxOCwgMTksIGl0IGluZGljYXRlcyB0aGF0IGZvdXIgdmFyaWFibGUgaXMgdGhlIG9wdGltYWwgY2hvaWNlLCB0aGVyZWZvcmUgdGhlIHZhcmlhYmxlcyB3aWxsIGJlIHNwZWVkX2Fpciwgc3BlZWRfZ3JvdW5kLCBhaXJjcmFmdCwgaGVpZ2h0LiBBbHRob3VnaCwgZnJvbSBwcmV2aW91cyBzdGVwcywgd2UgbGVhcm5lZCB0aGVyZSBpcyBtdWx0aWNvbGxpbmVhcml0eSBiZXR3ZWVuIHNwZWVkX2dyb3VuZCBhbmQgc3BlZWRfYWlyLCBzbyB3ZSBjb3VsZCBlbGltaW5hdGUgb25lLiBBbHNvLCBhaXJjcmFmdCBpcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBpbnN0ZWFkIG9mIGluY2x1ZGluZyBpdCwgbWF5YmUgaGF2ZSB0aGUgb3RoZXIgdmFyaWFibGUgcmVzdWx0cyBncm91cGVkIGJ5IGFpcmNyYWZ0IGNvdWxkIGFsc28gYmUgc3VmZmljaWVudC4KCiMjIyBWYXJpYWJsZSBzZWxlY3Rpb24gYmFzZWQgb24gYXV0b21hdGUgYWxnb3JpdGhtLgoKIyMjIyMgU3RlcCAyMS4gVXNlIHRoZSBSIGZ1bmN0aW9uIOKAnFN0ZXBBSUPigJ0gdG8gcGVyZm9ybSBmb3J3YXJkIHZhcmlhYmxlIHNlbGVjdGlvbi4gQ29tcGFyZSB0aGUgcmVzdWx0IHdpdGggdGhhdCBpbiBTdGVwIDE5LgoKYGBge3J9CiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcnkgZm9yIHN0ZXBBSUMKbGlicmFyeShNQVNTKQoKIyBDcmVhdGUgYSBmdWxsIG1vZGVsIHVzaW5nIGFsbCBwcmVkaWN0b3JzCmZ1bGxfbW9kZWwgPC0gbG0oZGlzdGFuY2UgfiAuLCBkYXRhID0gRkFBX25ld1ssIGMoImRpc3RhbmNlIiwgdmFyX3JhbmtlZCldKQoKIyBQZXJmb3JtIGZvcndhcmQgc2VsZWN0aW9uIHVzaW5nIHN0ZXBBSUMKc3RlcF9tb2RlbCA8LSBzdGVwQUlDKGZ1bGxfbW9kZWwsIGRpcmVjdGlvbiA9ICJmb3J3YXJkIiwgdHJhY2UgPSBGQUxTRSkKCiMgU3VtbWFyeSBvZiB0aGUgc3RlcHdpc2Utc2VsZWN0ZWQgbW9kZWwKc3VtbWFyeShzdGVwX21vZGVsKQoKIyBQcmludCB0aGUgc2VsZWN0ZWQgdmFyaWFibGVzCnNlbGVjdGVkX3ZhcmlhYmxlcyA8LSBuYW1lcyhjb2VmKHN0ZXBfbW9kZWwpKQpwcmludChzZWxlY3RlZF92YXJpYWJsZXMpCgojIENvbXBhcmUgdGhlIEFJQyB2YWx1ZSBvZiB0aGUgU3RlcEFJQyBzZWxlY3RlZCBtb2RlbCB3aXRoIG1hbnVhbCBBSUMgdmFsdWVzCnN0ZXBfbW9kZWxfYWljIDwtIEFJQyhzdGVwX21vZGVsKQptYW51YWxfYWljIDwtIGFpY192YWx1ZXMKCiMgUHJpbnQgdGhlIEFJQyBvZiB0aGUgU3RlcEFJQyBzZWxlY3RlZCBtb2RlbApwcmludChwYXN0ZSgiU3RlcEFJQyBTZWxlY3RlZCBNb2RlbCBBSUM6Iiwgc3RlcF9tb2RlbF9haWMpKQoKIyBDb21wYXJlIHdpdGggbWFudWFsIEFJQyB2YWx1ZXMKcHJpbnQobWFudWFsX2FpYykKCmBgYAoKRnJvbSB0aGUgcmVzdWx0IG9mIHN0ZXBBSUMgZnVuY3Rpb24sIHdlIGNhbiBzZWUgdGhhdCB0aGUgQUlDIHZhbHVlcyBhcmUgdmVyeSBtdWNoIHRoZSBzYW1lLiBTdGVwQUlDIHNlbGVjdGVkIDcgdmFyaWFibGVzLCBob3dldmVyLCB3aGVuIGxvb2tpbmcgYXQgdGhlIHN1bW1hcnkgb2YgQUlDIG1vZGVsLCB0aGVyZSBpcyBvbmx5IHRocmVlIHNob3dlZCBzaWduaWZpY2FudCBpbXBhY3QsIHdoaWNoIGlzIHRoZSBzaW1pbGFyIHJlc3VsdHMgYXMgdGhlIEFJQyBjYWxjdWxhdGlvbiBpbiBTdGVwIDE5IChzcGVlZF9ncm91bmQgaGFzIGJlZW4gZWxpbWluYXRlZCku