Kelompok 10:
1. Fathatia Cholida Syifa (5003231070)
2. Suhanur Haliza (5003231078)
3. Diazty Ifta Padvani (5003231171)
4. Pingky Oktania Tata Sefina (5003231184)

library(dplyr)
library(lubridate)
library(ggplot2)
library(tidyr)
library(scales)
library(forecast)

Filtering & Cleaning Data

WiFi Data

wifi=read.csv('C:/Users/Lenovo/Downloads/wifi.csv')
head(wifi)
colnames(wifi)
[1] "time"                       "Event.Time"                 "Associated.Client.Count"    "Authenticated.Client.Count"
[5] "Uni"                        "Building"                   "Floor"                     
str(wifi)
'data.frame':   1883844 obs. of  7 variables:
 $ time                      : chr  "2020-02-01 00:02:12" "2020-02-01 00:02:12" "2020-02-01 00:02:12" "2020-02-01 00:02:12" ...
 $ Event.Time                : chr  "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" ...
 $ Associated.Client.Count   : int  184 6 18 23 45 16 32 6 73 5 ...
 $ Authenticated.Client.Count: int  182 6 18 23 45 16 32 6 73 5 ...
 $ Uni                       : chr  "Lancaster University " "Lancaster University " "Lancaster University " "Lancaster University " ...
 $ Building                  : chr  " Graduate College " " Management School " " SW hse 32-33 " " SW hse 29 " ...
 $ Floor                     : chr  " A Floor" " C Floor" " D Floor" " B floor" ...
wifi$time=as.POSIXct(wifi$time)
str(wifi)
'data.frame':   1883844 obs. of  7 variables:
 $ time                      : POSIXct, format: "2020-02-01 00:02:12" "2020-02-01 00:02:12" "2020-02-01 00:02:12" "2020-02-01 00:02:12" ...
 $ Event.Time                : chr  "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" "Sat Feb 01 00:02:12 UTC 2020" ...
 $ Associated.Client.Count   : int  184 6 18 23 45 16 32 6 73 5 ...
 $ Authenticated.Client.Count: int  182 6 18 23 45 16 32 6 73 5 ...
 $ Uni                       : chr  "Lancaster University " "Lancaster University " "Lancaster University " "Lancaster University " ...
 $ Building                  : chr  " Graduate College " " Management School " " SW hse 32-33 " " SW hse 29 " ...
 $ Floor                     : chr  " A Floor" " C Floor" " D Floor" " B floor" ...
unique(wifi$Building)
 [1] " Graduate College "                 " Management School "                " SW hse 32-33 "                    
 [4] " SW hse 29 "                        " Furness outer "                    " Slaidburn House (LUSU) "          
 [7] " SW hse 34 "                        " Bowland hall "                     " Fylde "                           
[10] " SW hse 55-56 "                     " SW hse 40-42 "                     " Bowland Twr (Old Bowland Annexe) "
[13] " Pendle "                           " Faraday and cTAP "                 " Institute for Advanced Studies "  
[16] " University House "                 " SW hse 53-54 "                     " Engineering "                     
[19] " Field Station "                    " SW hse 36 "                        " Infolab "                         
[22] " SW hse 21-23 "                     " LICA "                             " FU Hse 71-74 "                    
[25] " Grizedale "                        " Charles Carter "                   " Furness "                         
[28] " SW hse 43-45 "                     " SW hse 12-16 "                     " Bowland Main "                    
[31] " SW hse 35 "                        " Human Resources "                  " County "                          
[34] " FY Hse 65-70 "                     " Barker House Farm "                " SW hse 27-28 "                    
[37] " Bowland Annexe "                   " John Creed "                       " grize-res "                       
[40] " SW hse 24-26 "                     " SW hse 20 "                        " Ruskin Library "                  
[43] " County South/Cartmel "             " Library "                          " Conference Centre "               
[46] " Postgrad Stats (PSC) "             " Bowland North "                    " George Fox "                      
[49] " Hse 75 77 "                        " Bailrigg House "                   " Sports Centre "                   
[52] " SW hse 30-31 "                     " Bowland Ash "                      " Alex Square "                     
[55] " LEC "                              " MDC "                              " ISS Building "                    
[58] " Chaplaincy Centre "                " CETAD "                            " SW hse 50-52 "                    
[61] " SW hse 17-19 "                     " Central Workshops "                " SW hse 46-49 "                    
[64] " SW hse 39 "                        " Science and technology "           " Whewell "                         
[67] " SW hse 37-38 "                     " Lonsdale College (SW) "            " Physics "                         
[70] " County Field "                     " Great Hall "                       " SW hse-158-179 "                  
[73] " Preschool "                        " Reception "                        " Hazelrigg "                       
[76] " Energy Centre "                   
wifi=wifi[wifi$Building == " Library ",]
head(wifi)
wifi=wifi[,c('time','Associated.Client.Count')]
head(wifi)
wifi=wifi %>%
  mutate(time = floor_date(time, "10 minutes")) %>%
  group_by(time) %>%
  summarise(
    occupancy = mean(`Associated.Client.Count`, na.rm = TRUE),
    .groups = "drop"
  )
head(wifi)
colSums(is.na(wifi))
     time occupancy 
        0         0 
sum(duplicated(wifi))
[1] 0
dim(wifi)
[1] 3683    2

Library Energy Data

library1=read.csv('C:/Users/Lenovo/Downloads/library1.csv')
library2=read.csv('C:/Users/Lenovo/Downloads/library2.csv')
library3=read.csv('C:/Users/Lenovo/Downloads/library3.csv')
head(library1)
str(library1)
'data.frame':   18864 obs. of  6 variables:
 $ ts        : chr  "2020-01-01 00:00:00" "2020-01-01 00:10:00" "2020-01-01 00:20:00" "2020-01-01 00:30:00" ...
 $ name      : chr  "MC065-L01/M9R2048" "MC065-L01/M9R2048" "MC065-L01/M9R2048" "MC065-L01/M9R2048" ...
 $ reading   : num  1489442 1489449 1489456 1489464 1489471 ...
 $ units     : chr  "KWh" "KWh" "KWh" "KWh" ...
 $ cumulative: num  1489442 1489449 1489456 1489464 1489471 ...
 $ rate      : num  NA 7 7 8 7 8 7 8 7 8 ...
library1$ts=as.POSIXct(library1$ts)
library2$ts=as.POSIXct(library2$ts)
library3$ts=as.POSIXct(library3$ts)
str(library1)
'data.frame':   18864 obs. of  6 variables:
 $ ts        : POSIXct, format: "2020-01-01 00:00:00" "2020-01-01 00:10:00" "2020-01-01 00:20:00" "2020-01-01 00:30:00" ...
 $ name      : chr  "MC065-L01/M9R2048" "MC065-L01/M9R2048" "MC065-L01/M9R2048" "MC065-L01/M9R2048" ...
 $ reading   : num  1489442 1489449 1489456 1489464 1489471 ...
 $ units     : chr  "KWh" "KWh" "KWh" "KWh" ...
 $ cumulative: num  1489442 1489449 1489456 1489464 1489471 ...
 $ rate      : num  NA 7 7 8 7 8 7 8 7 8 ...
colSums(is.na(library1))
        ts       name    reading      units cumulative       rate 
         0          0       3041          0       3041       3047 
colSums(is.na(library2))
        ts       name    reading      units cumulative       rate 
         0          0       3041          0       3041       3047 
colSums(is.na(library3))
        ts       name    reading      units cumulative       rate 
         0          0       3041          0       3041       3047 
