Bella Beat Data Analysis

Author: Idowu, Adetola

Date : 5th March 2022

Introduction

This case study is a capstone project for the Google Data Analytics Capstone Project.I used the six steps in data analysis to carry out this project.

Step 1: Ask Phase

1.0 Project Background

I joined a fiction company six months ago called Bellabeat. I joined as a junior data analyst. Bellabeat is a high-tech company that manufactures health-focused smart products for women since 2013.This product collects data on sleep,stress and reproductive activities in women.Thus empowering and informing women about their health and habits.

1.1 Deliverables / Business Task

The stakeholders wants to focus on analyzing how consumers use non-Bellabeat smart devices.. Then recommendations to improve the marketing strategy of Bellabeat products would be suggested from the insight gotten.

1.2 Business Objectives

  1. What are the trends identified in smart device usage?
  2. How could these trends apply to Bellabeat customers?
  3. How could these trends help influence Bellabeat marketing strategy?

1.3 Stakeholders

  • Urška Sršen: This is Bellabeat’s cofounder and Chief Creative Officer.
  • Sando Mur: Also a co founder of Bellabeat and an essential member of Bellabeat executive team.
  • Bellabeat marketing analytics team: This is a team of data analysts responsible for collecting, analyzing, and reporting data that helps guide Bellabeat’s marketing strategy.

Step 2: Prepare Phase

2.0 About the data source

As adviced by Chief Creative Officer, I used a public data set from a public domain called kaggle.The data set “FitBit Fitness Tracker Data”contains personal fitness tracker from thirty fitbit users.

2.1 Information in the dataset

  1. The data set contained each user’s minute-level output for physical activity, daily heart rate, sleep monitor,daily activity steps and users habits.
  2. The data set were organised in both long and wide formats.
  3. The data downloaded from kaagle and stored in a folder on the desktop. The folder contained 18 csv files.
  4. The data set was last updated on 16th December 2020.

2.2 Dataset Credibility

A good data source is ROCCC which stands for Reliable, Original, Comprehensive, Current, and Cited. 1. Reliable - The data set is not so reliable because the sample selection bias does not reflect the overall population. In this data set the sample size is only 30 users. 2. Original - The originality of the data set is also low because the data set is gotten from a third party provider “Amazon Mechanical Turk”. 3. Comprehensive - The comprehensiveness of the data set is okay because the data set contains the important information and parameters needed to answer the business task 4. Current - The data set is not current as it was last updated in December 2020. 5. Cited - The data set was gotten from a third party so we cannot identify the source of the data.

Step 3: Process Phase

3.0 Tool used

I am using R programming language tool to process the dataset because it is easy to use and i am very familiar with it

3.1 I loaded the important libraries

library(readr)
Warning: package ‘readr’ was built under R version 4.1.2
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------------- tidyverse 1.3.1 --
√ ggplot2 3.3.5     √ dplyr   1.0.8
√ tibble  3.1.6     √ stringr 1.4.0
√ tidyr   1.2.0     √ forcats 0.5.1
√ purrr   0.3.4     
Warning: package ‘ggplot2’ was built under R version 4.1.2
Warning: package ‘tibble’ was built under R version 4.1.2
Warning: package ‘tidyr’ was built under R version 4.1.2
Warning: package ‘dplyr’ was built under R version 4.1.2
-- Conflicts ------------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(ggplot2)
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(janitor)
Warning: package ‘janitor’ was built under R version 4.1.2

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(skimr)
Warning: package ‘skimr’ was built under R version 4.1.2
library(tinytex)
Warning: package ‘tinytex’ was built under R version 4.1.2
#Now to load the data sets
daily_Activity <- read_csv('dailyActivity_merged.csv')
Rows: 940 Columns: 15
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr  (1): ActivityDate
dbl (14): Id, TotalSteps, TotalDistance, TrackerDistance, LoggedActivitiesDistance...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
daily_Calories <- read_csv('dailyCalories_merged.csv')
Rows: 940 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityDay
dbl (2): Id, Calories

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
daily_Intensities <- read_csv('dailyIntensities_merged.csv')
Rows: 940 Columns: 10
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityDay
dbl (9): Id, SedentaryMinutes, LightlyActiveMinutes, FairlyActiveMinutes, VeryActi...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
daily_Steps <-  read_csv('dailySteps_merged.csv')
Rows: 940 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityDay
dbl (2): Id, StepTotal

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
heartrate_seconds <-  read_csv('heartrate_seconds_merged.csv')
Rows: 2483658 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): Time
dbl (2): Id, Value

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
hourly_Calories <-  read_csv('hourlyCalories_merged.csv')
Rows: 22099 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityHour
dbl (2): Id, Calories

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
hourly_Intensities <-  read_csv('hourlyIntensities_merged.csv')
Rows: 22099 Columns: 4
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityHour
dbl (3): Id, TotalIntensity, AverageIntensity

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
hourly_Steps <-  read_csv('hourlySteps_merged.csv')
Rows: 22099 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityHour
dbl (2): Id, StepTotal

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_cal_narrow <-  read_csv('minuteCaloriesNarrow_merged.csv')
Rows: 1325580 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityMinute
dbl (2): Id, Calories

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_cal_wide <- read_csv('minuteCaloriesWide_merged.csv')
Rows: 21645 Columns: 62
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr  (1): ActivityHour
dbl (61): Id, Calories00, Calories01, Calories02, Calories03, Calories04, Calories...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_int_narrow <- read_csv('minuteIntensitiesNarrow_merged.csv')
Rows: 1325580 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityMinute
dbl (2): Id, Intensity

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_int_wide <- read_csv('minuteIntensitiesWide_merged.csv')
Rows: 21645 Columns: 62
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr  (1): ActivityHour
dbl (61): Id, Intensity00, Intensity01, Intensity02, Intensity03, Intensity04, Int...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_met_narrow <- read_csv('minuteMETsNarrow_merged.csv')
Rows: 1325580 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityMinute
dbl (2): Id, METs

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_sleep <- read_csv('minuteSleep_merged.csv')
Rows: 188521 Columns: 4
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): date
dbl (3): Id, value, logId

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_step_narrow <- read_csv('minuteStepsNarrow_merged.csv')
Rows: 1325580 Columns: 3
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): ActivityMinute
dbl (2): Id, Steps

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
minute_step_wide <- read_csv('minuteStepsWide_merged.csv')
Rows: 21645 Columns: 62
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr  (1): ActivityHour
dbl (61): Id, Steps00, Steps01, Steps02, Steps03, Steps04, Steps05, Steps06, Steps...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
sleep_day <- read_csv('sleepDay_merged.csv')
Rows: 413 Columns: 5
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): SleepDay
dbl (4): Id, TotalSleepRecords, TotalMinutesAsleep, TotalTimeInBed

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
weight_log_info <- read_csv('weightLogInfo_merged.csv')
Rows: 67 Columns: 8
-- Column specification --------------------------------------------------------------
Delimiter: ","
chr (1): Date
dbl (6): Id, WeightKg, WeightPounds, Fat, BMI, LogId
lgl (1): IsManualReport

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.

3.2 I compared the column names

colnames(daily_Activity)
 [1] "Id"                       "ActivityDate"             "TotalSteps"              
 [4] "TotalDistance"            "TrackerDistance"          "LoggedActivitiesDistance"
 [7] "VeryActiveDistance"       "ModeratelyActiveDistance" "LightActiveDistance"     
[10] "SedentaryActiveDistance"  "VeryActiveMinutes"        "FairlyActiveMinutes"     
[13] "LightlyActiveMinutes"     "SedentaryMinutes"         "Calories"                
colnames(daily_Calories)
[1] "Id"          "ActivityDay" "Calories"   
colnames(daily_Intensities)
 [1] "Id"                       "ActivityDay"              "SedentaryMinutes"        
 [4] "LightlyActiveMinutes"     "FairlyActiveMinutes"      "VeryActiveMinutes"       
 [7] "SedentaryActiveDistance"  "LightActiveDistance"      "ModeratelyActiveDistance"
