Load the library:

library(ggplot2)
library(dplyr)
library(tidyr)
library(car)
library(gridExtra)
library(e1071)

Background:

#data <- read.csv("C:/Users/leduc/Downloads/depression.csv", sep=",",header=T)
#"C:/Users/leduc/OneDrive/Desktop/University/Undergrad/Biostats 3400/bolts.RData"
load("C:/Users/leduc/OneDrive/Desktop/University/Undergrad/Biostats 3400/bolts.RData")

A manufacturer of automotive health accessories provides hardware, e.g. nuts, bolts, washers and screws, to fasten the accessory to the ambulance car or truck. Hardware is counted and packaged automatically. Specifically, bolts are dumped into a large metal dish. A plate that forms the bottom of the dish rotates clockwise. This rotation forces bolts to the outside of the dish and up along a(n) (adjustable) narrow ledge. Due to the vibration of the dish, some bolts fall off the ledge and back into the dish. The ledge spirals up to a point where the bolts are allowed to drop into a pan on a conveyor belt. As a bolt drops, it passes by an electronic eye that counts it. When the electronic counter reaches the preset number of bolts (twenty in this case), the rotation is stopped and the conveyor belt is moved forward.

There are several adjustments on the machine that affect its operation which are detailed in the variables: - Speed: a setting that controls the speed of rotation of the plate at the bottom of the dish - Rotation: a setting that is used to change the rotation of the plate - BatchSize: the machine can be set to count in batches of 10 (coded as zero) or 20 (coded as 1) - LedgeWidth: the width of the ledge (in mm) for a given run - Sensitivity: the sensitivity of the electronic eye

The measured response is the time, in seconds, it takes to count twenty bolts.

Question 1: Examine the data graphically and comment. (5 marks)

Processing data:

bolts$Rotation <- as.factor(bolts$Rotation)
bolts$Success <- as.factor(bolts$Success)
bolts$Sensitivity <- as.factor(bolts$Sensitivity)
bolts$Time <- as.numeric(bolts$Time)
bolts$Speed <- as.numeric(bolts$Speed)
bolts$LedgeWidth <- as.numeric(bolts$LedgeWidth)

bolts$Rotation <- droplevels(na.omit(bolts$Rotation))
bolts$Success <- droplevels(na.omit(bolts$Success))
bolts$Sensitivity <- droplevels(na.omit(bolts$Sensitivity))
bolts$Time[is.na(bolts$Time)] <- mean(bolts$Time, na.rm = TRUE)  # Replace NA with mean
bolts$Time[is.na(bolts$Speed)] <- mean(bolts$Speed, na.rm = TRUE)  # Replace NA with mean
bolts$Time[is.na(bolts$LedgeWidth)] <- mean(bolts$LedgeWidth, na.rm = TRUE)  # Replace NA with mean

Descriptive data:

# Categorical Variables: Distribution
categorical_vars <- bolts %>% select(Rotation, Success, Sensitivity)
cat_summary <- categorical_vars %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Category") %>%
  group_by(Variable, Category) %>%
  summarise(Count = n(), .groups = "drop")

# Create Bar Plot for Categorical Variables
categorical_plot <- ggplot(cat_summary, aes(x = Category, y = Count, fill = Variable)) +
  geom_bar(stat = "identity", position = "dodge") +
  facet_wrap(~Variable, scales = "free_x") +
  labs(
    title = "Distribution of Categorical Variables",
    x = "Category",
    y = "Count"
  ) +
  theme_minimal()

# Select only the continuous variables
numeric_vars <- bolts %>% select(Time, Speed, LedgeWidth)

# Reshape data for plotting (long format)
numeric_vars_long <- numeric_vars %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Value")

# Define custom y-axis labels for each facet
custom_labels <- c(
  "Time" = "Time (seconds)",
  "Speed" = "Speed (units/sec)",
  "LedgeWidth" = "Ledge Width (mm)"
)

# Create Faceted Boxplots
ggplot(numeric_vars_long, aes(x = "", y = Value, fill = Variable)) +  # x = "" for single boxplot per facet
  geom_boxplot() +
  facet_wrap(
    ~Variable, 
    scales = "free_y", 
    labeller = as_labeller(custom_labels)
  ) + 
  labs(
    title = "Boxplots of Continuous Variables",
    x = "Variable",
    y = NULL  # Remove global y-axis label
  ) +
  theme_minimal() +
  theme(
    strip.text = element_text(size = 12, face = "bold"),  # Emphasize facet labels
    axis.text.x = element_blank(),  # Hide x-axis text (optional)
    axis.ticks.x = element_blank()  # Hide x-axis ticks (optional)
  )


# Print Plots
print(categorical_plot)

  • Should do both the table and graphically for the dataset? Do both?
  • Only reported the Min-Max-Median-…..
  • No need to report for outlier and statistical test
# Convert data to long format for plotting
bolts_long <- bolts %>%
  gather(key = "Variable", value = "Value", 
         Speed, LedgeWidth, Sensitivity, Rotation, Success)

# Scatter Plots for Time vs Speed, Time vs LedgeWidth
scatter_plot <- ggplot(bolts, aes(x = Speed, y = Time)) +
  geom_point() +
  geom_smooth(method = "lm", color = "blue", se = TRUE) +
  labs(title = "Time vs. Speed (Scatter Plot)", x = "Speed (m/s)", y = "Time (seconds)") +
  theme_minimal()

scatter_plot_2 <- ggplot(bolts, aes(x = LedgeWidth, y = Time)) +
  geom_point() +
  geom_smooth(method = "lm", color = "blue", se = TRUE) +
  labs(title = "Time vs. Ledge Width (Scatter Plot)", x = "Ledge Width (mm)", y = "Time (seconds)") +
  theme_minimal()

# Boxplots for Time vs Sensitivity, Time vs Rotation, Time vs Success
boxplot1 <- ggplot(bolts, aes(x = Sensitivity, y = Time, fill = Sensitivity)) +
  geom_boxplot() +
  labs(title = "Time vs Sensitivity (Boxplot)", x = "Sensitivity (High/Low)", y = "Time (seconds)") +
  theme_minimal() +
  scale_fill_manual(values = c("High" = "skyblue", "Low" = "salmon"))

boxplot2 <- ggplot(bolts, aes(x = Rotation, y = Time, fill = Rotation)) +
  geom_boxplot() +
  labs(title = "Time vs Rotation (Boxplot)", x = "Rotation (Clockwise/Counterclockwise)", y = "Time (seconds)") +
  theme_minimal() +
  scale_fill_manual(values = c("Clockwise" = "lightgreen", "Alternating" = "orange"))

boxplot3 <- ggplot(bolts, aes(x = Success, y = Time, fill = Success)) +
  geom_boxplot() +
  labs(title = "Time vs Success (Boxplot)", x = "Success (Yes/No)", y = "Time (seconds)") +
  theme_minimal() +
  scale_fill_manual(values = c("1" = "purple", "0" = "yellow"))

scatter_plot

scatter_plot_2

boxplot1

boxplot2

boxplot3

# Define a function to calculate the summary
summarize_continuous <- function(data, variable_name) {
  variable <- data[[variable_name]]
  
  summary_stats <- data.frame(
    Mean = round(mean(variable, na.rm = TRUE), 3),
    SD = round(sd(variable, na.rm = TRUE), 3),
    Median = round(median(variable, na.rm = TRUE)),
    IQR = round(IQR(variable, na.rm = TRUE)),
    Variance = round(var(variable, na.rm = TRUE), 3),
    Skewness = round(skewness(variable, na.rm = TRUE), 3),
    Kurtosis = round(kurtosis(variable, na.rm = TRUE), 3),
    Min = round(min(variable, na.rm = TRUE)),
    Max = round(max(variable, na.rm = TRUE)),
    `1%` = round(quantile(variable, 0.01, na.rm = TRUE)),
    `5%` = round(quantile(variable, 0.05, na.rm = TRUE)),
    `10%` = round(quantile(variable, 0.10, na.rm = TRUE)),
    `90%` = round(quantile(variable, 0.90, na.rm = TRUE)),
    `95%` = round(quantile(variable, 0.95, na.rm = TRUE)),
    `99%` = round(quantile(variable, 0.99, na.rm = TRUE))
  )
  
  # Add a range column (Min to Max)
  summary_stats$Range <- paste0(summary_stats$Min, " to ", summary_stats$Max)
  
  # Drop Min and Max columns after creating Range
  summary_stats <- summary_stats %>% select(-Min, -Max)
  
  # Transpose for better readability
  t(summary_stats)
}

# Example usage
summary_time <- summarize_continuous(bolts, "Time")
summary_speed <- summarize_continuous(bolts, "Speed")
summary_ledgewidth <- summarize_continuous(bolts, "LedgeWidth")

# Display summaries
cat("Summary for Time:\n")
Summary for Time:
print(summary_time)
         1%       
Mean     "10.884" 
SD       "2.785"  
Median   "11"     
IQR      "4"      
Variance "7.754"  
Skewness "0.419"  
Kurtosis "1.325"  
X1.      "5"      
X5.      "7"      
X10.     "8"      
X90.     "14"     
X95.     "15"     
X99.     "18"     
Range    "1 to 26"
cat("\nSummary for Speed:\n")

Summary for Speed:
print(summary_speed)
         1%        
Mean     "50.514"  
SD       "3.923"   
Median   "51"      
IQR      "5"       
Variance "15.386"  
Skewness "-0.077"  
Kurtosis "0.019"   
X1.      "41"      
X5.      "44"      
X10.     "45"      
X90.     "55"      
X95.     "57"      
X99.     "60"      
Range    "38 to 62"
cat("\nSummary for LedgeWidth:\n")

Summary for LedgeWidth:
print(summary_ledgewidth)
         1%        