library1$rate[is.na(library1$rate)]=mean(library1$rate[1:144],na.rm = TRUE)
library2$rate[is.na(library2$rate)]=mean(library2$rate[1:144],na.rm = TRUE)
library3$rate[is.na(library3$rate)]=mean(library3$rate[1:144],na.rm = TRUE)
library_all=merge(library1,library2,by='ts',all = TRUE)
library_all=merge(library_all,library3,by='ts',all = TRUE)
head(library_all)
library_all$energy_consumption<-library_all$rate.x + library_all$rate.y + library_all$rate
head(library_all)
names(library_all)[names(library_all)=='ts']='time'
sum(duplicated(library_all))
[1] 0

Data Integration

df=merge(wifi,library_all,by='time',all.x = TRUE)
df=df[,c('time','occupancy','energy_consumption')]
head(df)
dim(df)
[1] 3683    3

Visualization

Time Series Plot: Occupancy & Energy Consumption

ggplot(df, aes(x = time)) +
  geom_line(aes(y = occupancy, color = "Occupancy")) +
  geom_line(aes(y = energy_consumption, color = "Energy Consumption")) +
  scale_color_manual(values = c("Occupancy" = "blue", "Energy Consumption" = "red")) +
  labs(title = "Time Series of Occupancy and Energy Consumption",
       x = "Time",
       y = "Value",
       color = "Legend") +
  theme_minimal() +
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5))

Scatter Plot: Occupancy vs Energy Consumption

ggplot(df, aes(x = occupancy, y = energy_consumption)) +
  geom_point(alpha = 0.5, color = "blue") +
  labs(title = "Scatter Plot: Occupancy vs Energy Consumption",
       x = "Occupancy (Number of Clients)",
       y = "Energy Consumption (kWh)") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Daily Profiles (24h)

Occupancy

df = df %>%
  mutate(
    date = as.Date(time),
    hour = hour(time) + minute(time)/60
  )
ggplot(df, aes(x = hour, y = occupancy, group = date)) +
  geom_line(alpha = 0.1, color = "blue") +
  geom_line(
    data = df %>% group_by(hour) %>% summarise(avg_occ = mean(occupancy, na.rm=TRUE)),
    aes(x = hour, y = avg_occ, group = 1),
    color = "blue", size = 1.2
  ) +
  labs(
    title = "Daily Profiles of Occupancy",
    x = "Hour of Day",
    y = "Occupancy"
  ) +
  scale_x_continuous(breaks = seq(0, 24, 1)) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

df = df %>%
  mutate(
    date = as.Date(time),
    hour_decimal = hour(time) + minute(time)/60
  )
ggplot(df, aes(x = hour_decimal, y = occupancy, group = date)) +
  geom_line(alpha = 0.1, color = "blue") +
  geom_line(
    data = df %>% group_by(hour_decimal) %>% summarise(avg_occ = mean(occupancy, na.rm=TRUE)),
    aes(x = hour_decimal, y = avg_occ, group = 1),
    color = "blue", size = 1.2
  ) +
  labs(
    title = "Daily Profiles of Occupancy",
    x = "Time of Day",
    y = "Occupancy"
  ) +
  scale_x_continuous(
    breaks = seq(0, 24, by = 1/6),         
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x %% 1) * 60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Energy Consumption

ggplot(df, aes(x = hour, y = energy_consumption, group = date)) +
  geom_line(alpha = 0.1, color = "red") +
  geom_line(
    data = df %>% group_by(hour) %>% summarise(avg_energy = mean(energy_consumption, na.rm=TRUE)),
    aes(x = hour, y = avg_energy, group = 1),
    color = "red", size = 1.2
  ) +
  labs(
    title = "Daily Profiles of Energy Consumption",
    x = "Hour of Day",
    y = "Energy Consumption"
  ) +
  scale_x_continuous(breaks = seq(0, 24, 1)) +
  theme_minimal()+
  theme(plot.title = element_text(hjust = 0.5))

ggplot(df, aes(x = hour_decimal, y = energy_consumption, group = date)) +
  geom_line(alpha = 0.1, color = "red") +
  geom_line(
    data = df %>% group_by(hour_decimal) %>% summarise(avg_energy = mean(energy_consumption, na.rm=TRUE)),
    aes(x = hour_decimal, y = avg_energy, group = 1),
    color = "red", size = 1.2
  ) +
  labs(
    title = "Daily Profiles of Energy Consumption",
    x = "Time of Day",
    y = "Energy Consumption"
  ) +
  scale_x_continuous(
    breaks = seq(0, 24, by = 1/6),        
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x %% 1) * 60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Analysis

Peak Hour Occupancy

df_avg_hour <- df %>%
  group_by(hour_label = format(time, "%H:00")) %>% 
  summarise(mean_occupancy = base::mean(occupancy, na.rm = TRUE), .groups = "drop") %>%
arrange(hour_label)
peak_hours <- dplyr::arrange(df_avg_hour, desc(mean_occupancy))
head(peak_hours)
ggplot(df_avg_hour, aes(x = hour_label, y = mean_occupancy, group = 1)) +
  geom_line(color = "blue", linewidth = 1) +
  geom_point(color = "red", size = 3) +
  labs(
    title = "Rata-rata Occupancy per Jam",
    x = "Jam (00:00–23:00)",
    y = "Rata-rata Occupancy"
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5))

Correlation

corr=cor(electricity$mean_client_count, electricity$total_electricity)
corr
[1] 0.8782117

Time Series Regression

df_reg <- df %>%
  arrange(time) %>%
  mutate(t = row_number(),
         hour = factor(format(time, "%H")))
model_tslm <- lm(energy_consumption ~ occupancy + t + hour, data = df_reg)
summary(model_tslm)

Call:
lm(formula = energy_consumption ~ occupancy + t + hour, data = df_reg)

Residuals:
    Min      1Q  Median      3Q     Max 
-55.416  -8.208   0.084   8.520  55.706 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  1.162e+02  1.097e+00 105.958  < 2e-16 ***
occupancy    1.763e-01  3.346e-03  52.688  < 2e-16 ***
t            9.812e-04  2.033e-04   4.825 1.46e-06 ***
hour01      -7.731e+00  1.463e+00  -5.286 1.32e-07 ***
hour02      -1.517e+01  1.463e+00 -10.367  < 2e-16 ***
hour03      -2.251e+01  1.465e+00 -15.368  < 2e-16 ***
hour04      -3.260e+01  1.465e+00 -22.263  < 2e-16 ***
hour05      -4.356e+01  1.465e+00 -29.738  < 2e-16 ***
hour06      -4.390e+01  1.466e+00 -29.952  < 2e-16 ***
hour07      -3.567e+01  1.465e+00 -24.346  < 2e-16 ***
hour08      -1.530e+01  1.462e+00 -10.468  < 2e-16 ***
hour09      -1.983e+00  1.468e+00  -1.351    0.177    
hour10       7.604e+00  1.538e+00   4.945 7.97e-07 ***
hour11       8.377e+00  1.637e+00   5.117 3.26e-07 ***
hour12       1.191e+01  1.700e+00   7.006 2.91e-12 ***
hour13       1.155e+01  1.758e+00   6.568 5.81e-11 ***
hour14       8.922e+00  1.819e+00   4.905 9.75e-07 ***
hour15       9.191e+00  1.845e+00   4.982 6.57e-07 ***
hour16       1.284e+01  1.796e+00   7.147 1.06e-12 ***
hour17       1.907e+01  1.700e+00  11.215  < 2e-16 ***
hour18       2.014e+01  1.611e+00  12.504  < 2e-16 ***
hour19       2.170e+01  1.562e+00  13.889  < 2e-16 ***
hour20       2.130e+01  1.530e+00  13.924  < 2e-16 ***
hour21       1.992e+01  1.509e+00  13.202  < 2e-16 ***
hour22       1.912e+01  1.490e+00  12.832  < 2e-16 ***
hour23       1.143e+01  1.479e+00   7.726 1.42e-14 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 12.91 on 3657 degrees of freedom
Multiple R-squared:  0.9133,    Adjusted R-squared:  0.9127 
F-statistic:  1541 on 25 and 3657 DF,  p-value: < 2.2e-16

