1 Project Goal and Data Overview

1.1 Goal

This project aims to understand and predict daily bank customer visits (CUST) using:

  • A time trend (TimeIndex)
  • Weekday effects (DAYCAT)
  • Special events (Payday, holidays, before/after holidays, etc.)
  • Extra events (e.g., Christmas, New Year, Black Friday) and interactions

1.2 Load the dataset (Excel)

# # Load packages
library(tidyverse)   # # data wrangling + ggplot2
library(readxl)      # # read Excel
library(lubridate)   # # date functions (month(), wday(), etc.)
library(janitor)     # # clean_names()
library(broom)       # # tidy model outputs
library(knitr)       # # kable tables
library(kableExtra)  # # nicer tables
library(see)
# =========================

# # 1A) LOAD DATA

# =========================

# # Read Excel file (make sure it's in the same folder as this .Rmd)

raw <- read_excel("MiM811Quiz4MiniProj1Data.xlsx")

# # Clean column names (removes weird spaces like "  CUST")

data <- raw %>%
janitor::clean_names()

# # Quick look

glimpse(data)
## Rows: 254
## Columns: 13
## $ cust     <dbl> 1825, 1257, 969, 1672, 1098, 691, 672, 754, 972, 816, 717, 72…
## $ daycat   <chr> "Tuesday", "Wednesday", "Thursday", "Friday", "Monday", "Tues…
## $ date     <dttm> 2007-01-02, 2007-01-03, 2007-01-04, 2007-01-05, 2007-01-08, …
## $ month    <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ daymon   <dbl> 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24,…
## $ dayweek  <dbl> 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2…
## $ special  <chr> "SP,FAC,AH", "0", "0", "SP", "0", "0", "0", "0", "0", "0", "0…
## $ payday   <dbl> 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0…
## $ sp       <dbl> 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0…
## $ fac      <dbl> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ holidays <dbl> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ bh       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ ah       <dbl> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…

1.3 Quick interactive view

DT::datatable(
head(data, 20),
options = list(pageLength = 10, scrollX = TRUE),
caption = "First 20 rows of the dataset (interactive table)"
)

2 Part 1 — Clean and Prepare Data

2.1 Convert DATE + create TimeIndex

# =========================

# # 1B) FIX TYPES + CREATE TIME INDEX

# =========================

data <- data %>%
mutate(
# # Convert date to Date class (even if it already looks like a date)
date = as.Date(date),

# # Time trend index: 1, 2, 3, ..., n
time_index = row_number(),

# # DAYCAT as ordered factor (important for weekday comparisons)
daycat = factor(
  daycat,
  levels = c("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"),
  ordered = TRUE
),

# # Month as a factor (optional but useful)
month_f = factor(month, levels = 1:12, labels = month.name)
)

# # Review structure + summary (required “review structure” idea)

str(data)
## tibble [254 × 15] (S3: tbl_df/tbl/data.frame)
##  $ cust      : num [1:254] 1825 1257 969 1672 1098 ...
##  $ daycat    : Ord.factor w/ 7 levels "Monday"<"Tuesday"<..: 2 3 4 5 1 2 3 4 5 1 ...
##  $ date      : Date[1:254], format: "2007-01-02" "2007-01-03" ...
##  $ month     : num [1:254] 1 1 1 1 1 1 1 1 1 1 ...
##  $ daymon    : num [1:254] 2 3 4 5 8 9 10 11 12 15 ...
##  $ dayweek   : num [1:254] 2 3 4 5 1 2 3 4 5 1 ...
##  $ special   : chr [1:254] "SP,FAC,AH" "0" "0" "SP" ...
##  $ payday    : num [1:254] 1 0 0 1 0 0 0 0 0 0 ...
##  $ sp        : num [1:254] 1 0 0 1 0 0 0 0 0 0 ...
##  $ fac       : num [1:254] 1 0 0 0 0 0 0 0 0 0 ...
##  $ holidays  : num [1:254] 1 0 0 0 0 0 0 0 0 0 ...
##  $ bh        : num [1:254] 0 0 0 0 0 0 0 0 0 0 ...
##  $ ah        : num [1:254] 1 0 0 0 0 0 0 0 0 0 ...
##  $ time_index: int [1:254] 1 2 3 4 5 6 7 8 9 10 ...
##  $ month_f   : Factor w/ 12 levels "January","February",..: 1 1 1 1 1 1 1 1 1 1 ...
summary(data)
##       cust              daycat        date                month       
##  Min.   : 404.0   Monday   :50   Min.   :2007-01-02   Min.   : 1.000  
##  1st Qu.: 785.8   Tuesday  :51   1st Qu.:2007-03-30   1st Qu.: 3.250  
##  Median : 930.5   Wednesday:50   Median :2007-06-30   Median : 6.500  
##  Mean   :1037.5   Thursday :51   Mean   :2007-06-30   Mean   : 6.476  
##  3rd Qu.:1183.5   Friday   :52   3rd Qu.:2007-09-30   3rd Qu.: 9.750  
##  Max.   :2068.0   Saturday : 0   Max.   :2007-12-31   Max.   :12.000  
##                   Sunday   : 0                                        
##      daymon         dayweek        special              payday     
##  Min.   : 1.00   Min.   :1.000   Length:254         Min.   :0.000  
##  1st Qu.: 8.00   1st Qu.:2.000   Class :character   1st Qu.:0.000  
##  Median :16.00   Median :3.000   Mode  :character   Median :0.000  
##  Mean   :15.83   Mean   :3.016                      Mean   :0.122  
##  3rd Qu.:23.00   3rd Qu.:4.000                      3rd Qu.:0.000  
##  Max.   :31.00   Max.   :5.000                      Max.   :1.000  
##                                                                    
##        sp               fac             holidays             bh         
##  Min.   :0.00000   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
##  1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000  
##  Median :0.00000   Median :0.00000   Median :0.00000   Median :0.00000  
##  Mean   :0.09843   Mean   :0.03937   Mean   :0.04724   Mean   :0.01969  
##  3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000  
##  Max.   :1.00000   Max.   :1.00000   Max.   :1.00000   Max.   :1.00000  
##                                                                         
##        ah            time_index        month_f   
##  Min.   :0.00000   Min.   :  1.00   August : 23  
##  1st Qu.:0.00000   1st Qu.: 64.25   October: 23  
##  Median :0.00000   Median :127.50   January: 22  
##  Mean   :0.02756   Mean   :127.50   March  : 22  
##  3rd Qu.:0.00000   3rd Qu.:190.75   May    : 22  
##  Max.   :1.00000   Max.   :254.00   April  : 21  
##                                     (Other):121
# =========================

2.2 Understand the event flags (sanity checks)

# # 1C) UNDERSTAND EVENT FLAGS

# =========================

# # These event columns are your “special events” predictors.

# # Based on names, they typically mean:

# # payday   = payday indicator (1/0)

# # sp       = staff payday (1/0)  (guess from abbreviation)

# # fac      = faculty payday (1/0)

# # holidays = holiday day (1/0)

# # bh       = before-holiday (1/0)

# # ah       = after-holiday (1/0)

# # If your class notes define them differently, use the official meaning.

# # Count how many days are flagged as 1 (quick sanity check)