Mean     "14.967"  
SD       "1.461"   
Median   "15"      
IQR      "2"       
Variance "2.136"   
Skewness "0.035"   
Kurtosis "-0.134"  
X1.      "12"      
X5.      "13"      
X10.     "13"      
X90.     "17"      
X95.     "17"      
X99.     "18"      
Range    "11 to 20"

Question 2: Fit a regression model with main effects only and comment on the fit. (5 marks). State your hypotheses clearly.

M1 <- glm(Time ~ Speed + Rotation + LedgeWidth + Sensitivity + Success, 
          family = gaussian, data = bolts)
summary(M1)

Call:
glm(formula = Time ~ Speed + Rotation + LedgeWidth + Sensitivity + 
    Success, family = gaussian, data = bolts)

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)        5.41504    1.20406   4.497 7.91e-06 ***
Speed              0.01069    0.01841   0.581  0.56156    
RotationClockwise  3.15466    0.14452  21.829  < 2e-16 ***
LedgeWidth         0.14868    0.04949   3.004  0.00275 ** 
SensitivityHigh    2.07058    0.14577  14.204  < 2e-16 ***
Success1           0.26581    0.14597   1.821  0.06898 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 4.152716)

    Null deviance: 6195.7  on 799  degrees of freedom
Residual deviance: 3297.3  on 794  degrees of freedom
AIC: 3417.3

Number of Fisher Scoring iterations: 2
rss <- sum(residuals(M1)^2) # Residual Sum of Squares
tss <- sum((bolts$Time - mean(bolts$Time))^2) # Total Sum of Squares
r_squared <- 1 - (rss / tss)
cat("R-squared:", r_squared, "\n")
R-squared: 0.4678119 
cat("AIC", M1$aic, "\n")
AIC 3417.289 

Question 3: Based on the exploratory plots and the above model fit, modify the main effect model appropriately. State your justification for each additional model fitted. No more than two models (in addition to the main effect model) should be fitted and no interaction term needs to be investigated. (5 marks)

Choosing polynomial model for LedgeWidth Variable:

model_linear <- lm(Time ~ poly(LedgeWidth,1), data = bolts)
model_quadratic <- lm(Time ~ poly(LedgeWidth, 2), data = bolts)
model_cubic <- lm(Time ~ poly(LedgeWidth, 3), data = bolts)
model_quartic <- lm(Time ~ poly(LedgeWidth, 4), data = bolts)

anova(model_linear, model_quadratic, model_cubic, model_quartic)
Analysis of Variance Table

Model 1: Time ~ poly(LedgeWidth, 1)
Model 2: Time ~ poly(LedgeWidth, 2)
Model 3: Time ~ poly(LedgeWidth, 3)
Model 4: Time ~ poly(LedgeWidth, 4)
  Res.Df    RSS Df Sum of Sq        F Pr(>F)    
1    798 6191.7                                 
2    797 4036.4  1   2155.36 425.0796 <2e-16 ***
3    796 4032.4  1      3.92   0.7736 0.3794    
4    795 4031.0  1      1.42   0.2801 0.5968    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
AIC(model_linear, model_quadratic, model_cubic, model_quartic)
# Scatter plot with polynomial fits
library(ggplot2)

ggplot(bolts, aes(x = LedgeWidth, y = Time)) +
  geom_point() +
  stat_smooth(method = "lm", formula = y ~ x, color = "orange", se = FALSE, linetype = "dashed") +   # Linear fit
  stat_smooth(method = "lm", formula = y ~ poly(x, 2), color = "green", se = FALSE) +              # Quadratic fit
  stat_smooth(method = "lm", formula = y ~ poly(x, 3), color = "red", se = FALSE) +               # Cubic fit
  stat_smooth(method = "lm", formula = y ~ poly(x, 4), color = "blue", se = FALSE) +              # Quartic fit
  labs(title = "Polynomial Relationship Between Time and LedgeWidth",
       x = "LedgeWidth", y = "Time") +
  theme_minimal()

Assumptions: Linearity

crPlots(M1, ~ LedgeWidth, lwd=4, col="grey", smooth=list(lwd.smooth=4))

Component+Residual plots

bolts$LedgeWidth2 <- bolts$LedgeWidth^2
M2 <- glm(Time ~ Rotation + LedgeWidth + LedgeWidth2 + Sensitivity + Success, 
          family = gaussian, data = bolts)

#M2 <- glm(Time ~ Rotation + poly(LedgeWidth,2) + Sensitivity, 
          #family = gaussian, data = bolts)
#M2$coefficients

par(mfrow=c(1,2))
crPlots(M2, ~ LedgeWidth, lwd=4, col="grey", smooth=list(lwd.smooth=4))
crPlots(M2, ~ LedgeWidth2, lwd=4, col="grey", smooth=list(lwd.smooth=4))
par(mfrow=c(1,1))

Assumptions: Normality

Before the transformation of the outcome:

residuals <- residuals(M1)
# Histogram plot
hist_plot <- ggplot(bolts, aes(x = residuals)) +
  geom_histogram(bins=15, color = "black", alpha = 0.7) +
  labs(title = "Histogram Plot",
       x = "Residuals",
       y = "Density")

# Boxplot
boxplot <- ggplot(bolts, aes(x = residuals)) +
  geom_boxplot() +
  coord_flip() +
  labs(title = "Boxplot",
       x = "Residuals")

# Density plot
density_plot <- ggplot(bolts, aes(x = residuals)) +
  geom_density() +
  stat_function(fun = dnorm, args = list(mean = mean(residuals), 
                                         sd = sd(residuals)), 
                color = "red", linetype = "dashed", size = 1) +
  labs(title = "Density Plot",
       x = "Residuals",
       y = "Density")

# QQ Plot
qq_plot <- ggplot(bolts, aes(sample = residuals)) +
  stat_qq() +
  stat_qq_line(color = "red") +
  labs(title = "QQ Plot",
       y = "Residuals",
       x = "Inverse Normal")

grid_arrangement <- grid.arrange(hist_plot, boxplot, density_plot, qq_plot, ncol = 2,
                                 top = grid::textGrob
                                 ("Residual plots with Time (Model 1)", 
                                 gp = grid::gpar(fontsize = 14, fontface = "bold")))

After adding quadratic model for LedgeWidth:

residuals_tf <- residuals(M2)
# Histogram plot
hist_plot <- ggplot(bolts, aes(x = residuals_tf)) +
  geom_histogram(bins=15, color = "black", alpha = 0.7) +
  labs(title = "Histogram Plot",
       x = "Residuals",
       y = "Density")

# Boxplot
boxplot <- ggplot(bolts, aes(x = residuals_tf)) +
  geom_boxplot() +
  coord_flip() +
  labs(title = "Boxplot",
       x = "Residuals")

# Density plot
density_plot <- ggplot(bolts, aes(x = residuals_tf)) +
  geom_density() +
  stat_function(fun = dnorm, args = list(mean = mean(residuals_tf), 
                                         sd = sd(residuals_tf)), 
                color = "red", linetype = "dashed", size = 1) +
  labs(title = "Density Plot",
       x = "Residuals",
       y = "Density")

# QQ Plot
qq_plot <- ggplot(bolts, aes(sample = residuals_tf)) +
  stat_qq() +
  stat_qq_line(color = "red") +
  labs(title = "QQ Plot",
       y = "Residuals",
       x = "Inverse Normal")

grid_arrangement1 <- grid.arrange(hist_plot, boxplot, density_plot, qq_plot, ncol = 2,
                                 top = grid::textGrob
                                 ("Residual plots with Time (Model 2)", 
                                 gp = grid::gpar(fontsize = 14, fontface = "bold")))

# Before adjustment
shapiro_test_result <- shapiro.test(residuals)
skewness_value_before <- skewness(residuals)
kurtosis_value_before <- kurtosis(residuals)

# After adjustment
shapiro_test_result_after <- shapiro.test(residuals_tf)
skewness_value_after <- skewness(residuals_tf)
kurtosis_value_after <- kurtosis(residuals_tf)

knitr::kable(
  cbind(
    "Before Adjustment (Model 1)" = c("Shapiro-Wilk Test statistics:" = 
                              sprintf("%.3f", shapiro_test_result$statistic),
                            "Shapiro-Wilk Test p-value:" = 
                              sprintf("%.2e", shapiro_test_result$p.value),
                            "Skewness:" = sprintf("%.3f",skewness_value_before),
                            "Kurtosis:" = sprintf("%.3f",kurtosis_value_before)),
    "After Adjustment (Model 2)" = c("Shapiro-Wilk Test statistics:" = 
                              sprintf("%.2f",shapiro_test_result_after$statistic),
                           "Shapiro-Wilk Test p-value:" = 
                              sprintf("%.2e", shapiro_test_result_after$p.value),
                           "Skewness:" = sprintf("%.3f",skewness_value_after),
                           "Kurtosis:" = sprintf("%.3f",kurtosis_value_after))
  ),
  col.names = c("Before transformation (Model 1)", "After transformation (Model 2)"),
  format = "markdown"
)
Before transformation (Model 1) After transformation (Model 2)
Shapiro-Wilk Test statistics: 0.935 0.93
Shapiro-Wilk Test p-value: 3.81e-18 1.01e-18
Skewness: 0.454 -1.312
Kurtosis: 4.871 9.145

Assumptions: Homoskedasity

# Make predictions and calculate residuals
predicted <- predict(M1, newdata = bolts, type = "response")
residuals <- residuals(M1)
predicted_tf <- predict(M2, newdata = bolts, type = "response")
predicted_tf1 <- predict(M2, newdata = bolts)
residuals_tf <- residuals(M2)

# Residuals vs Predictor (RVP) plot
rvp_plot <- ggplot(bolts, aes(x = LedgeWidth, y = residuals)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "solid", color = "red") +
  labs(title = "Model 1 (RVP) Plot",
       x = "Ledge Width",
       y = "Residuals")

