This project is Case Study 2 In the Google Data analytics course.
I am demonstrating an analysis of Fitbit fitness tracker data and applying any insights gained to create recommendations using these trends to inform Bellabeat Leaf marketing strategy.
Goal
Identify trends in non Bellabeat fitness trackers and apply what is learned from these trends to the marketing of the Bellabeat Leaf. What edge does Bellabeat Leaf have over competitors?
The more that someone wears a device the more information that it will be able to gather. The more information that is gathered the more beneficial it will be for the wearer. I believe there are some trackers out there that people might not wear all the time for different reasons. This may be because of a fashion choices or battery life or other unknown factors. It may be that some people only wear trackers to look at their actual fitness activity where other people might wear a tracker to track their overall health.
I see the Bellabeat leaf as being unique in that it is a high fashion fitness tracker, that also has a very long battery life. I would also suggest that the Bellabeat Leaf is a Health Tracker not necessarily a fitness tracker. Looking into the attributes given to trackers on the Bellabeat website the trackers are labeled as wellness trackers not fitness trackers.
I plan to look into the data of the fitness trackers to see how often they are worn. I will be mainly looking into hours worn per day and daily wearing of the devices.
Loading Packages
library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5 v purrr 0.3.4
v tibble 3.1.2 v dplyr 1.0.7
v tidyr 1.1.3 v stringr 1.4.0
v readr 1.4.0 v forcats 0.5.1
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
library(lubridate)
Attaching package: 'lubridate'
The following objects are masked from 'package:base':
date, intersect, setdiff, union
library(dplyr)
library(ggplot2)
library(tidyr)
library(janitor)
Attaching package: 'janitor'
The following objects are masked from 'package:stats':
chisq.test, fisher.test
library(ggpubr)
Warning: package 'ggpubr' was built under R version 4.1.1
theme_set(theme_pubr())
Process the Data
Here we first clean our data by getting rid of days where the data doesn’t make sense.
This was done by removing rows that had less than 400 steps and less than 100 calories burnt. On average a person walks over 5000 steps a day Reference. About 70 calories are burnt per hour while sleeping Calorie Calculator. With these facts in place I feel it is important to remove these days from our analysis
We also removed any days that were logged as 1440 minutes of sedentary time. Looking around on the fitbit forum has led me to believe that there is a setting on some fitbit trackers that will log a day where the device is not worn as 100% or 1440 minutes of sedentary time. Although these observations are being removed from our main data set it is important to not forget about them. The other option we have here is to convert all of these days to 0 hours of usage but since we cannot be sure that somone didn’t just lay in bed all day with their tracker on it is better to just remove them from the equation.
We have also changed the format of the ActivityDate column from Char to Date. This will allow us to better analyze our data by date.
dailyActivity_merged <- read.csv("dailyActivity_merged.csv")
cleaned_daily_activity_merged <-
subset(dailyActivity_merged, TotalSteps > 399 & Calories > 100 & SedentaryMinutes != 1440)
cleaned_daily_activity_merged$ActivityDate <- as.Date(cleaned_daily_activity_merged$ActivityDate, "%m/%d/%Y")
head(cleaned_daily_activity_merged)
str(cleaned_daily_activity_merged)
'data.frame': 836 obs. of 15 variables:
$ Id : num 1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
$ ActivityDate : Date, format: "2016-04-12" "2016-04-13" ...
$ TotalSteps : int 13162 10735 10460 9762 12669 9705 13019 15506 10544 9819 ...
$ TotalDistance : num 8.5 6.97 6.74 6.28 8.16 ...
$ TrackerDistance : num 8.5 6.97 6.74 6.28 8.16 ...
$ LoggedActivitiesDistance: num 0 0 0 0 0 0 0 0 0 0 ...
$ VeryActiveDistance : num 1.88 1.57 2.44 2.14 2.71 ...
$ ModeratelyActiveDistance: num 0.55 0.69 0.4 1.26 0.41 ...
$ LightActiveDistance : num 6.06 4.71 3.91 2.83 5.04 ...
$ SedentaryActiveDistance : num 0 0 0 0 0 0 0 0 0 0 ...
$ VeryActiveMinutes : int 25 21 30 29 36 38 42 50 28 19 ...
$ FairlyActiveMinutes : int 13 19 11 34 10 20 16 31 12 8 ...
$ LightlyActiveMinutes : int 328 217 181 209 221 164 233 264 205 211 ...
$ SedentaryMinutes : int 728 776 1218 726 773 539 1149 775 818 838 ...
$ Calories : int 1985 1797 1776 1745 1863 1728 1921 2035 1786 1775 ...
Although the data is not perfect it is now much cleaner than it was. My main concern is that some of the sedentary times are still very high. I believe that there might be days where any time not logged is automatically considered sedintary. We will move forward with our analysis and keep this information in mind. If it were to skew our information in any direction it would be towards the side of more hours worn. So if it turns out that all of the participants wore their devices 24 hours a day then we would know that there is a bias.
Create Some Useful Columns
We’re interested in knowing how often our participants wear their device so we need to add a couple columns that will help us identify trends in this area.
Create a total minutes worn column
We know that we want to look at the total amount of time that the tracker was worn so lets add up all of the different activity levels and create a new column called TotalMinutesWorn.
cleaned_daily_activity_merged$TotalMinutesWorn <- cleaned_daily_activity_merged$VeryActiveMinutes + cleaned_daily_activity_merged$FairlyActiveMinutes + cleaned_daily_activity_merged$LightlyActiveMinutes + cleaned_daily_activity_merged$SedentaryMinutes
Create a total hours worn column
Sometimes its easier to think of a day in hours rather than minutes so lets add a column converting minutes worn into hours.
cleaned_daily_activity_merged$TotalHoursWorn <- cleaned_daily_activity_merged$TotalMinutesWorn / 60
Create a worn all day column
Next I think it will be useful to know whether or not the tracker was worn all day so lets create a new column that checks for days that units were worn for 24 hours a day.
cleaned_daily_activity_merged$WornAllDay <- cleaned_daily_activity_merged$TotalHoursWorn == 24
Create a days of the week column
Using the dates that are now in date format we can figure out what day of the week the readings were taken. Lets create a column showing that. It might be useful while analyzing to see if there are any trends associated with days of the week.
cleaned_daily_activity_merged$Weekday <- weekdays(cleaned_daily_activity_merged$ActivityDate)
Analyze the data
Looking at the removed data
Now that our main table has all of the information we’re looking for lets start looking for trends. Lets start by making a table showing the observations that were removed.
removed_daily_activity_merged <-
subset(dailyActivity_merged, TotalSteps < 399 | Calories < 100 | SedentaryMinutes == 1440)
head(removed_daily_activity_merged)
Here I am looking at how Sedentary Minutes stacked up. With 79 of the 104 removed observations showing they were sedentary for 1440 minutes out of the day (Which is equal to 24 hours aka the whole day).
count(removed_daily_activity_merged, SedentaryMinutes)
Now that we’ve got a look at the data we removed from our table lets move on to the rest of the analysis.
Do people wear trackers all day long?
Next I wanted to get a look at the how often the tracker was worn all day.
Total Counts of worn all day.
First lets get a look at how many times people wore the tracker all day vs not worn all day.
worn_all_day_yes_no <- count(cleaned_daily_activity_merged, WornAllDay) %>%
rename(Count = n)
ggplot(worn_all_day_yes_no) +
geom_col(aes(y=Count, x=WornAllDay, fill=WornAllDay)) +
ggtitle("Tracker Worn All Day Occurences")+
ylab("Count") +
xlab("Was The Tracker Worn All Day") +
theme_pubclean()
worn_all_day_percentage <- worn_all_day_yes_no %>%
mutate(percent = Count/sum(Count))
head(worn_all_day_percentage)
So about 54% of the time trackers are not worn for a full 24 hours.
Worn all day by days of the week
Lets look and see if there are any days of the week that stand out in particular for wearing a tracker all day vs not all day.
worn_all_day_weekday <- cleaned_daily_activity_merged[c("Weekday", "WornAllDay")] %>%
count(Weekday, WornAllDay)
worn_all_day_weekday$Weekday <- factor(worn_all_day_weekday$Weekday, levels= c("Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"))
ggplot(worn_all_day_weekday) +
geom_col(position = position_stack(reverse = TRUE), aes(y=n, x=Weekday, fill=WornAllDay, label=n, )) +
geom_text(aes(y=n, x=Weekday, label =n), position = position_stack(vjust = 0.5)) +
ggtitle("Wear Frequency By Day Of Week")+
ylab("Days Measured") +
xlab("Day Of The Week") +
labs(caption = "836 days counted") +
scale_fill_discrete(labels = c("NO", "YES")) +
theme_pubclean()
Warning: Ignoring unknown aesthetics: label
head(worn_all_day_weekday)
The biggest take away from this graph is that there are no days of the week where “Worn All Day” is greater than “Not Worn All Day”
Hours Worn Per day
Now lets look at not just how often the trackers are worn all day, but actually how many hours per day they’re worn.
Lets create a data frame including the total hours worn column and the weekday column then lets make sure that it will graph nicely by changing in level on the days of the week. Then lets create a graph showing hours worn per day organized by day of the week.
daily_wear_trends <-
cleaned_daily_activity_merged[c("Id","TotalHoursWorn", "ActivityDate","Weekday")]
daily_wear_trends$Weekday <- factor(daily_wear_trends$Weekday, levels= c("Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"))
ggplot(daily_wear_trends, aes(y=TotalHoursWorn, x=Weekday, group=1)) +
geom_point(alpha = 1/10) +
geom_smooth(color = "#01bfc4") +
theme(axis.text.x = element_text(angle = 90)) +
coord_cartesian(ylim = c(0, 24)) +
ggtitle("Hours Worn Per Day Of Week")+
ylab("Hours Worn In A Day") +
xlab("Day Of The Week") +
labs(caption = "836 days measured") +
theme_pubclean()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Here we can see all of the 24 hour days worn represented by the solid black dots across the top. We can also see that there are many instances where the trackers are worn less than 20 hours per day. When doing the math it comes out to 47.6% of the time the trackers are worn less than 20 hours per day. See the table below showing the cound of 398 days where trackers were worn less than 20hr.
daily_wear_trends %>%
count(TotalHoursWorn <20)
Average Hours Worn By Day Of the Week
weekday_summary <-
daily_wear_trends %>%
group_by(Weekday) %>%
summarize(AverageHoursWornDaily=mean(TotalHoursWorn))
weekday_summary$Weekday <- factor(weekday_summary$Weekday, levels= c("Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"))
ggplot(data=weekday_summary, aes(y=AverageHoursWornDaily, x=Weekday, group=1)) +
geom_line(color = "#01bfc4") +
theme(axis.text.x = element_text(angle = 90)) +
coord_cartesian(ylim = c(0, 24)) +
ggtitle("Average Hours Worn Per Day Of Week")+
ylab("Average Hours Worn") +
xlab("Day Of The Week") +
theme_pubclean()
Average Hours Worn By Participant
Bar Chart showing the average hours worn per day. This graph shows that 16 out of our 33 participants wear their tracker on average less than 20 hours per day. This leaves us asking the question why?
hours_worn_summary <-
cleaned_daily_activity_merged %>%
group_by(Id) %>%
summarize(average_daily_activity=mean(TotalHoursWorn))
ggplot(hours_worn_summary, aes(x=reorder(rownames(hours_worn_summary), average_daily_activity) , y=average_daily_activity )) +
geom_bar(stat = "identity" ,fill = "#01bfc4") +
ggtitle("Average Hours Worn Per Day By Participant") +
xlab("Participant Number") +
ylab("Average Hours Worn") +
theme(axis.text.x = element_text(angle = 45)) +
theme_pubclean()
Conclusion
There is great value generated for the wearer of fitness/wellness trackers. The value generated increases with the amount of information gathered from the wearer. In our analysis we found that 16 out of 33 wearers are wearing their device less than 20 hours per day on average. Out of all the days measured 54% of the days trackers were worn less than 24hours.
The Bellabeat Leaf is situated to well to target the market of people not wearing devices 24/7. A further anaylsis and survey would help target the advertizements more but there are only so many reasons people would not wear their tracker daily.
Reasons to not wear Tracker
- Battery Life and Recharging
- Fashion (doesn’t work with outfit or event)
- Comfort (doesn’t fit well on wrist or outfit)
- Accuracy (don’t trust the information from tracker)
- Some people don’t want to track fitness
- Syncing problems with App
Reasons People Will Wear A Bellabeat Leaf 24/7
- 6-Month Replaceable battery
- High Fashion can work with all outfits from Gyms to Weddings
- Many different ways to wear
- Easily Sync to App with a double tap
- Bellabeat is more than just about fitness it is about health and wellness
More Research Needed
This data in this study only included the information from 33 people over the course of about a month. The information was enough to figure out that we need to know the reasons why people don’t wear fitness trackers. A survey asking the general public their opinion of fitness/wellness trackers could greatly narrow down the focus for the Bellabeat marketing team.
LS0tDQp0aXRsZTogIkJlbGxhYmVhdCBDYXNlU3R1ZHkiDQpvdXRwdXQ6ICJodG1sX25vdGVib29rIg0KYXV0aG9yOiAiVHJhdmlzIENhcm5leSINCi0tLQ0KDQpUaGlzIHByb2plY3QgaXMgQ2FzZSBTdHVkeSAyIEluIHRoZSBHb29nbGUgRGF0YSBhbmFseXRpY3MgY291cnNlLiANCg0KSSBhbSBkZW1vbnN0cmF0aW5nIGFuIGFuYWx5c2lzIG9mIEZpdGJpdCBmaXRuZXNzIHRyYWNrZXIgZGF0YSBhbmQgYXBwbHlpbmcgYW55IGluc2lnaHRzIGdhaW5lZCB0byBjcmVhdGUgcmVjb21tZW5kYXRpb25zIHVzaW5nIHRoZXNlIHRyZW5kcyB0byBpbmZvcm0gQmVsbGFiZWF0IExlYWYgbWFya2V0aW5nIHN0cmF0ZWd5Lg0KDQojIyBHb2FsDQoNCklkZW50aWZ5IHRyZW5kcyBpbiBub24gQmVsbGFiZWF0IGZpdG5lc3MgdHJhY2tlcnMgYW5kIGFwcGx5IHdoYXQgaXMgbGVhcm5lZCBmcm9tIHRoZXNlIHRyZW5kcyB0byB0aGUgbWFya2V0aW5nIG9mIHRoZSBCZWxsYWJlYXQgTGVhZi4gV2hhdCBlZGdlIGRvZXMgQmVsbGFiZWF0IExlYWYgaGF2ZSBvdmVyIGNvbXBldGl0b3JzPw0KDQpUaGUgbW9yZSB0aGF0IHNvbWVvbmUgd2VhcnMgYSBkZXZpY2UgdGhlIG1vcmUgaW5mb3JtYXRpb24gdGhhdCBpdCB3aWxsIGJlIGFibGUgdG8gZ2F0aGVyLiBUaGUgbW9yZSBpbmZvcm1hdGlvbiB0aGF0IGlzIGdhdGhlcmVkIHRoZSBtb3JlIGJlbmVmaWNpYWwgaXQgd2lsbCBiZSBmb3IgdGhlIHdlYXJlci4gSSBiZWxpZXZlIHRoZXJlIGFyZSBzb21lIHRyYWNrZXJzIG91dCB0aGVyZSB0aGF0IHBlb3BsZSBtaWdodCBub3Qgd2VhciBhbGwgdGhlIHRpbWUgZm9yIGRpZmZlcmVudCByZWFzb25zLiBUaGlzIG1heSBiZSBiZWNhdXNlIG9mIGEgZmFzaGlvbiBjaG9pY2VzIG9yIGJhdHRlcnkgbGlmZSBvciBvdGhlciB1bmtub3duIGZhY3RvcnMuIEl0IG1heSBiZSB0aGF0IHNvbWUgcGVvcGxlIG9ubHkgd2VhciB0cmFja2VycyB0byBsb29rIGF0IHRoZWlyIGFjdHVhbCBmaXRuZXNzIGFjdGl2aXR5IHdoZXJlIG90aGVyIHBlb3BsZSBtaWdodCB3ZWFyIGEgdHJhY2tlciB0byB0cmFjayB0aGVpciBvdmVyYWxsIGhlYWx0aC4NCg0KSSBzZWUgdGhlIEJlbGxhYmVhdCBsZWFmIGFzIGJlaW5nIHVuaXF1ZSBpbiB0aGF0IGl0IGlzIGEgaGlnaCBmYXNoaW9uIGZpdG5lc3MgdHJhY2tlciwgdGhhdCBhbHNvIGhhcyBhIHZlcnkgbG9uZyBiYXR0ZXJ5IGxpZmUuIEkgd291bGQgYWxzbyBzdWdnZXN0IHRoYXQgdGhlIEJlbGxhYmVhdCBMZWFmIGlzIGEgSGVhbHRoIFRyYWNrZXIgbm90IG5lY2Vzc2FyaWx5IGEgZml0bmVzcyB0cmFja2VyLiBMb29raW5nIGludG8gdGhlIGF0dHJpYnV0ZXMgZ2l2ZW4gdG8gdHJhY2tlcnMgb24gdGhlIFtCZWxsYWJlYXRdKGh0dHBzOi8vYmVsbGFiZWF0LmNvbS8pIHdlYnNpdGUgdGhlIHRyYWNrZXJzIGFyZSBsYWJlbGVkIGFzIHdlbGxuZXNzIHRyYWNrZXJzIG5vdCBmaXRuZXNzIHRyYWNrZXJzLiANCg0KSSBwbGFuIHRvIGxvb2sgaW50byB0aGUgZGF0YSBvZiB0aGUgZml0bmVzcyB0cmFja2VycyB0byBzZWUgaG93IG9mdGVuIHRoZXkgYXJlIHdvcm4uIEkgd2lsbCBiZSBtYWlubHkgbG9va2luZyBpbnRvIGhvdXJzIHdvcm4gcGVyIGRheSBhbmQgZGFpbHkgd2VhcmluZyBvZiB0aGUgZGV2aWNlcy4NCg0KIyMgTG9hZGluZyBQYWNrYWdlcw0KDQpgYGB7ciBMb2FkaW5nIFBhY2thZ2VzfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShqYW5pdG9yKQ0KbGlicmFyeShnZ3B1YnIpDQp0aGVtZV9zZXQodGhlbWVfcHVicigpKQ0KYGBgDQoNCg0KIyMgUHJlcGFyaW5nIG91ciBEYXRhDQoNCiAgVGhlIGRhdGEgYmVpbmcgdXNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHkgY2FuIGJlIGZvdW5kIGhlcmUgW0ZpdEJpdCBGaXRuZXNzIFRyYWNrZXIgRGF0YSBdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vYXJhc2huaWMvZml0Yml0KSANCihDQzA6IFB1YmxpYyBEb21haW4sIGRhdGFzZXQgbWFkZSBhdmFpbGFibGUgdGhyb3VnaCBbTcO2Yml1c10oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9hcmFzaG5pYykpOg0KDQoNCiMjIFByb2Nlc3MgdGhlIERhdGENCg0KSGVyZSB3ZSBmaXJzdCBjbGVhbiBvdXIgZGF0YSBieSBnZXR0aW5nIHJpZCBvZiBkYXlzIHdoZXJlIHRoZSBkYXRhIGRvZXNuJ3QgbWFrZSBzZW5zZS4gDQoNClRoaXMgd2FzIGRvbmUgYnkgcmVtb3Zpbmcgcm93cyB0aGF0IGhhZCBsZXNzIHRoYW4gNDAwIHN0ZXBzIGFuZCBsZXNzIHRoYW4gMTAwIGNhbG9yaWVzIGJ1cm50LiBPbiBhdmVyYWdlIGEgcGVyc29uIHdhbGtzIG92ZXIgNTAwMCBzdGVwcyBhIGRheSBbUmVmZXJlbmNlXShodHRwczovL2pvdXJuYWxzLmx3dy5jb20vYWNzbS1tc3NlL0Z1bGx0ZXh0LzIwMTAvMTAwMDAvUGVkb21ldGVyX01lYXN1cmVkX1BoeXNpY2FsX0FjdGl2aXR5X2FuZF9IZWFsdGguNC5hc3B4KS4gQWJvdXQgNzAgY2Fsb3JpZXMgYXJlIGJ1cm50IHBlciBob3VyIHdoaWxlIHNsZWVwaW5nIFtDYWxvcmllIENhbGN1bGF0b3JdKGh0dHBzOi8vYnVybmVkLWNhbG9yaWVzLmNvbS9zcG9ydC9seWluZy1iZWQpLiBXaXRoIHRoZXNlIGZhY3RzIGluIHBsYWNlIEkgZmVlbCBpdCBpcyBpbXBvcnRhbnQgdG8gcmVtb3ZlIHRoZXNlIGRheXMgZnJvbSBvdXIgYW5hbHlzaXMNCg0KV2UgYWxzbyByZW1vdmVkIGFueSBkYXlzIHRoYXQgd2VyZSBsb2dnZWQgYXMgMTQ0MCBtaW51dGVzIG9mIHNlZGVudGFyeSB0aW1lLiBMb29raW5nIGFyb3VuZCBvbiB0aGUgZml0Yml0IGZvcnVtIGhhcyBsZWQgbWUgdG8gYmVsaWV2ZSB0aGF0IHRoZXJlIGlzIGEgc2V0dGluZyBvbiBzb21lIGZpdGJpdCB0cmFja2VycyB0aGF0IHdpbGwgbG9nIGEgZGF5IHdoZXJlIHRoZSBkZXZpY2UgaXMgbm90IHdvcm4gYXMgMTAwJSBvciBbMTQ0MCBtaW51dGVzIG9mIHNlZGVudGFyeSB0aW1lXShodHRwczovL2NvbW11bml0eS5maXRiaXQuY29tL3Q1L090aGVyLUNoYXJnZS1UcmFja2Vycy9zZWRlbnRhcnktbWludXRlcy90ZC1wLzMzNzI2MjEpLiBBbHRob3VnaCB0aGVzZSBvYnNlcnZhdGlvbnMgYXJlIGJlaW5nIHJlbW92ZWQgZnJvbSBvdXIgbWFpbiBkYXRhIHNldCBpdCBpcyBpbXBvcnRhbnQgdG8gbm90IGZvcmdldCBhYm91dCB0aGVtLiBUaGUgb3RoZXIgb3B0aW9uIHdlIGhhdmUgaGVyZSBpcyB0byBjb252ZXJ0IGFsbCBvZiB0aGVzZSBkYXlzIHRvIDAgaG91cnMgb2YgdXNhZ2UgYnV0IHNpbmNlIHdlIGNhbm5vdCBiZSBzdXJlIHRoYXQgc29tb25lIGRpZG4ndCBqdXN0IGxheSBpbiBiZWQgYWxsIGRheSB3aXRoIHRoZWlyIHRyYWNrZXIgb24gaXQgaXMgYmV0dGVyIHRvIGp1c3QgcmVtb3ZlIHRoZW0gZnJvbSB0aGUgZXF1YXRpb24uDQoNCldlIGhhdmUgYWxzbyBjaGFuZ2VkIHRoZSBmb3JtYXQgb2YgdGhlIEFjdGl2aXR5RGF0ZSBjb2x1bW4gZnJvbSBDaGFyIHRvIERhdGUuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBiZXR0ZXIgYW5hbHl6ZSBvdXIgZGF0YSBieSBkYXRlLg0KDQpgYGB7ciBJbXBvcnQgdGhlIERhdGF9DQpkYWlseUFjdGl2aXR5X21lcmdlZCA8LSByZWFkLmNzdigiZGFpbHlBY3Rpdml0eV9tZXJnZWQuY3N2IikNCmBgYA0KDQoNCmBgYHtyIENsZWFuIERhdGF9DQpjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCA8LSANCiAgc3Vic2V0KGRhaWx5QWN0aXZpdHlfbWVyZ2VkLCBUb3RhbFN0ZXBzID4gMzk5ICYgQ2Fsb3JpZXMgPiAxMDAgJiBTZWRlbnRhcnlNaW51dGVzICE9IDE0NDApDQpjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRBY3Rpdml0eURhdGUgPC0gYXMuRGF0ZShjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRBY3Rpdml0eURhdGUsICIlbS8lZC8lWSIpDQpoZWFkKGNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkKQ0KYGBgDQoNCmBgYHtyIFNlZSB0aGUgZm9ybWF0IG9mIEFjdGl2aXR5RGF0ZSBpcyBub3cgRGF0ZX0NCnN0cihjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCkNCmBgYA0KDQpBbHRob3VnaCB0aGUgZGF0YSBpcyBub3QgcGVyZmVjdCBpdCBpcyBub3cgbXVjaCBjbGVhbmVyIHRoYW4gaXQgd2FzLiBNeSBtYWluIGNvbmNlcm4gaXMgdGhhdCBzb21lIG9mIHRoZSBzZWRlbnRhcnkgdGltZXMgYXJlIHN0aWxsIHZlcnkgaGlnaC4gSSBiZWxpZXZlIHRoYXQgdGhlcmUgbWlnaHQgYmUgZGF5cyB3aGVyZSBhbnkgdGltZSBub3QgbG9nZ2VkIGlzIGF1dG9tYXRpY2FsbHkgY29uc2lkZXJlZCBzZWRpbnRhcnkuIFdlIHdpbGwgbW92ZSBmb3J3YXJkIHdpdGggb3VyIGFuYWx5c2lzIGFuZCBrZWVwIHRoaXMgaW5mb3JtYXRpb24gaW4gbWluZC4gSWYgaXQgd2VyZSB0byBza2V3IG91ciBpbmZvcm1hdGlvbiBpbiBhbnkgZGlyZWN0aW9uIGl0IHdvdWxkIGJlIHRvd2FyZHMgdGhlIHNpZGUgb2YgbW9yZSBob3VycyB3b3JuLiBTbyBpZiBpdCB0dXJucyBvdXQgdGhhdCBhbGwgb2YgdGhlIHBhcnRpY2lwYW50cyB3b3JlIHRoZWlyIGRldmljZXMgMjQgaG91cnMgYSBkYXkgdGhlbiB3ZSB3b3VsZCBrbm93IHRoYXQgdGhlcmUgaXMgYSBiaWFzLg0KDQojIyMgQ3JlYXRlIFNvbWUgVXNlZnVsIENvbHVtbnMgDQoNCldlJ3JlIGludGVyZXN0ZWQgaW4ga25vd2luZyBob3cgb2Z0ZW4gb3VyIHBhcnRpY2lwYW50cyB3ZWFyIHRoZWlyIGRldmljZSBzbyB3ZSBuZWVkIHRvIGFkZCBhIGNvdXBsZSBjb2x1bW5zIHRoYXQgd2lsbCBoZWxwIHVzIGlkZW50aWZ5IHRyZW5kcyBpbiB0aGlzIGFyZWEuDQoNCg0KIyMjIyBDcmVhdGUgYSB0b3RhbCBtaW51dGVzIHdvcm4gY29sdW1uDQoNCldlIGtub3cgdGhhdCB3ZSB3YW50IHRvIGxvb2sgYXQgdGhlIHRvdGFsIGFtb3VudCBvZiB0aW1lIHRoYXQgdGhlIHRyYWNrZXIgd2FzIHdvcm4gc28gbGV0cyBhZGQgdXAgYWxsIG9mIHRoZSBkaWZmZXJlbnQgYWN0aXZpdHkgbGV2ZWxzIGFuZCBjcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCBUb3RhbE1pbnV0ZXNXb3JuLg0KDQpgYGB7ciBBZGQgVG90YWwgTWludXRlcyBXb3JuIENvbHVtbn0NCmNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkJFRvdGFsTWludXRlc1dvcm4gPC0gY2xlYW5lZF9kYWlseV9hY3Rpdml0eV9tZXJnZWQkVmVyeUFjdGl2ZU1pbnV0ZXMgKyBjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRGYWlybHlBY3RpdmVNaW51dGVzICsgY2xlYW5lZF9kYWlseV9hY3Rpdml0eV9tZXJnZWQkTGlnaHRseUFjdGl2ZU1pbnV0ZXMgKyBjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRTZWRlbnRhcnlNaW51dGVzDQpgYGANCg0KIyMjIyBDcmVhdGUgYSB0b3RhbCBob3VycyB3b3JuIGNvbHVtbg0KDQpTb21ldGltZXMgaXRzIGVhc2llciB0byB0aGluayBvZiBhIGRheSBpbiBob3VycyByYXRoZXIgdGhhbiBtaW51dGVzIHNvIGxldHMgYWRkIGEgY29sdW1uIGNvbnZlcnRpbmcgbWludXRlcyB3b3JuIGludG8gaG91cnMuIA0KDQpgYGB7ciBBZGQgVG90YWwgSG91cnMgV29ybiBDb2x1bW59DQpjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRUb3RhbEhvdXJzV29ybiA8LSBjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRUb3RhbE1pbnV0ZXNXb3JuIC8gNjANCmBgYA0KDQojIyMjIENyZWF0ZSBhIHdvcm4gYWxsIGRheSBjb2x1bW4NCg0KTmV4dCBJIHRoaW5rIGl0IHdpbGwgYmUgdXNlZnVsIHRvIGtub3cgd2hldGhlciBvciBub3QgdGhlIHRyYWNrZXIgd2FzIHdvcm4gYWxsIGRheSBzbyBsZXRzIGNyZWF0ZSBhIG5ldyBjb2x1bW4gdGhhdCBjaGVja3MgZm9yIGRheXMgdGhhdCB1bml0cyB3ZXJlIHdvcm4gZm9yIDI0IGhvdXJzIGEgZGF5Lg0KDQpgYGB7ciBBZGQgV29ybkFsbERheSBDb2x1bW59DQpjbGVhbmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCRXb3JuQWxsRGF5IDwtIGNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkJFRvdGFsSG91cnNXb3JuID09IDI0DQpgYGANCg0KIyMjIyBDcmVhdGUgYSBkYXlzIG9mIHRoZSB3ZWVrIGNvbHVtbg0KDQpVc2luZyB0aGUgZGF0ZXMgdGhhdCBhcmUgbm93IGluIGRhdGUgZm9ybWF0IHdlIGNhbiBmaWd1cmUgb3V0IHdoYXQgZGF5IG9mIHRoZSB3ZWVrIHRoZSByZWFkaW5ncyB3ZXJlIHRha2VuLiBMZXRzIGNyZWF0ZSBhIGNvbHVtbiBzaG93aW5nIHRoYXQuIEl0IG1pZ2h0IGJlIHVzZWZ1bCB3aGlsZSBhbmFseXppbmcgdG8gc2VlIGlmIHRoZXJlIGFyZSBhbnkgdHJlbmRzIGFzc29jaWF0ZWQgd2l0aCBkYXlzIG9mIHRoZSB3ZWVrLg0KDQpgYGB7cn0NCmNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkJFdlZWtkYXkgPC0gd2Vla2RheXMoY2xlYW5lZF9kYWlseV9hY3Rpdml0eV9tZXJnZWQkQWN0aXZpdHlEYXRlKSANCmBgYA0KDQoNCiMjIEFuYWx5emUgdGhlIGRhdGENCg0KIyMjIExvb2tpbmcgYXQgdGhlIHJlbW92ZWQgZGF0YQ0KDQpOb3cgdGhhdCBvdXIgbWFpbiB0YWJsZSBoYXMgYWxsIG9mIHRoZSBpbmZvcm1hdGlvbiB3ZSdyZSBsb29raW5nIGZvciBsZXRzIHN0YXJ0IGxvb2tpbmcgZm9yIHRyZW5kcy4gTGV0cyBzdGFydCBieSBtYWtpbmcgYSB0YWJsZSBzaG93aW5nIHRoZSBvYnNlcnZhdGlvbnMgdGhhdCB3ZXJlIHJlbW92ZWQuIA0KDQpgYGB7ciBPYnNlcnZhdGlvbnMgUmVtb3ZlZH0NCnJlbW92ZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkIDwtIA0KICBzdWJzZXQoZGFpbHlBY3Rpdml0eV9tZXJnZWQsIFRvdGFsU3RlcHMgPCAzOTkgfCBDYWxvcmllcyA8IDEwMCB8IFNlZGVudGFyeU1pbnV0ZXMgPT0gMTQ0MCkNCmhlYWQocmVtb3ZlZF9kYWlseV9hY3Rpdml0eV9tZXJnZWQpDQpgYGANCiAgDQogIEhlcmUgSSBhbSBsb29raW5nIGF0IGhvdyBTZWRlbnRhcnkgTWludXRlcyBzdGFja2VkIHVwLiBXaXRoIDc5IG9mIHRoZSAxMDQgcmVtb3ZlZCBvYnNlcnZhdGlvbnMgc2hvd2luZyB0aGV5IHdlcmUgc2VkZW50YXJ5IGZvciAxNDQwIG1pbnV0ZXMgb3V0IG9mIHRoZSBkYXkgKFdoaWNoIGlzIGVxdWFsIHRvIDI0IGhvdXJzIGFrYSB0aGUgd2hvbGUgZGF5KS4gDQogIA0KYGBge3J9DQpjb3VudChyZW1vdmVkX2RhaWx5X2FjdGl2aXR5X21lcmdlZCwgU2VkZW50YXJ5TWludXRlcykNCmBgYA0KTm93IHRoYXQgd2UndmUgZ290IGEgbG9vayBhdCB0aGUgZGF0YSB3ZSByZW1vdmVkIGZyb20gb3VyIHRhYmxlIGxldHMgbW92ZSBvbiB0byB0aGUgcmVzdCBvZiB0aGUgYW5hbHlzaXMuDQoNCiMjIyBEbyBwZW9wbGUgd2VhciB0cmFja2VycyBhbGwgZGF5IGxvbmc/DQpOZXh0IEkgd2FudGVkIHRvIGdldCBhIGxvb2sgYXQgdGhlIGhvdyBvZnRlbiB0aGUgdHJhY2tlciB3YXMgd29ybiBhbGwgZGF5Lg0KDQojIyMjIFRvdGFsIENvdW50cyBvZiB3b3JuIGFsbCBkYXkuDQoNCkZpcnN0IGxldHMgZ2V0IGEgbG9vayBhdCBob3cgbWFueSB0aW1lcyBwZW9wbGUgd29yZSB0aGUgdHJhY2tlciBhbGwgZGF5IHZzIG5vdCB3b3JuIGFsbCBkYXkuIA0KYGBge3J9DQp3b3JuX2FsbF9kYXlfeWVzX25vIDwtIGNvdW50KGNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkLCBXb3JuQWxsRGF5KSAlPiUNCiAgcmVuYW1lKENvdW50ID0gbikNCg0KDQoNCmdncGxvdCh3b3JuX2FsbF9kYXlfeWVzX25vKSArIA0KICBnZW9tX2NvbChhZXMoeT1Db3VudCwgeD1Xb3JuQWxsRGF5LCBmaWxsPVdvcm5BbGxEYXkpKSArDQogIGdndGl0bGUoIlRyYWNrZXIgV29ybiBBbGwgRGF5IE9jY3VyZW5jZXMiKSsNCiAgeWxhYigiQ291bnQiKSArDQogIHhsYWIoIldhcyBUaGUgVHJhY2tlciBXb3JuIEFsbCBEYXkiKSArDQogIHRoZW1lX3B1YmNsZWFuKCkNCg0Kd29ybl9hbGxfZGF5X3BlcmNlbnRhZ2UgPC0gd29ybl9hbGxfZGF5X3llc19ubyAlPiUgDQogIG11dGF0ZShwZXJjZW50ID0gQ291bnQvc3VtKENvdW50KSkNCmhlYWQod29ybl9hbGxfZGF5X3BlcmNlbnRhZ2UpDQpgYGANClNvIGFib3V0IDU0JSBvZiB0aGUgdGltZSB0cmFja2VycyBhcmUgbm90IHdvcm4gZm9yIGEgZnVsbCAyNCBob3Vycy4gDQoNCiMjIyMgV29ybiBhbGwgZGF5IGJ5IGRheXMgb2YgdGhlIHdlZWsNCg0KTGV0cyBsb29rIGFuZCBzZWUgaWYgdGhlcmUgYXJlIGFueSBkYXlzIG9mIHRoZSB3ZWVrIHRoYXQgc3RhbmQgb3V0IGluIHBhcnRpY3VsYXIgZm9yIHdlYXJpbmcgYSB0cmFja2VyIGFsbCBkYXkgdnMgbm90IGFsbCBkYXkuDQoNCmBgYHtyfQ0Kd29ybl9hbGxfZGF5X3dlZWtkYXkgPC0gY2xlYW5lZF9kYWlseV9hY3Rpdml0eV9tZXJnZWRbYygiV2Vla2RheSIsICJXb3JuQWxsRGF5IildICU+JQ0KIGNvdW50KFdlZWtkYXksIFdvcm5BbGxEYXkpDQp3b3JuX2FsbF9kYXlfd2Vla2RheSRXZWVrZGF5IDwtIGZhY3Rvcih3b3JuX2FsbF9kYXlfd2Vla2RheSRXZWVrZGF5LCBsZXZlbHM9IGMoIlN1bmRheSIsICJNb25kYXkiLCANCiAgICAiVHVlc2RheSIsICJXZWRuZXNkYXkiLCAiVGh1cnNkYXkiLCAiRnJpZGF5IiwgIlNhdHVyZGF5IikpDQoNCmdncGxvdCh3b3JuX2FsbF9kYXlfd2Vla2RheSkgKyANCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayhyZXZlcnNlID0gVFJVRSksIGFlcyh5PW4sIHg9V2Vla2RheSwgZmlsbD1Xb3JuQWxsRGF5LCBsYWJlbD1uLCApKSArDQogIGdlb21fdGV4dChhZXMoeT1uLCB4PVdlZWtkYXksIGxhYmVsID1uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgiV2VhciBGcmVxdWVuY3kgQnkgRGF5IE9mIFdlZWsiKSsNCiAgeWxhYigiRGF5cyBNZWFzdXJlZCIpICsNCiAgeGxhYigiRGF5IE9mIFRoZSBXZWVrIikgKw0KICBsYWJzKGNhcHRpb24gPSAiODM2IGRheXMgY291bnRlZCIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJOTyIsICJZRVMiKSkgKw0KICB0aGVtZV9wdWJjbGVhbigpDQoNCmhlYWQod29ybl9hbGxfZGF5X3dlZWtkYXkpDQogICAgDQpgYGANClRoZSBiaWdnZXN0IHRha2UgYXdheSBmcm9tIHRoaXMgZ3JhcGggaXMgdGhhdCB0aGVyZSBhcmUgbm8gZGF5cyBvZiB0aGUgd2VlayB3aGVyZSAiV29ybiBBbGwgRGF5IiBpcyBncmVhdGVyIHRoYW4gIk5vdCBXb3JuIEFsbCBEYXkiDQoNCg0KIyMjIEhvdXJzIFdvcm4gUGVyIGRheQ0KTm93IGxldHMgbG9vayBhdCBub3QganVzdCBob3cgb2Z0ZW4gdGhlIHRyYWNrZXJzIGFyZSB3b3JuIGFsbCBkYXksIGJ1dCBhY3R1YWxseSBob3cgbWFueSBob3VycyBwZXIgZGF5IHRoZXkncmUgd29ybi4NCg0KDQpMZXRzIGNyZWF0ZSBhIGRhdGEgZnJhbWUgaW5jbHVkaW5nIHRoZSB0b3RhbCBob3VycyB3b3JuIGNvbHVtbiBhbmQgdGhlIHdlZWtkYXkgY29sdW1uIHRoZW4gbGV0cyBtYWtlIHN1cmUgdGhhdCBpdCB3aWxsIGdyYXBoIG5pY2VseSBieSBjaGFuZ2luZyBpbiBsZXZlbCBvbiB0aGUgZGF5cyBvZiB0aGUgd2Vlay4gVGhlbiBsZXRzIGNyZWF0ZSBhIGdyYXBoIHNob3dpbmcgaG91cnMgd29ybiBwZXIgZGF5IG9yZ2FuaXplZCBieSBkYXkgb2YgdGhlIHdlZWsuDQoNCmBgYHtyIERhaWx5IHdlYXIgdHJlbmRzfQ0KZGFpbHlfd2Vhcl90cmVuZHMgPC0gDQogICAgY2xlYW5lZF9kYWlseV9hY3Rpdml0eV9tZXJnZWRbYygiSWQiLCJUb3RhbEhvdXJzV29ybiIsICJBY3Rpdml0eURhdGUiLCJXZWVrZGF5IildIA0KZGFpbHlfd2Vhcl90cmVuZHMkV2Vla2RheSA8LSBmYWN0b3IoZGFpbHlfd2Vhcl90cmVuZHMkV2Vla2RheSwgbGV2ZWxzPSBjKCJTdW5kYXkiLCAiTW9uZGF5IiwgDQogICAgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIsICJTYXR1cmRheSIpKQ0KZ2dwbG90KGRhaWx5X3dlYXJfdHJlbmRzLCBhZXMoeT1Ub3RhbEhvdXJzV29ybiwgeD1XZWVrZGF5LCBncm91cD0xKSkgKyANCiAgZ2VvbV9wb2ludChhbHBoYSA9IDEvMTApICsNCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiIzAxYmZjNCIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDI0KSkgKw0KICBnZ3RpdGxlKCJIb3VycyBXb3JuIFBlciBEYXkgT2YgV2VlayIpKw0KICB5bGFiKCJIb3VycyBXb3JuIEluIEEgRGF5IikgKw0KICB4bGFiKCJEYXkgT2YgVGhlIFdlZWsiKSArDQogIGxhYnMoY2FwdGlvbiA9ICI4MzYgZGF5cyBtZWFzdXJlZCIpICsNCiAgdGhlbWVfcHViY2xlYW4oKQ0KYGBgDQoNCg0KSGVyZSB3ZSBjYW4gc2VlIGFsbCBvZiB0aGUgMjQgaG91ciBkYXlzIHdvcm4gcmVwcmVzZW50ZWQgYnkgdGhlIHNvbGlkIGJsYWNrIGRvdHMgYWNyb3NzIHRoZSB0b3AuICBXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGVyZSBhcmUgbWFueSBpbnN0YW5jZXMgd2hlcmUgdGhlIHRyYWNrZXJzIGFyZSB3b3JuIGxlc3MgdGhhbiAyMCBob3VycyBwZXIgZGF5LiBXaGVuIGRvaW5nIHRoZSBtYXRoIGl0IGNvbWVzIG91dCB0byA0Ny42JSBvZiB0aGUgdGltZSB0aGUgdHJhY2tlcnMgYXJlIHdvcm4gbGVzcyB0aGFuIDIwIGhvdXJzIHBlciBkYXkuIFNlZSB0aGUgdGFibGUgYmVsb3cgc2hvd2luZyB0aGUgY291bmQgb2YgMzk4IGRheXMgd2hlcmUgdHJhY2tlcnMgd2VyZSB3b3JuIGxlc3MgdGhhbiAyMGhyLg0KDQpgYGB7cn0NCmRhaWx5X3dlYXJfdHJlbmRzICU+JQ0KICBjb3VudChUb3RhbEhvdXJzV29ybiA8MjApIA0KDQpgYGANCg0KIyMjIyBBdmVyYWdlIEhvdXJzIFdvcm4gQnkgRGF5IE9mIHRoZSBXZWVrICANCg0KYGBge3J9DQp3ZWVrZGF5X3N1bW1hcnkgPC0NCiAgZGFpbHlfd2Vhcl90cmVuZHMgJT4lDQogIGdyb3VwX2J5KFdlZWtkYXkpICU+JQ0KICBzdW1tYXJpemUoQXZlcmFnZUhvdXJzV29ybkRhaWx5PW1lYW4oVG90YWxIb3Vyc1dvcm4pKQ0KDQp3ZWVrZGF5X3N1bW1hcnkkV2Vla2RheSA8LSBmYWN0b3Iod2Vla2RheV9zdW1tYXJ5JFdlZWtkYXksIGxldmVscz0gYygiU3VuZGF5IiwgIk1vbmRheSIsIA0KICAgICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiKSkNCg0KZ2dwbG90KGRhdGE9d2Vla2RheV9zdW1tYXJ5LCBhZXMoeT1BdmVyYWdlSG91cnNXb3JuRGFpbHksIHg9V2Vla2RheSwgZ3JvdXA9MSkpICsgDQogIGdlb21fbGluZShjb2xvciA9ICIjMDFiZmM0IikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMjQpKSArDQogIGdndGl0bGUoIkF2ZXJhZ2UgSG91cnMgV29ybiBQZXIgRGF5IE9mIFdlZWsiKSsNCiAgeWxhYigiQXZlcmFnZSBIb3VycyBXb3JuIikgKw0KICB4bGFiKCJEYXkgT2YgVGhlIFdlZWsiKSArDQogIHRoZW1lX3B1YmNsZWFuKCkNCg0KYGBgDQoNCg0KDQojIyMjIEF2ZXJhZ2UgSG91cnMgV29ybiBCeSBQYXJ0aWNpcGFudA0KDQpCYXIgQ2hhcnQgc2hvd2luZyB0aGUgYXZlcmFnZSBob3VycyB3b3JuIHBlciBkYXkuIFRoaXMgZ3JhcGggc2hvd3MgdGhhdCAxNiBvdXQgb2Ygb3VyIDMzIHBhcnRpY2lwYW50cyB3ZWFyIHRoZWlyIHRyYWNrZXIgb24gYXZlcmFnZSBsZXNzIHRoYW4gMjAgaG91cnMgcGVyIGRheS4gVGhpcyBsZWF2ZXMgdXMgYXNraW5nIHRoZSBxdWVzdGlvbiB3aHk/DQoNCmBgYHtyfQ0KaG91cnNfd29ybl9zdW1tYXJ5IDwtDQogIGNsZWFuZWRfZGFpbHlfYWN0aXZpdHlfbWVyZ2VkICU+JQ0KICBncm91cF9ieShJZCkgJT4lDQogIHN1bW1hcml6ZShhdmVyYWdlX2RhaWx5X2FjdGl2aXR5PW1lYW4oVG90YWxIb3Vyc1dvcm4pKQ0KZ2dwbG90KGhvdXJzX3dvcm5fc3VtbWFyeSwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhob3Vyc193b3JuX3N1bW1hcnkpLCBhdmVyYWdlX2RhaWx5X2FjdGl2aXR5KSAsIHk9YXZlcmFnZV9kYWlseV9hY3Rpdml0eSApKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiAsZmlsbCA9ICIjMDFiZmM0IikgKw0KICBnZ3RpdGxlKCJBdmVyYWdlIEhvdXJzIFdvcm4gUGVyIERheSBCeSBQYXJ0aWNpcGFudCIpICsNCiAgeGxhYigiUGFydGljaXBhbnQgTnVtYmVyIikgKw0KICB5bGFiKCJBdmVyYWdlIEhvdXJzIFdvcm4iKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArDQogdGhlbWVfcHViY2xlYW4oKQ0KYGBgDQojIyBDb25jbHVzaW9uIA0KIFRoZXJlIGlzIGdyZWF0IHZhbHVlIGdlbmVyYXRlZCBmb3IgdGhlIHdlYXJlciBvZiBmaXRuZXNzL3dlbGxuZXNzIHRyYWNrZXJzLiBUaGUgdmFsdWUgZ2VuZXJhdGVkIGluY3JlYXNlcyB3aXRoIHRoZSBhbW91bnQgb2YgaW5mb3JtYXRpb24gZ2F0aGVyZWQgZnJvbSB0aGUgd2VhcmVyLiBJbiBvdXIgYW5hbHlzaXMgd2UgZm91bmQgdGhhdCAxNiBvdXQgb2YgMzMgd2VhcmVycyBhcmUgd2VhcmluZyB0aGVpciBkZXZpY2UgbGVzcyB0aGFuIDIwIGhvdXJzIHBlciBkYXkgb24gYXZlcmFnZS4gT3V0IG9mIGFsbCB0aGUgZGF5cyBtZWFzdXJlZCA1NCUgb2YgdGhlIGRheXMgdHJhY2tlcnMgd2VyZSB3b3JuIGxlc3MgdGhhbiAyNGhvdXJzLiANCiANCiBUaGUgQmVsbGFiZWF0IExlYWYgaXMgc2l0dWF0ZWQgdG8gd2VsbCB0byB0YXJnZXQgdGhlIG1hcmtldCBvZiBwZW9wbGUgbm90IHdlYXJpbmcgZGV2aWNlcyAyNC83LiBBIGZ1cnRoZXIgYW5heWxzaXMgYW5kIHN1cnZleSB3b3VsZCBoZWxwIHRhcmdldCB0aGUgYWR2ZXJ0aXplbWVudHMgbW9yZSBidXQgdGhlcmUgYXJlIG9ubHkgc28gbWFueSByZWFzb25zIHBlb3BsZSB3b3VsZCBub3Qgd2VhciB0aGVpciB0cmFja2VyIGRhaWx5LiANCiANCiANCiMjIyBSZWFzb25zIHRvIG5vdCB3ZWFyIFRyYWNrZXINCiogQmF0dGVyeSBMaWZlIGFuZCBSZWNoYXJnaW5nIA0KKiBGYXNoaW9uIChkb2Vzbid0IHdvcmsgd2l0aCBvdXRmaXQgb3IgZXZlbnQpDQoqIENvbWZvcnQgKGRvZXNuJ3QgZml0IHdlbGwgb24gd3Jpc3Qgb3Igb3V0Zml0KQ0KKiBBY2N1cmFjeSAoZG9uJ3QgdHJ1c3QgdGhlIGluZm9ybWF0aW9uIGZyb20gdHJhY2tlcikNCiogU29tZSBwZW9wbGUgZG9uJ3Qgd2FudCB0byB0cmFjayBmaXRuZXNzDQoqIFN5bmNpbmcgcHJvYmxlbXMgd2l0aCBBcHANCg0KIyMjIFJlYXNvbnMgUGVvcGxlIFdpbGwgV2VhciBBIEJlbGxhYmVhdCBMZWFmIDI0LzcNCiogNi1Nb250aCBSZXBsYWNlYWJsZSBiYXR0ZXJ5DQoqIEhpZ2ggRmFzaGlvbiBjYW4gd29yayB3aXRoIGFsbCBvdXRmaXRzIGZyb20gR3ltcyB0byBXZWRkaW5ncw0KKiBNYW55IGRpZmZlcmVudCB3YXlzIHRvIHdlYXINCiAgKyBjbGlwDQogICsgYnJhY2VsZXQNCiAgKyBuZWNrbGFjZQ0KKiBFYXNpbHkgU3luYyB0byBBcHAgd2l0aCBhIGRvdWJsZSB0YXANCiogQmVsbGFiZWF0IGlzIG1vcmUgdGhhbiBqdXN0IGFib3V0IGZpdG5lc3MgaXQgaXMgYWJvdXQgaGVhbHRoIGFuZCB3ZWxsbmVzcw0KDQojIyBNb3JlIFJlc2VhcmNoIE5lZWRlZA0KDQpUaGlzIGRhdGEgaW4gdGhpcyBzdHVkeSBvbmx5IGluY2x1ZGVkIHRoZSBpbmZvcm1hdGlvbiBmcm9tIDMzIHBlb3BsZSBvdmVyIHRoZSBjb3Vyc2Ugb2YgYWJvdXQgYSBtb250aC4gVGhlIGluZm9ybWF0aW9uIHdhcyBlbm91Z2ggdG8gZmlndXJlIG91dCB0aGF0IHdlIG5lZWQgdG8ga25vdyB0aGUgcmVhc29ucyB3aHkgcGVvcGxlIGRvbid0IHdlYXIgZml0bmVzcyB0cmFja2Vycy4gQSBzdXJ2ZXkgYXNraW5nIHRoZSBnZW5lcmFsIHB1YmxpYyB0aGVpciBvcGluaW9uIG9mIGZpdG5lc3Mvd2VsbG5lc3MgdHJhY2tlcnMgY291bGQgZ3JlYXRseSBuYXJyb3cgZG93biB0aGUgZm9jdXMgZm9yIHRoZSBCZWxsYWJlYXQgbWFya2V0aW5nIHRlYW0uDQo=