Load installed packages
library(tidyverse)
library(lubridate)
library(dplyr)
library(ggplot2)
library(tidyr)
Load CSV files
daily_activity <- read.csv("C:/Users/cmor7/OneDrive/Desktop/Case Study/BellaBeat/Data/Fitabase Data 4.12.16-5.12.16/dailyActivity_merged.csv")
sleep_day <- read.csv("C:/Users/cmor7/OneDrive/Desktop/Case Study/BellaBeat/Data/Fitabase Data 4.12.16-5.12.16/sleepDay_merged.csv")
hourly_intensities <- read.csv("C:/Users/cmor7/OneDrive/Desktop/Case Study/BellaBeat/Data/Fitabase Data 4.12.16-5.12.16/hourlyIntensities_merged.csv")
hourly_calories <- read.csv("C:/Users/cmor7/OneDrive/Desktop/Case Study/BellaBeat/Data/Fitabase Data 4.12.16-5.12.16/hourlyCalories_merged.csv")
weight_log <- read.csv("C:/Users/cmor7/OneDrive/Desktop/Case Study/BellaBeat/Data/Fitabase Data 4.12.16-5.12.16/weightLogInfo_merged.csv")
Review head data of loaded CSV files
head(daily_activity)
head(sleep_day)
head(hourly_intensities)
head(hourly_calories)
head(weight_log)
Review column names of loaded CSV files
colnames(daily_activity)
[1] "Id" "ActivityDate"
[3] "TotalSteps" "TotalDistance"
[5] "TrackerDistance" "LoggedActivitiesDistance"
[7] "VeryActiveDistance" "ModeratelyActiveDistance"
[9] "LightActiveDistance" "SedentaryActiveDistance"
[11] "VeryActiveMinutes" "FairlyActiveMinutes"
[13] "LightlyActiveMinutes" "SedentaryMinutes"
[15] "Calories"
colnames(sleep_day)
[1] "Id" "SleepDay" "TotalSleepRecords"
[4] "TotalMinutesAsleep" "TotalTimeInBed"
colnames(hourly_intensities)
[1] "Id" "ActivityHour" "TotalIntensity" "AverageIntensity"
colnames(hourly_calories)
[1] "Id" "ActivityHour" "Calories"
colnames(weight_log)
[1] "Id" "Date" "WeightKg" "WeightPounds"
[5] "Fat" "BMI" "IsManualReport" "LogId"
Fix date mismatches
The daily_activity contains just a date but the others contain a date
and time. I will need to seperate the date and time into their own
columns in these other data frames. Additionally, the data type for each
date column will need to be set to a date format as well:
sleep_day <- sleep_day %>%
mutate(
SleepDay = mdy_hms(SleepDay), # Parse datetime (adjust format if needed)
Date = as.Date(SleepDay),
)
head(sleep_day)
daily_activity <- daily_activity %>%
mutate(
ActivityDate = mdy(ActivityDate),
Date = as.Date(ActivityDate)
)
hourly_intensities <- hourly_intensities %>%
mutate(
ActivityHour = mdy_hms(ActivityHour), # Parse datetime (adjust format if needed)
Date = as.Date(ActivityHour),
Time = format(ActivityHour, "%H:%M")
)
hourly_calories <- hourly_calories %>%
mutate(
ActivityHour = mdy_hms(ActivityHour), # Parse datetime (adjust format if needed)
Date = as.Date(ActivityHour),
Time = format(ActivityHour, "%H:%M")
)
weight_log <- weight_log %>%
mutate(
Date = mdy_hms(Date), # Parse datetime (adjust format if needed)
Date = as.Date(Date)
)
Summary Statistics
How many unique participants are there in each dataframe?
n_distinct(daily_activity$Id)
[1] 33
n_distinct(sleep_day$Id)
[1] 24
n_distinct(hourly_intensities$Id)
[1] 33
n_distinct(hourly_calories$Id)
[1] 33
n_distinct(weight_log$Id)
[1] 8
How many observations are there in each dataframe?
nrow(daily_activity)
[1] 940
nrow(sleep_day)
[1] 413
nrow(hourly_intensities)
[1] 22099
nrow(hourly_calories)
[1] 22099
nrow(weight_log)
[1] 67
daily_activity dataframe:
daily_activity %>%
select(TotalSteps,
TotalDistance,
SedentaryMinutes,
Calories) %>%
summary()
TotalSteps TotalDistance SedentaryMinutes Calories
Min. : 0 Min. : 0.000 Min. : 0.0 Min. : 0
1st Qu.: 3790 1st Qu.: 2.620 1st Qu.: 729.8 1st Qu.:1828
Median : 7406 Median : 5.245 Median :1057.5 Median :2134
Mean : 7638 Mean : 5.490 Mean : 991.2 Mean :2304
3rd Qu.:10727 3rd Qu.: 7.713 3rd Qu.:1229.5 3rd Qu.:2793
Max. :36019 Max. :28.030 Max. :1440.0 Max. :4900
sleep_day dataframe:
sleep_day %>%
select(TotalSleepRecords,
TotalMinutesAsleep,
TotalTimeInBed) %>%
summary()
TotalSleepRecords TotalMinutesAsleep TotalTimeInBed
Min. :1.000 Min. : 58.0 Min. : 61.0
1st Qu.:1.000 1st Qu.:361.0 1st Qu.:403.0
Median :1.000 Median :433.0 Median :463.0
Mean :1.119 Mean :419.5 Mean :458.6
3rd Qu.:1.000 3rd Qu.:490.0 3rd Qu.:526.0
Max. :3.000 Max. :796.0 Max. :961.0
hourly_intensities dataframe:
hourly_intensities %>%
select(TotalIntensity,
AverageIntensity) %>%
summary()
TotalIntensity AverageIntensity
Min. : 0.00 Min. :0.0000
1st Qu.: 0.00 1st Qu.:0.0000
Median : 3.00 Median :0.0500
Mean : 12.04 Mean :0.2006
3rd Qu.: 16.00 3rd Qu.:0.2667
Max. :180.00 Max. :3.0000
hourly_calories dataframe:
hourly_calories %>%
select(Calories) %>%
summary()
Calories
Min. : 42.00
1st Qu.: 63.00
Median : 83.00
Mean : 97.39
3rd Qu.:108.00
Max. :948.00
Joining sleep_day and daily_activity
activity_sleep <- full_join(sleep_day, daily_activity, by=c("Id", "Date"))
Verify Distinct Id Count After Join
n_distinct(activity_sleep$Id)
[1] 33
Visualization
ggplot(data=daily_activity, aes(x=TotalSteps, y=SedentaryMinutes)) + geom_point()+ geom_smooth()+ labs(title="Total Steps vs. Sedentary Minutes", y="Total Sedentary Minutes", x="Total Steps")