data %>%
summarise(across(c(payday, sp, fac, holidays, bh, ah), ~sum(.x, na.rm = TRUE))) %>%
kable(caption = "How many days are flagged for each event?") %>%
kableExtra::kable_styling(full_width = FALSE)
How many days are flagged for each event?
payday sp fac holidays bh ah
31 25 10 12 5 7
# =========================

2.3 Create extra event flags (New Year, Christmas, Black Friday)

# =========================================

# # 2.3) OPTIONAL EXTRA EVENTS

# =========================================

data <- data %>%
mutate(
year = year(date),

# # New Year (Jan 1)
is_new_year = if_else(month(date) == 1 & day(date) == 1, 1, 0),

# # Christmas (Dec 25)
is_christmas = if_else(month(date) == 12 & day(date) == 25, 1, 0)


)

# # Black Friday approximation:

# # US definition: 4th Friday of November.

black_fridays <- data %>%
filter(month(date) == 11, wday(date, label = TRUE) == "Fri") %>%
group_by(year) %>%
arrange(date) %>%
mutate(friday_number = row_number()) %>%
filter(friday_number == 4) %>%
pull(date)

data <- data %>%
mutate(is_black_friday = if_else(date %in% black_fridays, 1, 0))

data %>%
filter(is_new_year == 1 | is_christmas == 1 | is_black_friday == 1) %>%
select(date, is_new_year, is_christmas, is_black_friday) %>%
arrange(date) %>%
  kable(caption = "Detected dates for optional extra events")
Detected dates for optional extra events
date is_new_year is_christmas is_black_friday
2007-11-23 0 0 1

3 Part 2 — Visualize Customer Behavior

3.1 Daily visits over time (time series)

ggplot(data, aes(x = date, y = cust)) +
geom_line() +
labs(
title = "Daily Customer Visits Over Time",
x = "Date",
y = "CUST (Visits)"
)

3.2 Visits by weekday (DAYCAT)

ggplot(data, aes(x = daycat, y = cust)) +
geom_boxplot() +
labs(
title = "Customer Visits by Day of Week (DAYCAT)",
x = "Day of Week",
y = "CUST (Visits)"
)

3.3 Color by payday and facet by holidays

plot_data <- data %>%
mutate(
payday_label = factor(payday, levels = c(0,1), labels = c("Not Payday","Payday")),
holiday_label = factor(holidays, levels = c(0,1), labels = c("Not Holiday","Holiday"))
)

ggplot(plot_data, aes(x = date, y = cust, color = payday_label)) +
geom_line() +
facet_wrap(~ holiday_label, ncol = 1) +
labs(
title = "Daily Visits — Colored by Payday, Faceted by Holiday",
x = "Date",
y = "CUST (Visits)",
color = "Payday?"
)

3.4 Mark special dates with vertical lines

event_dates <- data %>%
filter(is_new_year == 1 | is_christmas == 1 | is_black_friday == 1) %>%
select(date) %>%
distinct()

ggplot(data, aes(x = date, y = cust)) +
geom_line() +
geom_vline(
data = event_dates,
aes(xintercept = as.numeric(date)),
linetype = "dashed"
) +
labs(
title = "Daily Visits with Special Event Markers (dashed lines)",
x = "Date",
y = "CUST (Visits)"
)

4 Part 3 — Regression Models

4.1 Model 1: baseline (trend + weekday)

m1 <- lm(cust ~ time_index + daycat, data = data)
summary(m1)
## 
## Call:
## lm(formula = cust ~ time_index + daycat, data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -572.91 -144.51  -35.06   92.18  962.35 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1.024e+03  2.924e+01  35.008  < 2e-16 ***
## time_index  8.908e-02  1.988e-01   0.448 0.654551    
## daycat.L    2.605e+02  3.253e+01   8.009 4.51e-14 ***
## daycat.Q    4.747e+02  3.263e+01  14.551  < 2e-16 ***
## daycat.C    1.205e+02  3.252e+01   3.706 0.000259 ***
## daycat^4    5.887e+01  3.269e+01   1.801 0.072949 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 232.3 on 248 degrees of freedom
## Multiple R-squared:  0.5456, Adjusted R-squared:  0.5365 
## F-statistic: 59.56 on 5 and 248 DF,  p-value: < 2.2e-16
kable(broom::tidy(m1), caption = "Model 1 coefficients (tidy)")
Model 1 coefficients (tidy)
term estimate std.error statistic p.value
(Intercept) 1023.7204995 29.2426951 35.0077343 0.0000000
time_index 0.0890758 0.1988343 0.4479902 0.6545514
daycat.L 260.4968532 32.5268084 8.0086816 0.0000000
daycat.Q 474.7217560 32.6256270 14.5505788 0.0000000
daycat.C 120.5438976 32.5248257 3.7062120 0.0002595
daycat^4 58.8745043 32.6934556 1.8008040 0.0729487

4.2 Model 2: add event flags

m2 <- lm(cust ~ time_index + daycat + payday + holidays + sp + fac + bh + ah, data = data)
summary(m2)
## 
## Call:
## lm(formula = cust ~ time_index + daycat + payday + holidays + 
##     sp + fac + bh + ah, data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -484.93 -123.98  -12.84   93.32  807.98 
## 
## Coefficients: (1 not defined because of singularities)
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 956.34903   23.46298  40.760  < 2e-16 ***
## time_index    0.06242    0.15627   0.399 0.689914    
## daycat.L    127.06006   28.86490   4.402 1.61e-05 ***
## daycat.Q    363.95776   27.94200  13.025  < 2e-16 ***
## daycat.C     47.74734   26.40794   1.808 0.071832 .  
## daycat^4     57.95678   25.57645   2.266 0.024330 *  
## payday      443.14322  128.13516   3.458 0.000641 ***
## holidays    302.35215   70.83869   4.268 2.83e-05 ***
## sp            0.97173  122.05212   0.008 0.993654    
## fac          82.61443  103.05425   0.802 0.423533    
## bh            6.55590  105.86856   0.062 0.950674    
## ah                 NA         NA      NA       NA    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 179.7 on 243 degrees of freedom
## Multiple R-squared:  0.7335, Adjusted R-squared:  0.7226 
## F-statistic:  66.9 on 10 and 243 DF,  p-value: < 2.2e-16
kable(broom::tidy(m2), caption = "Model 2 coefficients (tidy)")
Model 2 coefficients (tidy)
term estimate std.error statistic p.value
(Intercept) 956.3490313 23.4629831 40.7599080 0.0000000
time_index 0.0624229 0.1562731 0.3994474 0.6899144
daycat.L 127.0600608 28.8649022 4.4018878 0.0000161
daycat.Q 363.9577594 27.9419969 13.0254742 0.0000000
daycat.C 47.7473440 26.4079355 1.8080680 0.0718322
daycat^4 57.9567812 25.5764467 2.2660216 0.0243304
payday 443.1432183 128.1351649 3.4584044 0.0006415
holidays 302.3521510 70.8386880 4.2681783 0.0000283
sp 0.9717298 122.0521181 0.0079616 0.9936542
fac 82.6144252 103.0542468 0.8016596 0.4235331
bh 6.5558990 105.8685622 0.0619249 0.9506735
ah NA NA NA NA

4.3 Model 3: add month + interactions