Time Series Plot

df$fitted <- fitted(model_tslm)

ggplot(df, aes(x = time)) +
  geom_line(aes(y = energy_consumption, color = "Observed"), linewidth = 0.8, alpha = 0.7) +
  geom_line(aes(y = fitted, color = "Fitted"), linewidth = 1) +
  scale_color_manual(values = c("Observed" = "blue", "Fitted" = "red")) +
  labs(
    title = "Time Series Regression",
    x = "Time",
    y = "Energy Consumption",
    color = ""
  ) +
  theme_minimal(base_size = 14)+
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5))

Weekend vs Weekday Comparison

# Separate data into weekdays and weekends
df$time <- as_datetime(df$time)
df$day_of_week <- wday(df$time, week_start = 1) - 1
df_weekday <- df %>% filter(day_of_week < 5)
df_weekend <- df %>% filter(day_of_week >= 5)
df_weekday$time_of_day <- hms::as_hms(df_weekday$time)
df_weekend$time_of_day <- hms::as_hms(df_weekend$time)

Time Series Plot for Weekdays

ggplot(df_weekday, aes(x = time)) +
  geom_line(aes(y = occupancy, color = "Occupancy")) +
  geom_line(aes(y = energy_consumption, color = "Energy Consumption")) +
  labs(title = "Time Series: Occupancy vs Energy Consumption (Weekdays)",
       x = "Time",
       y = "Value") +
  scale_color_manual(values = c("Occupancy" = "blue", "Energy Consumption" = "red")) +
  theme_minimal() +
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5))

Time Series Plot for Weekends

ggplot(df_weekend, aes(x = time)) +
  geom_line(aes(y = occupancy, color = "Occupancy")) +
  geom_line(aes(y = energy_consumption, color = "Energy Consumption")) +
  labs(title = "Time Series: Occupancy vs Energy Consumption (Weekends)",
       x = "Time",
       y = "Value") +
  scale_color_manual(values = c("Occupancy" = "blue", "Energy Consumption" = "red")) +
  theme_minimal() +
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5))

Time Series Plot for Weekdays and Weekends

ggplot(df, aes(x = time)) +
  geom_line(data = df_weekday, aes(y = occupancy, color = "Occupancy - Weekdays")) +
  geom_line(data = df_weekday, aes(y = energy_consumption, color = "Energy Consumption - Weekdays")) +
  geom_line(data = df_weekend, aes(y = occupancy, color = "Occupancy - Weekends"), linetype = "dashed") +
  geom_line(data = df_weekend, aes(y = energy_consumption, color = "Energy Consumption - Weekends"), linetype = "dashed") +
  labs(title = "Time Series: Occupancy vs Energy Consumption (Weekdays and Weekends)",
       x = "Time",
       y = "Value") +
  scale_color_manual(values = c("Occupancy - Weekdays" = "blue", "Energy Consumption - Weekdays" = "red",
                                "Occupancy - Weekends" = "cyan", "Energy Consumption - Weekends" = "magenta")) +
  theme_minimal() +
  theme(legend.position = "bottom", plot.title = element_text(hjust = 0.5))

Scatter Plot for Weekdays

ggplot(df_weekday, aes(x = occupancy, y = energy_consumption)) +
  geom_point(alpha = 0.4, color = "blue") +
  labs(title = "Scatter Plot: Occupancy vs Energy (Weekdays)",
       x = "Occupancy (WiFi Clients)",
       y = "Energy Consumption") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Scatter Plot for Weekends

ggplot(df_weekend, aes(x = occupancy, y = energy_consumption)) +
  geom_point(alpha = 0.4, color = "red") +
  labs(title = "Scatter Plot: Occupancy vs Energy (Weekends)",
       x = "Occupancy (WiFi Clients)",
       y = "Energy Consumption") +
  theme_minimal() + 
  theme(plot.title = element_text(hjust = 0.5))

Scatter Plot for Weekdays and Weekends

ggplot(df, aes(x = occupancy, y = energy_consumption, color = factor(day_of_week < 5))) +
  geom_point(alpha = 0.4) +
  scale_color_manual(values = c("TRUE" = "blue", "FALSE" = "red"), labels = c("Weekdays", "Weekends")) +
  labs(title = "Scatter Plot: Occupancy vs Energy (Weekdays and Weekends)",
       x = "Occupancy (WiFi Clients)",
       y = "Energy Consumption",
       color = "Day Type") +
  theme_minimal() +
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5))

Daily Profiles (24h) - Occupancy for Weekdays