ggplot(data=daily_activity, aes(x=TotalSteps, y=Calories)) + geom_point() + geom_smooth()+ labs(title="Total Steps vs. Calories", x="Total Steps")

ggplot(data=sleep_day, aes(x=TotalMinutesAsleep, y=TotalTimeInBed)) + geom_point()+ geom_smooth()+ labs(title="Total Sleep Minutes vs. Total Time In Bed", y="Total Time in Bed", x="Total Sleep Minutes")

ggplot(data = activity_sleep, aes(x=TotalMinutesAsleep, y=TotalSteps)) + geom_point() + geom_smooth()+ labs(title="Total Sleep Minutes vs. Total Steps", y="Total Steps", x="Total Sleep Minutes")

ggplot(data = activity_sleep, aes(x=TotalMinutesAsleep, y=SedentaryMinutes)) + geom_point() + geom_smooth()+ labs(title="Total Sleep Minutes vs. Total Sedentary Minutes", y="Total Sedentary Minutes", x="Total Sleep Minutes")

ggplot(data = activity_sleep, aes(x=TotalMinutesAsleep, y=Calories)) + geom_point() + geom_smooth() + labs(title="Total Sleep Minutes vs. Calories", x="Total Sleep Minutes")

grouped_hourly_intensities <- hourly_intensities %>%
group_by(Time) %>%
drop_na() %>%
summarise(mean_intensity = mean(TotalIntensity))
ggplot(data=grouped_hourly_intensities, aes(x=Time, y=mean_intensity)) + geom_col(fill='grey', color="darkblue") + theme(axis.text.x = element_text(angle = 45)) + labs(title="Average Total Intensity vs. Time", y="Average Total Intensity")

grouped_hourly_calories <- hourly_calories %>%
group_by(Time) %>%
drop_na() %>%
summarise(mean_calories = mean(Calories))
ggplot(data=grouped_hourly_calories, aes(x=Time, y=mean_calories)) + geom_col(fill='grey', color="darkblue") + theme(axis.text.x = element_text(angle = 45)) + labs(title="Average Calories vs. Time", y="Mean Calories")