m3 <- lm(
cust ~ time_index + month_f + daycat * payday + holidays * fac + sp + bh + ah,
data = data
)
summary(m3)
## 
## Call:
## lm(formula = cust ~ time_index + month_f + daycat * payday + 
##     holidays * fac + sp + bh + ah, data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -405.80  -89.02  -15.41   68.44  546.85 
## 
## Coefficients: (2 not defined because of singularities)
##                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      1003.131     37.660  26.636  < 2e-16 ***
## time_index        -12.032      1.596  -7.538 1.12e-12 ***
## month_fFebruary   277.368     57.165   4.852 2.26e-06 ***
## month_fMarch      576.918     80.713   7.148 1.18e-11 ***
## month_fApril      867.141    110.434   7.852 1.59e-13 ***
## month_fMay       1213.237    142.457   8.517 2.24e-15 ***
## month_fJune      1511.428    174.634   8.655 9.03e-16 ***
## month_fJuly      1734.265    206.059   8.416 4.31e-15 ***
## month_fAugust    1925.714    239.655   8.035 5.00e-14 ***
## month_fSeptember 2051.795    273.620   7.499 1.42e-12 ***
## month_fOctober   2339.013    307.425   7.608 7.25e-13 ***
## month_fNovember  2604.374    341.224   7.632 6.25e-13 ***
## month_fDecember  2940.767    373.585   7.872 1.41e-13 ***
## daycat.L          140.937     24.401   5.776 2.49e-08 ***
## daycat.Q          362.260     23.462  15.440  < 2e-16 ***
## daycat.C           47.703     22.134   2.155  0.03220 *  
## daycat^4           68.904     21.205   3.249  0.00133 ** 
## payday            375.837    130.811   2.873  0.00445 ** 
## holidays          297.878     61.687   4.829 2.52e-06 ***
## fac               115.894    111.898   1.036  0.30143    
## sp                 56.356    170.155   0.331  0.74080    
## bh                 15.484     91.287   0.170  0.86546    
## ah                     NA         NA      NA       NA    
## daycat.L:payday   -26.654    133.276  -0.200  0.84166    
## daycat.Q:payday   -19.789    150.232  -0.132  0.89532    
## daycat.C:payday    77.822    129.226   0.602  0.54763    
## daycat^4:payday        NA         NA      NA       NA    
## holidays:fac      -34.927    180.755  -0.193  0.84695    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 147.6 on 228 degrees of freedom
## Multiple R-squared:  0.8313, Adjusted R-squared:  0.8128 
## F-statistic: 44.93 on 25 and 228 DF,  p-value: < 2.2e-16
kable(broom::tidy(m3), caption = "Model 3 coefficients (tidy)")
Model 3 coefficients (tidy)
term estimate std.error statistic p.value
(Intercept) 1003.13099 37.660147 26.6364063 0.0000000
time_index -12.03244 1.596212 -7.5381213 0.0000000
month_fFebruary 277.36798 57.164786 4.8520777 0.0000023
month_fMarch 576.91819 80.712549 7.1478128 0.0000000
month_fApril 867.14071 110.433875 7.8521261 0.0000000
month_fMay 1213.23683 142.456517 8.5165414 0.0000000
month_fJune 1511.42795 174.634334 8.6548156 0.0000000
month_fJuly 1734.26505 206.058605 8.4163680 0.0000000
month_fAugust 1925.71396 239.654723 8.0353683 0.0000000
month_fSeptember 2051.79494 273.619898 7.4987051 0.0000000
month_fOctober 2339.01257 307.425347 7.6083921 0.0000000
month_fNovember 2604.37428 341.223612 7.6324562 0.0000000
month_fDecember 2940.76705 373.585047 7.8717472 0.0000000
daycat.L 140.93724 24.401140 5.7758464 0.0000000
daycat.Q 362.26042 23.462429 15.4400223 0.0000000
daycat.C 47.70280 22.133998 2.1551824 0.0321951
daycat^4 68.90354 21.205033 3.2493958 0.0013311
payday 375.83676 130.811376 2.8731199 0.0044481
holidays 297.87763 61.687237 4.8288373 0.0000025
fac 115.89402 111.898080 1.0357105 0.3014344
sp 56.35569 170.155324 0.3312015 0.7407965
bh 15.48419 91.286798 0.1696213 0.8654583
ah NA NA NA NA
daycat.L:payday -26.65448 133.276496 -0.1999938 0.8416637
daycat.Q:payday -19.78862 150.232377 -0.1317201 0.8953219
daycat.C:payday 77.82195 129.226210 0.6022149 0.5476295
daycat^4:payday NA NA NA NA
holidays:fac -34.92723 180.754683 -0.1932300 0.8469509

4.4 Compare models (R² and Adjusted R²)

model_compare <- tibble(
model = c("m1: trend + weekday", "m2: + events", "m3: + month + interactions"),
r2 = c(summary(m1)$r.squared, summary(m2)$r.squared, summary(m3)$r.squared),
adj_r2 = c(summary(m1)$adj.r.squared, summary(m2)$adj.r.squared, summary(m3)$adj.r.squared)
)

kable(model_compare, caption = "Model comparison (R² / Adjusted R²)")
Model comparison (R² / Adjusted R²)
model r2 adj_r2
m1: trend + weekday 0.5456273 0.5364666
m2: + events 0.7335429 0.7225776
m3: + month + interactions 0.8312662 0.8127647

4.5 Model diagnostics

# # Quick diagnostic checks  see package is required

performance::check_model(m3)

5 Part 4 — Optional Direction : Lag Payday Effects

5.1 Create day-before and day-after payday variables

data <- data %>%
arrange(date) %>%
mutate(
payday_tomorrow = lead(payday, 1, default = 0),    # # 1 means: tomorrow is payday
payday_yesterday = lag(payday, 1, default = 0)     # # 1 means: yesterday was payday
)

m_lag <- lm(cust ~ time_index + daycat + payday + payday_tomorrow + payday_yesterday + holidays, data = data)
summary(m_lag)
## 
## Call:
## lm(formula = cust ~ time_index + daycat + payday + payday_tomorrow + 
##     payday_yesterday + holidays, data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -528.89 -103.69  -22.70   85.12  823.50 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      930.01802   23.74766  39.163  < 2e-16 ***
## time_index         0.08548    0.15035   0.569   0.5702    
## daycat.L         163.54276   30.14359   5.425 1.39e-07 ***
## daycat.Q         323.63235   28.78388  11.244  < 2e-16 ***
## daycat.C          72.68755   28.66353   2.536   0.0118 *  
## daycat^4          48.85463   25.86246   1.889   0.0601 .  
## payday           468.13677   40.34813  11.602  < 2e-16 ***
## payday_tomorrow   32.36819   41.59557   0.778   0.4372    
## payday_yesterday 161.41237   39.85161   4.050 6.88e-05 ***
## holidays         304.67794   52.12808   5.845 1.62e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 173.8 on 244 degrees of freedom
## Multiple R-squared:  0.7497, Adjusted R-squared:  0.7405 
## F-statistic: 81.21 on 9 and 244 DF,  p-value: < 2.2e-16
kable(broom::tidy(m_lag), caption = "Lag model coefficients (tidy)")
Lag model coefficients (tidy)
term estimate std.error statistic p.value
(Intercept) 930.0180150 23.7476625 39.1625077 0.0000000
time_index 0.0854849 0.1503468 0.5685846 0.5701610
daycat.L 163.5427613 30.1435912 5.4254571 0.0000001
daycat.Q 323.6323492 28.7838825 11.2435266 0.0000000
daycat.C 72.6875457 28.6635301 2.5358895 0.0118412
daycat^4 48.8546260 25.8624555 1.8890173 0.0600754
payday 468.1367725 40.3481276 11.6024411 0.0000000
payday_tomorrow 32.3681899 41.5955650 0.7781644 0.4372260
payday_yesterday 161.4123691 39.8516054 4.0503354 0.0000688
holidays 304.6779437 52.1280786 5.8447952 0.0000000