[10] "VeryActiveDistance"      
colnames(daily_Steps)
[1] "Id"          "ActivityDay" "StepTotal"  
colnames(heartrate_seconds)
[1] "Id"    "Time"  "Value"
colnames(hourly_Calories)
[1] "Id"           "ActivityHour" "Calories"    
colnames(hourly_Intensities)
[1] "Id"               "ActivityHour"     "TotalIntensity"   "AverageIntensity"
colnames(hourly_Steps)
[1] "Id"           "ActivityHour" "StepTotal"   
colnames(minute_cal_narrow)
[1] "Id"             "ActivityMinute" "Calories"      
colnames(minute_cal_wide)
 [1] "Id"           "ActivityHour" "Calories00"   "Calories01"   "Calories02"  
 [6] "Calories03"   "Calories04"   "Calories05"   "Calories06"   "Calories07"  
[11] "Calories08"   "Calories09"   "Calories10"   "Calories11"   "Calories12"  
[16] "Calories13"   "Calories14"   "Calories15"   "Calories16"   "Calories17"  
[21] "Calories18"   "Calories19"   "Calories20"   "Calories21"   "Calories22"  
[26] "Calories23"   "Calories24"   "Calories25"   "Calories26"   "Calories27"  
[31] "Calories28"   "Calories29"   "Calories30"   "Calories31"   "Calories32"  
[36] "Calories33"   "Calories34"   "Calories35"   "Calories36"   "Calories37"  
[41] "Calories38"   "Calories39"   "Calories40"   "Calories41"   "Calories42"  
[46] "Calories43"   "Calories44"   "Calories45"   "Calories46"   "Calories47"  
[51] "Calories48"   "Calories49"   "Calories50"   "Calories51"   "Calories52"  
[56] "Calories53"   "Calories54"   "Calories55"   "Calories56"   "Calories57"  
[61] "Calories58"   "Calories59"  
colnames(minute_int_narrow)
[1] "Id"             "ActivityMinute" "Intensity"     
colnames(minute_int_wide)
 [1] "Id"           "ActivityHour" "Intensity00"  "Intensity01"  "Intensity02" 
 [6] "Intensity03"  "Intensity04"  "Intensity05"  "Intensity06"  "Intensity07" 
[11] "Intensity08"  "Intensity09"  "Intensity10"  "Intensity11"  "Intensity12" 
[16] "Intensity13"  "Intensity14"  "Intensity15"  "Intensity16"  "Intensity17" 
[21] "Intensity18"  "Intensity19"  "Intensity20"  "Intensity21"  "Intensity22" 
[26] "Intensity23"  "Intensity24"  "Intensity25"  "Intensity26"  "Intensity27" 
[31] "Intensity28"  "Intensity29"  "Intensity30"  "Intensity31"  "Intensity32" 
[36] "Intensity33"  "Intensity34"  "Intensity35"  "Intensity36"  "Intensity37" 
[41] "Intensity38"  "Intensity39"  "Intensity40"  "Intensity41"  "Intensity42" 
[46] "Intensity43"  "Intensity44"  "Intensity45"  "Intensity46"  "Intensity47" 
[51] "Intensity48"  "Intensity49"  "Intensity50"  "Intensity51"  "Intensity52" 
[56] "Intensity53"  "Intensity54"  "Intensity55"  "Intensity56"  "Intensity57" 
[61] "Intensity58"  "Intensity59" 
colnames(minute_met_narrow)
[1] "Id"             "ActivityMinute" "METs"          
colnames(minute_sleep)
[1] "Id"    "date"  "value" "logId"
colnames(minute_step_narrow)
[1] "Id"             "ActivityMinute" "Steps"         
colnames(minute_step_wide)
 [1] "Id"           "ActivityHour" "Steps00"      "Steps01"      "Steps02"     
 [6] "Steps03"      "Steps04"      "Steps05"      "Steps06"      "Steps07"     
[11] "Steps08"      "Steps09"      "Steps10"      "Steps11"      "Steps12"     
[16] "Steps13"      "Steps14"      "Steps15"      "Steps16"      "Steps17"     
[21] "Steps18"      "Steps19"      "Steps20"      "Steps21"      "Steps22"     
[26] "Steps23"      "Steps24"      "Steps25"      "Steps26"      "Steps27"     
[31] "Steps28"      "Steps29"      "Steps30"      "Steps31"      "Steps32"     
[36] "Steps33"      "Steps34"      "Steps35"      "Steps36"      "Steps37"     
[41] "Steps38"      "Steps39"      "Steps40"      "Steps41"      "Steps42"     
[46] "Steps43"      "Steps44"      "Steps45"      "Steps46"      "Steps47"     
[51] "Steps48"      "Steps49"      "Steps50"      "Steps51"      "Steps52"     
[56] "Steps53"      "Steps54"      "Steps55"      "Steps56"      "Steps57"     
[61] "Steps58"      "Steps59"     
colnames(sleep_day)
[1] "Id"                 "SleepDay"           "TotalSleepRecords" 
[4] "TotalMinutesAsleep" "TotalTimeInBed"    
colnames(weight_log_info)
[1] "Id"             "Date"           "WeightKg"       "WeightPounds"  
[5] "Fat"            "BMI"            "IsManualReport" "LogId"         

3.3 I checked for the total missing values in each tibble

# First method
sum(is.na(daily_Activity))
[1] 0
sum(is.na(daily_Calories))
[1] 0
sum(is.na(daily_Intensities))
[1] 0
sum(is.na(daily_Steps))
[1] 0
# Second method
daily_Activity %>% duplicated () %>% sum()
[1] 0
daily_Calories %>% duplicated () %>% sum()
[1] 0
daily_Intensities %>% duplicated () %>% sum()
[1] 0
# Third method
daily_Activity %>% is.na() %>% sum()
[1] 0
daily_Calories %>% is.na() %>% sum()
[1] 0
sleep_day %>% duplicated() %>% sum()
[1] 3
View(sleep_day)

# Running these methods i found out that there were no missing data values in the data set but there were three duplicates found in sleep_day data set

#To remove the duplicates found in sleep_day
cleaned_sleep_day <- sleep_day[!duplicated(sleep_day),]


#To verify we have removed the duplicates
cleaned_sleep_day %>% duplicated() %>% sum()
[1] 0
# For daily_activity: I convert the string column (ActivityDate) to date format
daily_Activity$ActivityDate <- mdy(daily_Activity$ActivityDate)
head(daily_Activity)

# For heart_rate: I converted the Time column to date format and i removed the time stamp
heartrate_seconds$Time <- as_date(mdy_hms(heartrate_seconds$Time))
head(heartrate_seconds)

#For Sleep day: I converted the SleepDay column to date format and i removed the time stamp
sleep_day$SleepDay <- as_date(mdy_hms(sleep_day$SleepDay))
head(sleep_day)

#For weight_log_info: I converted the Date column to date format and i removed the time stamp
weight_log_info$Date <- as_date(mdy_hms(weight_log_info$Date))
View(weight_log_info)

3.4 I renamed the column names for consistency

# For daily Activity: We rename the ActivityDate column to Date
clean_daily_activity <- rename(daily_Activity, Date = ActivityDate)
View(clean_daily_activity)

# For heart rate: We rename the ActivityDate column to Date
clean_heart_rate_sec <- rename(heartrate_seconds, Date = Time)
View(clean_heart_rate_sec)

# For sleep_day: We rename the Sleepday column to Date
clean_sleep_day <- rename(sleep_day, Date = SleepDay)
View(clean_sleep_day)

# I did not rename the date variable in "clean_weight_log" because it is already named "Date"
clean_weight_log <- weight_log_info

3.5 I cleaned the column names

clean_daily_activity <- clean_daily_activity %>% janitor::clean_names()
clean_heart_rate_sec <- clean_heart_rate_sec %>% janitor::clean_names()
clean_sleep_day <- clean_sleep_day %>% janitor::clean_names()
clean_weight_log <- clean_weight_log %>% janitor::clean_names()

Step 4: Analyse Phase

4.0 I am using four metrics for this analysis. They are Daily Activity,Weight,sleep day and heart rate.

I want to know the number of distinct participants in each metric(our four data frames: “clean_daily_activity”, “clean_heart_rate_sec”, “clean_sleep_day” and “clean_weight_log”), total number of days tracked, and number of days tracked for each metric per participant.

4.1 The number of distinct participants in each data frame

# For clean_daily_activity: Number of distinct participants

daily_disinct_id <- n_distinct(clean_daily_activity$id)
# There were 33 distinct participants in daily_activity

daily_distinct_date <- n_distinct(clean_daily_activity$date)
# The daily_activity data was tracked for 31 days

daily_min_date <- min(clean_daily_activity$date)
#The earliest date was 2016-04-12

