title: “Multiple Linear Regression” author: “<136814, Jason Mwangi>” date: “2025-07-10” output: word_document: toc: true toc_depth: 4 number_sections: true fig_width: 5 keep_md: true html_notebook: toc: true toc_depth: 4 number_sections: true fig_width: 5 self_contained: false html_document: toc: true toc_depth: 4 number_sections: true fig_width: 5 fig_height: 5 self_contained: false keep_md: true pdf_document:
toc: true toc_depth: 4 number_sections: true fig_width: 5 fig_height: 5 fig_crop: false keep_tex: true latex_engine: xelatex —

1 Load Data set

if (!"pacman" %in% installed.packages()[, "Package"]) { 
install.packages("pacman", dependencies = TRUE) 
library("pacman", character.only = TRUE)} 

pacman::p_load("here") 
knitr::opts_knit$set(root.dir = here::here())
if (!"pacman" %in% installed.packages()[, "Package"]) { 
install.packages("pacman", dependencies = TRUE) 
library("pacman", character.only = TRUE)} 

pacman::p_load("here") 
knitr::opts_knit$set(root.dir = here::here())
pacman::p_load("readr") 
advertising_data <- read_csv("/advertising.csv") 
Rows: 10 Columns: 4── Column specification ───────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (4): YouTube, TikTok, Facebook, Sales
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(advertising_data)

2 Initial EDA

dim(advertising_data)
[1] 10  4
sapply(advertising_data, class)
  YouTube    TikTok  Facebook     Sales 
"numeric" "numeric" "numeric" "numeric" 
str(advertising_data)
spc_tbl_ [10 × 4] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ YouTube : num [1:10] 1200 1500 1300 1600 1100 1700 1400 1800 1250 1550
 $ TikTok  : num [1:10] 800 900 850 950 780 1000 880 1020 820 970
 $ Facebook: num [1:10] 1000 1100 1050 1150 980 1200 1080 1220 1010 1130
 $ Sales   : num [1:10] 95.3 101.2 99.5 106.8 93 ...
 - attr(*, "spec")=
  .. cols(
  ..   YouTube = col_double(),
  ..   TikTok = col_double(),
  ..   Facebook = col_double(),
  ..   Sales = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

2.0.0.1 Measures of frequency

2.0.0.1.1 Measure of central tendancy
summary(advertising_data)
    YouTube         TikTok          Facebook        Sales       
 Min.   :1100   Min.   : 780.0   Min.   : 980   Min.   : 93.02  
 1st Qu.:1262   1st Qu.: 827.5   1st Qu.:1020   1st Qu.: 97.27  
 Median :1450   Median : 890.0   Median :1090   Median :101.95  
 Mean   :1440   Mean   : 897.0   Mean   :1092   Mean   :101.93  
 3rd Qu.:1588   3rd Qu.: 965.0   3rd Qu.:1145   3rd Qu.:106.17  
 Max.   :1800   Max.   :1020.0   Max.   :1220   Max.   :111.82  

2.0.0.2 Measures of Distribution

2.0.0.2.1 Variance
sapply(advertising_data[,], var)
    YouTube      TikTok    Facebook       Sales 
52111.11111  7267.77778  6951.11111    36.13165 
2.0.0.2.2 Standard Deviation
sapply(advertising_data[,],sd)
  YouTube    TikTok  Facebook     Sales 
228.27858  85.25126  83.37332   6.01096 
2.0.0.2.3 Kurtosis
pacman::p_load("e1071")
sapply(advertising_data[,], kurtosis, type =2)
   YouTube     TikTok   Facebook      Sales 
-1.0800892 -1.4726766 -1.1989242 -0.8697324 
2.0.0.2.4 Skewness
sapply(advertising_data[,], skewness, type=2)
   YouTube     TikTok   Facebook      Sales 
0.08266188 0.09234643 0.19089944 0.10505432 
2.0.0.2.5 Covariance
cov(advertising_data, method = "spearman")
          YouTube   TikTok Facebook    Sales
YouTube  9.166667 9.055556 9.166667 9.055556
TikTok   9.055556 9.166667 9.055556 8.944444
Facebook 9.166667 9.055556 9.166667 9.055556
Sales    9.055556 8.944444 9.055556 9.166667
2.0.0.2.6 Correlation

cor.test(advertising_data$Sales, advertising_data$YouTube, method = "spearman")

    Spearman's rank correlation rho

data:  advertising_data$Sales and advertising_data$YouTube
S = 2, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9878788 
cor.test(advertising_data$Sales, advertising_data$TikTok, method = "spearman")

    Spearman's rank correlation rho

data:  advertising_data$Sales and advertising_data$TikTok
S = 4, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9757576 
cor.test(advertising_data$Sales, advertising_data$Facebook, method = "spearman")

    Spearman's rank correlation rho

data:  advertising_data$Sales and advertising_data$Facebook
S = 2, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9878788 
cor(advertising_data, method = "spearman")
           YouTube    TikTok  Facebook     Sales
YouTube  1.0000000 0.9878788 1.0000000 0.9878788
TikTok   0.9878788 1.0000000 0.9878788 0.9757576
Facebook 1.0000000 0.9878788 1.0000000 0.9878788
Sales    0.9878788 0.9757576 0.9878788 1.0000000

2.0.0.3 Basic Visualizations

2.0.0.3.1 Histogram
par(mfrow = c(1,2))
for (i in 1:4)
{if(is.numeric(advertising_data[[i]])){hist(advertising_data[[i]],main= names(advertising_data)[i],xlab=names(advertising_data)[i])}else{message(paste("column", names(advertising_data)[i],"is not numeric and will be skipped."))}}

NA

2.0.0.3.2 Boxplot
par(mfrow = c(1,2))
for( i in 1:4)
{ if(is.numeric(advertising_data[[i]])){boxplot(advertising_data[[i]], main=names(advertising_data)[i])}else{message(paste("column",names(advertising_data)[i],"is not numeric and will be skipped."))}}

NA

2.0.0.3.3 Missingness Map
pacman::p_load("Amelia")
missmap(advertising_data, col= c("red","grey"), legend= TRUE)

2.0.0.3.4 Correlation plot
pacman::p_load("ggcorrplot")
ggcorrplot(cor(advertising_data[,]))

2.0.0.3.5 Scatter plot
pacman::p_load("corrplot")
pairs(advertising_data$Sales~., data=advertising_data, col=advertising_data$Sales)

pacman::p_load("ggplot2")
ggplot(advertising_data, aes(x=YouTube, y=Sales)) + geom_point() + geom_smooth(method = lm) + labs(title="Relationship between Sales Revenue and\nExpenditure on YouTube Marketing", x= "Expenditure", y="Sales")

pacman::p_load("dplyr")
advertising_data_composite <- advertising_data %>%
  mutate(Total_Expenditure = YouTube + TikTok + Facebook)
ggplot(advertising_data_composite, aes(x=Total_Expenditure, y=Sales)) + geom_point() + geom_smooth(method = lm) + labs(title = "Relationship between Sales Revenue and \nTotal Marketing Expenditure", y="Sales" )

2.0.0.4 Application of statistical tests

mlr_test <- lm(Sales ~ YouTube + TikTok + Facebook, data = advertising_data)
summary(mlr_test)

Call:
lm(formula = Sales ~ YouTube + TikTok + Facebook, data = advertising_data)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.5436 -0.6159  0.1056  0.6598  1.5978 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept) 32.019096  24.432018   1.311    0.238
YouTube      0.006088   0.015876   0.384    0.715
TikTok      -0.007662   0.032263  -0.237    0.820
Facebook     0.062289   0.048787   1.277    0.249