6 Part 5 — AI-Powered Learning Journal

6.1 Prompt 1

“Explain how to interpret an interaction term in R regression (DAYCAT * Payday) in simple words.”

What I learned:

  • Interaction means the payday effect changes depending on weekday.

  • For example, a term like daycatFriday:payday means “extra payday impact on Fridays.”

6.2 Prompt 2

“Write ggplot code to plot daily visits over time, colored by Payday, and faceted by Holidays.”

What worked:

  • Specifying my exact column names (date, cust, payday, holidays) helped.

How my prompt improved:

  • I started including: dataset columns + the exact plot style I want (color, facet).

7 Conclusion

This study examined daily customer visits to a bank branch using event-based regression models that incorporate a time trend, weekday effects, and special events such as paydays and holidays.

Model 2 already explains a substantial portion of the variation in customer visits (Adjusted R² ≈ 0.723), indicating that weekday patterns and event flags provide strong predictive value. When monthly seasonality and interaction terms are added in Model 3, model fit improves further (Adjusted R² ≈ 0.813). This shows that incorporating seasonality significantly strengthens the model’s ability to explain daily visit behavior.

In Model 2, the time trend (time_index) is not statistically significant, suggesting there is no simple linear increase/decrease over time once weekday and event effects are controlled. However, after controlling for seasonality in Model 3, the time trend becomes negative and highly significant (time_index ≈ -12.0, p < 0.001), implying a modest underlying downward trend in visits within the seasonal pattern.

Weekday effects are strongly significant in both models, confirming that customer visits follow a systematic weekly rhythm rather than being evenly distributed across days. This indicates that operational planning should consider recurring weekday traffic differences.

Event variables provide clear managerial insights. Paydays have a large and statistically significant positive effect on visits in both models (about +443 in Model 2; about +376 in Model 3), meaning branches experience substantially higher traffic on payday periods. Holidays are also statistically significant (about +302 in Model 2; about +298 in Model 3), showing that customer visits differ meaningfully on holidays compared to normal days in the dataset.

In contrast, staff payday (sp), faculty payday (fac), and before-holiday (bh) are not statistically significant, suggesting these factors do not materially affect total visits after controlling for the main payday/holiday effects. Additionally, the interaction terms (weekday × payday and holiday × faculty payday) are not statistically significant, implying the payday effect is relatively consistent across weekdays rather than being concentrated on a specific day of the week.

Finally, monthly seasonality is one of the strongest drivers in Model 3, with month effects increasing substantially from February through December. This indicates pronounced seasonal variation in branch traffic and suggests that staffing and service capacity planning should consider both payday peaks and high-traffic months.

Overall, the results demonstrate that an event-based modeling approach combined with seasonality provides a strong framework for understanding and predicting bank customer visits, supporting better operational and staffing decisions.