Correlations
# Correlations with p-values
# Sedentary vs Sleep
cor_test_sed_sleep <- cor.test(activity_sleep$SedentaryMinutes, activity_sleep$TotalMinutesAsleep)
print(cor_test_sed_sleep) # r and p-value
Pearson's product-moment correlation
data: activity_sleep$SedentaryMinutes and activity_sleep$TotalMinutesAsleep
t = -15.181, df = 411, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.6578402 -0.5337719
sample estimates:
cor
-0.599394
# Steps vs Sedentary
cor_test_steps_sed <- cor.test(daily_activity$TotalSteps, daily_activity$SedentaryMinutes)
print(cor_test_steps_sed)
Pearson's product-moment correlation
data: daily_activity$TotalSteps and daily_activity$SedentaryMinutes
t = -10.615, df = 938, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.3833971 -0.2691782
sample estimates:
cor
-0.3274835
# Steps vs Calories
cor_test_steps_cal <- cor.test(daily_activity$TotalSteps, daily_activity$Calories)
print(cor_test_steps_cal)
Pearson's product-moment correlation
data: daily_activity$TotalSteps and daily_activity$Calories
t = 22.472, df = 938, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.5483688 0.6316184
sample estimates:
cor
0.5915681
# Sleep vs Time in Bed
cor_test_sleep_bed <- cor.test(sleep_day$TotalMinutesAsleep, sleep_day$TotalTimeInBed)
print(cor_test_sleep_bed)
Pearson's product-moment correlation
data: sleep_day$TotalMinutesAsleep and sleep_day$TotalTimeInBed
t = 51.483, df = 411, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.9162253 0.9423445
sample estimates:
cor
0.9304575
# Sleep efficiency (ratio) for insomnia outliers
sleep_day$SleepEfficiency <- sleep_day$TotalMinutesAsleep / sleep_day$TotalTimeInBed
mean_eff <- mean(sleep_day$SleepEfficiency, na.rm = TRUE)
std_eff <- sd(sleep_day$SleepEfficiency, na.rm = TRUE)
outliers <- sleep_day[sleep_day$SleepEfficiency < (mean_eff - 2 * std_eff), ]
print(paste("Mean Efficiency:", round(mean_eff, 3), "Std:", round(std_eff, 3), "Outliers:", nrow(outliers)))
[1] "Mean Efficiency: 0.917 Std: 0.087 Outliers: 27"
# Visualize efficiency
ggplot(sleep_day, aes(x = SleepEfficiency)) + geom_histogram(binwidth = 0.01, color="darkblue", fill="gray") +
labs(title = "Distribution of Sleep Efficiency", y = "Number of Sleep Records", x="Sleep Efficiency")