Residual standard error: 1.2 on 6 degrees of freedom
Multiple R-squared:  0.9734,    Adjusted R-squared:  0.9602 
F-statistic: 73.32 on 3 and 6 DF,  p-value: 4.055e-05
confint(mlr_test, level = 0.95) 
                   2.5 %      97.5 %
(Intercept) -27.76389745 91.80208927
YouTube      -0.03275855  0.04493539
TikTok       -0.08660653  0.07128263
Facebook     -0.05708823  0.18166580

2.0.0.5 Diagnostic EDA

2.0.0.5.1 Test for linearity
plot(mlr_test, which = 1)

2.0.0.5.2 Test for independence of errors
pacman::p_load("lmtest")
dwtest(mlr_test)

    Durbin-Watson test

data:  mlr_test
DW = 2.1498, p-value = 0.5316
alternative hypothesis: true autocorrelation is greater than 0
2.0.0.5.3 Test of Normality
plot(mlr_test, which=2)

2.0.0.5.4 Test of Homoscedasticity
plot(mlr_test, which = 3)

2.0.0.6 Quantitative Validation of Assumptions

pacman::p_load("gvlma")
gvlma_results <- gvlma(mlr_test)
summary(gvlma_results)

Call:
lm(formula = Sales ~ YouTube + TikTok + Facebook, data = advertising_data)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.5436 -0.6159  0.1056  0.6598  1.5978 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept) 32.019096  24.432018   1.311    0.238
YouTube      0.006088   0.015876   0.384    0.715
TikTok      -0.007662   0.032263  -0.237    0.820
Facebook     0.062289   0.048787   1.277    0.249

Residual standard error: 1.2 on 6 degrees of freedom
Multiple R-squared:  0.9734,    Adjusted R-squared:  0.9602 
F-statistic: 73.32 on 3 and 6 DF,  p-value: 4.055e-05


ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
Level of Significance =  0.05 