daily_max_date <- max(clean_daily_activity$date)
#The last date was 2016-05-12

#So from the calculations above we can conclude that the daily_activity data was tracked for a duration of 31days between 2016-04-12 nd 2016-05-12 and we had 33 distinct participants/Id's in the data set.


#For clean_heart_rate_sec: Number of distinct participants

heart_distinct_id <- n_distinct(clean_heart_rate_sec$id)
# There were 14 distinct participants in heart_rate_sec

heart_distinct_date <- n_distinct(clean_heart_rate_sec$date)
# The heart_rate_sec data was tracked for 31 days

heart_min_date <- min(clean_heart_rate_sec$date)
# The earliest date was 2016-04-12

heart_max_date <- max(clean_heart_rate_sec$date)
# The last date was 2016-05-12

# So from the calculations above we can conclude that the heart_rate data was tracked for a duration of 31days between 2016-04-12 nd 2016-05-12 and we had 14 distinct participants/Id's in the data set.


#For weight_log: Number of distinct participants

weight_distinct_id <- n_distinct(clean_weight_log$id)
# There were 8 distinct participants

weight_distinct_date <- n_distinct(clean_weight_log$date)
# The data was tracked for 31 days

weight_min_date <- min(clean_weight_log$date)
#  The earliest date was 2016-04-12

weight_max_date <- max(clean_weight_log$date)
# The last date was 2016-05-12

# So from the calculations above we can conclude that the weight_log data was tracked for a duration of 31days between 2016-04-12 nd 2016-05-12 and we had 8 distinct participants/Id's in the data set.

#For sleep_day: Number of distinct participants

sleep_distinct_id <- n_distinct(clean_sleep_day$id)
# There were 24 distinct participants

sleep_distinct_date <- n_distinct(clean_sleep_day$date)
# The data was tracked for 31 days

sleep_min_date <- min(clean_sleep_day$date)
# The earliest date was 2016-04-12

sleep_max_date <- max(clean_sleep_day$date)
# The last date was 2016-05-12

# So from the calculations above we can conclude that the sleep_day data was tracked for a duration of 31days between 2016-04-12 nd 2016-05-12 and we had 24 distinct participants/Id's in the data set.

Step 5. Share phase

To plot a graph of distinct participants per mertic

# The distinct participants of weight,sleep,heart and daily activity were 8,24,14 and 33 respectively

data <- c("daily_activity", "heartrate_sec", "sleep_day", "weight_log")
distinct_ids <- c(33,14,24,8)
participants_per_metric <- tibble(data, distinct_ids)

participants_per_metric %>%
  ggplot(aes(x = data, y = distinct_ids,fill = distinct_ids)) + 
  geom_col(position = "dodge") +
  labs(title = "Number of Unique Participants in each Metric",subtitle= "Data source from Amazon Mechanical Turk", x = "Metric Name", y = "Distinct Participants",caption = "figure 1") +
theme( plot.title = element_text(hjust = .5)) +
scale_fill_continuous()

Figure 1 graph Result

  • Participants used the smart device to record their daily activity the most.
  • We had 24 participants that used the smart device to record their sleep activity.
  • While 14 participants recorded their heart rate.
  • The least metric recorded by participants was the weight metric.

I want to plot a graph to see the relationship between total steps taken and calories burned

# I am using the daily activity dataframe for this

ggplot(clean_daily_activity, aes(x=total_steps, y=calories)) + 
  geom_point() + 
  geom_smooth() + 
  labs(title="Total Steps vs. Calories",caption = "figure 2")
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Figure 2 graph result

  • The graph shows us that a positive correlation exists between the total steps taken and the calories burnt.
  • This means that the more active the participants are, the more calories that are burned.

I want to plot a graph to know the day of the week participants are motivated to workout the most

Figure 3 graph result

  • The most active days are on Mondays and Saturdays
  • The least active days Thursdays and Sundays
  • Participants usually start the weekend by being active again (Fridays to Saturdays)

Step 6. Act phase

Thank you