# Residuals vs Fitted Value (RVF) plot
rvf_plot <- ggplot(bolts, aes(x = predicted, y = residuals)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "solid", color = "red") +
  labs(title = "Model 1 (RVF) Plot",
       x = "Fitted (Linear prediction)",
       y = "Residuals")

# Residuals vs Predictor (RVP) plot
rvp_plot_tf <- ggplot(bolts, aes(x = LedgeWidth, y = residuals_tf)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "solid", color = "red") +
  labs(title = "Model 2 (RVP) Plot",
       x = "Ledge Width",
       y = "Residuals")

# Residuals vs Fitted Value (RVF) plot
rvf_plot_tf <- ggplot(bolts, aes(x = predicted_tf, y = residuals_tf)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "solid", color = "red") +
  labs(title = "Model 2 (RVF) Plot",
       x = "Fitted (Linear prediction)",
       y = "Residuals")

grid_arrangement <- grid.arrange(rvp_plot, rvf_plot, rvp_plot_tf, rvf_plot_tf,
                                  ncol = 2, nrow = 2,
                                  top = grid::textGrob
                                 ("Residuals vs Predictor and Fitted Value Plots", 
                                   gp = grid::gpar(fontsize = 14, fontface = "bold")))

Final version of the regression model:

bolts$LedgeWidth2 <- bolts$LedgeWidth^2
M2 <- glm(Time ~ Rotation + LedgeWidth + LedgeWidth2 + Sensitivity + Success, 
          family = gaussian, data = bolts)
summary(M2)

Call:
glm(formula = Time ~ Rotation + LedgeWidth + LedgeWidth2 + Sensitivity + 
    Success, family = gaussian, data = bolts)

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       122.29143    3.72327  32.845   <2e-16 ***
RotationClockwise   3.08250    0.09629  32.013   <2e-16 ***
LedgeWidth        -15.48453    0.49676 -31.171   <2e-16 ***
LedgeWidth2         0.52114    0.01652  31.539   <2e-16 ***
SensitivityHigh     1.81934    0.09739  18.681   <2e-16 ***
Success1            0.17774    0.09730   1.827   0.0681 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 1.844145)

    Null deviance: 6195.7  on 799  degrees of freedom
Residual deviance: 1464.3  on 794  degrees of freedom
AIC: 2767.9

Number of Fisher Scoring iterations: 2

Compare between model:

M1 <- glm(Time ~ Speed + Rotation + LedgeWidth + Sensitivity + Success, 
          family = gaussian, data = bolts)
summary(M1)

Call:
glm(formula = Time ~ Speed + Rotation + LedgeWidth + Sensitivity + 
    Success, family = gaussian, data = bolts)

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)        5.41504    1.20406   4.497 7.91e-06 ***
Speed              0.01069    0.01841   0.581  0.56156    
RotationClockwise  3.15466    0.14452  21.829  < 2e-16 ***
LedgeWidth         0.14868    0.04949   3.004  0.00275 ** 
SensitivityHigh    2.07058    0.14577  14.204  < 2e-16 ***
Success1           0.26581    0.14597   1.821  0.06898 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 4.152716)

    Null deviance: 6195.7  on 799  degrees of freedom
Residual deviance: 3297.3  on 794  degrees of freedom
AIC: 3417.3

Number of Fisher Scoring iterations: 2
#with(M1, cbind(res.deviance = deviance, df = df.residual,
  #p = pchisq(deviance, df.residual, lower.tail=FALSE)))

rss <- sum(residuals(M1)^2) # Residual Sum of Squares
tss <- sum((bolts$Time - mean(bolts$Time))^2) # Total Sum of Squares
r_squared <- 1 - (rss / tss)
cat("R-squared:", r_squared, "\n")
R-squared: 0.4678119 
cat("AIC", M1$aic, "\n")
AIC 3417.289 
bolts$LedgeWidth2 <- bolts$LedgeWidth^2
M2 <- glm(Time ~ Rotation + LedgeWidth + LedgeWidth2 + Sensitivity + Success, 
          family = gaussian, data = bolts)
summary(M2)

Call:
glm(formula = Time ~ Rotation + LedgeWidth + LedgeWidth2 + Sensitivity + 
    Success, family = gaussian, data = bolts)

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       122.29143    3.72327  32.845   <2e-16 ***
RotationClockwise   3.08250    0.09629  32.013   <2e-16 ***
LedgeWidth        -15.48453    0.49676 -31.171   <2e-16 ***
LedgeWidth2         0.52114    0.01652  31.539   <2e-16 ***
SensitivityHigh     1.81934    0.09739  18.681   <2e-16 ***
Success1            0.17774    0.09730   1.827   0.0681 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 1.844145)

    Null deviance: 6195.7  on 799  degrees of freedom
Residual deviance: 1464.3  on 794  degrees of freedom
AIC: 2767.9

Number of Fisher Scoring iterations: 2
#with(M2, cbind(res.deviance = deviance, df = df.residual,
  #p = pchisq(deviance, df.residual, lower.tail=FALSE)))
rss <- sum(residuals(M2)^2) # Residual Sum of Squares
tss <- sum((bolts$Time - mean(bolts$Time))^2) # Total Sum of Squares
r_squared <- 1 - (rss / tss)
cat("R-squared:", r_squared, "\n")
R-squared: 0.763665 
cat("AIC", M2$aic, "\n")
AIC 2767.892 
#M_2 <- glm(Time ~ Rotation + LedgeWidth + Sensitivity, 
          #family = gaussian, data = bolts)
#summary(M_2)
#with(M_2, cbind(res.deviance = deviance, df = df.residual,
  #p = pchisq(deviance, df.residual, lower.tail=FALSE)))

# Calculate R-squared
#rss <- sum(residuals(M_2)^2) # Residual Sum of Squares
#tss <- sum((bolts$Time - mean(bolts$Time))^2) # Total Sum of Squares
#r_squared <- 1 - (rss / tss)
#cat("R-squared:", r_squared, "\n")

#N1 <- lm(Time ~ Speed + Rotation + LedgeWidth + Sensitivity + Success, data = bolts)
#N2 <- lm(Time ~ Rotation + LedgeWidth + Sensitivity, data = bolts)

# Do F-test for nested models (ANOVA): 
#anova(M_2,M1)

Question 4: Make recommendations on the settings that can shorten the time taken to count 20 bolts. (2.5 marks)

# Define a sequence of LedgeWidth values for prediction
ledge_width_values <- seq(min(bolts$LedgeWidth), max(bolts$LedgeWidth), length.out = 100)

# Create a new data frame with varying LedgeWidth and fixed settings for other variables
new_data <- data.frame(
  Rotation = "Alternating",  # Fixed at the optimal level
  Sensitivity = "Low",       # Fixed at the baseline level
  LedgeWidth = ledge_width_values
)

# Predict Time using the model
new_data$PredictedTime <- predict(M2, newdata = new_data)
Error in eval(predvars, data, env) : object 'LedgeWidth2' not found
library(ggplot2)
ggplot(new_data, aes(x = LedgeWidth, y = PredictedTime)) +
  geom_line(color = "blue", linewidth = 1.5) +
  labs(
    title = "Predicted Time vs. LedgeWidth",
    x = "LedgeWidth",
    y = "Predicted Time"
  ) +
  theme_minimal()

optimal_ledge_width <- new_data$LedgeWidth[which.min(new_data$PredictedTime)]
cat("The optimal LedgeWidth is:", optimal_ledge_width, "\n")
The optimal LedgeWidth is: 14.83773 

Question 5: State your hypotheses and conclusions clearly. (2. 5 marks)

Model assumption first (hypo?)