Data Limitations
- Sample size: Only 33 unique IDs
- No gender/age: Limits applicability to Bellabeat’s female
users.
- Bias: Self-selected participants; weight logging low due to manual
entry.
Key Insights From Data Analysis:
- 5pm-7pm are the most active hours of the day as confirmed by the
comparisons of Average Total Intensity and Calories burned to Time.
- 12pm-2pm is the second most active time period.
- People with higher sedentary minutes had less total minutes
asleep.
- Total sleep minutes increase with total time in bed so outliers that
spend more time in bed but get less sleep may be having insomnia or poor
sleep hygiene.
- People that took the most steps generally burned the most
calories
- There is a unique relationship between total steps and sedentary
minutes. Sedentary minutes decrease with more total steps up to about
10,000 steps. There is an inflection point here where more stpes after
10,000 tends to lead to an increase in sedentary minutes which may
indicate fatigue or needed rest.
Recomendations:
- Send activity related notification reminders to users to be active
prior to the 5pm-7pm most active window, especially if they have not
been active earlier in the day.
- Send notifications to people with less total minutes slept to
improve sleep by being more active throughout the day.
- Send notifications to outlying users who spend more time in bed but
get less sleep than the average with sleep hygiene tips since they might
be experiencing insomnia.
- Send notifications to people that exceed 10,000 steps per day to
remind them that they might need more recovery and rest activities.
LS0tDQp0aXRsZTogIkJlbGxhQmVhdCBDYXNlIFN0dWR5Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQojIyMgTG9hZCBpbnN0YWxsZWQgcGFja2FnZXMNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHlyKQ0KYGBgDQojIyMgTG9hZCBDU1YgZmlsZXMNCmBgYHtyfQ0KZGFpbHlfYWN0aXZpdHkgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL2Ntb3I3L09uZURyaXZlL0Rlc2t0b3AvQ2FzZSBTdHVkeS9CZWxsYUJlYXQvRGF0YS9GaXRhYmFzZSBEYXRhIDQuMTIuMTYtNS4xMi4xNi9kYWlseUFjdGl2aXR5X21lcmdlZC5jc3YiKQ0Kc2xlZXBfZGF5IDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9jbW9yNy9PbmVEcml2ZS9EZXNrdG9wL0Nhc2UgU3R1ZHkvQmVsbGFCZWF0L0RhdGEvRml0YWJhc2UgRGF0YSA0LjEyLjE2LTUuMTIuMTYvc2xlZXBEYXlfbWVyZ2VkLmNzdiIpDQpob3VybHlfaW50ZW5zaXRpZXMgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL2Ntb3I3L09uZURyaXZlL0Rlc2t0b3AvQ2FzZSBTdHVkeS9CZWxsYUJlYXQvRGF0YS9GaXRhYmFzZSBEYXRhIDQuMTIuMTYtNS4xMi4xNi9ob3VybHlJbnRlbnNpdGllc19tZXJnZWQuY3N2IikNCmhvdXJseV9jYWxvcmllcyA8LSByZWFkLmNzdigiQzovVXNlcnMvY21vcjcvT25lRHJpdmUvRGVza3RvcC9DYXNlIFN0dWR5L0JlbGxhQmVhdC9EYXRhL0ZpdGFiYXNlIERhdGEgNC4xMi4xNi01LjEyLjE2L2hvdXJseUNhbG9yaWVzX21lcmdlZC5jc3YiKQ0Kd2VpZ2h0X2xvZyA8LSByZWFkLmNzdigiQzovVXNlcnMvY21vcjcvT25lRHJpdmUvRGVza3RvcC9DYXNlIFN0dWR5L0JlbGxhQmVhdC9EYXRhL0ZpdGFiYXNlIERhdGEgNC4xMi4xNi01LjEyLjE2L3dlaWdodExvZ0luZm9fbWVyZ2VkLmNzdiIpDQpgYGANCiMjIyBSZXZpZXcgaGVhZCBkYXRhIG9mIGxvYWRlZCBDU1YgZmlsZXMNCmBgYHtyfQ0KaGVhZChkYWlseV9hY3Rpdml0eSkNCmhlYWQoc2xlZXBfZGF5KQ0KaGVhZChob3VybHlfaW50ZW5zaXRpZXMpDQpoZWFkKGhvdXJseV9jYWxvcmllcykNCmhlYWQod2VpZ2h0X2xvZykNCmBgYA0KIyMjIFJldmlldyBjb2x1bW4gbmFtZXMgb2YgbG9hZGVkIENTViBmaWxlcw0KYGBge3J9DQpjb2xuYW1lcyhkYWlseV9hY3Rpdml0eSkNCmNvbG5hbWVzKHNsZWVwX2RheSkNCmNvbG5hbWVzKGhvdXJseV9pbnRlbnNpdGllcykNCmNvbG5hbWVzKGhvdXJseV9jYWxvcmllcykNCmNvbG5hbWVzKHdlaWdodF9sb2cpDQpgYGANCiMjIyBGaXggZGF0ZSBtaXNtYXRjaGVzDQpUaGUgZGFpbHlfYWN0aXZpdHkgY29udGFpbnMganVzdCBhIGRhdGUgYnV0IHRoZSBvdGhlcnMgY29udGFpbiBhIGRhdGUgYW5kIHRpbWUuIEkgd2lsbCBuZWVkIHRvIHNlcGVyYXRlIHRoZSBkYXRlIGFuZCB0aW1lIGludG8gdGhlaXIgb3duIGNvbHVtbnMgaW4gdGhlc2Ugb3RoZXIgZGF0YSBmcmFtZXMuIEFkZGl0aW9uYWxseSwgdGhlIGRhdGEgdHlwZSBmb3IgZWFjaCBkYXRlIGNvbHVtbiB3aWxsIG5lZWQgdG8gYmUgc2V0IHRvIGEgZGF0ZSBmb3JtYXQgYXMgd2VsbDoNCmBgYHtyfQ0Kc2xlZXBfZGF5IDwtIHNsZWVwX2RheSAlPiUgDQogIG11dGF0ZSgNCiAgICBTbGVlcERheSA9IG1keV9obXMoU2xlZXBEYXkpLCAgIyBQYXJzZSBkYXRldGltZSAoYWRqdXN0IGZvcm1hdCBpZiBuZWVkZWQpDQogICAgRGF0ZSA9IGFzLkRhdGUoU2xlZXBEYXkpLA0KICApDQpoZWFkKHNsZWVwX2RheSkNCg0KZGFpbHlfYWN0aXZpdHkgPC0gZGFpbHlfYWN0aXZpdHkgJT4lIA0KICBtdXRhdGUoDQogICAgQWN0aXZpdHlEYXRlID0gbWR5KEFjdGl2aXR5RGF0ZSksDQogICAgRGF0ZSA9IGFzLkRhdGUoQWN0aXZpdHlEYXRlKQ0KICApDQoNCmhvdXJseV9pbnRlbnNpdGllcyA8LSBob3VybHlfaW50ZW5zaXRpZXMgJT4lIA0KICBtdXRhdGUoDQogICAgQWN0aXZpdHlIb3VyID0gbWR5X2htcyhBY3Rpdml0eUhvdXIpLCAgIyBQYXJzZSBkYXRldGltZSAoYWRqdXN0IGZvcm1hdCBpZiBuZWVkZWQpDQogICAgRGF0ZSA9IGFzLkRhdGUoQWN0aXZpdHlIb3VyKSwNCiAgICBUaW1lID0gZm9ybWF0KEFjdGl2aXR5SG91ciwgIiVIOiVNIikNCiAgKQ0KDQpob3VybHlfY2Fsb3JpZXMgPC0gaG91cmx5X2NhbG9yaWVzICU+JSANCiAgbXV0YXRlKA0KICAgIEFjdGl2aXR5SG91ciA9IG1keV9obXMoQWN0aXZpdHlIb3VyKSwgICMgUGFyc2UgZGF0ZXRpbWUgKGFkanVzdCBmb3JtYXQgaWYgbmVlZGVkKQ0KICAgIERhdGUgPSBhcy5EYXRlKEFjdGl2aXR5SG91ciksDQogICAgVGltZSA9IGZvcm1hdChBY3Rpdml0eUhvdXIsICIlSDolTSIpDQogICkNCg0Kd2VpZ2h0X2xvZyA8LSB3ZWlnaHRfbG9nICU+JSANCiAgbXV0YXRlKA0KICAgIERhdGUgPSBtZHlfaG1zKERhdGUpLCAgIyBQYXJzZSBkYXRldGltZSAoYWRqdXN0IGZvcm1hdCBpZiBuZWVkZWQpDQogICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZSkNCiAgKQ0KYGBgDQojIyBTdW1tYXJ5IFN0YXRpc3RpY3MNCiMjIyBIb3cgbWFueSB1bmlxdWUgcGFydGljaXBhbnRzIGFyZSB0aGVyZSBpbiBlYWNoIGRhdGFmcmFtZT8NCmBgYHtyfQ0Kbl9kaXN0aW5jdChkYWlseV9hY3Rpdml0eSRJZCkNCm5fZGlzdGluY3Qoc2xlZXBfZGF5JElkKQ0Kbl9kaXN0aW5jdChob3VybHlfaW50ZW5zaXRpZXMkSWQpDQpuX2Rpc3RpbmN0KGhvdXJseV9jYWxvcmllcyRJZCkNCm5fZGlzdGluY3Qod2VpZ2h0X2xvZyRJZCkNCmBgYA0KIyMjIEhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gZWFjaCBkYXRhZnJhbWU/DQpgYGB7cn0NCm5yb3coZGFpbHlfYWN0aXZpdHkpDQpucm93KHNsZWVwX2RheSkNCm5yb3coaG91cmx5X2ludGVuc2l0aWVzKQ0KbnJvdyhob3VybHlfY2Fsb3JpZXMpDQpucm93KHdlaWdodF9sb2cpDQpgYGANCiMjIyBkYWlseV9hY3Rpdml0eSBkYXRhZnJhbWU6DQpgYGB7cn0NCmRhaWx5X2FjdGl2aXR5ICU+JSAgDQogIHNlbGVjdChUb3RhbFN0ZXBzLA0KICAgICAgICAgVG90YWxEaXN0YW5jZSwNCiAgICAgICAgIFNlZGVudGFyeU1pbnV0ZXMsDQogICAgICAgICBDYWxvcmllcykgJT4lDQogIHN1bW1hcnkoKQ0KYGBgDQojIyMgc2xlZXBfZGF5IGRhdGFmcmFtZToNCmBgYHtyfQ0Kc2xlZXBfZGF5ICU+JSAgDQogIHNlbGVjdChUb3RhbFNsZWVwUmVjb3JkcywNCiAgICAgICAgIFRvdGFsTWludXRlc0FzbGVlcCwNCiAgICAgICAgIFRvdGFsVGltZUluQmVkKSAlPiUNCiAgc3VtbWFyeSgpDQpgYGANCiMjIyBob3VybHlfaW50ZW5zaXRpZXMgZGF0YWZyYW1lOg0KYGBge3J9DQpob3VybHlfaW50ZW5zaXRpZXMgJT4lICANCiAgc2VsZWN0KFRvdGFsSW50ZW5zaXR5LA0KICAgICAgICAgQXZlcmFnZUludGVuc2l0eSkgJT4lDQogIHN1bW1hcnkoKQ0KYGBgDQojIyMgaG91cmx5X2NhbG9yaWVzIGRhdGFmcmFtZToNCmBgYHtyfQ0KaG91cmx5X2NhbG9yaWVzICU+JSAgDQogIHNlbGVjdChDYWxvcmllcykgJT4lDQogIHN1bW1hcnkoKQ0KYGBgDQojIyBKb2luaW5nIHNsZWVwX2RheSBhbmQgZGFpbHlfYWN0aXZpdHkNCmBgYHtyfQ0KYWN0aXZpdHlfc2xlZXAgPC0gZnVsbF9qb2luKHNsZWVwX2RheSwgZGFpbHlfYWN0aXZpdHksIGJ5PWMoIklkIiwgIkRhdGUiKSkNCmBgYA0KIyMjIFZlcmlmeSBEaXN0aW5jdCBJZCBDb3VudCBBZnRlciBKb2luDQpgYGB7cn0NCm5fZGlzdGluY3QoYWN0aXZpdHlfc2xlZXAkSWQpDQpgYGANCiMjIFZpc3VhbGl6YXRpb24gDQpgYGB7cn0NCmdncGxvdChkYXRhPWRhaWx5X2FjdGl2aXR5LCBhZXMoeD1Ub3RhbFN0ZXBzLCB5PVNlZGVudGFyeU1pbnV0ZXMpKSArIGdlb21fcG9pbnQoKSsgZ2VvbV9zbW9vdGgoKSsgbGFicyh0aXRsZT0iVG90YWwgU3RlcHMgdnMuIFNlZGVudGFyeSBNaW51dGVzIiwgeT0iVG90YWwgU2VkZW50YXJ5IE1pbnV0ZXMiLCB4PSJUb3RhbCBTdGVwcyIpDQpnZ3Bsb3QoZGF0YT1kYWlseV9hY3Rpdml0eSwgYWVzKHg9VG90YWxTdGVwcywgeT1DYWxvcmllcykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSsgbGFicyh0aXRsZT0iVG90YWwgU3RlcHMgdnMuIENhbG9yaWVzIiwgeD0iVG90YWwgU3RlcHMiKQ0KZ2dwbG90KGRhdGE9c2xlZXBfZGF5LCBhZXMoeD1Ub3RhbE1pbnV0ZXNBc2xlZXAsIHk9VG90YWxUaW1lSW5CZWQpKSArIGdlb21fcG9pbnQoKSsgZ2VvbV9zbW9vdGgoKSsgbGFicyh0aXRsZT0iVG90YWwgU2xlZXAgTWludXRlcyB2cy4gVG90YWwgVGltZSBJbiBCZWQiLCB5PSJUb3RhbCBUaW1lIGluIEJlZCIsIHg9IlRvdGFsIFNsZWVwIE1pbnV0ZXMiKQ0KZ2dwbG90KGRhdGEgPSBhY3Rpdml0eV9zbGVlcCwgYWVzKHg9VG90YWxNaW51dGVzQXNsZWVwLCB5PVRvdGFsU3RlcHMpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkrIGxhYnModGl0bGU9IlRvdGFsIFNsZWVwIE1pbnV0ZXMgdnMuIFRvdGFsIFN0ZXBzIiwgeT0iVG90YWwgU3RlcHMiLCB4PSJUb3RhbCBTbGVlcCBNaW51dGVzIikNCmdncGxvdChkYXRhID0gYWN0aXZpdHlfc2xlZXAsIGFlcyh4PVRvdGFsTWludXRlc0FzbGVlcCwgeT1TZWRlbnRhcnlNaW51dGVzKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpKyBsYWJzKHRpdGxlPSJUb3RhbCBTbGVlcCBNaW51dGVzIHZzLiBUb3RhbCBTZWRlbnRhcnkgTWludXRlcyIsIHk9IlRvdGFsIFNlZGVudGFyeSBNaW51dGVzIiwgeD0iVG90YWwgU2xlZXAgTWludXRlcyIpDQpnZ3Bsb3QoZGF0YSA9IGFjdGl2aXR5X3NsZWVwLCBhZXMoeD1Ub3RhbE1pbnV0ZXNBc2xlZXAsIHk9Q2Fsb3JpZXMpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKyBsYWJzKHRpdGxlPSJUb3RhbCBTbGVlcCBNaW51dGVzIHZzLiBDYWxvcmllcyIsIHg9IlRvdGFsIFNsZWVwIE1pbnV0ZXMiKQ0KDQpncm91cGVkX2hvdXJseV9pbnRlbnNpdGllcyA8LSBob3VybHlfaW50ZW5zaXRpZXMgJT4lDQogIGdyb3VwX2J5KFRpbWUpICU+JQ0KICBkcm9wX25hKCkgJT4lDQogIHN1bW1hcmlzZShtZWFuX2ludGVuc2l0eSA9IG1lYW4oVG90YWxJbnRlbnNpdHkpKQ0KDQpnZ3Bsb3QoZGF0YT1ncm91cGVkX2hvdXJseV9pbnRlbnNpdGllcywgYWVzKHg9VGltZSwgeT1tZWFuX2ludGVuc2l0eSkpICsgZ2VvbV9jb2woZmlsbD0nZ3JleScsIGNvbG9yPSJkYXJrYmx1ZSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpICsgbGFicyh0aXRsZT0iQXZlcmFnZSBUb3RhbCBJbnRlbnNpdHkgdnMuIFRpbWUiLCB5PSJBdmVyYWdlIFRvdGFsIEludGVuc2l0eSIpDQoNCmdyb3VwZWRfaG91cmx5X2NhbG9yaWVzIDwtIGhvdXJseV9jYWxvcmllcyAlPiUNCiAgZ3JvdXBfYnkoVGltZSkgJT4lDQogIGRyb3BfbmEoKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fY2Fsb3JpZXMgPSBtZWFuKENhbG9yaWVzKSkNCg0KZ2dwbG90KGRhdGE9Z3JvdXBlZF9ob3VybHlfY2Fsb3JpZXMsIGFlcyh4PVRpbWUsIHk9bWVhbl9jYWxvcmllcykpICsgZ2VvbV9jb2woZmlsbD0nZ3JleScsIGNvbG9yPSJkYXJrYmx1ZSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpICsgbGFicyh0aXRsZT0iQXZlcmFnZSBDYWxvcmllcyB2cy4gVGltZSIsIHk9Ik1lYW4gQ2Fsb3JpZXMiKQ0KYGBgDQojIyBDb3JyZWxhdGlvbnMNCmBgYHtyfQ0KIyBDb3JyZWxhdGlvbnMgd2l0aCBwLXZhbHVlcw0KIyBTZWRlbnRhcnkgdnMgU2xlZXANCmNvcl90ZXN0X3NlZF9zbGVlcCA8LSBjb3IudGVzdChhY3Rpdml0eV9zbGVlcCRTZWRlbnRhcnlNaW51dGVzLCBhY3Rpdml0eV9zbGVlcCRUb3RhbE1pbnV0ZXNBc2xlZXApDQpwcmludChjb3JfdGVzdF9zZWRfc2xlZXApICAjIHIgYW5kIHAtdmFsdWUNCg0KIyBTdGVwcyB2cyBTZWRlbnRhcnkNCmNvcl90ZXN0X3N0ZXBzX3NlZCA8LSBjb3IudGVzdChkYWlseV9hY3Rpdml0eSRUb3RhbFN0ZXBzLCBkYWlseV9hY3Rpdml0eSRTZWRlbnRhcnlNaW51dGVzKQ0KcHJpbnQoY29yX3Rlc3Rfc3RlcHNfc2VkKQ0KDQojIFN0ZXBzIHZzIENhbG9yaWVzDQpjb3JfdGVzdF9zdGVwc19jYWwgPC0gY29yLnRlc3QoZGFpbHlfYWN0aXZpdHkkVG90YWxTdGVwcywgZGFpbHlfYWN0aXZpdHkkQ2Fsb3JpZXMpDQpwcmludChjb3JfdGVzdF9zdGVwc19jYWwpDQoNCiMgU2xlZXAgdnMgVGltZSBpbiBCZWQNCmNvcl90ZXN0X3NsZWVwX2JlZCA8LSBjb3IudGVzdChzbGVlcF9kYXkkVG90YWxNaW51dGVzQXNsZWVwLCBzbGVlcF9kYXkkVG90YWxUaW1lSW5CZWQpDQpwcmludChjb3JfdGVzdF9zbGVlcF9iZWQpDQoNCiMgU2xlZXAgZWZmaWNpZW5jeSAocmF0aW8pIGZvciBpbnNvbW5pYSBvdXRsaWVycw0Kc2xlZXBfZGF5JFNsZWVwRWZmaWNpZW5jeSA8LSBzbGVlcF9kYXkkVG90YWxNaW51dGVzQXNsZWVwIC8gc2xlZXBfZGF5JFRvdGFsVGltZUluQmVkDQptZWFuX2VmZiA8LSBtZWFuKHNsZWVwX2RheSRTbGVlcEVmZmljaWVuY3ksIG5hLnJtID0gVFJVRSkNCnN0ZF9lZmYgPC0gc2Qoc2xlZXBfZGF5JFNsZWVwRWZmaWNpZW5jeSwgbmEucm0gPSBUUlVFKQ0Kb3V0bGllcnMgPC0gc2xlZXBfZGF5W3NsZWVwX2RheSRTbGVlcEVmZmljaWVuY3kgPCAobWVhbl9lZmYgLSAyICogc3RkX2VmZiksIF0NCnByaW50KHBhc3RlKCJNZWFuIEVmZmljaWVuY3k6Iiwgcm91bmQobWVhbl9lZmYsIDMpLCAiU3RkOiIsIHJvdW5kKHN0ZF9lZmYsIDMpLCAiT3V0bGllcnM6IiwgbnJvdyhvdXRsaWVycykpKQ0KDQojIFZpc3VhbGl6ZSBlZmZpY2llbmN5DQpnZ3Bsb3Qoc2xlZXBfZGF5LCBhZXMoeCA9IFNsZWVwRWZmaWNpZW5jeSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxLCBjb2xvcj0iZGFya2JsdWUiLCBmaWxsPSJncmF5IikgKyANCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgU2xlZXAgRWZmaWNpZW5jeSIsIHkgPSAiTnVtYmVyIG9mIFNsZWVwIFJlY29yZHMiLCB4PSJTbGVlcCBFZmZpY2llbmN5IikNCmBgYA0KIyMgRGF0YSBMaW1pdGF0aW9ucw0KLSBTYW1wbGUgc2l6ZTogT25seSAzMyB1bmlxdWUgSURzDQotIE5vIGdlbmRlci9hZ2U6IExpbWl0cyBhcHBsaWNhYmlsaXR5IHRvIEJlbGxhYmVhdCdzIGZlbWFsZSB1c2Vycy4NCi0gQmlhczogU2VsZi1zZWxlY3RlZCBwYXJ0aWNpcGFudHM7IHdlaWdodCBsb2dnaW5nIGxvdyBkdWUgdG8gbWFudWFsIGVudHJ5Lg0KDQojIyBLZXkgSW5zaWdodHMgRnJvbSBEYXRhIEFuYWx5c2lzOg0KMSkgNXBtLTdwbSBhcmUgdGhlIG1vc3QgYWN0aXZlIGhvdXJzIG9mIHRoZSBkYXkgYXMgY29uZmlybWVkIGJ5IHRoZSBjb21wYXJpc29ucyBvZiBBdmVyYWdlIFRvdGFsIEludGVuc2l0eSBhbmQgQ2Fsb3JpZXMgYnVybmVkIHRvIFRpbWUuIA0KMikgMTJwbS0ycG0gaXMgdGhlIHNlY29uZCBtb3N0IGFjdGl2ZSB0aW1lIHBlcmlvZC4gIA0KMykgUGVvcGxlIHdpdGggaGlnaGVyIHNlZGVudGFyeSBtaW51dGVzIGhhZCBsZXNzIHRvdGFsIG1pbnV0ZXMgYXNsZWVwLiAgDQo0KSBUb3RhbCBzbGVlcCBtaW51dGVzIGluY3JlYXNlIHdpdGggdG90YWwgdGltZSBpbiBiZWQgc28gb3V0bGllcnMgdGhhdCBzcGVuZCBtb3JlIHRpbWUgaW4gYmVkIGJ1dCBnZXQgbGVzcyBzbGVlcCBtYXkgYmUgaGF2aW5nIGluc29tbmlhIG9yIHBvb3Igc2xlZXAgaHlnaWVuZS4gDQo1KSBQZW9wbGUgdGhhdCB0b29rIHRoZSBtb3N0IHN0ZXBzIGdlbmVyYWxseSBidXJuZWQgdGhlIG1vc3QgY2Fsb3JpZXMNCjYpIFRoZXJlIGlzIGEgdW5pcXVlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRvdGFsIHN0ZXBzIGFuZCBzZWRlbnRhcnkgbWludXRlcy4gU2VkZW50YXJ5IG1pbnV0ZXMgZGVjcmVhc2Ugd2l0aCBtb3JlIHRvdGFsIHN0ZXBzIHVwIHRvIGFib3V0IDEwLDAwMCBzdGVwcy4gIFRoZXJlIGlzIGFuIGluZmxlY3Rpb24gcG9pbnQgaGVyZSB3aGVyZSBtb3JlIHN0cGVzIGFmdGVyIDEwLDAwMCB0ZW5kcyB0byBsZWFkIHRvIGFuIGluY3JlYXNlIGluIHNlZGVudGFyeSBtaW51dGVzIHdoaWNoIG1heSBpbmRpY2F0ZSBmYXRpZ3VlIG9yIG5lZWRlZCByZXN0LiANCg0KIyMgUmVjb21lbmRhdGlvbnM6DQoxKSBTZW5kIGFjdGl2aXR5IHJlbGF0ZWQgbm90aWZpY2F0aW9uIHJlbWluZGVycyB0byB1c2VycyB0byBiZSBhY3RpdmUgcHJpb3IgdG8gdGhlIDVwbS03cG0gbW9zdCBhY3RpdmUgd2luZG93LCBlc3BlY2lhbGx5IGlmIHRoZXkgaGF2ZSBub3QgYmVlbiBhY3RpdmUgZWFybGllciBpbiB0aGUgZGF5Lg0KMikgU2VuZCBub3RpZmljYXRpb25zIHRvIHBlb3BsZSB3aXRoIGxlc3MgdG90YWwgbWludXRlcyBzbGVwdCB0byBpbXByb3ZlIHNsZWVwIGJ5IGJlaW5nIG1vcmUgYWN0aXZlIHRocm91Z2hvdXQgdGhlIGRheS4gDQozKSBTZW5kIG5vdGlmaWNhdGlvbnMgdG8gb3V0bHlpbmcgdXNlcnMgd2hvIHNwZW5kIG1vcmUgdGltZSBpbiBiZWQgYnV0IGdldCBsZXNzIHNsZWVwIHRoYW4gdGhlIGF2ZXJhZ2Ugd2l0aCBzbGVlcCBoeWdpZW5lIHRpcHMgc2luY2UgdGhleSBtaWdodCBiZSBleHBlcmllbmNpbmcgaW5zb21uaWEuIA0KNCkgU2VuZCBub3RpZmljYXRpb25zIHRvIHBlb3BsZSB0aGF0IGV4Y2VlZCAxMCwwMDAgc3RlcHMgcGVyIGRheSB0byByZW1pbmQgdGhlbSB0aGF0IHRoZXkgbWlnaHQgbmVlZCBtb3JlIHJlY292ZXJ5IGFuZCByZXN0IGFjdGl2aXRpZXMuIA0KDQo=