LS0tDQp0aXRsZTogIiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIEJlbGxhIEJlYXQgRGF0YSBBbmFseXNpcw0KIyMjIEF1dGhvcjogSWRvd3UsIEFkZXRvbGENCiMjIyBEYXRlIDogNXRoIE1hcmNoIDIwMjINCg0KDQojIyMgSW50cm9kdWN0aW9uDQoNCiMjIyBUaGlzIGNhc2Ugc3R1ZHkgaXMgYSBjYXBzdG9uZSBwcm9qZWN0IGZvciB0aGUgR29vZ2xlIERhdGEgQW5hbHl0aWNzIENhcHN0b25lIFByb2plY3QuSSB1c2VkIHRoZSBzaXggc3RlcHMgaW4gZGF0YSBhbmFseXNpcyB0byBjYXJyeSBvdXQgdGhpcyBwcm9qZWN0Lg0KDQojIFN0ZXAgMTogQXNrIFBoYXNlDQoNCiMjIyAxLjAgUHJvamVjdCBCYWNrZ3JvdW5kDQoNCkkgam9pbmVkIGEgZmljdGlvbiBjb21wYW55IHNpeCBtb250aHMgYWdvICBjYWxsZWQgQmVsbGFiZWF0LiBJIGpvaW5lZCBhcyBhIGp1bmlvciBkYXRhIGFuYWx5c3QuIEJlbGxhYmVhdCBpcyBhIGhpZ2gtdGVjaCBjb21wYW55IHRoYXQgbWFudWZhY3R1cmVzIGhlYWx0aC1mb2N1c2VkIHNtYXJ0IHByb2R1Y3RzIGZvciB3b21lbiBzaW5jZSAyMDEzLlRoaXMgcHJvZHVjdCBjb2xsZWN0cyBkYXRhIG9uIHNsZWVwLHN0cmVzcyBhbmQgcmVwcm9kdWN0aXZlIGFjdGl2aXRpZXMgaW4gd29tZW4uVGh1cyBlbXBvd2VyaW5nIGFuZCBpbmZvcm1pbmcgd29tZW4gYWJvdXQgdGhlaXIgaGVhbHRoIGFuZCBoYWJpdHMuDQoNCiMjIyAxLjEgRGVsaXZlcmFibGVzIC8gQnVzaW5lc3MgVGFzayANCg0KVGhlIHN0YWtlaG9sZGVycyB3YW50cyB0byBmb2N1cyBvbiBhbmFseXppbmcgaG93IGNvbnN1bWVycyB1c2Ugbm9uLUJlbGxhYmVhdCBzbWFydCBkZXZpY2VzLi4gVGhlbiByZWNvbW1lbmRhdGlvbnMgdG8gaW1wcm92ZSB0aGUgbWFya2V0aW5nIHN0cmF0ZWd5IG9mIEJlbGxhYmVhdCBwcm9kdWN0cyB3b3VsZCBiZSBzdWdnZXN0ZWQgZnJvbSB0aGUgaW5zaWdodCBnb3R0ZW4uDQoNCiMjIyAxLjIgQnVzaW5lc3MgT2JqZWN0aXZlcw0KDQoxLiBXaGF0IGFyZSB0aGUgdHJlbmRzIGlkZW50aWZpZWQgaW4gc21hcnQgZGV2aWNlIHVzYWdlPw0KMi4gSG93IGNvdWxkIHRoZXNlIHRyZW5kcyBhcHBseSB0byBCZWxsYWJlYXQgY3VzdG9tZXJzPw0KMy4gSG93IGNvdWxkIHRoZXNlIHRyZW5kcyBoZWxwIGluZmx1ZW5jZSBCZWxsYWJlYXQgbWFya2V0aW5nIHN0cmF0ZWd5Pw0KDQojIyMgMS4zIFN0YWtlaG9sZGVycw0KDQoqIFVyxaFrYSBTcsWhZW46IFRoaXMgaXMgQmVsbGFiZWF0J3MgY29mb3VuZGVyIGFuZCBDaGllZiBDcmVhdGl2ZSBPZmZpY2VyLg0KKiBTYW5kbyBNdXI6IEFsc28gYSBjbyBmb3VuZGVyIG9mIEJlbGxhYmVhdCBhbmQgYW4gZXNzZW50aWFsIG1lbWJlciBvZiBCZWxsYWJlYXQgZXhlY3V0aXZlIHRlYW0uDQoqIEJlbGxhYmVhdCBtYXJrZXRpbmcgYW5hbHl0aWNzIHRlYW06IFRoaXMgaXMgYSB0ZWFtIG9mIGRhdGEgYW5hbHlzdHMgcmVzcG9uc2libGUgZm9yIGNvbGxlY3RpbmcsIGFuYWx5emluZywgYW5kIHJlcG9ydGluZyBkYXRhIHRoYXQgaGVscHMgZ3VpZGUgQmVsbGFiZWF04oCZcyBtYXJrZXRpbmcgc3RyYXRlZ3kuDQoNCg0KIyBTdGVwIDI6IFByZXBhcmUgUGhhc2UNCg0KIyMjIDIuMCBBYm91dCB0aGUgZGF0YSBzb3VyY2UNCg0KQXMgYWR2aWNlZCBieSBDaGllZiBDcmVhdGl2ZSBPZmZpY2VyLCBJIHVzZWQgYSBwdWJsaWMgZGF0YSBzZXQgZnJvbSBhIHB1YmxpYyBkb21haW4gY2FsbGVkIGthZ2dsZS5UaGUgZGF0YSBzZXQgIkZpdEJpdCBGaXRuZXNzIFRyYWNrZXIgRGF0YSJjb250YWlucyBwZXJzb25hbCBmaXRuZXNzIHRyYWNrZXIgZnJvbSB0aGlydHkgZml0Yml0IHVzZXJzLg0KDQojIyMgMi4xIEluZm9ybWF0aW9uIGluIHRoZSBkYXRhc2V0DQoNCjEuIFRoZSBkYXRhIHNldCBjb250YWluZWQgZWFjaCB1c2VyJ3MgbWludXRlLWxldmVsIG91dHB1dCBmb3IgcGh5c2ljYWwgYWN0aXZpdHksIGRhaWx5IGhlYXJ0IHJhdGUsIHNsZWVwIG1vbml0b3IsZGFpbHkgYWN0aXZpdHkgc3RlcHMgYW5kIHVzZXJzIGhhYml0cy4NCjIuIFRoZSBkYXRhIHNldCB3ZXJlIG9yZ2FuaXNlZCBpbiBib3RoIGxvbmcgYW5kIHdpZGUgZm9ybWF0cy4NCjMuIFRoZSBkYXRhIGRvd25sb2FkZWQgZnJvbSBrYWFnbGUgYW5kIHN0b3JlZCBpbiBhIGZvbGRlciBvbiB0aGUgZGVza3RvcC4gVGhlIGZvbGRlciBjb250YWluZWQgMTggY3N2IGZpbGVzLg0KNC4gVGhlIGRhdGEgc2V0IHdhcyBsYXN0IHVwZGF0ZWQgb24gMTZ0aCBEZWNlbWJlciAyMDIwLg0KDQojIyMgMi4yIERhdGFzZXQgQ3JlZGliaWxpdHkNCg0KQSBnb29kIGRhdGEgc291cmNlIGlzIFJPQ0NDIHdoaWNoIHN0YW5kcyBmb3IgUmVsaWFibGUsIE9yaWdpbmFsLCBDb21wcmVoZW5zaXZlLCBDdXJyZW50LCBhbmQgQ2l0ZWQuDQoxLiBSZWxpYWJsZSAtIFRoZSBkYXRhIHNldCBpcyBub3Qgc28gcmVsaWFibGUgYmVjYXVzZSB0aGUgc2FtcGxlIHNlbGVjdGlvbiBiaWFzIGRvZXMgbm90IHJlZmxlY3QgdGhlIG92ZXJhbGwgcG9wdWxhdGlvbi4gSW4gdGhpcyBkYXRhIHNldCB0aGUgc2FtcGxlIHNpemUgaXMgb25seSAzMCB1c2Vycy4NCjIuIE9yaWdpbmFsIC0gVGhlIG9yaWdpbmFsaXR5IG9mIHRoZSBkYXRhIHNldCBpcyBhbHNvIGxvdyBiZWNhdXNlIHRoZSBkYXRhIHNldCBpcyBnb3R0ZW4gZnJvbSBhIHRoaXJkIHBhcnR5IHByb3ZpZGVyICJBbWF6b24gTWVjaGFuaWNhbCBUdXJrIi4NCjMuIENvbXByZWhlbnNpdmUgLSBUaGUgY29tcHJlaGVuc2l2ZW5lc3Mgb2YgdGhlIGRhdGEgc2V0IGlzIG9rYXkgYmVjYXVzZSB0aGUgZGF0YSBzZXQgY29udGFpbnMgdGhlIGltcG9ydGFudCBpbmZvcm1hdGlvbiBhbmQgcGFyYW1ldGVycyBuZWVkZWQgdG8gYW5zd2VyIHRoZSBidXNpbmVzcyB0YXNrDQo0LiBDdXJyZW50IC0gVGhlIGRhdGEgc2V0IGlzIG5vdCBjdXJyZW50IGFzIGl0IHdhcyBsYXN0IHVwZGF0ZWQgaW4gRGVjZW1iZXIgMjAyMC4NCjUuIENpdGVkIC0gVGhlIGRhdGEgc2V0IHdhcyBnb3R0ZW4gZnJvbSBhIHRoaXJkIHBhcnR5IHNvIHdlIGNhbm5vdCBpZGVudGlmeSB0aGUgc291cmNlIG9mIHRoZSBkYXRhLg0KDQoNCiMgU3RlcCAzOiBQcm9jZXNzIFBoYXNlDQoNCiMjIyAzLjAgVG9vbCB1c2VkDQpJIGFtIHVzaW5nIFIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgdG9vbCB0byBwcm9jZXNzIHRoZSBkYXRhc2V0IGJlY2F1c2UgaXQgaXMgZWFzeSB0byB1c2UgYW5kIGkgYW0gdmVyeSBmYW1pbGlhciB3aXRoIGl0DQoNCiMjIyAzLjEgSSBsb2FkZWQgdGhlIGltcG9ydGFudCBsaWJyYXJpZXMNCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KHNraW1yKQ0KbGlicmFyeSh0aW55dGV4KQ0KYGBgDQpgYGB7cn0NCiNOb3cgdG8gbG9hZCB0aGUgZGF0YSBzZXRzDQpkYWlseV9BY3Rpdml0eSA8LSByZWFkX2NzdignZGFpbHlBY3Rpdml0eV9tZXJnZWQuY3N2JykNCmRhaWx5X0NhbG9yaWVzIDwtIHJlYWRfY3N2KCdkYWlseUNhbG9yaWVzX21lcmdlZC5jc3YnKQ0KZGFpbHlfSW50ZW5zaXRpZXMgPC0gcmVhZF9jc3YoJ2RhaWx5SW50ZW5zaXRpZXNfbWVyZ2VkLmNzdicpDQpkYWlseV9TdGVwcyA8LSAgcmVhZF9jc3YoJ2RhaWx5U3RlcHNfbWVyZ2VkLmNzdicpDQpoZWFydHJhdGVfc2Vjb25kcyA8LSAgcmVhZF9jc3YoJ2hlYXJ0cmF0ZV9zZWNvbmRzX21lcmdlZC5jc3YnKQ0KaG91cmx5X0NhbG9yaWVzIDwtICByZWFkX2NzdignaG91cmx5Q2Fsb3JpZXNfbWVyZ2VkLmNzdicpDQpob3VybHlfSW50ZW5zaXRpZXMgPC0gIHJlYWRfY3N2KCdob3VybHlJbnRlbnNpdGllc19tZXJnZWQuY3N2JykNCmhvdXJseV9TdGVwcyA8LSAgcmVhZF9jc3YoJ2hvdXJseVN0ZXBzX21lcmdlZC5jc3YnKQ0KbWludXRlX2NhbF9uYXJyb3cgPC0gIHJlYWRfY3N2KCdtaW51dGVDYWxvcmllc05hcnJvd19tZXJnZWQuY3N2JykNCm1pbnV0ZV9jYWxfd2lkZSA8LSByZWFkX2NzdignbWludXRlQ2Fsb3JpZXNXaWRlX21lcmdlZC5jc3YnKQ0KbWludXRlX2ludF9uYXJyb3cgPC0gcmVhZF9jc3YoJ21pbnV0ZUludGVuc2l0aWVzTmFycm93X21lcmdlZC5jc3YnKQ0KbWludXRlX2ludF93aWRlIDwtIHJlYWRfY3N2KCdtaW51dGVJbnRlbnNpdGllc1dpZGVfbWVyZ2VkLmNzdicpDQptaW51dGVfbWV0X25hcnJvdyA8LSByZWFkX2NzdignbWludXRlTUVUc05hcnJvd19tZXJnZWQuY3N2JykNCm1pbnV0ZV9zbGVlcCA8LSByZWFkX2NzdignbWludXRlU2xlZXBfbWVyZ2VkLmNzdicpDQptaW51dGVfc3RlcF9uYXJyb3cgPC0gcmVhZF9jc3YoJ21pbnV0ZVN0ZXBzTmFycm93X21lcmdlZC5jc3YnKQ0KbWludXRlX3N0ZXBfd2lkZSA8LSByZWFkX2NzdignbWludXRlU3RlcHNXaWRlX21lcmdlZC5jc3YnKQ0Kc2xlZXBfZGF5IDwtIHJlYWRfY3N2KCdzbGVlcERheV9tZXJnZWQuY3N2JykNCndlaWdodF9sb2dfaW5mbyA8LSByZWFkX2Nzdignd2VpZ2h0TG9nSW5mb19tZXJnZWQuY3N2JykNCg0KYGBgDQojIyMgMy4yIEkgY29tcGFyZWQgdGhlIGNvbHVtbiBuYW1lcw0KYGBge3J9DQpjb2xuYW1lcyhkYWlseV9BY3Rpdml0eSkNCmNvbG5hbWVzKGRhaWx5X0NhbG9yaWVzKQ0KY29sbmFtZXMoZGFpbHlfSW50ZW5zaXRpZXMpDQpjb2xuYW1lcyhkYWlseV9TdGVwcykNCmNvbG5hbWVzKGhlYXJ0cmF0ZV9zZWNvbmRzKQ0KY29sbmFtZXMoaG91cmx5X0NhbG9yaWVzKQ0KY29sbmFtZXMoaG91cmx5X0ludGVuc2l0aWVzKQ0KY29sbmFtZXMoaG91cmx5X1N0ZXBzKQ0KY29sbmFtZXMobWludXRlX2NhbF9uYXJyb3cpDQpjb2xuYW1lcyhtaW51dGVfY2FsX3dpZGUpDQpjb2xuYW1lcyhtaW51dGVfaW50X25hcnJvdykNCmNvbG5hbWVzKG1pbnV0ZV9pbnRfd2lkZSkNCmNvbG5hbWVzKG1pbnV0ZV9tZXRfbmFycm93KQ0KY29sbmFtZXMobWludXRlX3NsZWVwKQ0KY29sbmFtZXMobWludXRlX3N0ZXBfbmFycm93KQ0KY29sbmFtZXMobWludXRlX3N0ZXBfd2lkZSkNCmNvbG5hbWVzKHNsZWVwX2RheSkNCmNvbG5hbWVzKHdlaWdodF9sb2dfaW5mbykNCg0KDQpgYGANCiMjIyAzLjMgSSBjaGVja2VkIGZvciB0aGUgdG90YWwgbWlzc2luZyB2YWx1ZXMgaW4gZWFjaCB0aWJibGUNCmBgYHtyfQ0KIyBGaXJzdCBtZXRob2QNCnN1bShpcy5uYShkYWlseV9BY3Rpdml0eSkpDQpzdW0oaXMubmEoZGFpbHlfQ2Fsb3JpZXMpKQ0Kc3VtKGlzLm5hKGRhaWx5X0ludGVuc2l0aWVzKSkNCnN1bShpcy5uYShkYWlseV9TdGVwcykpDQoNCiMgU2Vjb25kIG1ldGhvZA0KZGFpbHlfQWN0aXZpdHkgJT4lIGR1cGxpY2F0ZWQgKCkgJT4lIHN1bSgpDQpkYWlseV9DYWxvcmllcyAlPiUgZHVwbGljYXRlZCAoKSAlPiUgc3VtKCkNCmRhaWx5X0ludGVuc2l0aWVzICU+JSBkdXBsaWNhdGVkICgpICU+JSBzdW0oKQ0KDQojIFRoaXJkIG1ldGhvZA0KZGFpbHlfQWN0aXZpdHkgJT4lIGlzLm5hKCkgJT4lIHN1bSgpDQpkYWlseV9DYWxvcmllcyAlPiUgaXMubmEoKSAlPiUgc3VtKCkNCnNsZWVwX2RheSAlPiUgZHVwbGljYXRlZCgpICU+JSBzdW0oKQ0KDQpWaWV3KHNsZWVwX2RheSkNCg0KIyBSdW5uaW5nIHRoZXNlIG1ldGhvZHMgaSBmb3VuZCBvdXQgdGhhdCB0aGVyZSB3ZXJlIG5vIG1pc3NpbmcgZGF0YSB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0IGJ1dCB0aGVyZSB3ZXJlIHRocmVlIGR1cGxpY2F0ZXMgZm91bmQgaW4gc2xlZXBfZGF5IGRhdGEgc2V0DQoNCiNUbyByZW1vdmUgdGhlIGR1cGxpY2F0ZXMgZm91bmQgaW4gc2xlZXBfZGF5DQpjbGVhbmVkX3NsZWVwX2RheSA8LSBzbGVlcF9kYXlbIWR1cGxpY2F0ZWQoc2xlZXBfZGF5KSxdDQoNCg0KI1RvIHZlcmlmeSB3ZSBoYXZlIHJlbW92ZWQgdGhlIGR1cGxpY2F0ZXMNCmNsZWFuZWRfc2xlZXBfZGF5ICU+JSBkdXBsaWNhdGVkKCkgJT4lIHN1bSgpDQoNCg0KIyBGb3IgZGFpbHlfYWN0aXZpdHk6IEkgY29udmVydCB0aGUgc3RyaW5nIGNvbHVtbiAoQWN0aXZpdHlEYXRlKSB0byBkYXRlIGZvcm1hdA0KZGFpbHlfQWN0aXZpdHkkQWN0aXZpdHlEYXRlIDwtIG1keShkYWlseV9BY3Rpdml0eSRBY3Rpdml0eURhdGUpDQpoZWFkKGRhaWx5X0FjdGl2aXR5KQ0KDQojIEZvciBoZWFydF9yYXRlOiBJIGNvbnZlcnRlZCB0aGUgVGltZSBjb2x1bW4gdG8gZGF0ZSBmb3JtYXQgYW5kIGkgcmVtb3ZlZCB0aGUgdGltZSBzdGFtcA0KaGVhcnRyYXRlX3NlY29uZHMkVGltZSA8LSBhc19kYXRlKG1keV9obXMoaGVhcnRyYXRlX3NlY29uZHMkVGltZSkpDQpoZWFkKGhlYXJ0cmF0ZV9zZWNvbmRzKQ0KDQojRm9yIFNsZWVwIGRheTogSSBjb252ZXJ0ZWQgdGhlIFNsZWVwRGF5IGNvbHVtbiB0byBkYXRlIGZvcm1hdCBhbmQgaSByZW1vdmVkIHRoZSB0aW1lIHN0YW1wDQpzbGVlcF9kYXkkU2xlZXBEYXkgPC0gYXNfZGF0ZShtZHlfaG1zKHNsZWVwX2RheSRTbGVlcERheSkpDQpoZWFkKHNsZWVwX2RheSkNCg0KI0ZvciB3ZWlnaHRfbG9nX2luZm86IEkgY29udmVydGVkIHRoZSBEYXRlIGNvbHVtbiB0byBkYXRlIGZvcm1hdCBhbmQgaSByZW1vdmVkIHRoZSB0aW1lIHN0YW1wDQp3ZWlnaHRfbG9nX2luZm8kRGF0ZSA8LSBhc19kYXRlKG1keV9obXMod2VpZ2h0X2xvZ19pbmZvJERhdGUpKQ0KVmlldyh3ZWlnaHRfbG9nX2luZm8pDQoNCmBgYA0KIyMjIDMuNCBJIHJlbmFtZWQgdGhlIGNvbHVtbiBuYW1lcyBmb3IgY29uc2lzdGVuY3kNCmBgYHtyfQ0KIyBGb3IgZGFpbHkgQWN0aXZpdHk6IFdlIHJlbmFtZSB0aGUgQWN0aXZpdHlEYXRlIGNvbHVtbiB0byBEYXRlDQpjbGVhbl9kYWlseV9hY3Rpdml0eSA8LSByZW5hbWUoZGFpbHlfQWN0aXZpdHksIERhdGUgPSBBY3Rpdml0eURhdGUpDQpWaWV3KGNsZWFuX2RhaWx5X2FjdGl2aXR5KQ0KDQojIEZvciBoZWFydCByYXRlOiBXZSByZW5hbWUgdGhlIEFjdGl2aXR5RGF0ZSBjb2x1bW4gdG8gRGF0ZQ0KY2xlYW5faGVhcnRfcmF0ZV9zZWMgPC0gcmVuYW1lKGhlYXJ0cmF0ZV9zZWNvbmRzLCBEYXRlID0gVGltZSkNClZpZXcoY2xlYW5faGVhcnRfcmF0ZV9zZWMpDQoNCiMgRm9yIHNsZWVwX2RheTogV2UgcmVuYW1lIHRoZSBTbGVlcGRheSBjb2x1bW4gdG8gRGF0ZQ0KY2xlYW5fc2xlZXBfZGF5IDwtIHJlbmFtZShzbGVlcF9kYXksIERhdGUgPSBTbGVlcERheSkNClZpZXcoY2xlYW5fc2xlZXBfZGF5KQ0KDQojIEkgZGlkIG5vdCByZW5hbWUgdGhlIGRhdGUgdmFyaWFibGUgaW4gImNsZWFuX3dlaWdodF9sb2ciIGJlY2F1c2UgaXQgaXMgYWxyZWFkeSBuYW1lZCAiRGF0ZSINCmNsZWFuX3dlaWdodF9sb2cgPC0gd2VpZ2h0X2xvZ19pbmZvDQoNCmBgYA0KIyMjIDMuNSBJIGNsZWFuZWQgdGhlIGNvbHVtbiBuYW1lcyANCmBgYHtyfQ0KY2xlYW5fZGFpbHlfYWN0aXZpdHkgPC0gY2xlYW5fZGFpbHlfYWN0aXZpdHkgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkNCmNsZWFuX2hlYXJ0X3JhdGVfc2VjIDwtIGNsZWFuX2hlYXJ0X3JhdGVfc2VjICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpDQpjbGVhbl9zbGVlcF9kYXkgPC0gY2xlYW5fc2xlZXBfZGF5ICU+JSBqYW5pdG9yOjpjbGVhbl9uYW1lcygpDQpjbGVhbl93ZWlnaHRfbG9nIDwtIGNsZWFuX3dlaWdodF9sb2cgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkNCg0KYGBgDQojIFN0ZXAgNDogQW5hbHlzZSBQaGFzZQ0KDQojIyMgNC4wIEkgYW0gdXNpbmcgZm91ciBtZXRyaWNzIGZvciB0aGlzIGFuYWx5c2lzLiBUaGV5IGFyZSBEYWlseSBBY3Rpdml0eSxXZWlnaHQsc2xlZXAgZGF5IGFuZCBoZWFydCByYXRlLg0KDQojIyMgSSB3YW50IHRvIGtub3cgdGhlIG51bWJlciBvZiBkaXN0aW5jdCBwYXJ0aWNpcGFudHMgaW4gZWFjaCBtZXRyaWMob3VyIGZvdXIgZGF0YSBmcmFtZXM6IOKAnGNsZWFuX2RhaWx5X2FjdGl2aXR54oCdLCDigJxjbGVhbl9oZWFydF9yYXRlX3NlY+KAnSwg4oCcY2xlYW5fc2xlZXBfZGF54oCdIGFuZCDigJxjbGVhbl93ZWlnaHRfbG9n4oCdKSwgdG90YWwgbnVtYmVyIG9mIGRheXMgdHJhY2tlZCwgYW5kIG51bWJlciBvZiBkYXlzIHRyYWNrZWQgZm9yIGVhY2ggbWV0cmljIHBlciBwYXJ0aWNpcGFudC4NCg0KDQojIyMgNC4xIFRoZSBudW1iZXIgb2YgZGlzdGluY3QgcGFydGljaXBhbnRzIGluIGVhY2ggZGF0YSBmcmFtZQ0KYGBge3J9DQojIEZvciBjbGVhbl9kYWlseV9hY3Rpdml0eTogTnVtYmVyIG9mIGRpc3RpbmN0IHBhcnRpY2lwYW50cw0KDQpkYWlseV9kaXNpbmN0X2lkIDwtIG5fZGlzdGluY3QoY2xlYW5fZGFpbHlfYWN0aXZpdHkkaWQpDQojIFRoZXJlIHdlcmUgMzMgZGlzdGluY3QgcGFydGljaXBhbnRzIGluIGRhaWx5X2FjdGl2aXR5DQoNCmRhaWx5X2Rpc3RpbmN0X2RhdGUgPC0gbl9kaXN0aW5jdChjbGVhbl9kYWlseV9hY3Rpdml0eSRkYXRlKQ0KIyBUaGUgZGFpbHlfYWN0aXZpdHkgZGF0YSB3YXMgdHJhY2tlZCBmb3IgMzEgZGF5cw0KDQpkYWlseV9taW5fZGF0ZSA8LSBtaW4oY2xlYW5fZGFpbHlfYWN0aXZpdHkkZGF0ZSkNCiNUaGUgZWFybGllc3QgZGF0ZSB3YXMgMjAxNi0wNC0xMg0KDQpkYWlseV9tYXhfZGF0ZSA8LSBtYXgoY2xlYW5fZGFpbHlfYWN0aXZpdHkkZGF0ZSkNCiNUaGUgbGFzdCBkYXRlIHdhcyAyMDE2LTA1LTEyDQoNCiNTbyBmcm9tIHRoZSBjYWxjdWxhdGlvbnMgYWJvdmUgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIGRhaWx5X2FjdGl2aXR5IGRhdGEgd2FzIHRyYWNrZWQgZm9yIGEgZHVyYXRpb24gb2YgMzFkYXlzIGJldHdlZW4gMjAxNi0wNC0xMiBuZCAyMDE2LTA1LTEyIGFuZCB3ZSBoYWQgMzMgZGlzdGluY3QgcGFydGljaXBhbnRzL0lkJ3MgaW4gdGhlIGRhdGEgc2V0Lg0KDQoNCiNGb3IgY2xlYW5faGVhcnRfcmF0ZV9zZWM6IE51bWJlciBvZiBkaXN0aW5jdCBwYXJ0aWNpcGFudHMNCg0KaGVhcnRfZGlzdGluY3RfaWQgPC0gbl9kaXN0aW5jdChjbGVhbl9oZWFydF9yYXRlX3NlYyRpZCkNCiMgVGhlcmUgd2VyZSAxNCBkaXN0aW5jdCBwYXJ0aWNpcGFudHMgaW4gaGVhcnRfcmF0ZV9zZWMNCg0KaGVhcnRfZGlzdGluY3RfZGF0ZSA8LSBuX2Rpc3RpbmN0KGNsZWFuX2hlYXJ0X3JhdGVfc2VjJGRhdGUpDQojIFRoZSBoZWFydF9yYXRlX3NlYyBkYXRhIHdhcyB0cmFja2VkIGZvciAzMSBkYXlzDQoNCmhlYXJ0X21pbl9kYXRlIDwtIG1pbihjbGVhbl9oZWFydF9yYXRlX3NlYyRkYXRlKQ0KIyBUaGUgZWFybGllc3QgZGF0ZSB3YXMgMjAxNi0wNC0xMg0KDQpoZWFydF9tYXhfZGF0ZSA8LSBtYXgoY2xlYW5faGVhcnRfcmF0ZV9zZWMkZGF0ZSkNCiMgVGhlIGxhc3QgZGF0ZSB3YXMgMjAxNi0wNS0xMg0KDQojIFNvIGZyb20gdGhlIGNhbGN1bGF0aW9ucyBhYm92ZSB3ZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGUgaGVhcnRfcmF0ZSBkYXRhIHdhcyB0cmFja2VkIGZvciBhIGR1cmF0aW9uIG9mIDMxZGF5cyBiZXR3ZWVuIDIwMTYtMDQtMTIgbmQgMjAxNi0wNS0xMiBhbmQgd2UgaGFkIDE0IGRpc3RpbmN0IHBhcnRpY2lwYW50cy9JZCdzIGluIHRoZSBkYXRhIHNldC4NCg0KDQojRm9yIHdlaWdodF9sb2c6IE51bWJlciBvZiBkaXN0aW5jdCBwYXJ0aWNpcGFudHMNCg0Kd2VpZ2h0X2Rpc3RpbmN0X2lkIDwtIG5fZGlzdGluY3QoY2xlYW5fd2VpZ2h0X2xvZyRpZCkNCiMgVGhlcmUgd2VyZSA4IGRpc3RpbmN0IHBhcnRpY2lwYW50cw0KDQp3ZWlnaHRfZGlzdGluY3RfZGF0ZSA8LSBuX2Rpc3RpbmN0KGNsZWFuX3dlaWdodF9sb2ckZGF0ZSkNCiMgVGhlIGRhdGEgd2FzIHRyYWNrZWQgZm9yIDMxIGRheXMNCg0Kd2VpZ2h0X21pbl9kYXRlIDwtIG1pbihjbGVhbl93ZWlnaHRfbG9nJGRhdGUpDQojICBUaGUgZWFybGllc3QgZGF0ZSB3YXMgMjAxNi0wNC0xMg0KDQp3ZWlnaHRfbWF4X2RhdGUgPC0gbWF4KGNsZWFuX3dlaWdodF9sb2ckZGF0ZSkNCiMgVGhlIGxhc3QgZGF0ZSB3YXMgMjAxNi0wNS0xMg0KDQojIFNvIGZyb20gdGhlIGNhbGN1bGF0aW9ucyBhYm92ZSB3ZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGUgd2VpZ2h0X2xvZyBkYXRhIHdhcyB0cmFja2VkIGZvciBhIGR1cmF0aW9uIG9mIDMxZGF5cyBiZXR3ZWVuIDIwMTYtMDQtMTIgbmQgMjAxNi0wNS0xMiBhbmQgd2UgaGFkIDggZGlzdGluY3QgcGFydGljaXBhbnRzL0lkJ3MgaW4gdGhlIGRhdGEgc2V0Lg0KDQojRm9yIHNsZWVwX2RheTogTnVtYmVyIG9mIGRpc3RpbmN0IHBhcnRpY2lwYW50cw0KDQpzbGVlcF9kaXN0aW5jdF9pZCA8LSBuX2Rpc3RpbmN0KGNsZWFuX3NsZWVwX2RheSRpZCkNCiMgVGhlcmUgd2VyZSAyNCBkaXN0aW5jdCBwYXJ0aWNpcGFudHMNCg0Kc2xlZXBfZGlzdGluY3RfZGF0ZSA8LSBuX2Rpc3RpbmN0KGNsZWFuX3NsZWVwX2RheSRkYXRlKQ0KIyBUaGUgZGF0YSB3YXMgdHJhY2tlZCBmb3IgMzEgZGF5cw0KDQpzbGVlcF9taW5fZGF0ZSA8LSBtaW4oY2xlYW5fc2xlZXBfZGF5JGRhdGUpDQojIFRoZSBlYXJsaWVzdCBkYXRlIHdhcyAyMDE2LTA0LTEyDQoNCnNsZWVwX21heF9kYXRlIDwtIG1heChjbGVhbl9zbGVlcF9kYXkkZGF0ZSkNCiMgVGhlIGxhc3QgZGF0ZSB3YXMgMjAxNi0wNS0xMg0KDQojIFNvIGZyb20gdGhlIGNhbGN1bGF0aW9ucyBhYm92ZSB3ZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGUgc2xlZXBfZGF5IGRhdGEgd2FzIHRyYWNrZWQgZm9yIGEgZHVyYXRpb24gb2YgMzFkYXlzIGJldHdlZW4gMjAxNi0wNC0xMiBuZCAyMDE2LTA1LTEyIGFuZCB3ZSBoYWQgMjQgZGlzdGluY3QgcGFydGljaXBhbnRzL0lkJ3MgaW4gdGhlIGRhdGEgc2V0Lg0KDQpgYGANCiMgU3RlcCA1LiBTaGFyZSBwaGFzZQ0KDQojIyMgVG8gcGxvdCBhIGdyYXBoIG9mIGRpc3RpbmN0IHBhcnRpY2lwYW50cyBwZXIgbWVydGljDQpgYGB7cn0NCiMgVGhlIGRpc3RpbmN0IHBhcnRpY2lwYW50cyBvZiB3ZWlnaHQsc2xlZXAsaGVhcnQgYW5kIGRhaWx5IGFjdGl2aXR5IHdlcmUgOCwyNCwxNCBhbmQgMzMgcmVzcGVjdGl2ZWx5DQoNCmRhdGEgPC0gYygiZGFpbHlfYWN0aXZpdHkiLCAiaGVhcnRyYXRlX3NlYyIsICJzbGVlcF9kYXkiLCAid2VpZ2h0X2xvZyIpDQpkaXN0aW5jdF9pZHMgPC0gYygzMywxNCwyNCw4KQ0KcGFydGljaXBhbnRzX3Blcl9tZXRyaWMgPC0gdGliYmxlKGRhdGEsIGRpc3RpbmN0X2lkcykNCg0KcGFydGljaXBhbnRzX3Blcl9tZXRyaWMgJT4lDQogIGdncGxvdChhZXMoeCA9IGRhdGEsIHkgPSBkaXN0aW5jdF9pZHMsZmlsbCA9IGRpc3RpbmN0X2lkcykpICsgDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBVbmlxdWUgUGFydGljaXBhbnRzIGluIGVhY2ggTWV0cmljIixzdWJ0aXRsZT0gIkRhdGEgc291cmNlIGZyb20gQW1hem9uIE1lY2hhbmljYWwgVHVyayIsIHggPSAiTWV0cmljIE5hbWUiLCB5ID0gIkRpc3RpbmN0IFBhcnRpY2lwYW50cyIsY2FwdGlvbiA9ICJmaWd1cmUgMSIpICsNCnRoZW1lKCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gLjUpKSArDQpzY2FsZV9maWxsX2NvbnRpbnVvdXMoKQ0KYGBgDQojIyMgRmlndXJlIDEgZ3JhcGggUmVzdWx0DQoqIFBhcnRpY2lwYW50cyB1c2VkIHRoZSBzbWFydCBkZXZpY2UgdG8gcmVjb3JkIHRoZWlyIGRhaWx5IGFjdGl2aXR5IHRoZSBtb3N0Lg0KKiBXZSBoYWQgMjQgcGFydGljaXBhbnRzIHRoYXQgdXNlZCB0aGUgc21hcnQgZGV2aWNlIHRvIHJlY29yZCB0aGVpciBzbGVlcCBhY3Rpdml0eS4NCiogV2hpbGUgMTQgcGFydGljaXBhbnRzIHJlY29yZGVkIHRoZWlyIGhlYXJ0IHJhdGUuDQoqIFRoZSBsZWFzdCBtZXRyaWMgcmVjb3JkZWQgYnkgcGFydGljaXBhbnRzIHdhcyB0aGUgd2VpZ2h0IG1ldHJpYy4NCg0KIyMjIEkgd2FudCB0byBwbG90IGEgZ3JhcGggdG8gc2VlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0b3RhbCBzdGVwcyB0YWtlbiBhbmQgY2Fsb3JpZXMgYnVybmVkDQpgYGB7cn0NCiMgSSBhbSB1c2luZyB0aGUgZGFpbHkgYWN0aXZpdHkgZGF0YWZyYW1lIGZvciB0aGlzDQoNCmdncGxvdChjbGVhbl9kYWlseV9hY3Rpdml0eSwgYWVzKHg9dG90YWxfc3RlcHMsIHk9Y2Fsb3JpZXMpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgoKSArIA0KICBsYWJzKHRpdGxlPSJUb3RhbCBTdGVwcyB2cy4gQ2Fsb3JpZXMiLGNhcHRpb24gPSAiZmlndXJlIDIiKQ0KYGBgDQojIyMgRmlndXJlIDIgZ3JhcGggcmVzdWx0DQoqIFRoZSBncmFwaCBzaG93cyB1cyB0aGF0IGEgcG9zaXRpdmUgY29ycmVsYXRpb24gZXhpc3RzIGJldHdlZW4gdGhlIHRvdGFsIHN0ZXBzIHRha2VuIGFuZCB0aGUgY2Fsb3JpZXMgYnVybnQuDQoqIFRoaXMgbWVhbnMgdGhhdCB0aGUgbW9yZSBhY3RpdmUgdGhlIHBhcnRpY2lwYW50cyBhcmUsIHRoZSBtb3JlIGNhbG9yaWVzIHRoYXQgYXJlIGJ1cm5lZC4NCg0KIyMjIEkgd2FudCB0byBwbG90IGEgZ3JhcGggdG8ga25vdyB0aGUgZGF5IG9mIHRoZSB3ZWVrIHBhcnRpY2lwYW50cyBhcmUgbW90aXZhdGVkIHRvIHdvcmtvdXQgdGhlIG1vc3QNCmBgYHtyfQ0KIyBJIHdvdWxkIHVzZSB0aGUgZGFpbHkgYWN0aXZpdHkgZGF0YSBmcmFtZSB0byBmaXJzdCBnZXQgdGhlIG1lYW4gb2YgdGhlIHZlcnkgYWN0aXZlIG1pbnV0ZXMNCg0KI0FkZCBuZXcgY29sdW1uIHdpdGggd2Vla2RheXMgdG8gZGFpbHkgYWN0aXZpdHkgZGF0YSBmcmFtZQ0KDQpjbGVhbl9kYWlseV9hY3Rpdml0eSR3ZWVrZGF5czwtIHdkYXkoY2xlYW5fZGFpbHlfYWN0aXZpdHkkZGF0ZSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gRkFMU0UpDQoNCiMgTm93IHdlIGdldCB0aGUgbWVhbg0KbWVhbl92ZXJ5X2FjdGl2ZV9taW5zIDwtIGNsZWFuX2RhaWx5X2FjdGl2aXR5ICU+JSANCiAgZ3JvdXBfYnkod2Vla2RheXMpICU+JSANCiAgc3VtbWFyaXNlX2F0KHZhcnModmVyeV9hY3RpdmVfbWludXRlcyksDQogICAgICAgICAgICAgICBsaXN0KHZlcnlfYWN0aXZlX21pbnV0ZXMgPSBtZWFuKSkNCnByaW50KG1lYW5fdmVyeV9hY3RpdmVfbWlucykNCg0KIyBUbyBwbG90IHRoZSBncmFwaCBvZiB3ZWVrZGF5IGFnYWluc3QgdGhlIG1lYW5fdmVyeV9hY3RpdmVfbWlucw0KDQpnZ3Bsb3QoZGF0YSA9IG1lYW5fdmVyeV9hY3RpdmVfbWlucyxhZXMoeCA9IHdlZWtkYXlzLHkgPSB2ZXJ5X2FjdGl2ZV9taW51dGVzLGdyb3VwID0gMSkpICsNCiAgIGdlb21fbGluZShjb2xvciA9ICJob3RwaW5rMSIpKw0KICBsYWJzKHRpdGxlPSIgVGhlIEF2ZXJhZ2Ugb2YgdGhlIGFjdGl2ZSBtaW51dGVzIGJ5IFdlZWtkYXlzIiwgeD0gIldlZWtkYXlzIiwgeT0iRGFpbHkgVmVyeSBBY3RpdmUgTWludXRlcyIsY2FwdGlvbiA9ICJmaWd1cmUgMyIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKHZlcnlfYWN0aXZlX21pbnV0ZXMsIGRpZ2l0cz0wKSwgaGp1c3Q9LTAuNzUsIHZqdXN0PTAuNzUpLHNpemU9MykrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTM1LCBoanVzdD0xKSkNCmBgYA0KIyMjIEZpZ3VyZSAzIGdyYXBoIHJlc3VsdA0KKiBUaGUgbW9zdCBhY3RpdmUgZGF5cyBhcmUgb24gTW9uZGF5cyBhbmQgU2F0dXJkYXlzDQoqIFRoZSBsZWFzdCBhY3RpdmUgZGF5cyBUaHVyc2RheXMgYW5kIFN1bmRheXMNCiogUGFydGljaXBhbnRzIHVzdWFsbHkgc3RhcnQgdGhlIHdlZWtlbmQgYnkgYmVpbmcgYWN0aXZlIGFnYWluIChGcmlkYXlzIHRvIFNhdHVyZGF5cykNCg0KDQoNCiMgU3RlcCA2LiBBY3QgcGhhc2UNCg0KKiBJIGZvdW5kIG91dCB0aGF0IHdlaWdodCBpcyB0aGUgbGVhc3QgbWV0cmljIHRoYXQgaXMgdHJhY2tlZCBieSBwYXJ0aWNpcGFudHMuIFRvIGltcHJvdmUgdGhpcyBtZXRyaWMgZGF0YSxCZWxsYWJlYXQgY2FuIGNyZWF0ZSBhbiBhdXRvbWF0ZWQgc3lzdGVtIHRoYXQgd291bGQgcmVtaW5kIHBhcnRpY2lwYW50cyBpbiB0cmFja2luZyB0aGVpciB3ZWlnaHQuIFRoaXMgd2F5IHRoZSBwcm9jZXNzIHdvdWxkIGJlIG11Y2ggZWFzaWVyLg0KKiBJIGFsc28gb2JzZXJ2ZWQgdGhhdCBwYXJ0aWNpcGFudHMgd2VyZSBtb3N0IGFjdGl2ZSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSB3ZWVrIGFuZCBsYXRlciB0aGUgbW9tZW50dW0gdG8gd29ya291dCBkcm9wcy4gVG8gaW1wcm92ZSB0aGlzLCBCZWxsYWJlYXQgY2FuIGNyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBzeXN0ZW0gdGhhdCB3b3VsZCBlbmFibGUgcGFydGljaXBhbnRzIHRvIGhhdmUgcmVtaW5kIGVhY2ggb3RoZXIgZHVyaW5nIHRoZSB3ZWVrIHRvIGtlZXAgYmVpbmcgYWN0aXZlLg0KKiBBbm90aGVyIHdheSB0byBpbXByb3ZlIG1pZCB3ZWVrIGFjdGl2aXR5IGlzIGNyZWF0ZSBzaG9ydCB3b3JrIG91dCB2aWRlb3MgdG8gQmVsbGFiZWF0J3MgYXBwIGZvciBhbGwgZml0bmVzcyBsZXZlbHMgY2FuIGluc3BpcmUgdXNlcnMgdG8gc3RheSBhY3RpdmUgdGhyb3VnaCB0aGVpciB3b3JrIHdlZWtzLg0KKiBUbyBpbXByb3ZlIHRoZSBzbGVlcCBsZXZlbCBvZiBwYXJ0aWNpcGFudHMsIEkgd291bGQgc3VnZ2VzdCBCZWxsYWJlYXQgdG8gZGV2ZWxvcCBub3RpZmljYXRpb25zIHRoYXQgd291bGQgcmVtaW5kIHRoZSBwYXJ0aWNpcGFudHMgdG8gdHJhY2sgdGhlaXIgc2xlZXAgb3IgcGFydGljaXBhbnRzIGNhbiBpbnB1dCBhIHRpbWUgb24gdGhlIGFwcCB0aGF0IGNhbiBiZSByZWN5Y2xlZCBmb3IgYXMgbG9uZyBhcyB0aGUgcGFydGljaXBhbnQgd2FudHMuDQoqIFNpbmNlIHdlIGtub3cgdGhhdCB0aGlzIGFwcCB3YXMgY3JlYXRlZCBhcyBhIGd1aWRlIGZvciB3b21lbiB0byBrZWVwIGZpdCBhbmQgYmVpbmcgaGVhbHRoeS4gVGhlcmUgYXJlIGltcG9ydGFudCBkYXRhIHRoYXQgY291bGQgaW5mbHVlbmNlIHRoZSB0cmFja2luZyBvZiBlYWNoIG1ldHJpYy4NCiogRmFjdG9ycyBzdWNoIGFzIHN0YXJ0IGFuZCBjbG9zaW5nIGhvdXIgb2Ygam9iLCBudW1iZXIgb2Yga2lkcywgdW5kZXJseWluZyBoZWFsdGggY29uZGl0aW9ucy4gZXRjDQoqIEluIGNvbmNsdXNpb24sIGdhdGhlcmluZyBtb3JlIGRhdGEgYWJvdXQgdGhlIHBhcnRpY2lwYW50cyB3b3VsZCBiZSBiZW5lZmljaWFsIGluIHJlY29tbWVuZGluZyBhY2N1cmF0ZSBpbnNpZ2h0cy4NCg0KVGhhbmsgeW91DQo=