Call:
 gvlma(x = mlr_test) 
2.0.0.6.1 Test for Multicolinearity
pacman::p_load("car")
vif(mlr_test)
  YouTube    TikTok  Facebook 
 82.13782  47.30912 103.46518 

2.0.0.7 Interpret the results

A simultaneous multiple linear regression analysis was conducted on data from 10 observations (N=10) to examine whether advertising expenditures on YouTube, TikTok, and Facebook collectively predict Sales. The results indicated that neither expenses on YouTube (β = 0.01, 95% CI [-.03, .04], SE = 0.02, t(6) = 0.38, p = .715), nor TikTok (β = -0.01, 95% CI [-.09, .07], SE = 0.03, t(6) = -0.24, p = .820) nor Facebook (β = 0.06, 95% CI [-.06, .18], SE = 0.05, t(6) = 1.28, p = .249) individually significantly predicted Sales (all p > 0.05). The model explained 97.34% of the variance in Sales (Multiple R2 = .97, Adjusted R2 = .96, F(3, 6) = 73.32, p < .001). The intercept was 32.02, 95% CI [-27.76, 91.80], SE = 24.43, t(6) = 1.31, p = .238. The residual standard error was 1.2, indicating a robust model. The full results are presented in the table below.

Table: Regression Coefficients Predicting Sales from Multiple Advertising Channels Predictor β 95% CI SE t(6) p (Intercept) 32.02 [-27.76, 91.80] 24.43 1.31 .238 YouTube 0.01 [-.03, .04] 0.02 0.38 .715 TikTok -0.01 [-.09, .07] 0.03 -0.24 .820 Facebook 0.06 [-.06, .18] 0.05 1.28 .249 Note. N = 10; SE = standard error; CI = confidence interval.

Even though the results indicated a robust model whereby advertisement expenditures collectively predict sales, individual parameter estimates did not reach statistical significance when controlling for the other parameters. This suggests that the advertising channels collectively explain variation in Sales but do not uniquely predict Sales in this small sample. This may reflect multicollinearity among Page 46 of 51

the different advertising platforms or limited statistical power due to the small sample size (N = 10). Future research should investigate these predictors with a larger sample and assess potential collinearity

Business Analysis

Although aggregate digital advertising spend across YouTube, TikTok, and Facebook is highly predictive of Sales (accounting for nearly all observed variation), the absence of statistically significant individual coefficients indicates that no single channel can be reliably credited with driving incremental Sales in this dataset.

This finding suggests that, within the current investment levels and the constraints of a small sample, the three platforms function as a cohesive portfolio rather than as independent drivers of sales revenue. Recommendation for management:

1. Continue to view YouTube, TikTok, and Facebook as complementary elements of a unified digital marketing strategy focusing on the total expenditure rather than favouring a single platform.

Limitations

1. Small Sample Size (N = 10): Using a limited number of observations restricts statistical power and inflates standard errors, raising the risk of a Type II error (failing to detect true channel effects).

2. Potential Multicollinearity: High intercorrelations among YouTube, TikTok, and Facebook expenditures may obscure unique contributions.

3. Restricted Expenditure Range: Limited range of advertisement expenditures impairs the ability to detect linear effects.

4. Methodology: Lack of experimental variation in advertisement expenditure limits causal attribution to any single platform.