LS0tDQp0aXRsZTogIkZpbmFsIHByb2plY3QgZm9yIEJpb3N0YXRzIDM0MDAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KIyBMb2FkIHRoZSBsaWJyYXJ5OiANCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShlMTA3MSkNCmBgYA0KDQojIEJhY2tncm91bmQ6IA0KYGBge3IgbG9hZCB0aGUgZGF0YX0NCiNkYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9sZWR1Yy9Eb3dubG9hZHMvZGVwcmVzc2lvbi5jc3YiLCBzZXA9IiwiLGhlYWRlcj1UKQ0KIyJDOi9Vc2Vycy9sZWR1Yy9PbmVEcml2ZS9EZXNrdG9wL1VuaXZlcnNpdHkvVW5kZXJncmFkL0Jpb3N0YXRzIDM0MDAvYm9sdHMuUkRhdGEiDQpsb2FkKCJDOi9Vc2Vycy9sZWR1Yy9PbmVEcml2ZS9EZXNrdG9wL1VuaXZlcnNpdHkvVW5kZXJncmFkL0Jpb3N0YXRzIDM0MDAvYm9sdHMuUkRhdGEiKQ0KYGBgDQoNCkEgbWFudWZhY3R1cmVyIG9mIGF1dG9tb3RpdmUgaGVhbHRoIGFjY2Vzc29yaWVzIHByb3ZpZGVzIGhhcmR3YXJlLCBlLmcuIG51dHMsIGJvbHRzLCB3YXNoZXJzIGFuZCBzY3Jld3MsIHRvIGZhc3RlbiB0aGUgYWNjZXNzb3J5IHRvIHRoZSBhbWJ1bGFuY2UgY2FyIG9yIHRydWNrLiBIYXJkd2FyZSBpcyBjb3VudGVkIGFuZCBwYWNrYWdlZCBhdXRvbWF0aWNhbGx5LiBTcGVjaWZpY2FsbHksIGJvbHRzIGFyZSBkdW1wZWQgaW50byBhIGxhcmdlIG1ldGFsIGRpc2guIEEgcGxhdGUgdGhhdCBmb3JtcyB0aGUgYm90dG9tIG9mIHRoZSBkaXNoIHJvdGF0ZXMgY2xvY2t3aXNlLiBUaGlzIHJvdGF0aW9uIGZvcmNlcyBib2x0cyB0byB0aGUgb3V0c2lkZSBvZiB0aGUgZGlzaCBhbmQgdXAgYWxvbmcgYShuKSAoYWRqdXN0YWJsZSkgbmFycm93IGxlZGdlLiBEdWUgdG8gdGhlIHZpYnJhdGlvbiBvZiB0aGUgZGlzaCwgc29tZSBib2x0cyBmYWxsIG9mZiB0aGUgbGVkZ2UgYW5kIGJhY2sgaW50byB0aGUgZGlzaC4gVGhlIGxlZGdlIHNwaXJhbHMgdXAgdG8gYSBwb2ludCB3aGVyZSB0aGUgYm9sdHMgYXJlIGFsbG93ZWQgdG8gZHJvcCBpbnRvIGEgcGFuIG9uIGEgY29udmV5b3IgYmVsdC4gQXMgYSBib2x0IGRyb3BzLCBpdCBwYXNzZXMgYnkgYW4gZWxlY3Ryb25pYyBleWUgdGhhdCBjb3VudHMgaXQuIFdoZW4gdGhlIGVsZWN0cm9uaWMgY291bnRlciByZWFjaGVzIHRoZSBwcmVzZXQgbnVtYmVyIG9mIGJvbHRzICh0d2VudHkgaW4gdGhpcyBjYXNlKSwgdGhlIHJvdGF0aW9uIGlzIHN0b3BwZWQgYW5kIHRoZSBjb252ZXlvciBiZWx0IGlzIG1vdmVkIGZvcndhcmQuDQoNClRoZXJlIGFyZSBzZXZlcmFsIGFkanVzdG1lbnRzIG9uIHRoZSBtYWNoaW5lIHRoYXQgYWZmZWN0IGl0cyBvcGVyYXRpb24gd2hpY2ggYXJlIGRldGFpbGVkIGluIHRoZSB2YXJpYWJsZXM6DQogICAgLSBTcGVlZDogYSBzZXR0aW5nIHRoYXQgY29udHJvbHMgdGhlIHNwZWVkIG9mIHJvdGF0aW9uIG9mIHRoZSBwbGF0ZSBhdCB0aGUgYm90dG9tIG9mIHRoZSBkaXNoDQogICAgLSBSb3RhdGlvbjogYSBzZXR0aW5nIHRoYXQgaXMgdXNlZCB0byBjaGFuZ2UgdGhlIHJvdGF0aW9uIG9mIHRoZSBwbGF0ZQ0KICAgIC0gQmF0Y2hTaXplOiB0aGUgbWFjaGluZSBjYW4gYmUgc2V0IHRvIGNvdW50IGluIGJhdGNoZXMgb2YgMTAgKGNvZGVkIGFzIHplcm8pIG9yIDIwIChjb2RlZCBhcyAxKQ0KICAgIC0gTGVkZ2VXaWR0aDogdGhlIHdpZHRoIG9mIHRoZSBsZWRnZSAoaW4gbW0pIGZvciBhIGdpdmVuIHJ1bg0KICAgIC0gU2Vuc2l0aXZpdHk6IHRoZSBzZW5zaXRpdml0eSBvZiB0aGUgZWxlY3Ryb25pYyBleWUNCg0KVGhlIG1lYXN1cmVkIHJlc3BvbnNlIGlzIHRoZSB0aW1lLCBpbiBzZWNvbmRzLCBpdCB0YWtlcyB0byBjb3VudCB0d2VudHkgYm9sdHMuDQoNCiMgUXVlc3Rpb24gMTogRXhhbWluZSB0aGUgZGF0YSBncmFwaGljYWxseSBhbmQgY29tbWVudC4gKDUgbWFya3MpDQojIyBQcm9jZXNzaW5nIGRhdGE6DQpgYGB7cn0NCmJvbHRzJFJvdGF0aW9uIDwtIGFzLmZhY3Rvcihib2x0cyRSb3RhdGlvbikNCmJvbHRzJFN1Y2Nlc3MgPC0gYXMuZmFjdG9yKGJvbHRzJFN1Y2Nlc3MpDQpib2x0cyRTZW5zaXRpdml0eSA8LSBhcy5mYWN0b3IoYm9sdHMkU2Vuc2l0aXZpdHkpDQpib2x0cyRUaW1lIDwtIGFzLm51bWVyaWMoYm9sdHMkVGltZSkNCmJvbHRzJFNwZWVkIDwtIGFzLm51bWVyaWMoYm9sdHMkU3BlZWQpDQpib2x0cyRMZWRnZVdpZHRoIDwtIGFzLm51bWVyaWMoYm9sdHMkTGVkZ2VXaWR0aCkNCg0KYm9sdHMkUm90YXRpb24gPC0gZHJvcGxldmVscyhuYS5vbWl0KGJvbHRzJFJvdGF0aW9uKSkNCmJvbHRzJFN1Y2Nlc3MgPC0gZHJvcGxldmVscyhuYS5vbWl0KGJvbHRzJFN1Y2Nlc3MpKQ0KYm9sdHMkU2Vuc2l0aXZpdHkgPC0gZHJvcGxldmVscyhuYS5vbWl0KGJvbHRzJFNlbnNpdGl2aXR5KSkNCmJvbHRzJFRpbWVbaXMubmEoYm9sdHMkVGltZSldIDwtIG1lYW4oYm9sdHMkVGltZSwgbmEucm0gPSBUUlVFKSAgIyBSZXBsYWNlIE5BIHdpdGggbWVhbg0KYm9sdHMkVGltZVtpcy5uYShib2x0cyRTcGVlZCldIDwtIG1lYW4oYm9sdHMkU3BlZWQsIG5hLnJtID0gVFJVRSkgICMgUmVwbGFjZSBOQSB3aXRoIG1lYW4NCmJvbHRzJFRpbWVbaXMubmEoYm9sdHMkTGVkZ2VXaWR0aCldIDwtIG1lYW4oYm9sdHMkTGVkZ2VXaWR0aCwgbmEucm0gPSBUUlVFKSAgIyBSZXBsYWNlIE5BIHdpdGggbWVhbg0KYGBgDQoNCiMjIERlc2NyaXB0aXZlIGRhdGE6IA0KYGBge3J9DQojIENhdGVnb3JpY2FsIFZhcmlhYmxlczogRGlzdHJpYnV0aW9uDQpjYXRlZ29yaWNhbF92YXJzIDwtIGJvbHRzICU+JSBzZWxlY3QoUm90YXRpb24sIFN1Y2Nlc3MsIFNlbnNpdGl2aXR5KQ0KY2F0X3N1bW1hcnkgPC0gY2F0ZWdvcmljYWxfdmFycyAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIkNhdGVnb3J5IikgJT4lDQogIGdyb3VwX2J5KFZhcmlhYmxlLCBDYXRlZ29yeSkgJT4lDQogIHN1bW1hcmlzZShDb3VudCA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KIyBDcmVhdGUgQmFyIFBsb3QgZm9yIENhdGVnb3JpY2FsIFZhcmlhYmxlcw0KY2F0ZWdvcmljYWxfcGxvdCA8LSBnZ3Bsb3QoY2F0X3N1bW1hcnksIGFlcyh4ID0gQ2F0ZWdvcnksIHkgPSBDb3VudCwgZmlsbCA9IFZhcmlhYmxlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGZhY2V0X3dyYXAoflZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDYXRlZ29yaWNhbCBWYXJpYWJsZXMiLA0KICAgIHggPSAiQ2F0ZWdvcnkiLA0KICAgIHkgPSAiQ291bnQiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBTZWxlY3Qgb25seSB0aGUgY29udGludW91cyB2YXJpYWJsZXMNCm51bWVyaWNfdmFycyA8LSBib2x0cyAlPiUgc2VsZWN0KFRpbWUsIFNwZWVkLCBMZWRnZVdpZHRoKQ0KDQojIFJlc2hhcGUgZGF0YSBmb3IgcGxvdHRpbmcgKGxvbmcgZm9ybWF0KQ0KbnVtZXJpY192YXJzX2xvbmcgPC0gbnVtZXJpY192YXJzICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQ0KDQojIERlZmluZSBjdXN0b20geS1heGlzIGxhYmVscyBmb3IgZWFjaCBmYWNldA0KY3VzdG9tX2xhYmVscyA8LSBjKA0KICAiVGltZSIgPSAiVGltZSAoc2Vjb25kcykiLA0KICAiU3BlZWQiID0gIlNwZWVkICh1bml0cy9zZWMpIiwNCiAgIkxlZGdlV2lkdGgiID0gIkxlZGdlIFdpZHRoIChtbSkiDQopDQoNCiMgQ3JlYXRlIEZhY2V0ZWQgQm94cGxvdHMNCmdncGxvdChudW1lcmljX3ZhcnNfbG9uZywgYWVzKHggPSAiIiwgeSA9IFZhbHVlLCBmaWxsID0gVmFyaWFibGUpKSArICAjIHggPSAiIiBmb3Igc2luZ2xlIGJveHBsb3QgcGVyIGZhY2V0DQogIGdlb21fYm94cGxvdCgpICsNCiAgZmFjZXRfd3JhcCgNCiAgICB+VmFyaWFibGUsIA0KICAgIHNjYWxlcyA9ICJmcmVlX3kiLCANCiAgICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKGN1c3RvbV9sYWJlbHMpDQogICkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICJCb3hwbG90cyBvZiBDb250aW51b3VzIFZhcmlhYmxlcyIsDQogICAgeCA9ICJWYXJpYWJsZSIsDQogICAgeSA9IE5VTEwgICMgUmVtb3ZlIGdsb2JhbCB5LWF4aXMgbGFiZWwNCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgICMgRW1waGFzaXplIGZhY2V0IGxhYmVscw0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAgIyBIaWRlIHgtYXhpcyB0ZXh0IChvcHRpb25hbCkNCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkgICMgSGlkZSB4LWF4aXMgdGlja3MgKG9wdGlvbmFsKQ0KICApDQoNCiMgUHJpbnQgUGxvdHMNCnByaW50KGNhdGVnb3JpY2FsX3Bsb3QpDQpgYGANCi0gU2hvdWxkIGRvIGJvdGggdGhlIHRhYmxlIGFuZCBncmFwaGljYWxseSBmb3IgdGhlIGRhdGFzZXQ/IERvIGJvdGg/IA0KLSBPbmx5IHJlcG9ydGVkIHRoZSBNaW4tTWF4LU1lZGlhbi0uLi4uLiANCi0gTm8gbmVlZCB0byByZXBvcnQgZm9yIG91dGxpZXIgYW5kIHN0YXRpc3RpY2FsIHRlc3QNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIENvbnZlcnQgZGF0YSB0byBsb25nIGZvcm1hdCBmb3IgcGxvdHRpbmcNCmJvbHRzX2xvbmcgPC0gYm9sdHMgJT4lDQogIGdhdGhlcihrZXkgPSAiVmFyaWFibGUiLCB2YWx1ZSA9ICJWYWx1ZSIsIA0KICAgICAgICAgU3BlZWQsIExlZGdlV2lkdGgsIFNlbnNpdGl2aXR5LCBSb3RhdGlvbiwgU3VjY2VzcykNCg0KIyBTY2F0dGVyIFBsb3RzIGZvciBUaW1lIHZzIFNwZWVkLCBUaW1lIHZzIExlZGdlV2lkdGgNCnNjYXR0ZXJfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gU3BlZWQsIHkgPSBUaW1lKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICJibHVlIiwgc2UgPSBUUlVFKSArDQogIGxhYnModGl0bGUgPSAiVGltZSB2cy4gU3BlZWQgKFNjYXR0ZXIgUGxvdCkiLCB4ID0gIlNwZWVkIChtL3MpIiwgeSA9ICJUaW1lIChzZWNvbmRzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnNjYXR0ZXJfcGxvdF8yIDwtIGdncGxvdChib2x0cywgYWVzKHggPSBMZWRnZVdpZHRoLCB5ID0gVGltZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiYmx1ZSIsIHNlID0gVFJVRSkgKw0KICBsYWJzKHRpdGxlID0gIlRpbWUgdnMuIExlZGdlIFdpZHRoIChTY2F0dGVyIFBsb3QpIiwgeCA9ICJMZWRnZSBXaWR0aCAobW0pIiwgeSA9ICJUaW1lIChzZWNvbmRzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgQm94cGxvdHMgZm9yIFRpbWUgdnMgU2Vuc2l0aXZpdHksIFRpbWUgdnMgUm90YXRpb24sIFRpbWUgdnMgU3VjY2Vzcw0KYm94cGxvdDEgPC0gZ2dwbG90KGJvbHRzLCBhZXMoeCA9IFNlbnNpdGl2aXR5LCB5ID0gVGltZSwgZmlsbCA9IFNlbnNpdGl2aXR5KSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiVGltZSB2cyBTZW5zaXRpdml0eSAoQm94cGxvdCkiLCB4ID0gIlNlbnNpdGl2aXR5IChIaWdoL0xvdykiLCB5ID0gIlRpbWUgKHNlY29uZHMpIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJIaWdoIiA9ICJza3libHVlIiwgIkxvdyIgPSAic2FsbW9uIikpDQoNCmJveHBsb3QyIDwtIGdncGxvdChib2x0cywgYWVzKHggPSBSb3RhdGlvbiwgeSA9IFRpbWUsIGZpbGwgPSBSb3RhdGlvbikpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHRpdGxlID0gIlRpbWUgdnMgUm90YXRpb24gKEJveHBsb3QpIiwgeCA9ICJSb3RhdGlvbiAoQ2xvY2t3aXNlL0NvdW50ZXJjbG9ja3dpc2UpIiwgeSA9ICJUaW1lIChzZWNvbmRzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ2xvY2t3aXNlIiA9ICJsaWdodGdyZWVuIiwgIkFsdGVybmF0aW5nIiA9ICJvcmFuZ2UiKSkNCg0KYm94cGxvdDMgPC0gZ2dwbG90KGJvbHRzLCBhZXMoeCA9IFN1Y2Nlc3MsIHkgPSBUaW1lLCBmaWxsID0gU3VjY2VzcykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHRpdGxlID0gIlRpbWUgdnMgU3VjY2VzcyAoQm94cGxvdCkiLCB4ID0gIlN1Y2Nlc3MgKFllcy9ObykiLCB5ID0gIlRpbWUgKHNlY29uZHMpIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIxIiA9ICJwdXJwbGUiLCAiMCIgPSAieWVsbG93IikpDQoNCnNjYXR0ZXJfcGxvdA0Kc2NhdHRlcl9wbG90XzINCmJveHBsb3QxDQpib3hwbG90Mg0KYm94cGxvdDMNCmBgYA0KDQpgYGB7cn0NCiMgRGVmaW5lIGEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBzdW1tYXJ5DQpzdW1tYXJpemVfY29udGludW91cyA8LSBmdW5jdGlvbihkYXRhLCB2YXJpYWJsZV9uYW1lKSB7DQogIHZhcmlhYmxlIDwtIGRhdGFbW3ZhcmlhYmxlX25hbWVdXQ0KICANCiAgc3VtbWFyeV9zdGF0cyA8LSBkYXRhLmZyYW1lKA0KICAgIE1lYW4gPSByb3VuZChtZWFuKHZhcmlhYmxlLCBuYS5ybSA9IFRSVUUpLCAzKSwNCiAgICBTRCA9IHJvdW5kKHNkKHZhcmlhYmxlLCBuYS5ybSA9IFRSVUUpLCAzKSwNCiAgICBNZWRpYW4gPSByb3VuZChtZWRpYW4odmFyaWFibGUsIG5hLnJtID0gVFJVRSkpLA0KICAgIElRUiA9IHJvdW5kKElRUih2YXJpYWJsZSwgbmEucm0gPSBUUlVFKSksDQogICAgVmFyaWFuY2UgPSByb3VuZCh2YXIodmFyaWFibGUsIG5hLnJtID0gVFJVRSksIDMpLA0KICAgIFNrZXduZXNzID0gcm91bmQoc2tld25lc3ModmFyaWFibGUsIG5hLnJtID0gVFJVRSksIDMpLA0KICAgIEt1cnRvc2lzID0gcm91bmQoa3VydG9zaXModmFyaWFibGUsIG5hLnJtID0gVFJVRSksIDMpLA0KICAgIE1pbiA9IHJvdW5kKG1pbih2YXJpYWJsZSwgbmEucm0gPSBUUlVFKSksDQogICAgTWF4ID0gcm91bmQobWF4KHZhcmlhYmxlLCBuYS5ybSA9IFRSVUUpKSwNCiAgICBgMSVgID0gcm91bmQocXVhbnRpbGUodmFyaWFibGUsIDAuMDEsIG5hLnJtID0gVFJVRSkpLA0KICAgIGA1JWAgPSByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC4wNSwgbmEucm0gPSBUUlVFKSksDQogICAgYDEwJWAgPSByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC4xMCwgbmEucm0gPSBUUlVFKSksDQogICAgYDkwJWAgPSByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC45MCwgbmEucm0gPSBUUlVFKSksDQogICAgYDk1JWAgPSByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC45NSwgbmEucm0gPSBUUlVFKSksDQogICAgYDk5JWAgPSByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC45OSwgbmEucm0gPSBUUlVFKSkNCiAgKQ0KICANCiAgIyBBZGQgYSByYW5nZSBjb2x1bW4gKE1pbiB0byBNYXgpDQogIHN1bW1hcnlfc3RhdHMkUmFuZ2UgPC0gcGFzdGUwKHN1bW1hcnlfc3RhdHMkTWluLCAiIHRvICIsIHN1bW1hcnlfc3RhdHMkTWF4KQ0KICANCiAgIyBEcm9wIE1pbiBhbmQgTWF4IGNvbHVtbnMgYWZ0ZXIgY3JlYXRpbmcgUmFuZ2UNCiAgc3VtbWFyeV9zdGF0cyA8LSBzdW1tYXJ5X3N0YXRzICU+JSBzZWxlY3QoLU1pbiwgLU1heCkNCiAgDQogICMgVHJhbnNwb3NlIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkNCiAgdChzdW1tYXJ5X3N0YXRzKQ0KfQ0KDQojIEV4YW1wbGUgdXNhZ2UNCnN1bW1hcnlfdGltZSA8LSBzdW1tYXJpemVfY29udGludW91cyhib2x0cywgIlRpbWUiKQ0Kc3VtbWFyeV9zcGVlZCA8LSBzdW1tYXJpemVfY29udGludW91cyhib2x0cywgIlNwZWVkIikNCnN1bW1hcnlfbGVkZ2V3aWR0aCA8LSBzdW1tYXJpemVfY29udGludW91cyhib2x0cywgIkxlZGdlV2lkdGgiKQ0KDQojIERpc3BsYXkgc3VtbWFyaWVzDQpjYXQoIlN1bW1hcnkgZm9yIFRpbWU6XG4iKQ0KcHJpbnQoc3VtbWFyeV90aW1lKQ0KDQpjYXQoIlxuU3VtbWFyeSBmb3IgU3BlZWQ6XG4iKQ0KcHJpbnQoc3VtbWFyeV9zcGVlZCkNCg0KY2F0KCJcblN1bW1hcnkgZm9yIExlZGdlV2lkdGg6XG4iKQ0KcHJpbnQoc3VtbWFyeV9sZWRnZXdpZHRoKQ0KYGBgDQoNCiMgUXVlc3Rpb24gMjogRml0IGEgcmVncmVzc2lvbiBtb2RlbCB3aXRoIG1haW4gZWZmZWN0cyBvbmx5IGFuZCBjb21tZW50IG9uIHRoZSBmaXQuICg1IG1hcmtzKS4gU3RhdGUgeW91ciBoeXBvdGhlc2VzIGNsZWFybHkuDQpgYGB7cn0NCk0xIDwtIGdsbShUaW1lIH4gU3BlZWQgKyBSb3RhdGlvbiArIExlZGdlV2lkdGggKyBTZW5zaXRpdml0eSArIFN1Y2Nlc3MsIA0KICAgICAgICAgIGZhbWlseSA9IGdhdXNzaWFuLCBkYXRhID0gYm9sdHMpDQpzdW1tYXJ5KE0xKQ0KDQpyc3MgPC0gc3VtKHJlc2lkdWFscyhNMSleMikgIyBSZXNpZHVhbCBTdW0gb2YgU3F1YXJlcw0KdHNzIDwtIHN1bSgoYm9sdHMkVGltZSAtIG1lYW4oYm9sdHMkVGltZSkpXjIpICMgVG90YWwgU3VtIG9mIFNxdWFyZXMNCnJfc3F1YXJlZCA8LSAxIC0gKHJzcyAvIHRzcykNCmNhdCgiUi1zcXVhcmVkOiIsIHJfc3F1YXJlZCwgIlxuIikNCmNhdCgiQUlDIiwgTTEkYWljLCAiXG4iKQ0KYGBgDQotIE91dGNvbWUgaXMgVGltZQ0KDQoNCiMgUXVlc3Rpb24gMzogQmFzZWQgb24gdGhlIGV4cGxvcmF0b3J5IHBsb3RzIGFuZCB0aGUgYWJvdmUgbW9kZWwgZml0LCBtb2RpZnkgdGhlIG1haW4gZWZmZWN0IG1vZGVsIGFwcHJvcHJpYXRlbHkuIFN0YXRlIHlvdXIganVzdGlmaWNhdGlvbiBmb3IgZWFjaCBhZGRpdGlvbmFsIG1vZGVsIGZpdHRlZC4gTm8gbW9yZSB0aGFuIHR3byBtb2RlbHMgKGluIGFkZGl0aW9uIHRvIHRoZSBtYWluIGVmZmVjdCBtb2RlbCkgc2hvdWxkIGJlIGZpdHRlZCBhbmQgbm8gaW50ZXJhY3Rpb24gdGVybSBuZWVkcyB0byBiZSBpbnZlc3RpZ2F0ZWQuICg1IG1hcmtzKQ0KLSBFeGNsdWRlIHRoZSBpbnNpZ25pZmljYW50IHZhcmlhYmxlIG91dCANCi0gVHJhbnNmb3JtYXRpb24gPz8/IGN1YmljIC0gU3F1YXJlZCByb290IA0KLSBDb21wYXJlIHRoZSBtb2RlbCBmaXQgYmV0d2VlbiBtb2RlbHM/IFItc3F1YXJlZCBhbmQgQUlDLCAuLi4NCg0KIyMgQ2hvb3NpbmcgcG9seW5vbWlhbCBtb2RlbCBmb3IgTGVkZ2VXaWR0aCBWYXJpYWJsZTogDQpgYGB7cn0NCm1vZGVsX2xpbmVhciA8LSBsbShUaW1lIH4gcG9seShMZWRnZVdpZHRoLDEpLCBkYXRhID0gYm9sdHMpDQptb2RlbF9xdWFkcmF0aWMgPC0gbG0oVGltZSB+IHBvbHkoTGVkZ2VXaWR0aCwgMiksIGRhdGEgPSBib2x0cykNCm1vZGVsX2N1YmljIDwtIGxtKFRpbWUgfiBwb2x5KExlZGdlV2lkdGgsIDMpLCBkYXRhID0gYm9sdHMpDQptb2RlbF9xdWFydGljIDwtIGxtKFRpbWUgfiBwb2x5KExlZGdlV2lkdGgsIDQpLCBkYXRhID0gYm9sdHMpDQoNCmFub3ZhKG1vZGVsX2xpbmVhciwgbW9kZWxfcXVhZHJhdGljLCBtb2RlbF9jdWJpYywgbW9kZWxfcXVhcnRpYykNCkFJQyhtb2RlbF9saW5lYXIsIG1vZGVsX3F1YWRyYXRpYywgbW9kZWxfY3ViaWMsIG1vZGVsX3F1YXJ0aWMpDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIFNjYXR0ZXIgcGxvdCB3aXRoIHBvbHlub21pYWwgZml0cw0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gTGVkZ2VXaWR0aCwgeSA9IFRpbWUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgY29sb3IgPSAib3JhbmdlIiwgc2UgPSBGQUxTRSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAgICMgTGluZWFyIGZpdA0KICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHBvbHkoeCwgMiksIGNvbG9yID0gImdyZWVuIiwgc2UgPSBGQUxTRSkgKyAgICAgICAgICAgICAgIyBRdWFkcmF0aWMgZml0DQogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCAzKSwgY29sb3IgPSAicmVkIiwgc2UgPSBGQUxTRSkgKyAgICAgICAgICAgICAgICMgQ3ViaWMgZml0DQogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCA0KSwgY29sb3IgPSAiYmx1ZSIsIHNlID0gRkFMU0UpICsgICAgICAgICAgICAgICMgUXVhcnRpYyBmaXQNCiAgbGFicyh0aXRsZSA9ICJQb2x5bm9taWFsIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIFRpbWUgYW5kIExlZGdlV2lkdGgiLA0KICAgICAgIHggPSAiTGVkZ2VXaWR0aCIsIHkgPSAiVGltZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgQXNzdW1wdGlvbnM6IExpbmVhcml0eSANCmBgYHtyLCBsaW5ld2lkdGg9ODAsIGVjaG89VH0NCmNyUGxvdHMoTTEsIH4gTGVkZ2VXaWR0aCwgbHdkPTQsIGNvbD0iZ3JleSIsIHNtb290aD1saXN0KGx3ZC5zbW9vdGg9NCkpDQpgYGANCg0KIyMjIENvbXBvbmVudCtSZXNpZHVhbCBwbG90cyANCmBgYHtyLCBsaW5ld2lkdGg9ODAsIGVjaG89VH0NCmJvbHRzJExlZGdlV2lkdGgyIDwtIGJvbHRzJExlZGdlV2lkdGheMg0KTTIgPC0gZ2xtKFRpbWUgfiBSb3RhdGlvbiArIExlZGdlV2lkdGggKyBMZWRnZVdpZHRoMiArIFNlbnNpdGl2aXR5ICsgU3VjY2VzcywgDQogICAgICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sIGRhdGEgPSBib2x0cykNCg0KI00yIDwtIGdsbShUaW1lIH4gUm90YXRpb24gKyBwb2x5KExlZGdlV2lkdGgsMikgKyBTZW5zaXRpdml0eSwgDQogICAgICAgICAgI2ZhbWlseSA9IGdhdXNzaWFuLCBkYXRhID0gYm9sdHMpDQojTTIkY29lZmZpY2llbnRzDQoNCnBhcihtZnJvdz1jKDEsMikpDQpjclBsb3RzKE0yLCB+IExlZGdlV2lkdGgsIGx3ZD00LCBjb2w9ImdyZXkiLCBzbW9vdGg9bGlzdChsd2Quc21vb3RoPTQpKQ0KY3JQbG90cyhNMiwgfiBMZWRnZVdpZHRoMiwgbHdkPTQsIGNvbD0iZ3JleSIsIHNtb290aD1saXN0KGx3ZC5zbW9vdGg9NCkpDQpwYXIobWZyb3c9YygxLDEpKQ0KYGBgDQoNCiMjIEFzc3VtcHRpb25zOiBOb3JtYWxpdHkNCiMjIyBCZWZvcmUgdGhlIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBvdXRjb21lOiANCmBgYHtyfQ0KcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhNMSkNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgSGlzdG9ncmFtIHBsb3QNCmhpc3RfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gcmVzaWR1YWxzKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zPTE1LCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArDQogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIFBsb3QiLA0KICAgICAgIHggPSAiUmVzaWR1YWxzIiwNCiAgICAgICB5ID0gIkRlbnNpdHkiKQ0KDQojIEJveHBsb3QNCmJveHBsb3QgPC0gZ2dwbG90KGJvbHRzLCBhZXMoeCA9IHJlc2lkdWFscykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3QiLA0KICAgICAgIHggPSAiUmVzaWR1YWxzIikNCg0KIyBEZW5zaXR5IHBsb3QNCmRlbnNpdHlfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gcmVzaWR1YWxzKSkgKw0KICBnZW9tX2RlbnNpdHkoKSArDQogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIGFyZ3MgPSBsaXN0KG1lYW4gPSBtZWFuKHJlc2lkdWFscyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZCA9IHNkKHJlc2lkdWFscykpLCANCiAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgUGxvdCIsDQogICAgICAgeCA9ICJSZXNpZHVhbHMiLA0KICAgICAgIHkgPSAiRGVuc2l0eSIpDQoNCiMgUVEgUGxvdA0KcXFfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyhzYW1wbGUgPSByZXNpZHVhbHMpKSArDQogIHN0YXRfcXEoKSArDQogIHN0YXRfcXFfbGluZShjb2xvciA9ICJyZWQiKSArDQogIGxhYnModGl0bGUgPSAiUVEgUGxvdCIsDQogICAgICAgeSA9ICJSZXNpZHVhbHMiLA0KICAgICAgIHggPSAiSW52ZXJzZSBOb3JtYWwiKQ0KDQpncmlkX2FycmFuZ2VtZW50IDwtIGdyaWQuYXJyYW5nZShoaXN0X3Bsb3QsIGJveHBsb3QsIGRlbnNpdHlfcGxvdCwgcXFfcGxvdCwgbmNvbCA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3AgPSBncmlkOjp0ZXh0R3JvYg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKCJSZXNpZHVhbCBwbG90cyB3aXRoIFRpbWUgKE1vZGVsIDEpIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxNCwgZm9udGZhY2UgPSAiYm9sZCIpKSkNCmBgYA0KDQojIyMgQWZ0ZXIgYWRkaW5nIHF1YWRyYXRpYyBtb2RlbCBmb3IgTGVkZ2VXaWR0aDogDQpgYGB7cn0NCnJlc2lkdWFsc190ZiA8LSByZXNpZHVhbHMoTTIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEhpc3RvZ3JhbSBwbG90DQpoaXN0X3Bsb3QgPC0gZ2dwbG90KGJvbHRzLCBhZXMoeCA9IHJlc2lkdWFsc190ZikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0xNSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBQbG90IiwNCiAgICAgICB4ID0gIlJlc2lkdWFscyIsDQogICAgICAgeSA9ICJEZW5zaXR5IikNCg0KIyBCb3hwbG90DQpib3hwbG90IDwtIGdncGxvdChib2x0cywgYWVzKHggPSByZXNpZHVhbHNfdGYpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90IiwNCiAgICAgICB4ID0gIlJlc2lkdWFscyIpDQoNCiMgRGVuc2l0eSBwbG90DQpkZW5zaXR5X3Bsb3QgPC0gZ2dwbG90KGJvbHRzLCBhZXMoeCA9IHJlc2lkdWFsc190ZikpICsNCiAgZ2VvbV9kZW5zaXR5KCkgKw0KICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gbWVhbihyZXNpZHVhbHNfdGYpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2QgPSBzZChyZXNpZHVhbHNfdGYpKSwgDQogICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJEZW5zaXR5IFBsb3QiLA0KICAgICAgIHggPSAiUmVzaWR1YWxzIiwNCiAgICAgICB5ID0gIkRlbnNpdHkiKQ0KDQojIFFRIFBsb3QNCnFxX3Bsb3QgPC0gZ2dwbG90KGJvbHRzLCBhZXMoc2FtcGxlID0gcmVzaWR1YWxzX3RmKSkgKw0KICBzdGF0X3FxKCkgKw0KICBzdGF0X3FxX2xpbmUoY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIlFRIFBsb3QiLA0KICAgICAgIHkgPSAiUmVzaWR1YWxzIiwNCiAgICAgICB4ID0gIkludmVyc2UgTm9ybWFsIikNCg0KZ3JpZF9hcnJhbmdlbWVudDEgPC0gZ3JpZC5hcnJhbmdlKGhpc3RfcGxvdCwgYm94cGxvdCwgZGVuc2l0eV9wbG90LCBxcV9wbG90LCBuY29sID0gMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvcCA9IGdyaWQ6OnRleHRHcm9iDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoIlJlc2lkdWFsIHBsb3RzIHdpdGggVGltZSAoTW9kZWwgMikiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE0LCBmb250ZmFjZSA9ICJib2xkIikpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBCZWZvcmUgYWRqdXN0bWVudA0Kc2hhcGlyb190ZXN0X3Jlc3VsdCA8LSBzaGFwaXJvLnRlc3QocmVzaWR1YWxzKQ0Kc2tld25lc3NfdmFsdWVfYmVmb3JlIDwtIHNrZXduZXNzKHJlc2lkdWFscykNCmt1cnRvc2lzX3ZhbHVlX2JlZm9yZSA8LSBrdXJ0b3NpcyhyZXNpZHVhbHMpDQoNCiMgQWZ0ZXIgYWRqdXN0bWVudA0Kc2hhcGlyb190ZXN0X3Jlc3VsdF9hZnRlciA8LSBzaGFwaXJvLnRlc3QocmVzaWR1YWxzX3RmKQ0Kc2tld25lc3NfdmFsdWVfYWZ0ZXIgPC0gc2tld25lc3MocmVzaWR1YWxzX3RmKQ0Ka3VydG9zaXNfdmFsdWVfYWZ0ZXIgPC0ga3VydG9zaXMocmVzaWR1YWxzX3RmKQ0KDQprbml0cjo6a2FibGUoDQogIGNiaW5kKA0KICAgICJCZWZvcmUgQWRqdXN0bWVudCAoTW9kZWwgMSkiID0gYygiU2hhcGlyby1XaWxrIFRlc3Qgc3RhdGlzdGljczoiID0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlLjNmIiwgc2hhcGlyb190ZXN0X3Jlc3VsdCRzdGF0aXN0aWMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTaGFwaXJvLVdpbGsgVGVzdCBwLXZhbHVlOiIgPSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmUiLCBzaGFwaXJvX3Rlc3RfcmVzdWx0JHAudmFsdWUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTa2V3bmVzczoiID0gc3ByaW50ZigiJS4zZiIsc2tld25lc3NfdmFsdWVfYmVmb3JlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VydG9zaXM6IiA9IHNwcmludGYoIiUuM2YiLGt1cnRvc2lzX3ZhbHVlX2JlZm9yZSkpLA0KICAgICJBZnRlciBBZGp1c3RtZW50IChNb2RlbCAyKSIgPSBjKCJTaGFwaXJvLVdpbGsgVGVzdCBzdGF0aXN0aWNzOiIgPSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmYiLHNoYXBpcm9fdGVzdF9yZXN1bHRfYWZ0ZXIkc3RhdGlzdGljKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTaGFwaXJvLVdpbGsgVGVzdCBwLXZhbHVlOiIgPSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmUiLCBzaGFwaXJvX3Rlc3RfcmVzdWx0X2FmdGVyJHAudmFsdWUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNrZXduZXNzOiIgPSBzcHJpbnRmKCIlLjNmIixza2V3bmVzc192YWx1ZV9hZnRlciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VydG9zaXM6IiA9IHNwcmludGYoIiUuM2YiLGt1cnRvc2lzX3ZhbHVlX2FmdGVyKSkNCiAgKSwNCiAgY29sLm5hbWVzID0gYygiQmVmb3JlIHRyYW5zZm9ybWF0aW9uIChNb2RlbCAxKSIsICJBZnRlciB0cmFuc2Zvcm1hdGlvbiAoTW9kZWwgMikiKSwNCiAgZm9ybWF0ID0gIm1hcmtkb3duIg0KKQ0KYGBgDQoNCiMjIEFzc3VtcHRpb25zOiBIb21vc2tlZGFzaXR5DQpgYGB7cn0NCiMgTWFrZSBwcmVkaWN0aW9ucyBhbmQgY2FsY3VsYXRlIHJlc2lkdWFscw0KcHJlZGljdGVkIDwtIHByZWRpY3QoTTEsIG5ld2RhdGEgPSBib2x0cywgdHlwZSA9ICJyZXNwb25zZSIpDQpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKE0xKQ0KcHJlZGljdGVkX3RmIDwtIHByZWRpY3QoTTIsIG5ld2RhdGEgPSBib2x0cywgdHlwZSA9ICJyZXNwb25zZSIpDQpwcmVkaWN0ZWRfdGYxIDwtIHByZWRpY3QoTTIsIG5ld2RhdGEgPSBib2x0cykNCnJlc2lkdWFsc190ZiA8LSByZXNpZHVhbHMoTTIpDQoNCiMgUmVzaWR1YWxzIHZzIFByZWRpY3RvciAoUlZQKSBwbG90DQpydnBfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gTGVkZ2VXaWR0aCwgeSA9IHJlc2lkdWFscykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJyZWQiKSArDQogIGxhYnModGl0bGUgPSAiTW9kZWwgMSAoUlZQKSBQbG90IiwNCiAgICAgICB4ID0gIkxlZGdlIFdpZHRoIiwNCiAgICAgICB5ID0gIlJlc2lkdWFscyIpDQoNCiMgUmVzaWR1YWxzIHZzIEZpdHRlZCBWYWx1ZSAoUlZGKSBwbG90DQpydmZfcGxvdCA8LSBnZ3Bsb3QoYm9sdHMsIGFlcyh4ID0gcHJlZGljdGVkLCB5ID0gcmVzaWR1YWxzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJNb2RlbCAxIChSVkYpIFBsb3QiLA0KICAgICAgIHggPSAiRml0dGVkIChMaW5lYXIgcHJlZGljdGlvbikiLA0KICAgICAgIHkgPSAiUmVzaWR1YWxzIikNCg0KIyBSZXNpZHVhbHMgdnMgUHJlZGljdG9yIChSVlApIHBsb3QNCnJ2cF9wbG90X3RmIDwtIGdncGxvdChib2x0cywgYWVzKHggPSBMZWRnZVdpZHRoLCB5ID0gcmVzaWR1YWxzX3RmKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJNb2RlbCAyIChSVlApIFBsb3QiLA0KICAgICAgIHggPSAiTGVkZ2UgV2lkdGgiLA0KICAgICAgIHkgPSAiUmVzaWR1YWxzIikNCg0KIyBSZXNpZHVhbHMgdnMgRml0dGVkIFZhbHVlIChSVkYpIHBsb3QNCnJ2Zl9wbG90X3RmIDwtIGdncGxvdChib2x0cywgYWVzKHggPSBwcmVkaWN0ZWRfdGYsIHkgPSByZXNpZHVhbHNfdGYpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIk1vZGVsIDIgKFJWRikgUGxvdCIsDQogICAgICAgeCA9ICJGaXR0ZWQgKExpbmVhciBwcmVkaWN0aW9uKSIsDQogICAgICAgeSA9ICJSZXNpZHVhbHMiKQ0KDQpncmlkX2FycmFuZ2VtZW50IDwtIGdyaWQuYXJyYW5nZShydnBfcGxvdCwgcnZmX3Bsb3QsIHJ2cF9wbG90X3RmLCBydmZfcGxvdF90ZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgbnJvdyA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wID0gZ3JpZDo6dGV4dEdyb2INCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgiUmVzaWR1YWxzIHZzIFByZWRpY3RvciBhbmQgRml0dGVkIFZhbHVlIFBsb3RzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE0LCBmb250ZmFjZSA9ICJib2xkIikpKQ0KDQpgYGANCg0KIyMgRmluYWwgdmVyc2lvbiBvZiB0aGUgcmVncmVzc2lvbiBtb2RlbDogDQpgYGB7cn0NCmJvbHRzJExlZGdlV2lkdGgyIDwtIGJvbHRzJExlZGdlV2lkdGheMg0KTTIgPC0gZ2xtKFRpbWUgfiBSb3RhdGlvbiArIExlZGdlV2lkdGggKyBMZWRnZVdpZHRoMiArIFNlbnNpdGl2aXR5ICsgU3VjY2VzcywgDQogICAgICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sIGRhdGEgPSBib2x0cykNCnN1bW1hcnkoTTIpDQpgYGANCg0KIyMgQ29tcGFyZSBiZXR3ZWVuIG1vZGVsOiANCmBgYHtyfQ0KTTEgPC0gZ2xtKFRpbWUgfiBTcGVlZCArIFJvdGF0aW9uICsgTGVkZ2VXaWR0aCArIFNlbnNpdGl2aXR5ICsgU3VjY2VzcywgDQogICAgICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sIGRhdGEgPSBib2x0cykNCnN1bW1hcnkoTTEpDQojd2l0aChNMSwgY2JpbmQocmVzLmRldmlhbmNlID0gZGV2aWFuY2UsIGRmID0gZGYucmVzaWR1YWwsDQogICNwID0gcGNoaXNxKGRldmlhbmNlLCBkZi5yZXNpZHVhbCwgbG93ZXIudGFpbD1GQUxTRSkpKQ0KDQpyc3MgPC0gc3VtKHJlc2lkdWFscyhNMSleMikgIyBSZXNpZHVhbCBTdW0gb2YgU3F1YXJlcw0KdHNzIDwtIHN1bSgoYm9sdHMkVGltZSAtIG1lYW4oYm9sdHMkVGltZSkpXjIpICMgVG90YWwgU3VtIG9mIFNxdWFyZXMNCnJfc3F1YXJlZCA8LSAxIC0gKHJzcyAvIHRzcykNCmNhdCgiUi1zcXVhcmVkOiIsIHJfc3F1YXJlZCwgIlxuIikNCmNhdCgiQUlDIiwgTTEkYWljLCAiXG4iKQ0KDQpib2x0cyRMZWRnZVdpZHRoMiA8LSBib2x0cyRMZWRnZVdpZHRoXjINCk0yIDwtIGdsbShUaW1lIH4gUm90YXRpb24gKyBMZWRnZVdpZHRoICsgTGVkZ2VXaWR0aDIgKyBTZW5zaXRpdml0eSArIFN1Y2Nlc3MsIA0KICAgICAgICAgIGZhbWlseSA9IGdhdXNzaWFuLCBkYXRhID0gYm9sdHMpDQpzdW1tYXJ5KE0yKQ0KI3dpdGgoTTIsIGNiaW5kKHJlcy5kZXZpYW5jZSA9IGRldmlhbmNlLCBkZiA9IGRmLnJlc2lkdWFsLA0KICAjcCA9IHBjaGlzcShkZXZpYW5jZSwgZGYucmVzaWR1YWwsIGxvd2VyLnRhaWw9RkFMU0UpKSkNCnJzcyA8LSBzdW0ocmVzaWR1YWxzKE0yKV4yKSAjIFJlc2lkdWFsIFN1bSBvZiBTcXVhcmVzDQp0c3MgPC0gc3VtKChib2x0cyRUaW1lIC0gbWVhbihib2x0cyRUaW1lKSleMikgIyBUb3RhbCBTdW0gb2YgU3F1YXJlcw0Kcl9zcXVhcmVkIDwtIDEgLSAocnNzIC8gdHNzKQ0KY2F0KCJSLXNxdWFyZWQ6Iiwgcl9zcXVhcmVkLCAiXG4iKQ0KY2F0KCJBSUMiLCBNMiRhaWMsICJcbiIpDQoNCiNNXzIgPC0gZ2xtKFRpbWUgfiBSb3RhdGlvbiArIExlZGdlV2lkdGggKyBTZW5zaXRpdml0eSwgDQogICAgICAgICAgI2ZhbWlseSA9IGdhdXNzaWFuLCBkYXRhID0gYm9sdHMpDQojc3VtbWFyeShNXzIpDQojd2l0aChNXzIsIGNiaW5kKHJlcy5kZXZpYW5jZSA9IGRldmlhbmNlLCBkZiA9IGRmLnJlc2lkdWFsLA0KICAjcCA9IHBjaGlzcShkZXZpYW5jZSwgZGYucmVzaWR1YWwsIGxvd2VyLnRhaWw9RkFMU0UpKSkNCg0KIyBDYWxjdWxhdGUgUi1zcXVhcmVkDQojcnNzIDwtIHN1bShyZXNpZHVhbHMoTV8yKV4yKSAjIFJlc2lkdWFsIFN1bSBvZiBTcXVhcmVzDQojdHNzIDwtIHN1bSgoYm9sdHMkVGltZSAtIG1lYW4oYm9sdHMkVGltZSkpXjIpICMgVG90YWwgU3VtIG9mIFNxdWFyZXMNCiNyX3NxdWFyZWQgPC0gMSAtIChyc3MgLyB0c3MpDQojY2F0KCJSLXNxdWFyZWQ6Iiwgcl9zcXVhcmVkLCAiXG4iKQ0KDQojTjEgPC0gbG0oVGltZSB+IFNwZWVkICsgUm90YXRpb24gKyBMZWRnZVdpZHRoICsgU2Vuc2l0aXZpdHkgKyBTdWNjZXNzLCBkYXRhID0gYm9sdHMpDQojTjIgPC0gbG0oVGltZSB+IFJvdGF0aW9uICsgTGVkZ2VXaWR0aCArIFNlbnNpdGl2aXR5LCBkYXRhID0gYm9sdHMpDQoNCiMgRG8gRi10ZXN0IGZvciBuZXN0ZWQgbW9kZWxzIChBTk9WQSk6IA0KI2Fub3ZhKE1fMixNMSkNCmBgYA0KDQojIFF1ZXN0aW9uIDQ6IE1ha2UgcmVjb21tZW5kYXRpb25zIG9uIHRoZSBzZXR0aW5ncyB0aGF0IGNhbiBzaG9ydGVuIHRoZSB0aW1lIHRha2VuIHRvIGNvdW50IDIwIGJvbHRzLiAoMi41IG1hcmtzKQ0KDQpgYGB7cn0NCiMgRGVmaW5lIGEgc2VxdWVuY2Ugb2YgTGVkZ2VXaWR0aCB2YWx1ZXMgZm9yIHByZWRpY3Rpb24NCmxlZGdlX3dpZHRoX3ZhbHVlcyA8LSBzZXEobWluKGJvbHRzJExlZGdlV2lkdGgpLCBtYXgoYm9sdHMkTGVkZ2VXaWR0aCksIGxlbmd0aC5vdXQgPSAxMDApDQoNCiMgQ3JlYXRlIGEgbmV3IGRhdGEgZnJhbWUgd2l0aCB2YXJ5aW5nIExlZGdlV2lkdGggYW5kIGZpeGVkIHNldHRpbmdzIGZvciBvdGhlciB2YXJpYWJsZXMNCm5ld19kYXRhIDwtIGRhdGEuZnJhbWUoDQogIFJvdGF0aW9uID0gIkFsdGVybmF0aW5nIiwgICMgRml4ZWQgYXQgdGhlIG9wdGltYWwgbGV2ZWwNCiAgU2Vuc2l0aXZpdHkgPSAiTG93IiwgICAgICAgIyBGaXhlZCBhdCB0aGUgYmFzZWxpbmUgbGV2ZWwNCiAgTGVkZ2VXaWR0aCA9IGxlZGdlX3dpZHRoX3ZhbHVlcw0KKQ0KDQojIFByZWRpY3QgVGltZSB1c2luZyB0aGUgbW9kZWwNCm5ld19kYXRhJFByZWRpY3RlZFRpbWUgPC0gcHJlZGljdChNMiwgbmV3ZGF0YSA9IG5ld19kYXRhKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KG5ld19kYXRhLCBhZXMoeCA9IExlZGdlV2lkdGgsIHkgPSBQcmVkaWN0ZWRUaW1lKSkgKw0KICBnZW9tX2xpbmUoY29sb3IgPSAiYmx1ZSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlByZWRpY3RlZCBUaW1lIHZzLiBMZWRnZVdpZHRoIiwNCiAgICB4ID0gIkxlZGdlV2lkdGgiLA0KICAgIHkgPSAiUHJlZGljdGVkIFRpbWUiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCm9wdGltYWxfbGVkZ2Vfd2lkdGggPC0gbmV3X2RhdGEkTGVkZ2VXaWR0aFt3aGljaC5taW4obmV3X2RhdGEkUHJlZGljdGVkVGltZSldDQpjYXQoIlRoZSBvcHRpbWFsIExlZGdlV2lkdGggaXM6Iiwgb3B0aW1hbF9sZWRnZV93aWR0aCwgIlxuIikNCmBgYA0KDQojIFF1ZXN0aW9uIDU6IFN0YXRlIHlvdXIgaHlwb3RoZXNlcyBhbmQgY29uY2x1c2lvbnMgY2xlYXJseS4gKDIuIDUgbWFya3MpDQotIEFib3V0IHRoZSBtb2RlbCBidXQgbm90IGFib3V0IHRoZSB2YXJpYWJsZSANCg0KTW9kZWwgYXNzdW1wdGlvbiBmaXJzdCAoaHlwbz8pDQo=