LS0tCnRpdGxlOiAiTWluaSBQcm9qZWN0IDEg4oCUIEV2ZW50LUJhc2VkIE1vZGVsaW5nIG9mIEJhbmsgQ3VzdG9tZXIgVmlzaXRzIgpzdWJ0aXRsZTogIk1hcmtldGluZyBBbmFseXRpY3MgKE1pTTgxMSkg4oCUIE1pbmkgUHJvamVjdCBSZXBvcnQiCmF1dGhvcjogIkdyb3VwIDQiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIG1hdGhqYXg6IGRlZmF1bHQKLS0tCgojIFByb2plY3QgR29hbCBhbmQgRGF0YSBPdmVydmlldwoKIyMgR29hbAoKVGhpcyBwcm9qZWN0IGFpbXMgdG8gdW5kZXJzdGFuZCBhbmQgcHJlZGljdCBkYWlseSBiYW5rIGN1c3RvbWVyIHZpc2l0cyAoQ1VTVCkgdXNpbmc6CgotICAgKipBIHRpbWUgdHJlbmQqKiAoVGltZUluZGV4KQotICAgKipXZWVrZGF5IGVmZmVjdHMqKiAoREFZQ0FUKQotICAgKipTcGVjaWFsIGV2ZW50cyoqIChQYXlkYXksIGhvbGlkYXlzLCBiZWZvcmUvYWZ0ZXIgaG9saWRheXMsIGV0Yy4pCi0gICAqKkV4dHJhIGV2ZW50cyoqIChlLmcuLCBDaHJpc3RtYXMsIE5ldyBZZWFyLCBCbGFjayBGcmlkYXkpIGFuZCBpbnRlcmFjdGlvbnMKCiMjIExvYWQgdGhlIGRhdGFzZXQgKEV4Y2VsKQoKYGBge3IgMUEsIGluY2x1ZGU9RkFMU0V9CiMgPT09PT09PT09PT09PT09PT09PT09PT09PQojICMgMCkgU0VUVVAgKFJVTiBPTkNFKQojID09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgIyBUaGlzIGNvbnRyb2xzIGhvdyBjb2RlL291dHB1dCBhcHBlYXJzIGluIHRoZSBmaW5hbCBIVE1MCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKIyAjIEluc3RhbGwgcGFja2FnZXMgT05MWSBpZiB5b3UgZG9uJ3QgaGF2ZSB0aGVtCiMgaW5zdGFsbC5wYWNrYWdlcyhjKCJ0aWR5dmVyc2UiLCJyZWFkeGwiLCJsdWJyaWRhdGUiLCJqYW5pdG9yIiwiYnJvb20iLCJrbml0ciIsImthYmxlRXh0cmEiKSkKYGBgCgpgYGB7ciBwYWNrYWdlX2luc3RhbGwgfQojICMgTG9hZCBwYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAjICMgZGF0YSB3cmFuZ2xpbmcgKyBnZ3Bsb3QyCmxpYnJhcnkocmVhZHhsKSAgICAgICMgIyByZWFkIEV4Y2VsCmxpYnJhcnkobHVicmlkYXRlKSAgICMgIyBkYXRlIGZ1bmN0aW9ucyAobW9udGgoKSwgd2RheSgpLCBldGMuKQpsaWJyYXJ5KGphbml0b3IpICAgICAjICMgY2xlYW5fbmFtZXMoKQpsaWJyYXJ5KGJyb29tKSAgICAgICAjICMgdGlkeSBtb2RlbCBvdXRwdXRzCmxpYnJhcnkoa25pdHIpICAgICAgICMgIyBrYWJsZSB0YWJsZXMKbGlicmFyeShrYWJsZUV4dHJhKSAgIyAjIG5pY2VyIHRhYmxlcwpsaWJyYXJ5KHNlZSkKIyA9PT09PT09PT09PT09PT09PT09PT09PT09CgojICMgMUEpIExPQUQgREFUQQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09CgojICMgUmVhZCBFeGNlbCBmaWxlIChtYWtlIHN1cmUgaXQncyBpbiB0aGUgc2FtZSBmb2xkZXIgYXMgdGhpcyAuUm1kKQoKcmF3IDwtIHJlYWRfZXhjZWwoIk1pTTgxMVF1aXo0TWluaVByb2oxRGF0YS54bHN4IikKCiMgIyBDbGVhbiBjb2x1bW4gbmFtZXMgKHJlbW92ZXMgd2VpcmQgc3BhY2VzIGxpa2UgIiAgQ1VTVCIpCgpkYXRhIDwtIHJhdyAlPiUKamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQoKIyAjIFF1aWNrIGxvb2sKCmdsaW1wc2UoZGF0YSkKCmBgYAoKIyMgUXVpY2sgaW50ZXJhY3RpdmUgdmlldwpgYGB7ciBRdWljay1pbnRlcmFjdGl2ZS12aWV3fQpEVDo6ZGF0YXRhYmxlKApoZWFkKGRhdGEsIDIwKSwKb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLCBzY3JvbGxYID0gVFJVRSksCmNhcHRpb24gPSAiRmlyc3QgMjAgcm93cyBvZiB0aGUgZGF0YXNldCAoaW50ZXJhY3RpdmUgdGFibGUpIgopCmBgYAoKIyBQYXJ0IDEg4oCUIENsZWFuIGFuZCBQcmVwYXJlIERhdGEKCiMjIENvbnZlcnQgREFURSArIGNyZWF0ZSBUaW1lSW5kZXgKCmBgYHtyIDFCfQojID09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgIyAxQikgRklYIFRZUEVTICsgQ1JFQVRFIFRJTUUgSU5ERVgKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PQoKZGF0YSA8LSBkYXRhICU+JQptdXRhdGUoCiMgIyBDb252ZXJ0IGRhdGUgdG8gRGF0ZSBjbGFzcyAoZXZlbiBpZiBpdCBhbHJlYWR5IGxvb2tzIGxpa2UgYSBkYXRlKQpkYXRlID0gYXMuRGF0ZShkYXRlKSwKCiMgIyBUaW1lIHRyZW5kIGluZGV4OiAxLCAyLCAzLCAuLi4sIG4KdGltZV9pbmRleCA9IHJvd19udW1iZXIoKSwKCiMgIyBEQVlDQVQgYXMgb3JkZXJlZCBmYWN0b3IgKGltcG9ydGFudCBmb3Igd2Vla2RheSBjb21wYXJpc29ucykKZGF5Y2F0ID0gZmFjdG9yKAogIGRheWNhdCwKICBsZXZlbHMgPSBjKCJNb25kYXkiLCJUdWVzZGF5IiwiV2VkbmVzZGF5IiwiVGh1cnNkYXkiLCJGcmlkYXkiLCJTYXR1cmRheSIsIlN1bmRheSIpLAogIG9yZGVyZWQgPSBUUlVFCiksCgojICMgTW9udGggYXMgYSBmYWN0b3IgKG9wdGlvbmFsIGJ1dCB1c2VmdWwpCm1vbnRoX2YgPSBmYWN0b3IobW9udGgsIGxldmVscyA9IDE6MTIsIGxhYmVscyA9IG1vbnRoLm5hbWUpCikKCiMgIyBSZXZpZXcgc3RydWN0dXJlICsgc3VtbWFyeSAocmVxdWlyZWQg4oCccmV2aWV3IHN0cnVjdHVyZeKAnSBpZGVhKQoKc3RyKGRhdGEpCnN1bW1hcnkoZGF0YSkKIyA9PT09PT09PT09PT09PT09PT09PT09PT09CmBgYAoKIyMgVW5kZXJzdGFuZCB0aGUgZXZlbnQgZmxhZ3MgKHNhbml0eSBjaGVja3MpCmBgYHtyIHNhbml0eS1jaGVja3N9CiMgIyAxQykgVU5ERVJTVEFORCBFVkVOVCBGTEFHUwoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09CgojICMgVGhlc2UgZXZlbnQgY29sdW1ucyBhcmUgeW91ciDigJxzcGVjaWFsIGV2ZW50c+KAnSBwcmVkaWN0b3JzLgoKIyAjIEJhc2VkIG9uIG5hbWVzLCB0aGV5IHR5cGljYWxseSBtZWFuOgoKIyAjIHBheWRheSAgID0gcGF5ZGF5IGluZGljYXRvciAoMS8wKQoKIyAjIHNwICAgICAgID0gc3RhZmYgcGF5ZGF5ICgxLzApICAoZ3Vlc3MgZnJvbSBhYmJyZXZpYXRpb24pCgojICMgZmFjICAgICAgPSBmYWN1bHR5IHBheWRheSAoMS8wKQoKIyAjIGhvbGlkYXlzID0gaG9saWRheSBkYXkgKDEvMCkKCiMgIyBiaCAgICAgICA9IGJlZm9yZS1ob2xpZGF5ICgxLzApCgojICMgYWggICAgICAgPSBhZnRlci1ob2xpZGF5ICgxLzApCgojICMgSWYgeW91ciBjbGFzcyBub3RlcyBkZWZpbmUgdGhlbSBkaWZmZXJlbnRseSwgdXNlIHRoZSBvZmZpY2lhbCBtZWFuaW5nLgoKIyAjIENvdW50IGhvdyBtYW55IGRheXMgYXJlIGZsYWdnZWQgYXMgMSAocXVpY2sgc2FuaXR5IGNoZWNrKQoKZGF0YSAlPiUKc3VtbWFyaXNlKGFjcm9zcyhjKHBheWRheSwgc3AsIGZhYywgaG9saWRheXMsIGJoLCBhaCksIH5zdW0oLngsIG5hLnJtID0gVFJVRSkpKSAlPiUKa2FibGUoY2FwdGlvbiA9ICJIb3cgbWFueSBkYXlzIGFyZSBmbGFnZ2VkIGZvciBlYWNoIGV2ZW50PyIpICU+JQprYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PQoKYGBgCgojIyBDcmVhdGUgZXh0cmEgZXZlbnQgZmxhZ3MgKE5ldyBZZWFyLCBDaHJpc3RtYXMsIEJsYWNrIEZyaWRheSkKCmBgYHtyIGV4dHJhLWV2ZW50fQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojICMgMi4zKSBPUFRJT05BTCBFWFRSQSBFVkVOVFMKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmRhdGEgPC0gZGF0YSAlPiUKbXV0YXRlKAp5ZWFyID0geWVhcihkYXRlKSwKCiMgIyBOZXcgWWVhciAoSmFuIDEpCmlzX25ld195ZWFyID0gaWZfZWxzZShtb250aChkYXRlKSA9PSAxICYgZGF5KGRhdGUpID09IDEsIDEsIDApLAoKIyAjIENocmlzdG1hcyAoRGVjIDI1KQppc19jaHJpc3RtYXMgPSBpZl9lbHNlKG1vbnRoKGRhdGUpID09IDEyICYgZGF5KGRhdGUpID09IDI1LCAxLCAwKQoKCikKCiMgIyBCbGFjayBGcmlkYXkgYXBwcm94aW1hdGlvbjoKCiMgIyBVUyBkZWZpbml0aW9uOiA0dGggRnJpZGF5IG9mIE5vdmVtYmVyLgoKYmxhY2tfZnJpZGF5cyA8LSBkYXRhICU+JQpmaWx0ZXIobW9udGgoZGF0ZSkgPT0gMTEsIHdkYXkoZGF0ZSwgbGFiZWwgPSBUUlVFKSA9PSAiRnJpIikgJT4lCmdyb3VwX2J5KHllYXIpICU+JQphcnJhbmdlKGRhdGUpICU+JQptdXRhdGUoZnJpZGF5X251bWJlciA9IHJvd19udW1iZXIoKSkgJT4lCmZpbHRlcihmcmlkYXlfbnVtYmVyID09IDQpICU+JQpwdWxsKGRhdGUpCgpkYXRhIDwtIGRhdGEgJT4lCm11dGF0ZShpc19ibGFja19mcmlkYXkgPSBpZl9lbHNlKGRhdGUgJWluJSBibGFja19mcmlkYXlzLCAxLCAwKSkKCmRhdGEgJT4lCmZpbHRlcihpc19uZXdfeWVhciA9PSAxIHwgaXNfY2hyaXN0bWFzID09IDEgfCBpc19ibGFja19mcmlkYXkgPT0gMSkgJT4lCnNlbGVjdChkYXRlLCBpc19uZXdfeWVhciwgaXNfY2hyaXN0bWFzLCBpc19ibGFja19mcmlkYXkpICU+JQphcnJhbmdlKGRhdGUpICU+JQogIGthYmxlKGNhcHRpb24gPSAiRGV0ZWN0ZWQgZGF0ZXMgZm9yIG9wdGlvbmFsIGV4dHJhIGV2ZW50cyIpCgpgYGAKIyBQYXJ0IDIg4oCUIFZpc3VhbGl6ZSBDdXN0b21lciBCZWhhdmlvcgoKIyMgRGFpbHkgdmlzaXRzIG92ZXIgdGltZSAodGltZSBzZXJpZXMpCgpgYGB7ciBkYWlseS12aXNpdHN9CmdncGxvdChkYXRhLCBhZXMoeCA9IGRhdGUsIHkgPSBjdXN0KSkgKwpnZW9tX2xpbmUoKSArCmxhYnMoCnRpdGxlID0gIkRhaWx5IEN1c3RvbWVyIFZpc2l0cyBPdmVyIFRpbWUiLAp4ID0gIkRhdGUiLAp5ID0gIkNVU1QgKFZpc2l0cykiCikKCmBgYAoKIyMgVmlzaXRzIGJ5IHdlZWtkYXkgKERBWUNBVCkKCmBgYHtyIHZpc2l0cy13ZWVrZGF5fQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBkYXljYXQsIHkgPSBjdXN0KSkgKwpnZW9tX2JveHBsb3QoKSArCmxhYnMoCnRpdGxlID0gIkN1c3RvbWVyIFZpc2l0cyBieSBEYXkgb2YgV2VlayAoREFZQ0FUKSIsCnggPSAiRGF5IG9mIFdlZWsiLAp5ID0gIkNVU1QgKFZpc2l0cykiCikKCmBgYAoKIyMgQ29sb3IgYnkgcGF5ZGF5IGFuZCBmYWNldCBieSBob2xpZGF5cwoKYGBge3IgY29sb3ItYnktcGF5ZGF5fQpwbG90X2RhdGEgPC0gZGF0YSAlPiUKbXV0YXRlKApwYXlkYXlfbGFiZWwgPSBmYWN0b3IocGF5ZGF5LCBsZXZlbHMgPSBjKDAsMSksIGxhYmVscyA9IGMoIk5vdCBQYXlkYXkiLCJQYXlkYXkiKSksCmhvbGlkYXlfbGFiZWwgPSBmYWN0b3IoaG9saWRheXMsIGxldmVscyA9IGMoMCwxKSwgbGFiZWxzID0gYygiTm90IEhvbGlkYXkiLCJIb2xpZGF5IikpCikKCmdncGxvdChwbG90X2RhdGEsIGFlcyh4ID0gZGF0ZSwgeSA9IGN1c3QsIGNvbG9yID0gcGF5ZGF5X2xhYmVsKSkgKwpnZW9tX2xpbmUoKSArCmZhY2V0X3dyYXAofiBob2xpZGF5X2xhYmVsLCBuY29sID0gMSkgKwpsYWJzKAp0aXRsZSA9ICJEYWlseSBWaXNpdHMg4oCUIENvbG9yZWQgYnkgUGF5ZGF5LCBGYWNldGVkIGJ5IEhvbGlkYXkiLAp4ID0gIkRhdGUiLAp5ID0gIkNVU1QgKFZpc2l0cykiLApjb2xvciA9ICJQYXlkYXk/IgopCgpgYGAKCiMjIE1hcmsgc3BlY2lhbCBkYXRlcyB3aXRoIHZlcnRpY2FsIGxpbmVzCgpgYGB7ciBtYXJrLXNwZWNpYWwtZGF0ZXN9CmV2ZW50X2RhdGVzIDwtIGRhdGEgJT4lCmZpbHRlcihpc19uZXdfeWVhciA9PSAxIHwgaXNfY2hyaXN0bWFzID09IDEgfCBpc19ibGFja19mcmlkYXkgPT0gMSkgJT4lCnNlbGVjdChkYXRlKSAlPiUKZGlzdGluY3QoKQoKZ2dwbG90KGRhdGEsIGFlcyh4ID0gZGF0ZSwgeSA9IGN1c3QpKSArCmdlb21fbGluZSgpICsKZ2VvbV92bGluZSgKZGF0YSA9IGV2ZW50X2RhdGVzLAphZXMoeGludGVyY2VwdCA9IGFzLm51bWVyaWMoZGF0ZSkpLApsaW5ldHlwZSA9ICJkYXNoZWQiCikgKwpsYWJzKAp0aXRsZSA9ICJEYWlseSBWaXNpdHMgd2l0aCBTcGVjaWFsIEV2ZW50IE1hcmtlcnMgKGRhc2hlZCBsaW5lcykiLAp4ID0gIkRhdGUiLAp5ID0gIkNVU1QgKFZpc2l0cykiCikKCmBgYAoKIyBQYXJ0IDMg4oCUIFJlZ3Jlc3Npb24gTW9kZWxzCgojIyBNb2RlbCAxOiBiYXNlbGluZSAodHJlbmQgKyB3ZWVrZGF5KQoKYGBge3IgbW9kZWwxfQptMSA8LSBsbShjdXN0IH4gdGltZV9pbmRleCArIGRheWNhdCwgZGF0YSA9IGRhdGEpCnN1bW1hcnkobTEpCgprYWJsZShicm9vbTo6dGlkeShtMSksIGNhcHRpb24gPSAiTW9kZWwgMSBjb2VmZmljaWVudHMgKHRpZHkpIikKCmBgYAoKIyMgTW9kZWwgMjogYWRkIGV2ZW50IGZsYWdzCgpgYGB7ciBtb2RlbDJ9Cm0yIDwtIGxtKGN1c3QgfiB0aW1lX2luZGV4ICsgZGF5Y2F0ICsgcGF5ZGF5ICsgaG9saWRheXMgKyBzcCArIGZhYyArIGJoICsgYWgsIGRhdGEgPSBkYXRhKQpzdW1tYXJ5KG0yKQoKa2FibGUoYnJvb206OnRpZHkobTIpLCBjYXB0aW9uID0gIk1vZGVsIDIgY29lZmZpY2llbnRzICh0aWR5KSIpCgpgYGAKCiMjIE1vZGVsIDM6IGFkZCBtb250aCArIGludGVyYWN0aW9ucwoKYGBge3IgbW9kZWwzfQptMyA8LSBsbSgKY3VzdCB+IHRpbWVfaW5kZXggKyBtb250aF9mICsgZGF5Y2F0ICogcGF5ZGF5ICsgaG9saWRheXMgKiBmYWMgKyBzcCArIGJoICsgYWgsCmRhdGEgPSBkYXRhCikKc3VtbWFyeShtMykKCmthYmxlKGJyb29tOjp0aWR5KG0zKSwgY2FwdGlvbiA9ICJNb2RlbCAzIGNvZWZmaWNpZW50cyAodGlkeSkiKQoKYGBgCgojIyBDb21wYXJlIG1vZGVscyAoUsKyIGFuZCBBZGp1c3RlZCBSwrIpCgpgYGB7ciBtb2RlbH0KbW9kZWxfY29tcGFyZSA8LSB0aWJibGUoCm1vZGVsID0gYygibTE6IHRyZW5kICsgd2Vla2RheSIsICJtMjogKyBldmVudHMiLCAibTM6ICsgbW9udGggKyBpbnRlcmFjdGlvbnMiKSwKcjIgPSBjKHN1bW1hcnkobTEpJHIuc3F1YXJlZCwgc3VtbWFyeShtMikkci5zcXVhcmVkLCBzdW1tYXJ5KG0zKSRyLnNxdWFyZWQpLAphZGpfcjIgPSBjKHN1bW1hcnkobTEpJGFkai5yLnNxdWFyZWQsIHN1bW1hcnkobTIpJGFkai5yLnNxdWFyZWQsIHN1bW1hcnkobTMpJGFkai5yLnNxdWFyZWQpCikKCmthYmxlKG1vZGVsX2NvbXBhcmUsIGNhcHRpb24gPSAiTW9kZWwgY29tcGFyaXNvbiAoUsKyIC8gQWRqdXN0ZWQgUsKyKSIpCgpgYGAKCiMjIE1vZGVsIGRpYWdub3N0aWNzCgpgYGB7ciBkaWFnbm9zdGljfQojICMgUXVpY2sgZGlhZ25vc3RpYyBjaGVja3MgIHNlZSBwYWNrYWdlIGlzIHJlcXVpcmVkCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwobTMpCgpgYGAKCiMgUGFydCA0IOKAlCBPcHRpb25hbCBEaXJlY3Rpb24gOiBMYWcgUGF5ZGF5IEVmZmVjdHMKCiMjIENyZWF0ZSBkYXktYmVmb3JlIGFuZCBkYXktYWZ0ZXIgcGF5ZGF5IHZhcmlhYmxlcwoKYGBge3IgbW9kZWw1fQpkYXRhIDwtIGRhdGEgJT4lCmFycmFuZ2UoZGF0ZSkgJT4lCm11dGF0ZSgKcGF5ZGF5X3RvbW9ycm93ID0gbGVhZChwYXlkYXksIDEsIGRlZmF1bHQgPSAwKSwgICAgIyAjIDEgbWVhbnM6IHRvbW9ycm93IGlzIHBheWRheQpwYXlkYXlfeWVzdGVyZGF5ID0gbGFnKHBheWRheSwgMSwgZGVmYXVsdCA9IDApICAgICAjICMgMSBtZWFuczogeWVzdGVyZGF5IHdhcyBwYXlkYXkKKQoKbV9sYWcgPC0gbG0oY3VzdCB+IHRpbWVfaW5kZXggKyBkYXljYXQgKyBwYXlkYXkgKyBwYXlkYXlfdG9tb3Jyb3cgKyBwYXlkYXlfeWVzdGVyZGF5ICsgaG9saWRheXMsIGRhdGEgPSBkYXRhKQpzdW1tYXJ5KG1fbGFnKQoKa2FibGUoYnJvb206OnRpZHkobV9sYWcpLCBjYXB0aW9uID0gIkxhZyBtb2RlbCBjb2VmZmljaWVudHMgKHRpZHkpIikKCmBgYAoKIyBQYXJ0IDUg4oCUIEFJLVBvd2VyZWQgTGVhcm5pbmcgSm91cm5hbCAKCiMjIFByb21wdCAxCgo+IOKAnEV4cGxhaW4gaG93IHRvIGludGVycHJldCBhbiBpbnRlcmFjdGlvbiB0ZXJtIGluIFIgcmVncmVzc2lvbiAoREFZQ0FUICogUGF5ZGF5KSBpbiBzaW1wbGUgd29yZHMu4oCdCgoqKldoYXQgSSBsZWFybmVkOioqCgotIEludGVyYWN0aW9uIG1lYW5zIHRoZSBwYXlkYXkgZWZmZWN0IGNoYW5nZXMgZGVwZW5kaW5nIG9uIHdlZWtkYXkuCgotIEZvciBleGFtcGxlLCBhIHRlcm0gbGlrZSBkYXljYXRGcmlkYXk6cGF5ZGF5IG1lYW5zIOKAnGV4dHJhIHBheWRheSBpbXBhY3Qgb24gRnJpZGF5cy7igJ0KCiMjIFByb21wdCAyCgo+IOKAnFdyaXRlIGdncGxvdCBjb2RlIHRvIHBsb3QgZGFpbHkgdmlzaXRzIG92ZXIgdGltZSwgY29sb3JlZCBieSBQYXlkYXksIGFuZCBmYWNldGVkIGJ5IEhvbGlkYXlzLuKAnQoKKipXaGF0IHdvcmtlZDoqKgoKLSBTcGVjaWZ5aW5nIG15IGV4YWN0IGNvbHVtbiBuYW1lcyAoZGF0ZSwgY3VzdCwgcGF5ZGF5LCBob2xpZGF5cykgaGVscGVkLgoKKipIb3cgbXkgcHJvbXB0IGltcHJvdmVkOioqCgotIEkgc3RhcnRlZCBpbmNsdWRpbmc6IGRhdGFzZXQgY29sdW1ucyArIHRoZSBleGFjdCBwbG90IHN0eWxlIEkgd2FudCAoY29sb3IsIGZhY2V0KS4KCiMgQ29uY2x1c2lvbgoKVGhpcyBzdHVkeSBleGFtaW5lZCBkYWlseSBjdXN0b21lciB2aXNpdHMgdG8gYSBiYW5rIGJyYW5jaCB1c2luZyBldmVudC1iYXNlZCByZWdyZXNzaW9uIG1vZGVscyB0aGF0IGluY29ycG9yYXRlIGEgdGltZSB0cmVuZCwgd2Vla2RheSBlZmZlY3RzLCBhbmQgc3BlY2lhbCBldmVudHMgc3VjaCBhcyBwYXlkYXlzIGFuZCBob2xpZGF5cy4KCk1vZGVsIDIgYWxyZWFkeSBleHBsYWlucyBhIHN1YnN0YW50aWFsIHBvcnRpb24gb2YgdGhlIHZhcmlhdGlvbiBpbiBjdXN0b21lciB2aXNpdHMgKiooQWRqdXN0ZWQgUsKyIOKJiCAwLjcyMykqKiwgaW5kaWNhdGluZyB0aGF0IHdlZWtkYXkgcGF0dGVybnMgYW5kIGV2ZW50IGZsYWdzIHByb3ZpZGUgc3Ryb25nIHByZWRpY3RpdmUgdmFsdWUuIFdoZW4gKiptb250aGx5IHNlYXNvbmFsaXR5KiogYW5kICoqaW50ZXJhY3Rpb24gdGVybXMqKiBhcmUgYWRkZWQgaW4gTW9kZWwgMywgbW9kZWwgZml0IGltcHJvdmVzIGZ1cnRoZXIgKiooQWRqdXN0ZWQgUsKyIOKJiCAwLjgxMykqKi4gVGhpcyBzaG93cyB0aGF0IGluY29ycG9yYXRpbmcgc2Vhc29uYWxpdHkgc2lnbmlmaWNhbnRseSBzdHJlbmd0aGVucyB0aGUgbW9kZWzigJlzIGFiaWxpdHkgdG8gZXhwbGFpbiBkYWlseSB2aXNpdCBiZWhhdmlvci4KCkluIE1vZGVsIDIsIHRoZSB0aW1lIHRyZW5kICh0aW1lX2luZGV4KSBpcyAqKm5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50KiosIHN1Z2dlc3RpbmcgdGhlcmUgaXMgbm8gc2ltcGxlIGxpbmVhciBpbmNyZWFzZS9kZWNyZWFzZSBvdmVyIHRpbWUgb25jZSB3ZWVrZGF5IGFuZCBldmVudCBlZmZlY3RzIGFyZSBjb250cm9sbGVkLiBIb3dldmVyLCBhZnRlciBjb250cm9sbGluZyBmb3Igc2Vhc29uYWxpdHkgaW4gTW9kZWwgMywgdGhlIHRpbWUgdHJlbmQgYmVjb21lcyAqKm5lZ2F0aXZlIGFuZCBoaWdobHkgc2lnbmlmaWNhbnQqKiAodGltZV9pbmRleCDiiYggLTEyLjAsIHAgPCAwLjAwMSksIGltcGx5aW5nIGEgbW9kZXN0IHVuZGVybHlpbmcgZG93bndhcmQgdHJlbmQgaW4gdmlzaXRzIHdpdGhpbiB0aGUgc2Vhc29uYWwgcGF0dGVybi4KCldlZWtkYXkgZWZmZWN0cyBhcmUgc3Ryb25nbHkgc2lnbmlmaWNhbnQgaW4gYm90aCBtb2RlbHMsIGNvbmZpcm1pbmcgdGhhdCBjdXN0b21lciB2aXNpdHMgZm9sbG93IGEgc3lzdGVtYXRpYyB3ZWVrbHkgcmh5dGhtIHJhdGhlciB0aGFuIGJlaW5nIGV2ZW5seSBkaXN0cmlidXRlZCBhY3Jvc3MgZGF5cy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBvcGVyYXRpb25hbCBwbGFubmluZyBzaG91bGQgY29uc2lkZXIgcmVjdXJyaW5nIHdlZWtkYXkgdHJhZmZpYyBkaWZmZXJlbmNlcy4KCkV2ZW50IHZhcmlhYmxlcyBwcm92aWRlIGNsZWFyIG1hbmFnZXJpYWwgaW5zaWdodHMuIFBheWRheXMgaGF2ZSBhIGxhcmdlIGFuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHBvc2l0aXZlIGVmZmVjdCBvbiB2aXNpdHMgaW4gYm90aCBtb2RlbHMgKGFib3V0ICs0NDMgaW4gTW9kZWwgMjsgYWJvdXQgKzM3NiBpbiBNb2RlbCAzKSwgbWVhbmluZyBicmFuY2hlcyBleHBlcmllbmNlIHN1YnN0YW50aWFsbHkgaGlnaGVyIHRyYWZmaWMgb24gcGF5ZGF5IHBlcmlvZHMuIEhvbGlkYXlzIGFyZSBhbHNvIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKGFib3V0ICszMDIgaW4gTW9kZWwgMjsgYWJvdXQgKzI5OCBpbiBNb2RlbCAzKSwgc2hvd2luZyB0aGF0ICoqY3VzdG9tZXIgdmlzaXRzIGRpZmZlciBtZWFuaW5nZnVsbHkgb24gaG9saWRheXMgY29tcGFyZWQgdG8gbm9ybWFsIGRheXMgaW4gdGhlIGRhdGFzZXQqKi4KCkluIGNvbnRyYXN0LCAqKnN0YWZmIHBheWRheSAoc3ApLCBmYWN1bHR5IHBheWRheSAoZmFjKSwgYW5kIGJlZm9yZS1ob2xpZGF5IChiaCkqKiBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHN1Z2dlc3RpbmcgdGhlc2UgZmFjdG9ycyBkbyBub3QgbWF0ZXJpYWxseSBhZmZlY3QgdG90YWwgdmlzaXRzIGFmdGVyIGNvbnRyb2xsaW5nIGZvciB0aGUgbWFpbiBwYXlkYXkvaG9saWRheSBlZmZlY3RzLiBBZGRpdGlvbmFsbHksIHRoZSBpbnRlcmFjdGlvbiB0ZXJtcyAod2Vla2RheSDDlyBwYXlkYXkgYW5kIGhvbGlkYXkgw5cgZmFjdWx0eSBwYXlkYXkpIGFyZSBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgaW1wbHlpbmcgdGhlIHBheWRheSBlZmZlY3QgaXMgKipyZWxhdGl2ZWx5IGNvbnNpc3RlbnQgYWNyb3NzIHdlZWtkYXlzKiogcmF0aGVyIHRoYW4gYmVpbmcgY29uY2VudHJhdGVkIG9uIGEgc3BlY2lmaWMgZGF5IG9mIHRoZSB3ZWVrLgoKRmluYWxseSwgbW9udGhseSBzZWFzb25hbGl0eSBpcyBvbmUgb2YgdGhlIHN0cm9uZ2VzdCBkcml2ZXJzIGluIE1vZGVsIDMsIHdpdGggbW9udGggZWZmZWN0cyBpbmNyZWFzaW5nIHN1YnN0YW50aWFsbHkgZnJvbSBGZWJydWFyeSB0aHJvdWdoIERlY2VtYmVyLiBUaGlzIGluZGljYXRlcyBwcm9ub3VuY2VkIHNlYXNvbmFsIHZhcmlhdGlvbiBpbiBicmFuY2ggdHJhZmZpYyBhbmQgc3VnZ2VzdHMgdGhhdCBzdGFmZmluZyBhbmQgc2VydmljZSBjYXBhY2l0eSBwbGFubmluZyBzaG91bGQgY29uc2lkZXIgKipib3RoIHBheWRheSBwZWFrcyBhbmQgaGlnaC10cmFmZmljIG1vbnRocyoqLgoKKipPdmVyYWxsKiosIHRoZSByZXN1bHRzIGRlbW9uc3RyYXRlIHRoYXQgYW4gZXZlbnQtYmFzZWQgbW9kZWxpbmcgYXBwcm9hY2ggY29tYmluZWQgd2l0aCBzZWFzb25hbGl0eSBwcm92aWRlcyBhIHN0cm9uZyBmcmFtZXdvcmsgZm9yIHVuZGVyc3RhbmRpbmcgYW5kIHByZWRpY3RpbmcgYmFuayBjdXN0b21lciB2aXNpdHMsIHN1cHBvcnRpbmcgYmV0dGVyIG9wZXJhdGlvbmFsIGFuZCBzdGFmZmluZyBkZWNpc2lvbnMuCgoKYGBge3IgYn0KYGBgCmBgYHtyIGN9CmBgYApgYGB7ciBkfQpgYGAK