df_weekday$hour <- hour(df_weekday$time) + minute(df_weekday$time)/60.0
ggplot(df_weekday, aes(x = hour, y = occupancy, group = date(time))) +
  geom_line(alpha = 0.2, color = "blue") +
  stat_summary(aes(group = 1), fun = mean, geom = "line", color = "blue", size = 1.5, linetype = "solid") +
  labs(title = "Daily Profiles of Occupancy (Weekdays)",
       x = "Time of Day",
       y = "Occupancy (WiFi Clients)") +
  scale_x_continuous(
    breaks = seq(0, 24, by = 10/60),   # interval 10 menit
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Daily Profiles (24h) - Occupancy for Weekends

df_weekend$hour <- hour(df_weekend$time) + minute(df_weekend$time)/60.0
ggplot(df_weekend, aes(x = hour, y = occupancy, group = date(time))) +
  geom_line(alpha = 0.2, color = "blue") +
  stat_summary(aes(group = 1), fun = mean, geom = "line", color = "blue", size = 1.5, linetype = "solid") +
  labs(title = "Daily Profiles of Occupancy (Weekends)",
       x = "Time of Day",
       y = "Occupancy (WiFi Clients)") +
    scale_x_continuous(
    breaks = seq(0, 24, by = 10/60),
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Daily Profiles (24h) - Occupancy (Weekdays and Weekends)

df$hour <- hour(df$time) + minute(df$time)/60.0
ggplot(df, aes(x = hour, y = occupancy, group = date(time))) +
  geom_line(data = df_weekday, aes(color = "Weekdays"), alpha = 0.2) +
  stat_summary(data = df_weekday, aes(color = "Weekdays", group = 1), fun = mean, geom = "line", size = 1.5, linetype = "solid") +
  geom_line(data = df_weekend, aes(color = "Weekends"), alpha = 0.2, linetype = "dashed") +
  stat_summary(data = df_weekend, aes(color = "Weekends", group = 1), fun = mean, geom = "line", size = 1.5, linetype = "dashed") +
  labs(title = "Daily Profiles of Occupancy (Weekdays and Weekends)",
       x = "Time of Day",
       y = "Occupancy (WiFi Clients)") +
  scale_color_manual(values = c("Weekdays" = "red", "Weekends" = "blue")) +
  scale_x_continuous(
  breaks = seq(0, 24, by = 10/60),
  labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal() +
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5,size=30),
        axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Daily Profiles (24h) - Energy Consumption for Weekdays

ggplot(df_weekday, aes(x = hour, y = energy_consumption, group = date(time))) +
  geom_line(alpha = 0.2, color = "red") +
  stat_summary(aes(group = 1), fun = mean, geom = "line", color = "red", size = 1.5, linetype = "solid") +
  labs(title = "Daily Profiles of Energy Consumption (Weekdays)",
       x = "Time of Day",
       y = "Energy Consumption") +
  scale_x_continuous(
    breaks = seq(0, 24, by = 10/60),   # interval 10 menit
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),
        axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Daily Profiles (24h) - Energy Consumption for Weekends

ggplot(df_weekend, aes(x = hour, y = energy_consumption, group = date(time))) +
  geom_line(alpha = 0.2, color = "red") +
  stat_summary(aes(group = 1), fun = mean, geom = "line", color = "red", size = 1.5, linetype = "solid") +
  labs(title = "Daily Profiles of Energy Consumption (Weekends)",
       x = "Time of Day",
       y = "Energy Consumption") +
  scale_x_continuous(
    breaks = seq(0, 24, by = 10/60),   # interval 10 menit
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5,size=30),
        axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

Daily Profiles (24h) - Energy Consumption (Weekdays and Weekends)

ggplot(df, aes(x = hour, y = energy_consumption, group = date(time))) +
  geom_line(data = df_weekday, aes(color = "Weekdays"), alpha = 0.2) +
  stat_summary(data = df_weekday, aes(color = "Weekdays", group = 1), fun = mean, geom = "line", size = 1.5, linetype = "solid") +
  geom_line(data = df_weekend, aes(color = "Weekends"), alpha = 0.2, linetype = "dashed") +
  stat_summary(data = df_weekend, aes(color = "Weekends", group = 1), fun = mean, geom = "line", size = 1.5, linetype = "dashed") +
  labs(title = "Daily Profiles of Energy Consumption (Weekdays and Weekends)",
       x = "Time of Day",
       y = "Energy Consumption") +
  scale_color_manual(values = c("Weekdays" = "red", "Weekends" = "blue")) +
  scale_x_continuous(
    breaks = seq(0, 24, by = 10/60),   # interval 10 menit
    labels = function(x) sprintf("%02d:%02d", floor(x), round((x%%1)*60))
  ) +
  theme_minimal()+
  theme(legend.position = "bottom",plot.title = element_text(hjust = 0.5,size=30),
        axis.text.x = element_text(angle = 90, hjust = 1, size = 15))

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMjogRGF0YSBNaW5pbmcgTWFkbmVzcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCktlbG9tcG9rIDEwOiAgDQoxLiBGYXRoYXRpYSBDaG9saWRhIFN5aWZhICg1MDAzMjMxMDcwKSAgDQoyLiBTdWhhbnVyIEhhbGl6YSAoNTAwMzIzMTA3OCkgIA0KMy4gRGlhenR5IElmdGEgUGFkdmFuaSAoNTAwMzIzMTE3MSkgIA0KNC4gUGluZ2t5IE9rdGFuaWEgVGF0YSBTZWZpbmEgKDUwMDMyMzExODQpDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KYGBgDQoNCiMgKipGaWx0ZXJpbmcgJiBDbGVhbmluZyBEYXRhKioNCg0KV2lGaSBEYXRhDQpgYGB7cn0NCndpZmk9cmVhZC5jc3YoJ0M6L1VzZXJzL0xlbm92by9Eb3dubG9hZHMvd2lmaS5jc3YnKQ0KaGVhZCh3aWZpKQ0KYGBgDQoNCg0KYGBge3J9DQpjb2xuYW1lcyh3aWZpKQ0KYGBgDQoNCg0KYGBge3J9DQpzdHIod2lmaSkNCmBgYA0KDQoNCmBgYHtyfQ0Kd2lmaSR0aW1lPWFzLlBPU0lYY3Qod2lmaSR0aW1lKQ0Kc3RyKHdpZmkpDQpgYGANCg0KDQpgYGB7cn0NCnVuaXF1ZSh3aWZpJEJ1aWxkaW5nKQ0KYGBgDQoNCg0KYGBge3J9DQp3aWZpPXdpZmlbd2lmaSRCdWlsZGluZyA9PSAiIExpYnJhcnkgIixdDQpoZWFkKHdpZmkpDQpgYGANCg0KDQpgYGB7cn0NCndpZmk9d2lmaVssYygndGltZScsJ0Fzc29jaWF0ZWQuQ2xpZW50LkNvdW50JyldDQpoZWFkKHdpZmkpDQpgYGANCg0KDQpgYGB7cn0NCndpZmk9d2lmaSAlPiUNCiAgbXV0YXRlKHRpbWUgPSBmbG9vcl9kYXRlKHRpbWUsICIxMCBtaW51dGVzIikpICU+JQ0KICBncm91cF9ieSh0aW1lKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG9jY3VwYW5jeSA9IG1lYW4oYEFzc29jaWF0ZWQuQ2xpZW50LkNvdW50YCwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCmhlYWQod2lmaSkNCmBgYA0KDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYSh3aWZpKSkNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtKGR1cGxpY2F0ZWQod2lmaSkpDQpgYGANCg0KDQpgYGB7cn0NCmRpbSh3aWZpKQ0KYGBgDQogIA0KTGlicmFyeSBFbmVyZ3kgRGF0YQ0KYGBge3J9DQpsaWJyYXJ5MT1yZWFkLmNzdignQzovVXNlcnMvTGVub3ZvL0Rvd25sb2Fkcy9saWJyYXJ5MS5jc3YnKQ0KbGlicmFyeTI9cmVhZC5jc3YoJ0M6L1VzZXJzL0xlbm92by9Eb3dubG9hZHMvbGlicmFyeTIuY3N2JykNCmxpYnJhcnkzPXJlYWQuY3N2KCdDOi9Vc2Vycy9MZW5vdm8vRG93bmxvYWRzL2xpYnJhcnkzLmNzdicpDQpgYGANCg0KDQpgYGB7cn0NCmhlYWQobGlicmFyeTEpDQpgYGANCg0KDQpgYGB7cn0NCnN0cihsaWJyYXJ5MSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeTEkdHM9YXMuUE9TSVhjdChsaWJyYXJ5MSR0cykNCmxpYnJhcnkyJHRzPWFzLlBPU0lYY3QobGlicmFyeTIkdHMpDQpsaWJyYXJ5MyR0cz1hcy5QT1NJWGN0KGxpYnJhcnkzJHRzKQ0KYGBgDQoNCg0KYGBge3J9DQpzdHIobGlicmFyeTEpDQpgYGANCg0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEobGlicmFyeTEpKQ0KYGBgDQoNCg0KYGBge3J9DQpjb2xTdW1zKGlzLm5hKGxpYnJhcnkyKSkNCmBgYA0KDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShsaWJyYXJ5MykpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkxJHJhdGVbaXMubmEobGlicmFyeTEkcmF0ZSldPW1lYW4obGlicmFyeTEkcmF0ZVsxOjE0NF0sbmEucm0gPSBUUlVFKQ0KbGlicmFyeTIkcmF0ZVtpcy5uYShsaWJyYXJ5MiRyYXRlKV09bWVhbihsaWJyYXJ5MiRyYXRlWzE6MTQ0XSxuYS5ybSA9IFRSVUUpDQpsaWJyYXJ5MyRyYXRlW2lzLm5hKGxpYnJhcnkzJHJhdGUpXT1tZWFuKGxpYnJhcnkzJHJhdGVbMToxNDRdLG5hLnJtID0gVFJVRSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeV9hbGw9bWVyZ2UobGlicmFyeTEsbGlicmFyeTIsYnk9J3RzJyxhbGwgPSBUUlVFKQ0KbGlicmFyeV9hbGw9bWVyZ2UobGlicmFyeV9hbGwsbGlicmFyeTMsYnk9J3RzJyxhbGwgPSBUUlVFKQ0KaGVhZChsaWJyYXJ5X2FsbCkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeV9hbGwkZW5lcmd5X2NvbnN1bXB0aW9uPC1saWJyYXJ5X2FsbCRyYXRlLnggKyBsaWJyYXJ5X2FsbCRyYXRlLnkgKyBsaWJyYXJ5X2FsbCRyYXRlDQpoZWFkKGxpYnJhcnlfYWxsKQ0KYGBgDQoNCg0KYGBge3J9DQpuYW1lcyhsaWJyYXJ5X2FsbClbbmFtZXMobGlicmFyeV9hbGwpPT0ndHMnXT0ndGltZScNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtKGR1cGxpY2F0ZWQobGlicmFyeV9hbGwpKQ0KYGBgDQoNCiMgKipEYXRhIEludGVncmF0aW9uKioNCmBgYHtyfQ0KZGY9bWVyZ2Uod2lmaSxsaWJyYXJ5X2FsbCxieT0ndGltZScsYWxsLnggPSBUUlVFKQ0KZGY9ZGZbLGMoJ3RpbWUnLCdvY2N1cGFuY3knLCdlbmVyZ3lfY29uc3VtcHRpb24nKV0NCmhlYWQoZGYpDQpgYGANCg0KDQpgYGB7cn0NCmRpbShkZikNCmBgYA0KDQojICoqVmlzdWFsaXphdGlvbioqDQo+IFRpbWUgU2VyaWVzIFBsb3Q6IE9jY3VwYW5jeSAmIEVuZXJneSBDb25zdW1wdGlvbg0KDQpgYGB7cn0NCmdncGxvdChkZiwgYWVzKHggPSB0aW1lKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBvY2N1cGFuY3ksIGNvbG9yID0gIk9jY3VwYW5jeSIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IGVuZXJneV9jb25zdW1wdGlvbiwgY29sb3IgPSAiRW5lcmd5IENvbnN1bXB0aW9uIikpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk9jY3VwYW5jeSIgPSAiYmx1ZSIsICJFbmVyZ3kgQ29uc3VtcHRpb24iID0gInJlZCIpKSArDQogIGxhYnModGl0bGUgPSAiVGltZSBTZXJpZXMgb2YgT2NjdXBhbmN5IGFuZCBFbmVyZ3kgQ29uc3VtcHRpb24iLA0KICAgICAgIHggPSAiVGltZSIsDQogICAgICAgeSA9ICJWYWx1ZSIsDQogICAgICAgY29sb3IgPSAiTGVnZW5kIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIixwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KPiBTY2F0dGVyIFBsb3Q6IE9jY3VwYW5jeSB2cyBFbmVyZ3kgQ29uc3VtcHRpb24NCg0KYGBge3J9DQpnZ3Bsb3QoZGYsIGFlcyh4ID0gb2NjdXBhbmN5LCB5ID0gZW5lcmd5X2NvbnN1bXB0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBjb2xvciA9ICJibHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgUGxvdDogT2NjdXBhbmN5IHZzIEVuZXJneSBDb25zdW1wdGlvbiIsDQogICAgICAgeCA9ICJPY2N1cGFuY3kgKE51bWJlciBvZiBDbGllbnRzKSIsDQogICAgICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24gKGtXaCkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQo+IERhaWx5IFByb2ZpbGVzICgyNGgpDQoNCk9jY3VwYW5jeQ0KYGBge3J9DQpkZiA9IGRmICU+JQ0KICBtdXRhdGUoDQogICAgZGF0ZSA9IGFzLkRhdGUodGltZSksDQogICAgaG91ciA9IGhvdXIodGltZSkgKyBtaW51dGUodGltZSkvNjANCiAgKQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXIsIHkgPSBvY2N1cGFuY3ksIGdyb3VwID0gZGF0ZSkpICsNCiAgZ2VvbV9saW5lKGFscGhhID0gMC4xLCBjb2xvciA9ICJibHVlIikgKw0KICBnZW9tX2xpbmUoDQogICAgZGF0YSA9IGRmICU+JSBncm91cF9ieShob3VyKSAlPiUgc3VtbWFyaXNlKGF2Z19vY2MgPSBtZWFuKG9jY3VwYW5jeSwgbmEucm09VFJVRSkpLA0KICAgIGFlcyh4ID0gaG91ciwgeSA9IGF2Z19vY2MsIGdyb3VwID0gMSksDQogICAgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAxLjINCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRGFpbHkgUHJvZmlsZXMgb2YgT2NjdXBhbmN5IiwNCiAgICB4ID0gIkhvdXIgb2YgRGF5IiwNCiAgICB5ID0gIk9jY3VwYW5jeSINCiAgKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjQsIDEpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTMwLCBmaWcuaGVpZ2h0PTEwfQ0KZGYgPSBkZiAlPiUNCiAgbXV0YXRlKA0KICAgIGRhdGUgPSBhcy5EYXRlKHRpbWUpLA0KICAgIGhvdXJfZGVjaW1hbCA9IGhvdXIodGltZSkgKyBtaW51dGUodGltZSkvNjANCiAgKQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXJfZGVjaW1hbCwgeSA9IG9jY3VwYW5jeSwgZ3JvdXAgPSBkYXRlKSkgKw0KICBnZW9tX2xpbmUoYWxwaGEgPSAwLjEsIGNvbG9yID0gImJsdWUiKSArDQogIGdlb21fbGluZSgNCiAgICBkYXRhID0gZGYgJT4lIGdyb3VwX2J5KGhvdXJfZGVjaW1hbCkgJT4lIHN1bW1hcmlzZShhdmdfb2NjID0gbWVhbihvY2N1cGFuY3ksIG5hLnJtPVRSVUUpKSwNCiAgICBhZXMoeCA9IGhvdXJfZGVjaW1hbCwgeSA9IGF2Z19vY2MsIGdyb3VwID0gMSksDQogICAgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAxLjINCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRGFpbHkgUHJvZmlsZXMgb2YgT2NjdXBhbmN5IiwNCiAgICB4ID0gIlRpbWUgb2YgRGF5IiwNCiAgICB5ID0gIk9jY3VwYW5jeSINCiAgKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEoMCwgMjQsIGJ5ID0gMS82KSwgICAgICAgICANCiAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSBzcHJpbnRmKCIlMDJkOiUwMmQiLCBmbG9vcih4KSwgcm91bmQoKHggJSUgMSkgKiA2MCkpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHNpemU9MzApLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE1KSkNCmBgYA0KDQpFbmVyZ3kgQ29uc3VtcHRpb24NCmBgYHtyfQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXIsIHkgPSBlbmVyZ3lfY29uc3VtcHRpb24sIGdyb3VwID0gZGF0ZSkpICsNCiAgZ2VvbV9saW5lKGFscGhhID0gMC4xLCBjb2xvciA9ICJyZWQiKSArDQogIGdlb21fbGluZSgNCiAgICBkYXRhID0gZGYgJT4lIGdyb3VwX2J5KGhvdXIpICU+JSBzdW1tYXJpc2UoYXZnX2VuZXJneSA9IG1lYW4oZW5lcmd5X2NvbnN1bXB0aW9uLCBuYS5ybT1UUlVFKSksDQogICAgYWVzKHggPSBob3VyLCB5ID0gYXZnX2VuZXJneSwgZ3JvdXAgPSAxKSwNCiAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMS4yDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRhaWx5IFByb2ZpbGVzIG9mIEVuZXJneSBDb25zdW1wdGlvbiIsDQogICAgeCA9ICJIb3VyIG9mIERheSIsDQogICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24iDQogICkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDI0LCAxKSkgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTMwLCBmaWcuaGVpZ2h0PTEwfQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXJfZGVjaW1hbCwgeSA9IGVuZXJneV9jb25zdW1wdGlvbiwgZ3JvdXAgPSBkYXRlKSkgKw0KICBnZW9tX2xpbmUoYWxwaGEgPSAwLjEsIGNvbG9yID0gInJlZCIpICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBkZiAlPiUgZ3JvdXBfYnkoaG91cl9kZWNpbWFsKSAlPiUgc3VtbWFyaXNlKGF2Z19lbmVyZ3kgPSBtZWFuKGVuZXJneV9jb25zdW1wdGlvbiwgbmEucm09VFJVRSkpLA0KICAgIGFlcyh4ID0gaG91cl9kZWNpbWFsLCB5ID0gYXZnX2VuZXJneSwgZ3JvdXAgPSAxKSwNCiAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMS4yDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRhaWx5IFByb2ZpbGVzIG9mIEVuZXJneSBDb25zdW1wdGlvbiIsDQogICAgeCA9ICJUaW1lIG9mIERheSIsDQogICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24iDQogICkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgYnJlYWtzID0gc2VxKDAsIDI0LCBieSA9IDEvNiksICAgICAgICANCiAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSBzcHJpbnRmKCIlMDJkOiUwMmQiLCBmbG9vcih4KSwgcm91bmQoKHggJSUgMSkgKiA2MCkpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHNpemU9MzApLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE1KSkNCmBgYA0KDQojICoqQW5hbHlzaXMqKg0KPiBQZWFrIEhvdXIgT2NjdXBhbmN5DQoNCmBgYHtyfQ0KZGZfYXZnX2hvdXIgPC0gZGYgJT4lDQogIGdyb3VwX2J5KGhvdXJfbGFiZWwgPSBmb3JtYXQodGltZSwgIiVIOjAwIikpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5fb2NjdXBhbmN5ID0gYmFzZTo6bWVhbihvY2N1cGFuY3ksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQ0KYXJyYW5nZShob3VyX2xhYmVsKQ0KcGVha19ob3VycyA8LSBkcGx5cjo6YXJyYW5nZShkZl9hdmdfaG91ciwgZGVzYyhtZWFuX29jY3VwYW5jeSkpDQpoZWFkKHBlYWtfaG91cnMpDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChkZl9hdmdfaG91ciwgYWVzKHggPSBob3VyX2xhYmVsLCB5ID0gbWVhbl9vY2N1cGFuY3ksIGdyb3VwID0gMSkpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAxKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAicmVkIiwgc2l6ZSA9IDMpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSYXRhLXJhdGEgT2NjdXBhbmN5IHBlciBKYW0iLA0KICAgIHggPSAiSmFtICgwMDowMOKAkzIzOjAwKSIsDQogICAgeSA9ICJSYXRhLXJhdGEgT2NjdXBhbmN5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQo+IENvcnJlbGF0aW9uDQoNCmBgYHtyfQ0KY29ycj1jb3IoZWxlY3RyaWNpdHkkbWVhbl9jbGllbnRfY291bnQsIGVsZWN0cmljaXR5JHRvdGFsX2VsZWN0cmljaXR5KQ0KY29ycg0KYGBgDQoNCj4gVGltZSBTZXJpZXMgUmVncmVzc2lvbg0KDQpgYGB7cn0NCmRmX3JlZyA8LSBkZiAlPiUNCiAgYXJyYW5nZSh0aW1lKSAlPiUNCiAgbXV0YXRlKHQgPSByb3dfbnVtYmVyKCksDQogICAgICAgICBob3VyID0gZmFjdG9yKGZvcm1hdCh0aW1lLCAiJUgiKSkpDQptb2RlbF90c2xtIDwtIGxtKGVuZXJneV9jb25zdW1wdGlvbiB+IG9jY3VwYW5jeSArIHQgKyBob3VyLCBkYXRhID0gZGZfcmVnKQ0Kc3VtbWFyeShtb2RlbF90c2xtKQ0KYGBgDQo+IFRpbWUgU2VyaWVzIFBsb3QNCg0KYGBge3J9DQpkZiRmaXR0ZWQgPC0gZml0dGVkKG1vZGVsX3RzbG0pDQoNCmdncGxvdChkZiwgYWVzKHggPSB0aW1lKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBlbmVyZ3lfY29uc3VtcHRpb24sIGNvbG9yID0gIk9ic2VydmVkIiksIGxpbmV3aWR0aCA9IDAuOCwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZml0dGVkLCBjb2xvciA9ICJGaXR0ZWQiKSwgbGluZXdpZHRoID0gMSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiT2JzZXJ2ZWQiID0gImJsdWUiLCAiRml0dGVkIiA9ICJyZWQiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlRpbWUgU2VyaWVzIFJlZ3Jlc3Npb24iLA0KICAgIHggPSAiVGltZSIsDQogICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24iLA0KICAgIGNvbG9yID0gIiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIixwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQojICoqV2Vla2VuZCB2cyBXZWVrZGF5IENvbXBhcmlzb24qKg0KYGBge3J9DQojIFNlcGFyYXRlIGRhdGEgaW50byB3ZWVrZGF5cyBhbmQgd2Vla2VuZHMNCmRmJHRpbWUgPC0gYXNfZGF0ZXRpbWUoZGYkdGltZSkNCmRmJGRheV9vZl93ZWVrIDwtIHdkYXkoZGYkdGltZSwgd2Vla19zdGFydCA9IDEpIC0gMQ0KZGZfd2Vla2RheSA8LSBkZiAlPiUgZmlsdGVyKGRheV9vZl93ZWVrIDwgNSkNCmRmX3dlZWtlbmQgPC0gZGYgJT4lIGZpbHRlcihkYXlfb2Zfd2VlayA+PSA1KQ0KYGBgDQoNCg0KYGBge3J9DQpkZl93ZWVrZGF5JHRpbWVfb2ZfZGF5IDwtIGhtczo6YXNfaG1zKGRmX3dlZWtkYXkkdGltZSkNCmRmX3dlZWtlbmQkdGltZV9vZl9kYXkgPC0gaG1zOjphc19obXMoZGZfd2Vla2VuZCR0aW1lKQ0KYGBgDQoNCj4gVGltZSBTZXJpZXMgUGxvdCBmb3IgV2Vla2RheXMNCg0KYGBge3J9DQpnZ3Bsb3QoZGZfd2Vla2RheSwgYWVzKHggPSB0aW1lKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBvY2N1cGFuY3ksIGNvbG9yID0gIk9jY3VwYW5jeSIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IGVuZXJneV9jb25zdW1wdGlvbiwgY29sb3IgPSAiRW5lcmd5IENvbnN1bXB0aW9uIikpICsNCiAgbGFicyh0aXRsZSA9ICJUaW1lIFNlcmllczogT2NjdXBhbmN5IHZzIEVuZXJneSBDb25zdW1wdGlvbiAoV2Vla2RheXMpIiwNCiAgICAgICB4ID0gIlRpbWUiLA0KICAgICAgIHkgPSAiVmFsdWUiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJPY2N1cGFuY3kiID0gImJsdWUiLCAiRW5lcmd5IENvbnN1bXB0aW9uIiA9ICJyZWQiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIixwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQo+IFRpbWUgU2VyaWVzIFBsb3QgZm9yIFdlZWtlbmRzDQoNCmBgYHtyfQ0KZ2dwbG90KGRmX3dlZWtlbmQsIGFlcyh4ID0gdGltZSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gb2NjdXBhbmN5LCBjb2xvciA9ICJPY2N1cGFuY3kiKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBlbmVyZ3lfY29uc3VtcHRpb24sIGNvbG9yID0gIkVuZXJneSBDb25zdW1wdGlvbiIpKSArDQogIGxhYnModGl0bGUgPSAiVGltZSBTZXJpZXM6IE9jY3VwYW5jeSB2cyBFbmVyZ3kgQ29uc3VtcHRpb24gKFdlZWtlbmRzKSIsDQogICAgICAgeCA9ICJUaW1lIiwNCiAgICAgICB5ID0gIlZhbHVlIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiT2NjdXBhbmN5IiA9ICJibHVlIiwgIkVuZXJneSBDb25zdW1wdGlvbiIgPSAicmVkIikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KPiBUaW1lIFNlcmllcyBQbG90IGZvciBXZWVrZGF5cyBhbmQgV2Vla2VuZHMNCg0KYGBge3J9DQpnZ3Bsb3QoZGYsIGFlcyh4ID0gdGltZSkpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkZl93ZWVrZGF5LCBhZXMoeSA9IG9jY3VwYW5jeSwgY29sb3IgPSAiT2NjdXBhbmN5IC0gV2Vla2RheXMiKSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRmX3dlZWtkYXksIGFlcyh5ID0gZW5lcmd5X2NvbnN1bXB0aW9uLCBjb2xvciA9ICJFbmVyZ3kgQ29uc3VtcHRpb24gLSBXZWVrZGF5cyIpKSArDQogIGdlb21fbGluZShkYXRhID0gZGZfd2Vla2VuZCwgYWVzKHkgPSBvY2N1cGFuY3ksIGNvbG9yID0gIk9jY3VwYW5jeSAtIFdlZWtlbmRzIiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkZl93ZWVrZW5kLCBhZXMoeSA9IGVuZXJneV9jb25zdW1wdGlvbiwgY29sb3IgPSAiRW5lcmd5IENvbnN1bXB0aW9uIC0gV2Vla2VuZHMiKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBsYWJzKHRpdGxlID0gIlRpbWUgU2VyaWVzOiBPY2N1cGFuY3kgdnMgRW5lcmd5IENvbnN1bXB0aW9uIChXZWVrZGF5cyBhbmQgV2Vla2VuZHMpIiwNCiAgICAgICB4ID0gIlRpbWUiLA0KICAgICAgIHkgPSAiVmFsdWUiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJPY2N1cGFuY3kgLSBXZWVrZGF5cyIgPSAiYmx1ZSIsICJFbmVyZ3kgQ29uc3VtcHRpb24gLSBXZWVrZGF5cyIgPSAicmVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9jY3VwYW5jeSAtIFdlZWtlbmRzIiA9ICJjeWFuIiwgIkVuZXJneSBDb25zdW1wdGlvbiAtIFdlZWtlbmRzIiA9ICJtYWdlbnRhIikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoNCj4gU2NhdHRlciBQbG90IGZvciBXZWVrZGF5cw0KDQpgYGB7cn0NCmdncGxvdChkZl93ZWVrZGF5LCBhZXMoeCA9IG9jY3VwYW5jeSwgeSA9IGVuZXJneV9jb25zdW1wdGlvbikpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCwgY29sb3IgPSAiYmx1ZSIpICsNCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVyIFBsb3Q6IE9jY3VwYW5jeSB2cyBFbmVyZ3kgKFdlZWtkYXlzKSIsDQogICAgICAgeCA9ICJPY2N1cGFuY3kgKFdpRmkgQ2xpZW50cykiLA0KICAgICAgIHkgPSAiRW5lcmd5IENvbnN1bXB0aW9uIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQo+IFNjYXR0ZXIgUGxvdCBmb3IgV2Vla2VuZHMNCg0KYGBge3J9DQpnZ3Bsb3QoZGZfd2Vla2VuZCwgYWVzKHggPSBvY2N1cGFuY3ksIHkgPSBlbmVyZ3lfY29uc3VtcHRpb24pKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjQsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVyIFBsb3Q6IE9jY3VwYW5jeSB2cyBFbmVyZ3kgKFdlZWtlbmRzKSIsDQogICAgICAgeCA9ICJPY2N1cGFuY3kgKFdpRmkgQ2xpZW50cykiLA0KICAgICAgIHkgPSAiRW5lcmd5IENvbnN1bXB0aW9uIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KPiBTY2F0dGVyIFBsb3QgZm9yIFdlZWtkYXlzIGFuZCBXZWVrZW5kcw0KDQpgYGB7cn0NCmdncGxvdChkZiwgYWVzKHggPSBvY2N1cGFuY3ksIHkgPSBlbmVyZ3lfY29uc3VtcHRpb24sIGNvbG9yID0gZmFjdG9yKGRheV9vZl93ZWVrIDwgNSkpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjQpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gImJsdWUiLCAiRkFMU0UiID0gInJlZCIpLCBsYWJlbHMgPSBjKCJXZWVrZGF5cyIsICJXZWVrZW5kcyIpKSArDQogIGxhYnModGl0bGUgPSAiU2NhdHRlciBQbG90OiBPY2N1cGFuY3kgdnMgRW5lcmd5IChXZWVrZGF5cyBhbmQgV2Vla2VuZHMpIiwNCiAgICAgICB4ID0gIk9jY3VwYW5jeSAoV2lGaSBDbGllbnRzKSIsDQogICAgICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24iLA0KICAgICAgIGNvbG9yID0gIkRheSBUeXBlIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIixwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQo+IERhaWx5IFByb2ZpbGVzICgyNGgpIC0gT2NjdXBhbmN5IGZvciBXZWVrZGF5cw0KDQpgYGB7ciBmaWcud2lkdGg9MzAsIGZpZy5oZWlnaHQ9MTB9DQpkZl93ZWVrZGF5JGhvdXIgPC0gaG91cihkZl93ZWVrZGF5JHRpbWUpICsgbWludXRlKGRmX3dlZWtkYXkkdGltZSkvNjAuMA0KZ2dwbG90KGRmX3dlZWtkYXksIGFlcyh4ID0gaG91ciwgeSA9IG9jY3VwYW5jeSwgZ3JvdXAgPSBkYXRlKHRpbWUpKSkgKw0KICBnZW9tX2xpbmUoYWxwaGEgPSAwLjIsIGNvbG9yID0gImJsdWUiKSArDQogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSAxKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAxLjUsIGxpbmV0eXBlID0gInNvbGlkIikgKw0KICBsYWJzKHRpdGxlID0gIkRhaWx5IFByb2ZpbGVzIG9mIE9jY3VwYW5jeSAoV2Vla2RheXMpIiwNCiAgICAgICB4ID0gIlRpbWUgb2YgRGF5IiwNCiAgICAgICB5ID0gIk9jY3VwYW5jeSAoV2lGaSBDbGllbnRzKSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgwLCAyNCwgYnkgPSAxMC82MCksICAgIyBpbnRlcnZhbCAxMCBtZW5pdA0KICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNwcmludGYoIiUwMmQ6JTAyZCIsIGZsb29yKHgpLCByb3VuZCgoeCUlMSkqNjApKQ0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSxzaXplPTMwKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHNpemUgPSAxNSkpDQpgYGANCg0KPiBEYWlseSBQcm9maWxlcyAoMjRoKSAtIE9jY3VwYW5jeSBmb3IgV2Vla2VuZHMNCg0KYGBge3IgZmlnLndpZHRoPTMwLCBmaWcuaGVpZ2h0PTEwfQ0KZGZfd2Vla2VuZCRob3VyIDwtIGhvdXIoZGZfd2Vla2VuZCR0aW1lKSArIG1pbnV0ZShkZl93ZWVrZW5kJHRpbWUpLzYwLjANCmdncGxvdChkZl93ZWVrZW5kLCBhZXMoeCA9IGhvdXIsIHkgPSBvY2N1cGFuY3ksIGdyb3VwID0gZGF0ZSh0aW1lKSkpICsNCiAgZ2VvbV9saW5lKGFscGhhID0gMC4yLCBjb2xvciA9ICJibHVlIikgKw0KICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gMSksIGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIsIGNvbG9yID0gImJsdWUiLCBzaXplID0gMS41LCBsaW5ldHlwZSA9ICJzb2xpZCIpICsNCiAgbGFicyh0aXRsZSA9ICJEYWlseSBQcm9maWxlcyBvZiBPY2N1cGFuY3kgKFdlZWtlbmRzKSIsDQogICAgICAgeCA9ICJUaW1lIG9mIERheSIsDQogICAgICAgeSA9ICJPY2N1cGFuY3kgKFdpRmkgQ2xpZW50cykiKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgwLCAyNCwgYnkgPSAxMC82MCksDQogICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgc3ByaW50ZigiJTAyZDolMDJkIiwgZmxvb3IoeCksIHJvdW5kKCh4JSUxKSo2MCkpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHNpemU9MzApLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE1KSkNCmBgYA0KDQo+IERhaWx5IFByb2ZpbGVzICgyNGgpIC0gT2NjdXBhbmN5IChXZWVrZGF5cyBhbmQgV2Vla2VuZHMpDQoNCmBgYHtyIGZpZy53aWR0aD0zMCwgZmlnLmhlaWdodD0xMH0NCmRmJGhvdXIgPC0gaG91cihkZiR0aW1lKSArIG1pbnV0ZShkZiR0aW1lKS82MC4wDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gaG91ciwgeSA9IG9jY3VwYW5jeSwgZ3JvdXAgPSBkYXRlKHRpbWUpKSkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRmX3dlZWtkYXksIGFlcyhjb2xvciA9ICJXZWVrZGF5cyIpLCBhbHBoYSA9IDAuMikgKw0KICBzdGF0X3N1bW1hcnkoZGF0YSA9IGRmX3dlZWtkYXksIGFlcyhjb2xvciA9ICJXZWVrZGF5cyIsIGdyb3VwID0gMSksIGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIsIHNpemUgPSAxLjUsIGxpbmV0eXBlID0gInNvbGlkIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRmX3dlZWtlbmQsIGFlcyhjb2xvciA9ICJXZWVrZW5kcyIpLCBhbHBoYSA9IDAuMiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBzdGF0X3N1bW1hcnkoZGF0YSA9IGRmX3dlZWtlbmQsIGFlcyhjb2xvciA9ICJXZWVrZW5kcyIsIGdyb3VwID0gMSksIGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIsIHNpemUgPSAxLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJEYWlseSBQcm9maWxlcyBvZiBPY2N1cGFuY3kgKFdlZWtkYXlzIGFuZCBXZWVrZW5kcykiLA0KICAgICAgIHggPSAiVGltZSBvZiBEYXkiLA0KICAgICAgIHkgPSAiT2NjdXBhbmN5IChXaUZpIENsaWVudHMpIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiV2Vla2RheXMiID0gInJlZCIsICJXZWVrZW5kcyIgPSAiYmx1ZSIpKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgYnJlYWtzID0gc2VxKDAsIDI0LCBieSA9IDEwLzYwKSwNCiAgbGFiZWxzID0gZnVuY3Rpb24oeCkgc3ByaW50ZigiJTAyZDolMDJkIiwgZmxvb3IoeCksIHJvdW5kKCh4JSUxKSo2MCkpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIixwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHNpemU9MzApLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHNpemUgPSAxNSkpDQpgYGANCg0KPiBEYWlseSBQcm9maWxlcyAoMjRoKSAtIEVuZXJneSBDb25zdW1wdGlvbiBmb3IgV2Vla2RheXMNCg0KYGBge3IgZmlnLndpZHRoPTMwLCBmaWcuaGVpZ2h0PTEwfQ0KZ2dwbG90KGRmX3dlZWtkYXksIGFlcyh4ID0gaG91ciwgeSA9IGVuZXJneV9jb25zdW1wdGlvbiwgZ3JvdXAgPSBkYXRlKHRpbWUpKSkgKw0KICBnZW9tX2xpbmUoYWxwaGEgPSAwLjIsIGNvbG9yID0gInJlZCIpICsNCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IDEpLCBmdW4gPSBtZWFuLCBnZW9tID0gImxpbmUiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMS41LCBsaW5ldHlwZSA9ICJzb2xpZCIpICsNCiAgbGFicyh0aXRsZSA9ICJEYWlseSBQcm9maWxlcyBvZiBFbmVyZ3kgQ29uc3VtcHRpb24gKFdlZWtkYXlzKSIsDQogICAgICAgeCA9ICJUaW1lIG9mIERheSIsDQogICAgICAgeSA9ICJFbmVyZ3kgQ29uc3VtcHRpb24iKSArDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEoMCwgMjQsIGJ5ID0gMTAvNjApLCAgICMgaW50ZXJ2YWwgMTAgbWVuaXQNCiAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSBzcHJpbnRmKCIlMDJkOiUwMmQiLCBmbG9vcih4KSwgcm91bmQoKHglJTEpKjYwKSkNCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsc2l6ZT0zMCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE1KSkNCmBgYA0KDQo+IERhaWx5IFByb2ZpbGVzICgyNGgpIC0gRW5lcmd5IENvbnN1bXB0aW9uIGZvciBXZWVrZW5kcw0KDQpgYGB7ciBmaWcud2lkdGg9MzAsIGZpZy5oZWlnaHQ9MTB9DQpnZ3Bsb3QoZGZfd2Vla2VuZCwgYWVzKHggPSBob3VyLCB5ID0gZW5lcmd5X2NvbnN1bXB0aW9uLCBncm91cCA9IGRhdGUodGltZSkpKSArDQogIGdlb21fbGluZShhbHBoYSA9IDAuMiwgY29sb3IgPSAicmVkIikgKw0KICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gMSksIGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxLjUsIGxpbmV0eXBlID0gInNvbGlkIikgKw0KICBsYWJzKHRpdGxlID0gIkRhaWx5IFByb2ZpbGVzIG9mIEVuZXJneSBDb25zdW1wdGlvbiAoV2Vla2VuZHMpIiwNCiAgICAgICB4ID0gIlRpbWUgb2YgRGF5IiwNCiAgICAgICB5ID0gIkVuZXJneSBDb25zdW1wdGlvbiIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgwLCAyNCwgYnkgPSAxMC82MCksICAgIyBpbnRlcnZhbCAxMCBtZW5pdA0KICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNwcmludGYoIiUwMmQ6JTAyZCIsIGZsb29yKHgpLCByb3VuZCgoeCUlMSkqNjApKQ0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSxzaXplPTMwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCBzaXplID0gMTUpKQ0KYGBgDQoNCj4gRGFpbHkgUHJvZmlsZXMgKDI0aCkgLSBFbmVyZ3kgQ29uc3VtcHRpb24gKFdlZWtkYXlzIGFuZCBXZWVrZW5kcykNCg0KYGBge3IgZmlnLndpZHRoPTMwLCBmaWcuaGVpZ2h0PTEwfQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXIsIHkgPSBlbmVyZ3lfY29uc3VtcHRpb24sIGdyb3VwID0gZGF0ZSh0aW1lKSkpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkZl93ZWVrZGF5LCBhZXMoY29sb3IgPSAiV2Vla2RheXMiKSwgYWxwaGEgPSAwLjIpICsNCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBkZl93ZWVrZGF5LCBhZXMoY29sb3IgPSAiV2Vla2RheXMiLCBncm91cCA9IDEpLCBmdW4gPSBtZWFuLCBnZW9tID0gImxpbmUiLCBzaXplID0gMS41LCBsaW5ldHlwZSA9ICJzb2xpZCIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkZl93ZWVrZW5kLCBhZXMoY29sb3IgPSAiV2Vla2VuZHMiKSwgYWxwaGEgPSAwLjIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBkZl93ZWVrZW5kLCBhZXMoY29sb3IgPSAiV2Vla2VuZHMiLCBncm91cCA9IDEpLCBmdW4gPSBtZWFuLCBnZW9tID0gImxpbmUiLCBzaXplID0gMS41LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGxhYnModGl0bGUgPSAiRGFpbHkgUHJvZmlsZXMgb2YgRW5lcmd5IENvbnN1bXB0aW9uIChXZWVrZGF5cyBhbmQgV2Vla2VuZHMpIiwNCiAgICAgICB4ID0gIlRpbWUgb2YgRGF5IiwNCiAgICAgICB5ID0gIkVuZXJneSBDb25zdW1wdGlvbiIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIldlZWtkYXlzIiA9ICJyZWQiLCAiV2Vla2VuZHMiID0gImJsdWUiKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgYnJlYWtzID0gc2VxKDAsIDI0LCBieSA9IDEwLzYwKSwgICAjIGludGVydmFsIDEwIG1lbml0DQogICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgc3ByaW50ZigiJTAyZDolMDJkIiwgZmxvb3IoeCksIHJvdW5kKCh4JSUxKSo2MCkpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsc2l6ZT0zMCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE1KSkNCmBgYA==