LS0tDQp0aXRsZTogIk11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHRydWUNCiAgICBjc3M6IDJfTXVsdGlwbGVfbGluZWFyX3JlZ3Jlc3Npb24ubmIuaHRtbA0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIGtlZXBfbWQ6IHRydWUNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB0cnVlDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAga2VlcF90ZXg6IHRydWUNCi0tLQ0KDQp0aXRsZTogIk11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIiBhdXRob3I6ICJcPDEzNjgxNCwgSmFzb24gTXdhbmdpXD4iIGRhdGU6ICIyMDI1LTA3LTEwIiBvdXRwdXQ6IHdvcmRfZG9jdW1lbnQ6IHRvYzogdHJ1ZSB0b2NfZGVwdGg6IDQgbnVtYmVyX3NlY3Rpb25zOiB0cnVlIGZpZ193aWR0aDogNSBrZWVwX21kOiB0cnVlIGh0bWxfbm90ZWJvb2s6IHRvYzogdHJ1ZSB0b2NfZGVwdGg6IDQgbnVtYmVyX3NlY3Rpb25zOiB0cnVlIGZpZ193aWR0aDogNSBzZWxmX2NvbnRhaW5lZDogZmFsc2UgaHRtbF9kb2N1bWVudDogdG9jOiB0cnVlIHRvY19kZXB0aDogNCBudW1iZXJfc2VjdGlvbnM6IHRydWUgZmlnX3dpZHRoOiA1IGZpZ19oZWlnaHQ6IDUgc2VsZl9jb250YWluZWQ6IGZhbHNlIGtlZXBfbWQ6IHRydWUgcGRmX2RvY3VtZW50OlwNCnRvYzogdHJ1ZSB0b2NfZGVwdGg6IDQgbnVtYmVyX3NlY3Rpb25zOiB0cnVlIGZpZ193aWR0aDogNSBmaWdfaGVpZ2h0OiA1IGZpZ19jcm9wOiBmYWxzZSBrZWVwX3RleDogdHJ1ZSBsYXRleF9lbmdpbmU6IHhlbGF0ZXggLS0tDQoNCiMgTG9hZCBEYXRhIHNldA0KDQpgYGB7cn0NCmlmICghInBhY21hbiIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pIHsgDQppbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iLCBkZXBlbmRlbmNpZXMgPSBUUlVFKSANCmxpYnJhcnkoInBhY21hbiIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSl9IA0KDQpwYWNtYW46OnBfbG9hZCgiaGVyZSIpIA0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBoZXJlOjpoZXJlKCkpDQpgYGANCg0KYGBgIHINCmlmICghInBhY21hbiIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pIHsgDQppbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iLCBkZXBlbmRlbmNpZXMgPSBUUlVFKSANCmxpYnJhcnkoInBhY21hbiIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSl9IA0KDQpwYWNtYW46OnBfbG9hZCgiaGVyZSIpIA0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBoZXJlOjpoZXJlKCkpDQpgYGANCg0KYGBge3J9DQpwYWNtYW46OnBfbG9hZCgicmVhZHIiKSANCmFkdmVydGlzaW5nX2RhdGEgPC0gcmVhZF9jc3YoIi9hZHZlcnRpc2luZy5jc3YiKSANCmhlYWQoYWR2ZXJ0aXNpbmdfZGF0YSkNCmBgYA0KDQojIEluaXRpYWwgRURBDQoNCmBgYHtyfQ0KZGltKGFkdmVydGlzaW5nX2RhdGEpDQpgYGANCg0KYGBge3Igc2hvd19kYXRhX3R5cGVzLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzYXBwbHkoYWR2ZXJ0aXNpbmdfZGF0YSwgY2xhc3MpDQoNCmBgYA0KDQpgYGB7ciBzaG93X2RhdGFfdHlwZXNfMiwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3RyKGFkdmVydGlzaW5nX2RhdGEpDQoNCmBgYA0KDQojIyMjIE1lYXN1cmVzIG9mIGZyZXF1ZW5jeQ0KDQojIyMjIyBNZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGFuY3kNCg0KYGBge3IgY2VudHJhbF90ZW5kYW5jeSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShhZHZlcnRpc2luZ19kYXRhKQ0KDQpgYGANCg0KIyMjIyBNZWFzdXJlcyBvZiBEaXN0cmlidXRpb24NCg0KIyMjIyMgVmFyaWFuY2UNCg0KYGBge3IgZGlzdHJpYnV0aW9uX3ZhcmlhbmNlLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzYXBwbHkoYWR2ZXJ0aXNpbmdfZGF0YVssXSwgdmFyKQ0KDQpgYGANCg0KIyMjIyMgU3RhbmRhcmQgRGV2aWF0aW9uDQoNCmBgYHtyIGRpc3RyaWJ1dGlvbl9zdGFuZGFyZF9kZXZpYXRpb24sIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnNhcHBseShhZHZlcnRpc2luZ19kYXRhWyxdLHNkKQ0KDQpgYGANCg0KIyMjIyMgS3VydG9zaXMNCg0KYGBge3IgZGlzdHJpYnV0aW9uX0t1dXJ0b3NpcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFjbWFuOjpwX2xvYWQoImUxMDcxIikNCnNhcHBseShhZHZlcnRpc2luZ19kYXRhWyxdLCBrdXJ0b3NpcywgdHlwZSA9MikNCg0KYGBgDQoNCiMjIyMjIFNrZXduZXNzDQoNCmBgYHtyIGRpc3RyaWJ1dGlvbl9za2V3bmVzcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc2FwcGx5KGFkdmVydGlzaW5nX2RhdGFbLF0sIHNrZXduZXNzLCB0eXBlPTIpDQoNCmBgYA0KDQojIyMjIyBDb3ZhcmlhbmNlDQoNCmBgYHtyIGRpc3RyaWJ1dGlvbl9jb3ZhcmlhbmNlLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjb3YoYWR2ZXJ0aXNpbmdfZGF0YSwgbWV0aG9kID0gInNwZWFybWFuIikNCg0KYGBgDQoNCiMjIyMjIENvcnJlbGF0aW9uDQoNCmBgYHtyIGRpc3RyaWJ1dGlvbl9jb3JyZWxhdGlvaW9uXzEsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KY29yLnRlc3QoYWR2ZXJ0aXNpbmdfZGF0YSRTYWxlcywgYWR2ZXJ0aXNpbmdfZGF0YSRZb3VUdWJlLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KY29yLnRlc3QoYWR2ZXJ0aXNpbmdfZGF0YSRTYWxlcywgYWR2ZXJ0aXNpbmdfZGF0YSRUaWtUb2ssIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQpjb3IudGVzdChhZHZlcnRpc2luZ19kYXRhJFNhbGVzLCBhZHZlcnRpc2luZ19kYXRhJEZhY2Vib29rLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KDQpgYGANCg0KYGBge3IgZGlzdHJpYnV0aW9uX2NvcnJlbGF0aW9pb25fMiwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KY29yKGFkdmVydGlzaW5nX2RhdGEsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQpgYGANCg0KIyMjIyBCYXNpYyBWaXN1YWxpemF0aW9ucw0KDQojIyMjIyBIaXN0b2dyYW0NCg0KYGBge3IgdmlzdWFsaXphdGlvbl9oc2l0b2dyYW0sIGVjaG89VFJVRSwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYXIobWZyb3cgPSBjKDEsMikpDQpmb3IgKGkgaW4gMTo0KQ0Ke2lmKGlzLm51bWVyaWMoYWR2ZXJ0aXNpbmdfZGF0YVtbaV1dKSl7aGlzdChhZHZlcnRpc2luZ19kYXRhW1tpXV0sbWFpbj0gbmFtZXMoYWR2ZXJ0aXNpbmdfZGF0YSlbaV0seGxhYj1uYW1lcyhhZHZlcnRpc2luZ19kYXRhKVtpXSl9ZWxzZXttZXNzYWdlKHBhc3RlKCJjb2x1bW4iLCBuYW1lcyhhZHZlcnRpc2luZ19kYXRhKVtpXSwiaXMgbm90IG51bWVyaWMgYW5kIHdpbGwgYmUgc2tpcHBlZC4iKSl9fQ0KDQpgYGANCg0KIyMjIyMgQm94cGxvdA0KDQpgYGB7ciB2aXNhdWxpemF0aW9uX2JveGxwb3QsIGVjaG89VFJVRSwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYXIobWZyb3cgPSBjKDEsMikpDQpmb3IoIGkgaW4gMTo0KQ0KeyBpZihpcy5udW1lcmljKGFkdmVydGlzaW5nX2RhdGFbW2ldXSkpe2JveHBsb3QoYWR2ZXJ0aXNpbmdfZGF0YVtbaV1dLCBtYWluPW5hbWVzKGFkdmVydGlzaW5nX2RhdGEpW2ldKX1lbHNle21lc3NhZ2UocGFzdGUoImNvbHVtbiIsbmFtZXMoYWR2ZXJ0aXNpbmdfZGF0YSlbaV0sImlzIG5vdCBudW1lcmljIGFuZCB3aWxsIGJlIHNraXBwZWQuIikpfX0NCg0KYGBgDQoNCiMjIyMjIE1pc3NpbmduZXNzIE1hcA0KDQpgYGB7ciB2aXN1YWxpemF0aW9uX21pc3NpbmdfZGF0YV9wbG90LCBlY2hvPVRSVUUsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFjbWFuOjpwX2xvYWQoIkFtZWxpYSIpDQptaXNzbWFwKGFkdmVydGlzaW5nX2RhdGEsIGNvbD0gYygicmVkIiwiZ3JleSIpLCBsZWdlbmQ9IFRSVUUpDQoNCmBgYA0KDQojIyMjIyBDb3JyZWxhdGlvbiBwbG90DQoNCmBgYHtyIHZpc3VhbGl6YXRpb25fY29ycmVsYXRpb25fcGxvdCwgZWNobz1UUlVFLGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFjbWFuOjpwX2xvYWQoImdnY29ycnBsb3QiKQ0KZ2djb3JycGxvdChjb3IoYWR2ZXJ0aXNpbmdfZGF0YVssXSkpDQoNCmBgYA0KDQojIyMjIyBTY2F0dGVyIHBsb3QNCg0KYGBge3Igc2NhdHRlcl9wbG90XzEsIGVjaG89VFJVRSwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYWNtYW46OnBfbG9hZCgiY29ycnBsb3QiKQ0KcGFpcnMoYWR2ZXJ0aXNpbmdfZGF0YSRTYWxlc34uLCBkYXRhPWFkdmVydGlzaW5nX2RhdGEsIGNvbD1hZHZlcnRpc2luZ19kYXRhJFNhbGVzKQ0KDQpgYGANCg0KYGBge3Igc2NhdHRlcl9wbG90XzIsIGVjaG89VFJVRSwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYWNtYW46OnBfbG9hZCgiZ2dwbG90MiIpDQpnZ3Bsb3QoYWR2ZXJ0aXNpbmdfZGF0YSwgYWVzKHg9WW91VHViZSwgeT1TYWxlcykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsgbGFicyh0aXRsZT0iUmVsYXRpb25zaGlwIGJldHdlZW4gU2FsZXMgUmV2ZW51ZSBhbmRcbkV4cGVuZGl0dXJlIG9uIFlvdVR1YmUgTWFya2V0aW5nIiwgeD0gIkV4cGVuZGl0dXJlIiwgeT0iU2FsZXMiKQ0KDQpgYGANCg0KYGBge3Igc2NhdHRlcl9wbG90XzMsIGVjaG89VFJVRSwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYWNtYW46OnBfbG9hZCgiZHBseXIiKQ0KYWR2ZXJ0aXNpbmdfZGF0YV9jb21wb3NpdGUgPC0gYWR2ZXJ0aXNpbmdfZGF0YSAlPiUNCiAgbXV0YXRlKFRvdGFsX0V4cGVuZGl0dXJlID0gWW91VHViZSArIFRpa1RvayArIEZhY2Vib29rKQ0KZ2dwbG90KGFkdmVydGlzaW5nX2RhdGFfY29tcG9zaXRlLCBhZXMoeD1Ub3RhbF9FeHBlbmRpdHVyZSwgeT1TYWxlcykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBTYWxlcyBSZXZlbnVlIGFuZCBcblRvdGFsIE1hcmtldGluZyBFeHBlbmRpdHVyZSIsIHk9IlNhbGVzIiApDQoNCmBgYA0KDQojIyMjIEFwcGxpY2F0aW9uIG9mIHN0YXRpc3RpY2FsIHRlc3RzDQoNCmBgYHtyfQ0KbWxyX3Rlc3QgPC0gbG0oU2FsZXMgfiBZb3VUdWJlICsgVGlrVG9rICsgRmFjZWJvb2ssIGRhdGEgPSBhZHZlcnRpc2luZ19kYXRhKQ0Kc3VtbWFyeShtbHJfdGVzdCkNCmBgYA0KDQpgYGB7cn0NCmNvbmZpbnQobWxyX3Rlc3QsIGxldmVsID0gMC45NSkgDQpgYGANCg0KIyMjIyBEaWFnbm9zdGljIEVEQQ0KDQojIyMjIyBUZXN0IGZvciBsaW5lYXJpdHkNCg0KYGBge3J9DQpwbG90KG1scl90ZXN0LCB3aGljaCA9IDEpDQpgYGANCg0KIyMjIyMgVGVzdCBmb3IgaW5kZXBlbmRlbmNlIG9mIGVycm9ycw0KDQpgYGB7cn0NCnBhY21hbjo6cF9sb2FkKCJsbXRlc3QiKQ0KZHd0ZXN0KG1scl90ZXN0KQ0KYGBgDQoNCiMjIyMjIFRlc3Qgb2YgTm9ybWFsaXR5DQoNCmBgYHtyfQ0KcGxvdChtbHJfdGVzdCwgd2hpY2g9MikNCmBgYA0KDQojIyMjIyBUZXN0IG9mIEhvbW9zY2VkYXN0aWNpdHkNCg0KYGBge3J9DQpwbG90KG1scl90ZXN0LCB3aGljaCA9IDMpDQpgYGANCg0KIyMjIyBRdWFudGl0YXRpdmUgVmFsaWRhdGlvbiBvZiBBc3N1bXB0aW9ucw0KDQpgYGB7cn0NCnBhY21hbjo6cF9sb2FkKCJndmxtYSIpDQpndmxtYV9yZXN1bHRzIDwtIGd2bG1hKG1scl90ZXN0KQ0Kc3VtbWFyeShndmxtYV9yZXN1bHRzKQ0KYGBgDQoNCiMjIyMjIFRlc3QgZm9yIE11bHRpY29saW5lYXJpdHkNCg0KYGBge3J9DQpwYWNtYW46OnBfbG9hZCgiY2FyIikNCnZpZihtbHJfdGVzdCkNCmBgYA0KDQojIyMjIEludGVycHJldCB0aGUgcmVzdWx0cw0KDQpBIHNpbXVsdGFuZW91cyBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyB3YXMgY29uZHVjdGVkIG9uIGRhdGEgZnJvbSAxMCBvYnNlcnZhdGlvbnMgKE49MTApIHRvIGV4YW1pbmUgd2hldGhlciBhZHZlcnRpc2luZyBleHBlbmRpdHVyZXMgb24gWW91VHViZSwgVGlrVG9rLCBhbmQgRmFjZWJvb2sgY29sbGVjdGl2ZWx5IHByZWRpY3QgU2FsZXMuIFRoZSByZXN1bHRzIGluZGljYXRlZCB0aGF0IG5laXRoZXIgZXhwZW5zZXMgb24gWW91VHViZSAozrIgPSAwLjAxLCA5NSUgQ0kgWy0uMDMsIC4wNF0sIFNFID0gMC4wMiwgdCg2KSA9IDAuMzgsIHAgPSAuNzE1KSwgbm9yIFRpa1RvayAozrIgPSAtMC4wMSwgOTUlIENJIFstLjA5LCAuMDddLCBTRSA9IDAuMDMsIHQoNikgPSAtMC4yNCwgcCA9IC44MjApIG5vciBGYWNlYm9vayAozrIgPSAwLjA2LCA5NSUgQ0kgWy0uMDYsIC4xOF0sIFNFID0gMC4wNSwgdCg2KSA9IDEuMjgsIHAgPSAuMjQ5KSBpbmRpdmlkdWFsbHkgc2lnbmlmaWNhbnRseSBwcmVkaWN0ZWQgU2FsZXMgKGFsbCBwIFw+IDAuMDUpLiBUaGUgbW9kZWwgZXhwbGFpbmVkIDk3LjM0JSBvZiB0aGUgdmFyaWFuY2UgaW4gU2FsZXMgKE11bHRpcGxlIFIyID0gLjk3LCBBZGp1c3RlZCBSMiA9IC45NiwgRigzLCA2KSA9IDczLjMyLCBwIFw8IC4wMDEpLiBUaGUgaW50ZXJjZXB0IHdhcyAzMi4wMiwgOTUlIENJIFstMjcuNzYsIDkxLjgwXSwgU0UgPSAyNC40MywgdCg2KSA9IDEuMzEsIHAgPSAuMjM4LiBUaGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3Igd2FzIDEuMiwgaW5kaWNhdGluZyBhIHJvYnVzdCBtb2RlbC4gVGhlIGZ1bGwgcmVzdWx0cyBhcmUgcHJlc2VudGVkIGluIHRoZSB0YWJsZSBiZWxvdy4NCg0KKipUYWJsZTogUmVncmVzc2lvbiBDb2VmZmljaWVudHMgUHJlZGljdGluZyBTYWxlcyBmcm9tIE11bHRpcGxlIEFkdmVydGlzaW5nIENoYW5uZWxzKiogUHJlZGljdG9yIM6yIDk1JSBDSSBTRSB0KDYpIHAgKEludGVyY2VwdCkgMzIuMDIgWy0yNy43NiwgOTEuODBdIDI0LjQzIDEuMzEgLjIzOCBZb3VUdWJlIDAuMDEgWy0uMDMsIC4wNF0gMC4wMiAwLjM4IC43MTUgVGlrVG9rIC0wLjAxIFstLjA5LCAuMDddIDAuMDMgLTAuMjQgLjgyMCBGYWNlYm9vayAwLjA2IFstLjA2LCAuMThdIDAuMDUgMS4yOCAuMjQ5IE5vdGUuIE7igK894oCvMTA7IFNF4oCvPeKAr3N0YW5kYXJkIGVycm9yOyBDSeKArz3igK9jb25maWRlbmNlIGludGVydmFsLg0KDQpFdmVuIHRob3VnaCB0aGUgcmVzdWx0cyBpbmRpY2F0ZWQgYSByb2J1c3QgbW9kZWwgd2hlcmVieSBhZHZlcnRpc2VtZW50IGV4cGVuZGl0dXJlcyBjb2xsZWN0aXZlbHkgcHJlZGljdCBzYWxlcywgaW5kaXZpZHVhbCBwYXJhbWV0ZXIgZXN0aW1hdGVzIGRpZCBub3QgcmVhY2ggc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIHdoZW4gY29udHJvbGxpbmcgZm9yIHRoZSBvdGhlciBwYXJhbWV0ZXJzLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGFkdmVydGlzaW5nIGNoYW5uZWxzIGNvbGxlY3RpdmVseSBleHBsYWluIHZhcmlhdGlvbiBpbiBTYWxlcyBidXQgZG8gbm90IHVuaXF1ZWx5IHByZWRpY3QgU2FsZXMgaW4gdGhpcyBzbWFsbCBzYW1wbGUuIFRoaXMgbWF5IHJlZmxlY3QgbXVsdGljb2xsaW5lYXJpdHkgYW1vbmcgUGFnZSA0NiBvZiA1MQ0KDQp0aGUgZGlmZmVyZW50IGFkdmVydGlzaW5nIHBsYXRmb3JtcyBvciBsaW1pdGVkIHN0YXRpc3RpY2FsIHBvd2VyIGR1ZSB0byB0aGUgc21hbGwgc2FtcGxlIHNpemUgKE4gPSAxMCkuIEZ1dHVyZSByZXNlYXJjaCBzaG91bGQgaW52ZXN0aWdhdGUgdGhlc2UgcHJlZGljdG9ycyB3aXRoIGEgbGFyZ2VyIHNhbXBsZSBhbmQgYXNzZXNzIHBvdGVudGlhbCBjb2xsaW5lYXJpdHkNCg0KKipCdXNpbmVzcyBBbmFseXNpcyoqDQoNCkFsdGhvdWdoIGFnZ3JlZ2F0ZSBkaWdpdGFsIGFkdmVydGlzaW5nIHNwZW5kIGFjcm9zcyBZb3VUdWJlLCBUaWtUb2ssIGFuZCBGYWNlYm9vayBpcyBoaWdobHkgcHJlZGljdGl2ZSBvZiBTYWxlcyAoYWNjb3VudGluZyBmb3IgbmVhcmx5IGFsbCBvYnNlcnZlZCB2YXJpYXRpb24pLCB0aGUgYWJzZW5jZSBvZiBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGluZGl2aWR1YWwgY29lZmZpY2llbnRzIGluZGljYXRlcyB0aGF0IG5vIHNpbmdsZSBjaGFubmVsIGNhbiBiZSByZWxpYWJseSBjcmVkaXRlZCB3aXRoIGRyaXZpbmcgaW5jcmVtZW50YWwgU2FsZXMgaW4gdGhpcyBkYXRhc2V0Lg0KDQpUaGlzIGZpbmRpbmcgc3VnZ2VzdHMgdGhhdCwgd2l0aGluIHRoZSBjdXJyZW50IGludmVzdG1lbnQgbGV2ZWxzIGFuZCB0aGUgY29uc3RyYWludHMgb2YgYSBzbWFsbCBzYW1wbGUsIHRoZSB0aHJlZSBwbGF0Zm9ybXMgZnVuY3Rpb24gYXMgYSBjb2hlc2l2ZSBwb3J0Zm9saW8gcmF0aGVyIHRoYW4gYXMgaW5kZXBlbmRlbnQgZHJpdmVycyBvZiBzYWxlcyByZXZlbnVlLiBSZWNvbW1lbmRhdGlvbiBmb3IgbWFuYWdlbWVudDoNCg0KMVwuIENvbnRpbnVlIHRvIHZpZXcgWW91VHViZSwgVGlrVG9rLCBhbmQgRmFjZWJvb2sgYXMgY29tcGxlbWVudGFyeSBlbGVtZW50cyBvZiBhIHVuaWZpZWQgZGlnaXRhbCBtYXJrZXRpbmcgc3RyYXRlZ3kgZm9jdXNpbmcgb24gdGhlIHRvdGFsIGV4cGVuZGl0dXJlIHJhdGhlciB0aGFuIGZhdm91cmluZyBhIHNpbmdsZSBwbGF0Zm9ybS4NCg0KKipMaW1pdGF0aW9ucyoqDQoNCjFcLiBTbWFsbCBTYW1wbGUgU2l6ZSAoTuKArz3igK8xMCk6IFVzaW5nIGEgbGltaXRlZCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHJlc3RyaWN0cyBzdGF0aXN0aWNhbCBwb3dlciBhbmQgaW5mbGF0ZXMgc3RhbmRhcmQgZXJyb3JzLCByYWlzaW5nIHRoZSByaXNrIG9mIGEgVHlwZSBJSSBlcnJvciAoZmFpbGluZyB0byBkZXRlY3QgdHJ1ZSBjaGFubmVsIGVmZmVjdHMpLg0KDQoyXC4gUG90ZW50aWFsIE11bHRpY29sbGluZWFyaXR5OiBIaWdoIGludGVyY29ycmVsYXRpb25zIGFtb25nIFlvdVR1YmUsIFRpa1RvaywgYW5kIEZhY2Vib29rIGV4cGVuZGl0dXJlcyBtYXkgb2JzY3VyZSB1bmlxdWUgY29udHJpYnV0aW9ucy4NCg0KM1wuIFJlc3RyaWN0ZWQgRXhwZW5kaXR1cmUgUmFuZ2U6IExpbWl0ZWQgcmFuZ2Ugb2YgYWR2ZXJ0aXNlbWVudCBleHBlbmRpdHVyZXMgaW1wYWlycyB0aGUgYWJpbGl0eSB0byBkZXRlY3QgbGluZWFyIGVmZmVjdHMuDQoNCjRcLiBNZXRob2RvbG9neTogTGFjayBvZiBleHBlcmltZW50YWwgdmFyaWF0aW9uIGluIGFkdmVydGlzZW1lbnQgZXhwZW5kaXR1cmUgbGltaXRzIGNhdXNhbCBhdHRyaWJ1dGlvbiB0byBhbnkgc2luZ2xlIHBsYXRmb3JtLg0K