On this Case Study I used the same dataset on my previous work Capstone: Bellabeat Case Study with R but this time Im using soley on SQL and Excel to showcase my skill.

Alt text

Summary

Bellabeat is a high-tech company that manufactures health-focused smart products.They offer different smart devices that collect data on activity, sleep, stress, and reproductive health to empower women with knowledge about their own health and habits.

The main focus of this case is to analyze smart devices fitness data and determine how it could help unlock new growth opportunities for Bellabeat. We will focus on one of Bellabeat’s products: Bellabeat app and Leaf.

The Bellabeat app provides users with health data related to their activity, sleep, stress, menstrual cycle, and mindfulness habits. This data can help users better understand their current

The Leaf is Bellabeat’s classic wellness tracker can be worn as a bracelet, necklace, or clip. The Leaf tracker connects to the Bellabeat app to track activity, sleep, and stress habits and make healthy decisions. The Bellabeat app connects to their line of smart wellness products

Ask Phase

Business Task

Identify trends in how consumers use non-Bellabeat smart devices to apply insights into Bellabeat’s marketing strategy.

Stakeholders

  • Urška Sršen - Bellabeat cofounder and Chief Creative Officer
  • Sando Mur - Bellabeat cofounder and key member of Bellabeat executive team
  • Bellabeat Marketing Analytics team

Prepare Phase

Dataset used:

The data source used for our case study is FitBit Fitness Tracker Data. This data set is stored in Kaggle and was made available through Mobius.

Accessibility and privacy of data:

Verifying the metadata of our data set we can confirm it is open-source. The owner has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission.

Information about our dataset:

These data sets were generated by respondents to a distributed survey via Amazon Mechanical Turk between 03.12.2016-05.12.2016. Thirty eligible Fitbit users consented to the submission of personal tracker data, including minute-level output for physical activity, heart rate, and sleep monitoring. Variation between output represents use of different types of Fitbit trackers and individual tracking behaviors / preferences.

Cleaning the data using Excel

The following steps were taken within each dataset:

  • Sorted and filtered data by Id to obtain how many unique users there were within the dataset.
  • Checked for duplicate data using the ‘duplicate data’ tool in Excel
  • Formatted date data into MM/DD/YY date format
  • Formatted all numerical data into Number format with either no decimils or up to 2 decimials.
  • Sorted by date to find the first and last date of the dataset (this is what first indicated only a 31-day period of activity was captured).
  • Separated Date and Hour into two columns when needed for later analysis. Utilized the ‘Text to Columns’ tool to do so.
  • Formatted any time data into 00:00:00 format for consistency.
  • Checked Id entries and other columns for LEN to make sure the data was correct and uniform in length

After the cleaning process was finished, only 3 rows of duplicate information was found within the Daily_Sleep_Merged file. These were removed before analysis.

Process phase

In this analysis I will focus on Bigquery SQL and MS excel and to be able to create data viz for the stakeholders.

Importing dataset

I opened Bigquery Console, then select “Create Project”. Typed down the name of the project you are going to explore, in this case I used first-analyst. I created a new dataset for Bellabeat and named it bellabeat_data. Inside bellabeat dataset, I imported the .csv datasets I previously downloaded from FitBit Fitness Tracker Data.

  • Daily_Activity_Merged
  • Daily_Sleep_Merged
  • Hourly_Steps_Merged

After that, I started my work by finding the total number of users’ id

Number of users


SELECT 
  COUNT( DISTINCT Id)
FROM
  `first-analyst.bellabeat_data.hourly_steps` -- 33


SELECT 
  COUNT(DISTINCT Id)
FROM 
  `first-analyst.bellabeat_data.daily_activity` --33
  
  
SELECT 
  COUNT(DISTINCT Id)
FROM 
  `first-analyst.bellabeat_data.daily_sleep` -- 24

Checking Start-End Date and Id


SELECT 
  MIN(Date) as start_date,
  MAX(Date) as end_date
FROM 
  `first-analyst.bellabeat_data.daily_activity`

SELECT 
  MIN(Date) as start_date,
  MAX(Date) as end_date
FROM 
  `first-analyst.bellabeat_data.daily_sleep`

SELECT 
  MIN(Date) as start_date,
  MAX(Date) as end_date
FROM 
  `first-analyst.bellabeat_data.hourly_steps`

  -- daily activity, daily sleep, hourlysteps are same startdate: 2016-04-12, enddate: 2016-05-12. 31 days in total

Check all ids have the same length

SELECT 
  Id
FROM 
  `first-analyst.bellabeat_data.daily_activity`
WHERE
  LENGTH(CAST(Id as STRING)) > 10 OR LENGTH(CAST(Id as String)) < 10

  -- No data display meaning there are no Id more than or less than to 10
  
  SELECT 
  Id
FROM 
  `first-analyst.bellabeat_data.daily_sleep`
WHERE
  LENGTH(CAST(Id as STRING)) > 10 OR LENGTH(CAST(Id as String)) < 10

  -- No data display meaning there are no Id more than or less than to 10


SELECT 
  Id
FROM 
  `first-analyst.bellabeat_data.hourly_steps`
WHERE
  LENGTH(CAST(Id as STRING)) > 10 OR LENGTH(CAST(Id as String)) < 10

  -- No data display meaning there are no Id more than or less than to 10

It showed that all datasets have the same start and end date: start 2016-04-12 and end 2016-05-12. In term of id’s length, all datasets also showed the same length: 10 characters.

Cleaning the data

Finding Duplicates

Note: I just repating this below code to check for daily sleep and hourly steps

SELECT 
  Id,
  Date,
  COUNT(*) as num_of_id
FROM 
  `first-analyst.bellabeat_data.daily_activity`
GROUP BY
  Id, Date
HAVING 
  num_of_id > 1

-- no data to display / no duplicates in daily_activity
  
SELECT 
  Id,
  Date,
  COUNT(*) as num_of_id
FROM 
  `first-analyst.bellabeat_data.hourly_steps`
GROUP BY
  Id, Date
HAVING 
  num_of_id > 24
-- I put 24 because it is 24 hours in a day / no display no duplicates
  
  
SELECT 
  Id,
  Date,
  COUNT(*) as num_of_id
FROM 
  `first-analyst.bellabeat_data.daily_sleep`
GROUP BY
  Id, Date
HAVING 
  num_of_id > 1

-- displays 3 duplicates

According to the result of finding duplicates, it showed that there are 3 duplicate rows in sleep_day dataset. We need to create a new sleep_day table, and remove the duplicates in the new table. In this case, I named the new table: daily_sleep_new.

Duplicate rows in daily_step table need to be removed

Creating and replacing new sleep_day table with all distinct values

CREATE or REPLACE TABLE `first-analyst.bellabeat_data.daily_sleep_new`
AS SELECT *
FROM
(
  SELECT *, 
  ROW_NUMBER() 
  OVER (PARTITION BY Id, Date)
  row_number
  FROM `first-analyst.bellabeat_data.daily_sleep`
)
WHERE row_number = 1


-- Check it again if it the new table had no duplicates

SELECT
  Id,
  Date,
  COUNT(*) as num_of_id
FROM `first-analyst.bellabeat_data.daily_sleep_new`
GROUP BY
  Id, Date
HAVING 
  num_of_id > 1

  -- no data display/ no duplicates

Removing the unwanted Data

During the checking and cleaning process, I found that there were some zero data in TotalSteps column inside the daily_activity dataset. Therefore, I decided to check and remove those zero value. I created new table and named it daily_activity_new, so that the previous dataset still remained.

--Check if total steps = 0 in daily_activity table
SELECT 
  Id, 
  Count(*) as num_of_zero_steps
FROM `first-analyst.bellabeat_data.daily_activity`
WHERE 
  Total_Steps = 0
GROUP BY Id
ORDER BY num_of_zero_steps

  -- 15 ids with 0 total steps

-- Create new daily activity table
CREATE TABLE `first-analyst.bellabeat_data.daily_activity_new`
AS SELECT *
FROM `first-analyst.bellabeat_data.daily_activity`


-- Delete all rows that contain zero total steps
DELETE FROM `first-analyst.bellabeat_data.daily_activity_new`
WHERE Total_Steps = 0
--77 data deleted


-- Removing the zero value on Hourly steps
SELECT 
  Id, 
  Count(*) as num_of_zero_steps
FROM `first-analyst.bellabeat_data.hourly_steps`
WHERE 
  Step_Total = 0
GROUP BY Id
ORDER BY num_of_zero_steps
-- 33 ids with 0 total steps

DELETE FROM `first-analyst.bellabeat_data.hourly_steps`
WHERE Step_Total = 0
-- 7535 deleted

Find the null data


--Check for null data
SELECT *
FROM `first-analyst.bellabeat_data.daily_activity_new`
WHERE Id IS NULL
-- no data display

SELECT *
FROM `first-analyst.bellabeat_data.daily_sleep_new`
WHERE Id IS NULL
-- no data display

SELECT *
FROM `first-analyst.bellabeat_data.hourly_steps`
WHERE Id IS NULL
-- no data display


--Delete rows of null data
DELETE FROM `first-analyst.bellabeat_data.daily_activity_new`
WHERE Id IS NULL

Analyze Phase and Share Phase

We were going analyze the trends of FitBit user and to determine if can help us to make a decision for marketing strategy

User Level

We want to determine the type of users with the data we have because we don’t have any demographic variables from our sample. We can categorize users based on their daily number of steps. Users can be classified as follows:

  • Sedentary - Less than 5000 steps a day.
  • Lightly active - Between 5000 and 7499 steps a day.
  • Fairly active - Between 7500 and 9999 steps a day.
  • Very active - More than 10000 steps a day. Classification has been made per the following article https://www.10000steps.org.au/articles/counting-steps/
--Creating temp table for the mean of daily steps
WITH
  daily_average AS (
  SELECT
    Id,
    AVG(Total_Steps) AS totalsteps_mean,
  FROM
    `first-analyst.bellabeat_data.daily_activity_new`
  GROUP BY
    Id
  ORDER BY
    totalsteps_mean  
  
),
--After getting all the total mean, we will now categorize each user base on User Level 
 users AS (
SELECT 
  Id, 
  AVG(totalsteps_mean) as avg_total_steps,
  CASE
  WHEN AVG(totalsteps_mean) < 5000 THEN 'Sedentary'
  WHEN AVG(totalsteps_mean) BETWEEN 5001 AND 7500 THEN 'Lightly Active'
  WHEN AVG(totalsteps_mean) BETWEEN 7501 AND 10000 THEN 'Fairly Active'
  WHEN AVG(totalsteps_mean) > 10000 THEN 'Very Active'
  END AS user_level
FROM daily_average
GROUP BY
  Id
ORDER BY avg_total_steps

),
 user_level_counts AS (
    SELECT user_level, COUNT(*) AS total
    FROM users
    GROUP BY user_level
  ),
  total_user_level_counts AS (
    SELECT SUM(total) AS total_user_level
    FROM user_level_counts
  ),
  user_level_percentages AS (
    SELECT user_level, CAST(total AS FLOAT64) / total_user_level_counts.total_user_level AS total_percent
    FROM user_level_counts, total_user_level_counts
    WHERE 1 = 1
  )
SELECT user_level,
total_percent,
FROM user_level_percentages


User Level

Spreedsheet data

Steps and minutes asleep per weekday

We want to know now what days of the week are the users more active and also what days of the week users sleep more. We will also verify if the users walk the recommended amount of steps and have the recommended amount of sleep.

Below we are calculating the weekdays based on our column date. We are also calculating the average steps walked and minutes asleep by weekday.

WITH
-- Merging  two tables
  daily_activity_sleep  AS (
    SELECT
    Total_Steps,
    TotalMinutesAsleep,
    daily_activity_new.Id AS id,
    daily_activity_new.Date AS date
  FROM `first-analyst.bellabeat_data.daily_activity_new` AS daily_activity_new
  INNER JOIN 
    `first-analyst.bellabeat_data.daily_sleep_new` AS daily_sleep_new
  ON
  daily_activity_new.Id = daily_sleep_new.Id  AND
   daily_activity_new.Date = daily_sleep_new.Date
   )


--Find the average of Total steps and Total minute asleep per week
SELECT 
  day_of_week, 
  ROUND(AVG(Total_Steps),2) as ave_totalsteps_perday,
  ROUND(AVG(TotalMinutesAsleep),2) AS ave_minutesasleep_perday
FROM
  (
  SELECT *,
  CASE
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 1) THEN 'Mon'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 2) THEN 'Tue'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 3) THEN 'Wed'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 4) THEN 'Thu'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 5) THEN 'Fri'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 6) THEN 'Sat'
  WHEN (EXTRACT(DAYOFWEEK FROM date)= 7) THEN 'Sun'
  END AS day_of_week
  FROM daily_activity_sleep
  )

GROUP BY day_of_week


Steps and minutes asleep per weekday

Spreedsheet data

In the graphs above we can determine the following:

Users walk daily the recommended amount of steps of 7500 besides Sunday’s. based on the article above Users don’t sleep the recommended amount of minutes/ hours - 8 hours.

Hourly steps within a day

We were going to find out when the users more active throughout the day.

Hourly steps within a day

Spreedsheet data

As we can see the graph above user are more active 7:00AM to 9:00PM. We also user more likely walk more at 11:00AM to 2:00PM, rest at 3:00PM, and 5:00PM to 7:00PM in the evening.

Correlation

We will now determine if there is any correlation between different variables: - Daily steps and daily sleep - Daily steps and calories

Daily steps and daily sleep

Spreedsheet data

Based on our plots:

There’s is no correlation between the daily steps and minutes asleep. Basically walking daily does not affect the minutes of their sleep But, there is a correlation between the daily steps and calories. Basically the more user steps the more they burn calories.

Total days used by users

Now that we have seen some trends in activity, sleep and calories burned, we want to see how often do the users in our sample use their device. That way we can plan our marketing strategy and see what features would benefit the use of smart devices.

We will calculate the number of users that use their smart device on a daily basis, classifying our sample into three categories knowing that the date interval is 31 days:

  • high use - users who use their device between 21 and 31 days.
  • moderate use - users who use their device between 11 and 20 days.
  • low use - users who use their device between 1 and 10 days.

First I will make a temp table.


WITH
  --Merging two tables with two primary key
  daily_activity_and_sleep AS (
    SELECT
    daily_activity.Id as Id,
    COUNT(*) as num_of_use
    FROM `first-analyst.bellabeat_data.daily_activity_new` as daily_activity
    INNER JOIN `first-analyst.bellabeat_data.daily_sleep_new` as daily_sleep
    ON daily_activity.Id = daily_sleep.Id AND daily_activity.Date = daily_sleep.Date
    GROUP BY Id
  ),
  #Filtering user usage based on daily sleep and activity of a users
  usages AS (
    SELECT 
  Id, 
  SUM(num_of_use) AS day_used, 
  CASE 
    WHEN SUM(num_of_use) BETWEEN 1 AND 10 THEN 'low use'
    WHEN SUM(num_of_use) BETWEEN 11 AND 20 THEN 'moderate use'
    WHEN SUM(num_of_use) BETWEEN 21 AND 31 THEN 'high use'
  END AS usage
FROM daily_activity_and_sleep
GROUP BY Id
  ),
  -- Counting the number of usage
  usage_summary AS (
    SELECT 
      usage, 
      COUNT(*) AS total
    FROM usages
    GROUP BY usage
  ),
  -- Getting the average of number of usage and total usage
  usage_percentage AS (
    SELECT 
      usage, 
      total, 
      total_usage, 
      CAST(total AS FLOAT64) / total_usage AS total_percentage
   -- Selecting it FROM usage summary, and finding the total usage 
    FROM (
      SELECT 
        usage, 
        total, 
        SUM(total) OVER () AS total_usage
      FROM usage_summary
    ) 
  )
SELECT 
  usage, 
  total_percentage, 
  CONCAT(CAST(ROUND(total_percentage * 100, 1) AS INT64), '% (', CAST(total AS INT64), ')') AS labels
FROM usage_percentage

Total days used by users

Spreedsheet data

The results on out graph are: - Between 21 and 31 days, 50% of users frequently use their phone. - 38% of users balance their phone usage between 11 and 20 days. - 12% of the users are rarely used their phone 1 to 10 days

Time used smart device

Being more precise we want to see how many minutes do users wear their device per day. For that we will merge the created daily_use data frame and daily_activity to be able to filter results by daily use of device as well.


WITH
  --Merging two tables with two primary key
  daily_activity_and_sleep AS (
    SELECT
    daily_activity.Id as Id,
    COUNT(*) as num_of_use
    FROM `first-analyst.bellabeat_data.daily_activity_new` as daily_activity
    INNER JOIN `first-analyst.bellabeat_data.daily_sleep_new` as daily_sleep
    ON daily_activity.Id = daily_sleep.Id AND daily_activity.Date = daily_sleep.Date
    GROUP BY Id
  ),
  --Filtering user usage based on daily sleep and activity of a users
  usages AS (
    SELECT 
  Id, 
  SUM(num_of_use) AS day_used, 
  CASE 
    WHEN SUM(num_of_use) BETWEEN 1 AND 10 THEN 'low use'
    WHEN SUM(num_of_use) BETWEEN 11 AND 20 THEN 'moderate use'
    WHEN SUM(num_of_use) BETWEEN 21 AND 31 THEN 'high use'
  END AS usage
FROM daily_activity_and_sleep
GROUP BY Id
  ),
  -- Counting the number of usage
  usage_summary AS (
    SELECT 
      usage, 
      COUNT(*) AS total
    FROM usages
    GROUP BY usage
  ),
  -- Getting the average of number of usage and total usage
  usage_percentage AS (
    SELECT 
      usage, 
      total, 
      total_usage, 
      CAST(total AS FLOAT64) / total_usage AS total_percentage
   -- Selecting it FROM usage summary, and finding the total usage 
    FROM (
      SELECT 
        usage, 
        total, 
        SUM(total) OVER () AS total_usage
      FROM usage_summary
    ) 
  ), 
  -- Creating new subquery for daily used
  daily_activity_used AS (
    SELECT *
    FROM  `first-analyst.bellabeat_data.daily_activity_new`, usage_summary
  ),

  minutes_worn AS (
   SELECT *,
   CASE 
    WHEN minutes_worn_percentage = 100 THEN 'All day'
    WHEN minutes_worn_percentage >= 50 AND minutes_worn_percentage < 100 THEN 'More than half day'
    WHEN minutes_worn_percentage > 0 AND minutes_worn_percentage < 50 THEN 'Less than half day'
   END as worn

  FROM (
     SELECT *, 
      (Very_Active_Minutes + Fairly_Active_Minutes + Lightly_Active_Minutes +
Sedentary_Minutes) as total_worn_minutes,
  (Very_Active_Minutes + Fairly_Active_Minutes + Lightly_Active_Minutes +
Sedentary_Minutes) / 1440 * 100 as minutes_worn_percentage
     FROM daily_activity_used
   )

  ),

-- As we have done before, to better visualize our results we will create new subqueries. 

worn_summary AS (
  SELECT 
  worn,
  COUNT(*) as total
  FROM minutes_worn
  GROUP BY worn
),
worn_percentage AS (
  SELECT
  worn,
  total,
  total_worn,

  FROM (
    SELECT
    worn,
    total,
    SUM(total) OVER() total_worn
    FROM worn_summary
  )

),



  minutes_worn_highuse AS (
    SELECT
    worn,
    total/totals AS total_percentage,
    CONCAT(ROUND(total / totals * 100, 2), '%') AS labels,
    FROM (
      SELECT 
      worn,
      COUNT(*) AS total,
      SUM(COUNT(*)) OVER () AS totals   -- Calculating the sum of the number of rows (which is total)
      FROM minutes_worn
      WHERE usage = 'high use'
      GROUP BY worn
    )
    GROUP BY worn, total_percentage,labels
  ),
  minutes_worn_moderateuse AS (
    SELECT
    worn,
    total / totals as total_percentage,
    CONCAT(ROUND(total/totals * 100, 2), '%') as labels
    FROM (
      SELECT
      worn,
      COUNT(*) as total,
      SUM(COUNT(*)) OVER() as totals 
      FROM minutes_worn
      WHERE usage = 'moderate use'
      GROUP BY worn

    )
    GROUP BY worn, total_percentage,labels
  ),
   minutes_worn_lowuse AS (
    SELECT
    worn,
    total / totals as total_percentage,
    CONCAT(ROUND(total/totals * 100, 2), '%') as labels
    FROM (
      SELECT
      worn,
      COUNT(*) as total,
      SUM(COUNT(*)) OVER() as totals 
      FROM minutes_worn
      WHERE usage = 'low use'
      GROUP BY worn

    )
    GROUP BY worn, total_percentage,labels
  )

-- SHOWING THE TOTAL USAGE OF ALL USER
-- SELECT 
-- worn,
-- total_percentage,
--  CONCAT(CAST(ROUND(total_percentage * 100, 1) AS INT64), '% (', CAST(total AS INT64), ')') AS labels
-- FROM worn_percentage


SELECT
*
FROM minutes_worn_lowuse

Conclusion and Recommendation

Based on our findings, I would recommend that we use our own tracking data for further analysis in order to respond to our business task and assist Bellabeat with their mission. Because we didn’t have any demographic information about users, the data sets we used had a small sample size and could be biased. Knowing that our primary demographic is young and adult women, I would encourage you to continue looking for trends in order to develop a marketing strategy centered on them.

That being said, after our analysis we have found different trends that may help our online campaign and improve Bellabeat app:

library(knitr)
recommendation <- c("Adding a 'goal' on the app", "Sleeping recommendation for users", "Level or rank badge system")
description <- c("Putting a goal to track daily steps and calories helps users monitor their progress towards their fitness goals.", 
                 "A sleep recommendation feature can remind users to maintain a healthy sleep routine and provide helpful tips for better sleep.",
                 "A level or rank system can motivate users to be more active by allowing them to track their progress and earn badges as rewards.")
tbl <- data.frame(Recommendation = recommendation, Description = description)
kable(tbl)
Recommendation Description
Adding a ‘goal’ on the app Putting a goal to track daily steps and calories helps users monitor their progress towards their fitness goals.
Sleeping recommendation for users A sleep recommendation feature can remind users to maintain a healthy sleep routine and provide helpful tips for better sleep.
Level or rank badge system A level or rank system can motivate users to be more active by allowing them to track their progress and earn badges as rewards.
NA
NA

On our analysis we dint just check for the trends but also we see that healthy users tend to be use their device and 36% of the users wear the device all time.

LS0tDQp0aXRsZTogIkNhcHN0b25lOiBCZWxsYWJlYXQgQ2FzZSBTdHVkeSBTUUwiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KX09uIHRoaXMgQ2FzZSBTdHVkeSBJIHVzZWQgdGhlIHNhbWUgZGF0YXNldCBvbiBteSBwcmV2aW91cyB3b3JrIFtDYXBzdG9uZTogQmVsbGFiZWF0IENhc2UgU3R1ZHkgd2l0aCBSXShodHRwczovL3d3dy5rYWdnbGUuY29tL2NvZGUvam9uZGVyZWNrbmlmYXMvY2Fwc3RvbmUtYmVsbGFiZWF0LWNhc2Utc3R1ZHkvKSAgYnV0IHRoaXMgdGltZSBJbSB1c2luZyBzb2xleSBvbiBTUUwgYW5kIEV4Y2VsIHRvIHNob3djYXNlIG15IHNraWxsLl8NCg0KIVtBbHQgdGV4dF0oaHR0cHM6Ly9wb2x5Z3Jvd3RoLmlvL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDIyLzAxL0JlbGxhYmVhdC1jYXNlLXN0dWR5LTEyMDB4Njc1LnBuZykgPC9icj4NCg0KDQojIFN1bW1hcnkNCkJlbGxhYmVhdCBpcyBhIGhpZ2gtdGVjaCBjb21wYW55IHRoYXQgbWFudWZhY3R1cmVzIGhlYWx0aC1mb2N1c2VkIHNtYXJ0IHByb2R1Y3RzLlRoZXkgb2ZmZXIgZGlmZmVyZW50IHNtYXJ0IGRldmljZXMgdGhhdCBjb2xsZWN0IGRhdGEgb24gYWN0aXZpdHksIHNsZWVwLCBzdHJlc3MsIGFuZCByZXByb2R1Y3RpdmUgaGVhbHRoIHRvIGVtcG93ZXIgd29tZW4gd2l0aCBrbm93bGVkZ2UgYWJvdXQgdGhlaXIgb3duIGhlYWx0aCBhbmQgaGFiaXRzLg0KDQpUaGUgbWFpbiBmb2N1cyBvZiB0aGlzIGNhc2UgaXMgdG8gYW5hbHl6ZSBzbWFydCBkZXZpY2VzIGZpdG5lc3MgZGF0YSBhbmQgZGV0ZXJtaW5lIGhvdyBpdCBjb3VsZCBoZWxwIHVubG9jayBuZXcgZ3Jvd3RoIG9wcG9ydHVuaXRpZXMgZm9yIEJlbGxhYmVhdC4gV2Ugd2lsbCBmb2N1cyBvbiBvbmUgb2YgQmVsbGFiZWF04oCZcyBwcm9kdWN0czogKkJlbGxhYmVhdCBhcHAgYW5kIExlYWYqLg0KDQpUaGUgQmVsbGFiZWF0IGFwcCBwcm92aWRlcyB1c2VycyB3aXRoIGhlYWx0aCBkYXRhIHJlbGF0ZWQgdG8gdGhlaXIgYWN0aXZpdHksIHNsZWVwLCBzdHJlc3MsIG1lbnN0cnVhbCBjeWNsZSwgYW5kIG1pbmRmdWxuZXNzIGhhYml0cy4gVGhpcyBkYXRhIGNhbiBoZWxwIHVzZXJzIGJldHRlciB1bmRlcnN0YW5kIHRoZWlyIGN1cnJlbnQgDQoNClRoZSBMZWFmIGlzIEJlbGxhYmVhdOKAmXMgY2xhc3NpYyB3ZWxsbmVzcyB0cmFja2VyIGNhbiBiZSB3b3JuIGFzIGEgYnJhY2VsZXQsIG5lY2tsYWNlLCBvciBjbGlwLiBUaGUgTGVhZiB0cmFja2VyIGNvbm5lY3RzDQp0byB0aGUgQmVsbGFiZWF0IGFwcCB0byB0cmFjayBhY3Rpdml0eSwgc2xlZXAsIGFuZCBzdHJlc3MgaGFiaXRzIGFuZCBtYWtlIGhlYWx0aHkgZGVjaXNpb25zLiBUaGUgQmVsbGFiZWF0IGFwcCBjb25uZWN0cyB0byB0aGVpciBsaW5lIG9mIHNtYXJ0IHdlbGxuZXNzIHByb2R1Y3RzDQoNCiMgQXNrIFBoYXNlIA0KIyMgQnVzaW5lc3MgVGFzayANCklkZW50aWZ5IHRyZW5kcyBpbiBob3cgY29uc3VtZXJzIHVzZSBub24tQmVsbGFiZWF0IHNtYXJ0IGRldmljZXMgdG8gYXBwbHkgaW5zaWdodHMgaW50byBCZWxsYWJlYXTigJlzIG1hcmtldGluZyBzdHJhdGVneS4NCg0KIyMgU3Rha2Vob2xkZXJzDQoNCiogVXLFoWthIFNyxaFlbiAtIEJlbGxhYmVhdCBjb2ZvdW5kZXIgYW5kIENoaWVmIENyZWF0aXZlIE9mZmljZXINCiogU2FuZG8gTXVyIC0gQmVsbGFiZWF0IGNvZm91bmRlciBhbmQga2V5IG1lbWJlciBvZiBCZWxsYWJlYXQgZXhlY3V0aXZlIHRlYW0NCiogQmVsbGFiZWF0IE1hcmtldGluZyBBbmFseXRpY3MgdGVhbQ0KDQojIFByZXBhcmUgUGhhc2UgDQojIyBEYXRhc2V0IHVzZWQ6IA0KVGhlIGRhdGEgc291cmNlIHVzZWQgZm9yIG91ciBjYXNlIHN0dWR5IGlzIEZpdEJpdCBGaXRuZXNzIFRyYWNrZXIgRGF0YS4gVGhpcyBkYXRhIHNldCBpcyBzdG9yZWQgaW4gS2FnZ2xlIGFuZCB3YXMgbWFkZSBhdmFpbGFibGUgdGhyb3VnaCBNb2JpdXMuDQoNCiMjIEFjY2Vzc2liaWxpdHkgYW5kIHByaXZhY3kgb2YgZGF0YTogDQpWZXJpZnlpbmcgdGhlIG1ldGFkYXRhIG9mIG91ciBkYXRhIHNldCB3ZSBjYW4gY29uZmlybSBpdCBpcyBvcGVuLXNvdXJjZS4gVGhlIG93bmVyIGhhcyBkZWRpY2F0ZWQgdGhlIHdvcmsgdG8gdGhlIHB1YmxpYyBkb21haW4gYnkgd2FpdmluZyBhbGwgb2YgaGlzIG9yIGhlciByaWdodHMgdG8gdGhlIHdvcmsgd29ybGR3aWRlIHVuZGVyIGNvcHlyaWdodCBsYXcsIGluY2x1ZGluZyBhbGwgcmVsYXRlZCBhbmQgbmVpZ2hib3JpbmcgcmlnaHRzLCB0byB0aGUgZXh0ZW50IGFsbG93ZWQgYnkgbGF3LiBZb3UgY2FuIGNvcHksIG1vZGlmeSwgZGlzdHJpYnV0ZSBhbmQgcGVyZm9ybSB0aGUgd29yaywgZXZlbiBmb3IgY29tbWVyY2lhbCBwdXJwb3NlcywgYWxsIHdpdGhvdXQgYXNraW5nIHBlcm1pc3Npb24uDQoNCiMjIEluZm9ybWF0aW9uIGFib3V0IG91ciBkYXRhc2V0Og0KVGhlc2UgZGF0YSBzZXRzIHdlcmUgZ2VuZXJhdGVkIGJ5IHJlc3BvbmRlbnRzIHRvIGEgZGlzdHJpYnV0ZWQgc3VydmV5IHZpYSBBbWF6b24gTWVjaGFuaWNhbCBUdXJrIGJldHdlZW4gMDMuMTIuMjAxNi0wNS4xMi4yMDE2LiBUaGlydHkgZWxpZ2libGUgRml0Yml0IHVzZXJzIGNvbnNlbnRlZCB0byB0aGUgc3VibWlzc2lvbiBvZiBwZXJzb25hbCB0cmFja2VyIGRhdGEsIGluY2x1ZGluZyBtaW51dGUtbGV2ZWwgb3V0cHV0IGZvciBwaHlzaWNhbCBhY3Rpdml0eSwgaGVhcnQgcmF0ZSwgYW5kIHNsZWVwIG1vbml0b3JpbmcuIFZhcmlhdGlvbiBiZXR3ZWVuIG91dHB1dCByZXByZXNlbnRzIHVzZSBvZiBkaWZmZXJlbnQgdHlwZXMgb2YgRml0Yml0IHRyYWNrZXJzIGFuZCBpbmRpdmlkdWFsIHRyYWNraW5nIGJlaGF2aW9ycyAvIHByZWZlcmVuY2VzLg0KDQojIyBDbGVhbmluZyB0aGUgZGF0YSB1c2luZyBFeGNlbA0KVGhlIGZvbGxvd2luZyBzdGVwcyB3ZXJlIHRha2VuIHdpdGhpbiBlYWNoIGRhdGFzZXQ6DQoNCi0gU29ydGVkIGFuZCBmaWx0ZXJlZCBkYXRhIGJ5IElkIHRvIG9idGFpbiBob3cgbWFueSB1bmlxdWUgdXNlcnMgdGhlcmUgd2VyZSB3aXRoaW4gdGhlIGRhdGFzZXQuDQotIENoZWNrZWQgZm9yIGR1cGxpY2F0ZSBkYXRhIHVzaW5nIHRoZSAnZHVwbGljYXRlIGRhdGEnIHRvb2wgaW4gRXhjZWwNCi0gRm9ybWF0dGVkIGRhdGUgZGF0YSBpbnRvIE1NL0REL1lZIGRhdGUgZm9ybWF0DQotIEZvcm1hdHRlZCBhbGwgbnVtZXJpY2FsIGRhdGEgaW50byBOdW1iZXIgZm9ybWF0IHdpdGggZWl0aGVyIG5vIGRlY2ltaWxzIG9yIHVwIHRvIDIgZGVjaW1pYWxzLg0KLSBTb3J0ZWQgYnkgZGF0ZSB0byBmaW5kIHRoZSBmaXJzdCBhbmQgbGFzdCBkYXRlIG9mIHRoZSBkYXRhc2V0ICh0aGlzIGlzIHdoYXQgZmlyc3QgaW5kaWNhdGVkIG9ubHkgYSAzMS1kYXkgcGVyaW9kIG9mIGFjdGl2aXR5IHdhcyBjYXB0dXJlZCkuDQotIFNlcGFyYXRlZCBEYXRlIGFuZCBIb3VyIGludG8gdHdvIGNvbHVtbnMgd2hlbiBuZWVkZWQgZm9yIGxhdGVyIGFuYWx5c2lzLiBVdGlsaXplZCB0aGUgJ1RleHQgdG8gQ29sdW1ucycgdG9vbCB0byBkbyBzby4NCi0gRm9ybWF0dGVkIGFueSB0aW1lIGRhdGEgaW50byAwMDowMDowMCBmb3JtYXQgZm9yIGNvbnNpc3RlbmN5Lg0KLSBDaGVja2VkIElkIGVudHJpZXMgYW5kIG90aGVyIGNvbHVtbnMgZm9yIExFTiB0byBtYWtlIHN1cmUgdGhlIGRhdGEgd2FzIGNvcnJlY3QgYW5kIHVuaWZvcm0gaW4gbGVuZ3RoDQoNCkFmdGVyIHRoZSBjbGVhbmluZyBwcm9jZXNzIHdhcyBmaW5pc2hlZCwgb25seSAzIHJvd3Mgb2YgZHVwbGljYXRlIGluZm9ybWF0aW9uIHdhcyBmb3VuZCB3aXRoaW4gdGhlIERhaWx5X1NsZWVwX01lcmdlZCBmaWxlLiBUaGVzZSB3ZXJlIHJlbW92ZWQgYmVmb3JlIGFuYWx5c2lzLg0KDQojIFByb2Nlc3MgcGhhc2UNCkluIHRoaXMgYW5hbHlzaXMgSSB3aWxsIGZvY3VzIG9uIEJpZ3F1ZXJ5IFNRTCBhbmQgTVMgZXhjZWwgYW5kIHRvIGJlIGFibGUgdG8gY3JlYXRlIGRhdGEgdml6IGZvciB0aGUgc3Rha2Vob2xkZXJzLg0KDQojIyMgSW1wb3J0aW5nIGRhdGFzZXQNCiBJIG9wZW5lZCBCaWdxdWVyeSBDb25zb2xlLCB0aGVuIHNlbGVjdCAiQ3JlYXRlIFByb2plY3QiLiBUeXBlZCBkb3duIHRoZSBuYW1lIG9mIHRoZSBwcm9qZWN0IHlvdSBhcmUgZ29pbmcgdG8gZXhwbG9yZSwgaW4gdGhpcyBjYXNlIEkgdXNlZCBgZmlyc3QtYW5hbHlzdGAuIEkgY3JlYXRlZCBhIG5ldyBkYXRhc2V0IGZvciBCZWxsYWJlYXQgYW5kIG5hbWVkIGl0IGJlbGxhYmVhdF9kYXRhLiBJbnNpZGUgYmVsbGFiZWF0IGRhdGFzZXQsIEkgaW1wb3J0ZWQgdGhlIC5jc3YgZGF0YXNldHMgSSBwcmV2aW91c2x5IGRvd25sb2FkZWQgZnJvbSBGaXRCaXQgRml0bmVzcyBUcmFja2VyIERhdGEuIA0KIA0KIC0gRGFpbHlfQWN0aXZpdHlfTWVyZ2VkDQogLSBEYWlseV9TbGVlcF9NZXJnZWQNCiAtIEhvdXJseV9TdGVwc19NZXJnZWQNCiANCkFmdGVyIHRoYXQsIEkgc3RhcnRlZCBteSB3b3JrIGJ5IGZpbmRpbmcgdGhlIHRvdGFsIG51bWJlciBvZiB1c2VycycgaWQNCg0KIyMjIE51bWJlciBvZiB1c2Vycw0KYGBge3NxbCBjb25uZWN0aW9uPX0NCg0KU0VMRUNUIA0KICBDT1VOVCggRElTVElOQ1QgSWQpDQpGUk9NDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmhvdXJseV9zdGVwc2AgLS0gMzMNCg0KDQpTRUxFQ1QgDQogIENPVU5UKERJU1RJTkNUIElkKQ0KRlJPTSANCiAgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfYWN0aXZpdHlgIC0tMzMNCiAgDQogIA0KU0VMRUNUIA0KICBDT1VOVChESVNUSU5DVCBJZCkNCkZST00gDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwYCAtLSAyNA0KYGBgDQoNCg0KIyMjIENoZWNraW5nIFN0YXJ0LUVuZCBEYXRlIGFuZCBJZCANCmBgYHtzcWwgY29ubmVjdGlvbj19DQoNClNFTEVDVCANCiAgTUlOKERhdGUpIGFzIHN0YXJ0X2RhdGUsDQogIE1BWChEYXRlKSBhcyBlbmRfZGF0ZQ0KRlJPTSANCiAgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfYWN0aXZpdHlgDQoNClNFTEVDVCANCiAgTUlOKERhdGUpIGFzIHN0YXJ0X2RhdGUsDQogIE1BWChEYXRlKSBhcyBlbmRfZGF0ZQ0KRlJPTSANCiAgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfc2xlZXBgDQoNClNFTEVDVCANCiAgTUlOKERhdGUpIGFzIHN0YXJ0X2RhdGUsDQogIE1BWChEYXRlKSBhcyBlbmRfZGF0ZQ0KRlJPTSANCiAgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuaG91cmx5X3N0ZXBzYA0KDQogIC0tIGRhaWx5IGFjdGl2aXR5LCBkYWlseSBzbGVlcCwgaG91cmx5c3RlcHMgYXJlIHNhbWUgc3RhcnRkYXRlOiAyMDE2LTA0LTEyLCBlbmRkYXRlOiAyMDE2LTA1LTEyLiAzMSBkYXlzIGluIHRvdGFsDQoNCmBgYA0KIyMjIENoZWNrIGFsbCBpZHMgaGF2ZSB0aGUgc2FtZSBsZW5ndGgNCg0KYGBge3NxbCBjb25uZWN0aW9uPX0NClNFTEVDVCANCiAgSWQNCkZST00gDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5YA0KV0hFUkUNCiAgTEVOR1RIKENBU1QoSWQgYXMgU1RSSU5HKSkgPiAxMCBPUiBMRU5HVEgoQ0FTVChJZCBhcyBTdHJpbmcpKSA8IDEwDQoNCiAgLS0gTm8gZGF0YSBkaXNwbGF5IG1lYW5pbmcgdGhlcmUgYXJlIG5vIElkIG1vcmUgdGhhbiBvciBsZXNzIHRoYW4gdG8gMTANCiAgDQogIFNFTEVDVCANCiAgSWQNCkZST00gDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwYA0KV0hFUkUNCiAgTEVOR1RIKENBU1QoSWQgYXMgU1RSSU5HKSkgPiAxMCBPUiBMRU5HVEgoQ0FTVChJZCBhcyBTdHJpbmcpKSA8IDEwDQoNCiAgLS0gTm8gZGF0YSBkaXNwbGF5IG1lYW5pbmcgdGhlcmUgYXJlIG5vIElkIG1vcmUgdGhhbiBvciBsZXNzIHRoYW4gdG8gMTANCg0KDQpTRUxFQ1QgDQogIElkDQpGUk9NIA0KICBgZmlyc3QtYW5hbHlzdC5iZWxsYWJlYXRfZGF0YS5ob3VybHlfc3RlcHNgDQpXSEVSRQ0KICBMRU5HVEgoQ0FTVChJZCBhcyBTVFJJTkcpKSA+IDEwIE9SIExFTkdUSChDQVNUKElkIGFzIFN0cmluZykpIDwgMTANCg0KICAtLSBObyBkYXRhIGRpc3BsYXkgbWVhbmluZyB0aGVyZSBhcmUgbm8gSWQgbW9yZSB0aGFuIG9yIGxlc3MgdGhhbiB0byAxMA0KDQoNCg0KDQpgYGANCg0KSXQgc2hvd2VkIHRoYXQgYWxsIGRhdGFzZXRzIGhhdmUgdGhlIHNhbWUgc3RhcnQgYW5kIGVuZCBkYXRlOiBzdGFydCAyMDE2LTA0LTEyIGFuZCBlbmQgMjAxNi0wNS0xMi4gSW4gdGVybSBvZiBpZCdzIGxlbmd0aCwgYWxsIGRhdGFzZXRzIGFsc28gc2hvd2VkIHRoZSBzYW1lIGxlbmd0aDogMTAgY2hhcmFjdGVycy4NCg0KIyMgQ2xlYW5pbmcgdGhlIGRhdGENCg0KDQojIyMgRmluZGluZyBEdXBsaWNhdGVzDQoqKk5vdGU6KiogIEkganVzdCByZXBhdGluZyB0aGlzIGJlbG93IGNvZGUgdG8gY2hlY2sgZm9yIGRhaWx5IHNsZWVwIGFuZCBob3VybHkgc3RlcHMNCmBgYHtzcWwgY29ubmVjdGlvbj19DQpTRUxFQ1QgDQogIElkLA0KICBEYXRlLA0KICBDT1VOVCgqKSBhcyBudW1fb2ZfaWQNCkZST00gDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5YA0KR1JPVVAgQlkNCiAgSWQsIERhdGUNCkhBVklORyANCiAgbnVtX29mX2lkID4gMQ0KDQotLSBubyBkYXRhIHRvIGRpc3BsYXkgLyBubyBkdXBsaWNhdGVzIGluIGRhaWx5X2FjdGl2aXR5DQogIA0KU0VMRUNUIA0KICBJZCwNCiAgRGF0ZSwNCiAgQ09VTlQoKikgYXMgbnVtX29mX2lkDQpGUk9NIA0KICBgZmlyc3QtYW5hbHlzdC5iZWxsYWJlYXRfZGF0YS5ob3VybHlfc3RlcHNgDQpHUk9VUCBCWQ0KICBJZCwgRGF0ZQ0KSEFWSU5HIA0KICBudW1fb2ZfaWQgPiAyNA0KLS0gSSBwdXQgMjQgYmVjYXVzZSBpdCBpcyAyNCBob3VycyBpbiBhIGRheSAvIG5vIGRpc3BsYXkgbm8gZHVwbGljYXRlcw0KICANCiAgDQpTRUxFQ1QgDQogIElkLA0KICBEYXRlLA0KICBDT1VOVCgqKSBhcyBudW1fb2ZfaWQNCkZST00gDQogIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwYA0KR1JPVVAgQlkNCiAgSWQsIERhdGUNCkhBVklORyANCiAgbnVtX29mX2lkID4gMQ0KDQotLSBkaXNwbGF5cyAzIGR1cGxpY2F0ZXMNCg0KDQpgYGANCkFjY29yZGluZyB0byB0aGUgcmVzdWx0IG9mIGZpbmRpbmcgZHVwbGljYXRlcywgaXQgc2hvd2VkIHRoYXQgdGhlcmUgYXJlIDMgZHVwbGljYXRlIHJvd3MgaW4gc2xlZXBfZGF5IGRhdGFzZXQuIFdlIG5lZWQgdG8gY3JlYXRlIGEgbmV3IHNsZWVwX2RheSB0YWJsZSwgYW5kIHJlbW92ZSB0aGUgZHVwbGljYXRlcyBpbiB0aGUgbmV3IHRhYmxlLiBJbiB0aGlzIGNhc2UsIEkgbmFtZWQgdGhlIG5ldyB0YWJsZTogZGFpbHlfc2xlZXBfbmV3Lg0KDQojIyBEdXBsaWNhdGUgcm93cyBpbiBkYWlseV9zdGVwIHRhYmxlIG5lZWQgdG8gYmUgcmVtb3ZlZA0KQ3JlYXRpbmcgYW5kIHJlcGxhY2luZyBuZXcgc2xlZXBfZGF5IHRhYmxlIHdpdGggYWxsIGRpc3RpbmN0IHZhbHVlcw0KDQpgYGB7c3FsIGNvbm5lY3Rpb249fQ0KQ1JFQVRFIG9yIFJFUExBQ0UgVEFCTEUgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfc2xlZXBfbmV3YA0KQVMgU0VMRUNUICoNCkZST00NCigNCiAgU0VMRUNUICosIA0KICBST1dfTlVNQkVSKCkgDQogIE9WRVIgKFBBUlRJVElPTiBCWSBJZCwgRGF0ZSkNCiAgcm93X251bWJlcg0KICBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwYA0KKQ0KV0hFUkUgcm93X251bWJlciA9IDENCg0KDQotLSBDaGVjayBpdCBhZ2FpbiBpZiBpdCB0aGUgbmV3IHRhYmxlIGhhZCBubyBkdXBsaWNhdGVzDQoNClNFTEVDVA0KICBJZCwNCiAgRGF0ZSwNCiAgQ09VTlQoKikgYXMgbnVtX29mX2lkDQpGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwX25ld2ANCkdST1VQIEJZDQogIElkLCBEYXRlDQpIQVZJTkcgDQogIG51bV9vZl9pZCA+IDENCg0KICAtLSBubyBkYXRhIGRpc3BsYXkvIG5vIGR1cGxpY2F0ZXMNCmBgYA0KDQojIyMgUmVtb3ZpbmcgdGhlIHVud2FudGVkIERhdGEgDQpEdXJpbmcgdGhlIGNoZWNraW5nIGFuZCBjbGVhbmluZyBwcm9jZXNzLCBJIGZvdW5kIHRoYXQgdGhlcmUgd2VyZSBzb21lIHplcm8gZGF0YSBpbiBUb3RhbFN0ZXBzIGNvbHVtbiBpbnNpZGUgdGhlIGRhaWx5X2FjdGl2aXR5IGRhdGFzZXQuIFRoZXJlZm9yZSwgSSBkZWNpZGVkIHRvIGNoZWNrIGFuZCByZW1vdmUgdGhvc2UgemVybyB2YWx1ZS4gSSBjcmVhdGVkIG5ldyB0YWJsZSBhbmQgbmFtZWQgaXQgZGFpbHlfYWN0aXZpdHlfbmV3LCBzbyB0aGF0IHRoZSBwcmV2aW91cyBkYXRhc2V0IHN0aWxsIHJlbWFpbmVkLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249fQ0KLS1DaGVjayBpZiB0b3RhbCBzdGVwcyA9IDAgaW4gZGFpbHlfYWN0aXZpdHkgdGFibGUNClNFTEVDVCANCiAgSWQsIA0KICBDb3VudCgqKSBhcyBudW1fb2ZfemVyb19zdGVwcw0KRlJPTSBgZmlyc3QtYW5hbHlzdC5iZWxsYWJlYXRfZGF0YS5kYWlseV9hY3Rpdml0eWANCldIRVJFIA0KICBUb3RhbF9TdGVwcyA9IDANCkdST1VQIEJZIElkDQpPUkRFUiBCWSBudW1fb2ZfemVyb19zdGVwcw0KDQogIC0tIDE1IGlkcyB3aXRoIDAgdG90YWwgc3RlcHMNCg0KLS0gQ3JlYXRlIG5ldyBkYWlseSBhY3Rpdml0eSB0YWJsZQ0KQ1JFQVRFIFRBQkxFIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2ANCkFTIFNFTEVDVCAqDQpGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5YA0KDQoNCi0tIERlbGV0ZSBhbGwgcm93cyB0aGF0IGNvbnRhaW4gemVybyB0b3RhbCBzdGVwcw0KREVMRVRFIEZST00gYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfYWN0aXZpdHlfbmV3YA0KV0hFUkUgVG90YWxfU3RlcHMgPSAwDQotLTc3IGRhdGEgZGVsZXRlZA0KDQoNCi0tIFJlbW92aW5nIHRoZSB6ZXJvIHZhbHVlIG9uIEhvdXJseSBzdGVwcw0KU0VMRUNUIA0KICBJZCwgDQogIENvdW50KCopIGFzIG51bV9vZl96ZXJvX3N0ZXBzDQpGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmhvdXJseV9zdGVwc2ANCldIRVJFIA0KICBTdGVwX1RvdGFsID0gMA0KR1JPVVAgQlkgSWQNCk9SREVSIEJZIG51bV9vZl96ZXJvX3N0ZXBzDQotLSAzMyBpZHMgd2l0aCAwIHRvdGFsIHN0ZXBzDQoNCkRFTEVURSBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmhvdXJseV9zdGVwc2ANCldIRVJFIFN0ZXBfVG90YWwgPSAwDQotLSA3NTM1IGRlbGV0ZWQNCmBgYA0KIyMjIEZpbmQgdGhlIG51bGwgZGF0YQ0KDQpgYGB7c3FsIGNvbm5lY3Rpb249fQ0KDQotLUNoZWNrIGZvciBudWxsIGRhdGENClNFTEVDVCAqDQpGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2ANCldIRVJFIElkIElTIE5VTEwNCi0tIG5vIGRhdGEgZGlzcGxheQ0KDQpTRUxFQ1QgKg0KRlJPTSBgZmlyc3QtYW5hbHlzdC5iZWxsYWJlYXRfZGF0YS5kYWlseV9zbGVlcF9uZXdgDQpXSEVSRSBJZCBJUyBOVUxMDQotLSBubyBkYXRhIGRpc3BsYXkNCg0KU0VMRUNUICoNCkZST00gYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuaG91cmx5X3N0ZXBzYA0KV0hFUkUgSWQgSVMgTlVMTA0KLS0gbm8gZGF0YSBkaXNwbGF5DQoNCg0KLS1EZWxldGUgcm93cyBvZiBudWxsIGRhdGENCkRFTEVURSBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2ANCldIRVJFIElkIElTIE5VTEwNCg0KDQpgYGANCiMgQW5hbHl6ZSBQaGFzZSBhbmQgU2hhcmUgUGhhc2UNCldlIHdlcmUgZ29pbmcgYW5hbHl6ZSB0aGUgdHJlbmRzIG9mIEZpdEJpdCB1c2VyIGFuZCB0byBkZXRlcm1pbmUgaWYgY2FuIGhlbHAgdXMgdG8gbWFrZSBhIGRlY2lzaW9uIGZvciBtYXJrZXRpbmcgc3RyYXRlZ3kNCg0KIyMjIFVzZXIgTGV2ZWwNCldlIHdhbnQgdG8gZGV0ZXJtaW5lIHRoZSB0eXBlIG9mIHVzZXJzIHdpdGggdGhlIGRhdGEgd2UgaGF2ZSBiZWNhdXNlIHdlIGRvbuKAmXQgaGF2ZSBhbnkgZGVtb2dyYXBoaWMgdmFyaWFibGVzIGZyb20gb3VyIHNhbXBsZS4gV2UgY2FuIGNhdGVnb3JpemUgdXNlcnMgYmFzZWQgb24gdGhlaXIgZGFpbHkgbnVtYmVyIG9mIHN0ZXBzLiBVc2VycyBjYW4gYmUgY2xhc3NpZmllZCBhcyBmb2xsb3dzOg0KDQoqIFNlZGVudGFyeSAtIExlc3MgdGhhbiA1MDAwIHN0ZXBzIGEgZGF5LiANCiogTGlnaHRseSBhY3RpdmUgLSBCZXR3ZWVuIDUwMDAgYW5kIDc0OTkgc3RlcHMgYSBkYXkuIA0KKiBGYWlybHkgYWN0aXZlIC0gQmV0d2VlbiA3NTAwIGFuZCA5OTk5IHN0ZXBzIGEgZGF5LiANCiogVmVyeSBhY3RpdmUgLSBNb3JlIHRoYW4gMTAwMDAgc3RlcHMgYSBkYXkuIA0KQ2xhc3NpZmljYXRpb24gaGFzIGJlZW4gbWFkZSBwZXIgdGhlIGZvbGxvd2luZyBhcnRpY2xlIGh0dHBzOi8vd3d3LjEwMDAwc3RlcHMub3JnLmF1L2FydGljbGVzL2NvdW50aW5nLXN0ZXBzLw0KDQpgYGB7c3FsIGNvbm5lY3Rpb249fQ0KLS1DcmVhdGluZyB0ZW1wIHRhYmxlIGZvciB0aGUgbWVhbiBvZiBkYWlseSBzdGVwcw0KV0lUSA0KICBkYWlseV9hdmVyYWdlIEFTICgNCiAgU0VMRUNUDQogICAgSWQsDQogICAgQVZHKFRvdGFsX1N0ZXBzKSBBUyB0b3RhbHN0ZXBzX21lYW4sDQogIEZST00NCiAgICBgZmlyc3QtYW5hbHlzdC5iZWxsYWJlYXRfZGF0YS5kYWlseV9hY3Rpdml0eV9uZXdgDQogIEdST1VQIEJZDQogICAgSWQNCiAgT1JERVIgQlkNCiAgICB0b3RhbHN0ZXBzX21lYW4gIA0KICANCiksDQotLUFmdGVyIGdldHRpbmcgYWxsIHRoZSB0b3RhbCBtZWFuLCB3ZSB3aWxsIG5vdyBjYXRlZ29yaXplIGVhY2ggdXNlciBiYXNlIG9uIFVzZXIgTGV2ZWwgDQogdXNlcnMgQVMgKA0KU0VMRUNUIA0KICBJZCwgDQogIEFWRyh0b3RhbHN0ZXBzX21lYW4pIGFzIGF2Z190b3RhbF9zdGVwcywNCiAgQ0FTRQ0KICBXSEVOIEFWRyh0b3RhbHN0ZXBzX21lYW4pIDwgNTAwMCBUSEVOICdTZWRlbnRhcnknDQogIFdIRU4gQVZHKHRvdGFsc3RlcHNfbWVhbikgQkVUV0VFTiA1MDAxIEFORCA3NTAwIFRIRU4gJ0xpZ2h0bHkgQWN0aXZlJw0KICBXSEVOIEFWRyh0b3RhbHN0ZXBzX21lYW4pIEJFVFdFRU4gNzUwMSBBTkQgMTAwMDAgVEhFTiAnRmFpcmx5IEFjdGl2ZScNCiAgV0hFTiBBVkcodG90YWxzdGVwc19tZWFuKSA+IDEwMDAwIFRIRU4gJ1ZlcnkgQWN0aXZlJw0KICBFTkQgQVMgdXNlcl9sZXZlbA0KRlJPTSBkYWlseV9hdmVyYWdlDQpHUk9VUCBCWQ0KICBJZA0KT1JERVIgQlkgYXZnX3RvdGFsX3N0ZXBzDQoNCiksDQogdXNlcl9sZXZlbF9jb3VudHMgQVMgKA0KICAgIFNFTEVDVCB1c2VyX2xldmVsLCBDT1VOVCgqKSBBUyB0b3RhbA0KICAgIEZST00gdXNlcnMNCiAgICBHUk9VUCBCWSB1c2VyX2xldmVsDQogICksDQogIHRvdGFsX3VzZXJfbGV2ZWxfY291bnRzIEFTICgNCiAgICBTRUxFQ1QgU1VNKHRvdGFsKSBBUyB0b3RhbF91c2VyX2xldmVsDQogICAgRlJPTSB1c2VyX2xldmVsX2NvdW50cw0KICApLA0KICB1c2VyX2xldmVsX3BlcmNlbnRhZ2VzIEFTICgNCiAgICBTRUxFQ1QgdXNlcl9sZXZlbCwgQ0FTVCh0b3RhbCBBUyBGTE9BVDY0KSAvIHRvdGFsX3VzZXJfbGV2ZWxfY291bnRzLnRvdGFsX3VzZXJfbGV2ZWwgQVMgdG90YWxfcGVyY2VudA0KICAgIEZST00gdXNlcl9sZXZlbF9jb3VudHMsIHRvdGFsX3VzZXJfbGV2ZWxfY291bnRzDQogICAgV0hFUkUgMSA9IDENCiAgKQ0KU0VMRUNUIHVzZXJfbGV2ZWwsDQp0b3RhbF9wZXJjZW50LA0KRlJPTSB1c2VyX2xldmVsX3BlcmNlbnRhZ2VzDQoNCg0KYGBgDQo8L2JyPg0KDQohW1VzZXIgTGV2ZWxdKGh0dHBzOi8vaS5pYmIuY28vR0ZHTlJuQi9TY3JlZW5zaG90LTIwMjMtMDItMTctMDkzMDM4LnBuZykNCg0KW1NwcmVlZHNoZWV0IGRhdGFdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFCa2p3bDhtQnJVRmhOaVFKb0tibHI5Ump5dS10bkJRajhxMmNJNlZvZEY4L2VkaXQjZ2lkPTE4NDAzOTMxMjIpPC9icj4NCg0KIyMjIFN0ZXBzIGFuZCBtaW51dGVzIGFzbGVlcCBwZXIgd2Vla2RheSAgIA0KV2Ugd2FudCB0byBrbm93IG5vdyB3aGF0IGRheXMgb2YgdGhlIHdlZWsgYXJlIHRoZSB1c2VycyBtb3JlIGFjdGl2ZSBhbmQgYWxzbyB3aGF0IGRheXMgb2YgdGhlIHdlZWsgdXNlcnMgc2xlZXAgbW9yZS4gV2Ugd2lsbCBhbHNvIHZlcmlmeSBpZiB0aGUgdXNlcnMgd2FsayB0aGUgcmVjb21tZW5kZWQgYW1vdW50IG9mIHN0ZXBzIGFuZCBoYXZlIHRoZSByZWNvbW1lbmRlZCBhbW91bnQgb2Ygc2xlZXAuDQoNCkJlbG93IHdlIGFyZSBjYWxjdWxhdGluZyB0aGUgd2Vla2RheXMgYmFzZWQgb24gb3VyIGNvbHVtbiBkYXRlLiBXZSBhcmUgYWxzbyBjYWxjdWxhdGluZyB0aGUgYXZlcmFnZSBzdGVwcyB3YWxrZWQgYW5kIG1pbnV0ZXMgYXNsZWVwIGJ5IHdlZWtkYXkuDQoNCmBgYHtzcWwgY29ubmVjdGlvbj0gfQ0KV0lUSA0KLS0gTWVyZ2luZyAgdHdvIHRhYmxlcw0KICBkYWlseV9hY3Rpdml0eV9zbGVlcCAgQVMgKA0KICAgIFNFTEVDVA0KICAgIFRvdGFsX1N0ZXBzLA0KICAgIFRvdGFsTWludXRlc0FzbGVlcCwNCiAgICBkYWlseV9hY3Rpdml0eV9uZXcuSWQgQVMgaWQsDQogICAgZGFpbHlfYWN0aXZpdHlfbmV3LkRhdGUgQVMgZGF0ZQ0KICBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2AgQVMgZGFpbHlfYWN0aXZpdHlfbmV3DQogIElOTkVSIEpPSU4gDQogICAgYGZpcnN0LWFuYWx5c3QuYmVsbGFiZWF0X2RhdGEuZGFpbHlfc2xlZXBfbmV3YCBBUyBkYWlseV9zbGVlcF9uZXcNCiAgT04NCiAgZGFpbHlfYWN0aXZpdHlfbmV3LklkID0gZGFpbHlfc2xlZXBfbmV3LklkICBBTkQNCiAgIGRhaWx5X2FjdGl2aXR5X25ldy5EYXRlID0gZGFpbHlfc2xlZXBfbmV3LkRhdGUNCiAgICkNCg0KDQotLUZpbmQgdGhlIGF2ZXJhZ2Ugb2YgVG90YWwgc3RlcHMgYW5kIFRvdGFsIG1pbnV0ZSBhc2xlZXAgcGVyIHdlZWsNClNFTEVDVCANCiAgZGF5X29mX3dlZWssIA0KICBST1VORChBVkcoVG90YWxfU3RlcHMpLDIpIGFzIGF2ZV90b3RhbHN0ZXBzX3BlcmRheSwNCiAgUk9VTkQoQVZHKFRvdGFsTWludXRlc0FzbGVlcCksMikgQVMgYXZlX21pbnV0ZXNhc2xlZXBfcGVyZGF5DQpGUk9NDQogICgNCiAgU0VMRUNUICosDQogIENBU0UNCiAgV0hFTiAoRVhUUkFDVChEQVlPRldFRUsgRlJPTSBkYXRlKT0gMSkgVEhFTiAnTW9uJw0KICBXSEVOIChFWFRSQUNUKERBWU9GV0VFSyBGUk9NIGRhdGUpPSAyKSBUSEVOICdUdWUnDQogIFdIRU4gKEVYVFJBQ1QoREFZT0ZXRUVLIEZST00gZGF0ZSk9IDMpIFRIRU4gJ1dlZCcNCiAgV0hFTiAoRVhUUkFDVChEQVlPRldFRUsgRlJPTSBkYXRlKT0gNCkgVEhFTiAnVGh1Jw0KICBXSEVOIChFWFRSQUNUKERBWU9GV0VFSyBGUk9NIGRhdGUpPSA1KSBUSEVOICdGcmknDQogIFdIRU4gKEVYVFJBQ1QoREFZT0ZXRUVLIEZST00gZGF0ZSk9IDYpIFRIRU4gJ1NhdCcNCiAgV0hFTiAoRVhUUkFDVChEQVlPRldFRUsgRlJPTSBkYXRlKT0gNykgVEhFTiAnU3VuJw0KICBFTkQgQVMgZGF5X29mX3dlZWsNCiAgRlJPTSBkYWlseV9hY3Rpdml0eV9zbGVlcA0KICApDQoNCkdST1VQIEJZIGRheV9vZl93ZWVrDQoNCg0KYGBgDQo8L2JyPg0KDQohW1N0ZXBzIGFuZCBtaW51dGVzIGFzbGVlcCBwZXIgd2Vla2RheSAgIF0oaHR0cHM6Ly9pLmliYi5jby9Ka2g4S3haL1NjcmVlbnNob3QtMjAyMy0wMi0xNy0xMTQ0MjAucG5nKQ0KDQpbU3ByZWVkc2hlZXQgZGF0YV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMWNMTDlMeEtpSTVKR0ZEZk5BN0R2U0ZfWTlhV2JIb2JaMERBYU1rTkxyb0EvZWRpdCNnaWQ9NTM5OTgyMTE5KSANCg0KSW4gdGhlIGdyYXBocyBhYm92ZSB3ZSBjYW4gZGV0ZXJtaW5lIHRoZSBmb2xsb3dpbmc6DQoNClVzZXJzIHdhbGsgZGFpbHkgdGhlIHJlY29tbWVuZGVkIGFtb3VudCBvZiBzdGVwcyBvZiA3NTAwIGJlc2lkZXMgU3VuZGF54oCZcy4gYmFzZWQgb24gdGhlIGFydGljbGUgYWJvdmUNClVzZXJzIGRvbuKAmXQgc2xlZXAgdGhlIHJlY29tbWVuZGVkIGFtb3VudCBvZiBtaW51dGVzLyBob3VycyAtIDggaG91cnMuDQoNCiMjIyBIb3VybHkgc3RlcHMgd2l0aGluIGEgZGF5DQpXZSB3ZXJlIGdvaW5nIHRvIGZpbmQgb3V0IHdoZW4gdGhlIHVzZXJzIG1vcmUgYWN0aXZlIHRocm91Z2hvdXQgdGhlIGRheS4NCg0KIVtIb3VybHkgc3RlcHMgd2l0aGluIGEgZGF5XShodHRwczovL2kuaWJiLmNvL3lSVGs5cUsvU2NyZWVuc2hvdC0yMDIzLTAyLTE3LTEzMDEwNi5wbmcpDQoNCg0KW1NwcmVlZHNoZWV0IGRhdGFdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFwcXpaTkh1SURkRDlfRnhNRktzVmowN2tKa0gzRlduTTZWZi00aUNOMTVnL2VkaXQjZ2lkPTk5NzIyMzM5KSANCg0KDQpBcyB3ZSBjYW4gc2VlIHRoZSBncmFwaCBhYm92ZSB1c2VyIGFyZSBtb3JlIGFjdGl2ZSA3OjAwQU0gdG8gOTowMFBNLiBXZSBhbHNvIHVzZXIgbW9yZSBsaWtlbHkgd2FsayBtb3JlIGF0IDExOjAwQU0gdG8gMjowMFBNLCByZXN0IGF0IDM6MDBQTSwgYW5kIDU6MDBQTSB0byA3OjAwUE0gaW4gdGhlIGV2ZW5pbmcuDQoNCg0KIyMjIENvcnJlbGF0aW9uDQpXZSB3aWxsIG5vdyBkZXRlcm1pbmUgaWYgdGhlcmUgaXMgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gZGlmZmVyZW50IHZhcmlhYmxlczoNCi0gRGFpbHkgc3RlcHMgYW5kIGRhaWx5IHNsZWVwIA0KLSBEYWlseSBzdGVwcyBhbmQgY2Fsb3JpZXMgDQoNCg0KIVtEYWlseSBzdGVwcyBhbmQgZGFpbHkgc2xlZXBdKGh0dHBzOi8vaS5pYmIuY28vNDRwZldnSy9TY3JlZW5zaG90LTIwMjMtMDItMTctMTI1NjU1LnBuZykNCg0KW1NwcmVlZHNoZWV0IGRhdGFdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFwcXpaTkh1SURkRDlfRnhNRktzVmowN2tKa0gzRlduTTZWZi00aUNOMTVnL2VkaXQjZ2lkPTk5NzIyMzM5KSANCg0KQmFzZWQgb24gb3VyIHBsb3RzOg0KDQpUaGVyZeKAmXMgaXMgbm8gY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgZGFpbHkgc3RlcHMgYW5kIG1pbnV0ZXMgYXNsZWVwLiBCYXNpY2FsbHkgd2Fsa2luZyBkYWlseSBkb2VzIG5vdCBhZmZlY3QgdGhlIG1pbnV0ZXMgb2YgdGhlaXIgc2xlZXANCkJ1dCwgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBkYWlseSBzdGVwcyBhbmQgY2Fsb3JpZXMuIEJhc2ljYWxseSB0aGUgbW9yZSB1c2VyIHN0ZXBzIHRoZSBtb3JlIHRoZXkgYnVybiBjYWxvcmllcy4NCg0KDQoNCiMjIyBUb3RhbCBkYXlzIHVzZWQgYnkgdXNlcnMNCk5vdyB0aGF0IHdlIGhhdmUgc2VlbiBzb21lIHRyZW5kcyBpbiBhY3Rpdml0eSwgc2xlZXAgYW5kIGNhbG9yaWVzIGJ1cm5lZCwgd2Ugd2FudCB0byBzZWUgaG93IG9mdGVuIGRvIHRoZSB1c2VycyBpbiBvdXIgc2FtcGxlIHVzZSB0aGVpciBkZXZpY2UuIFRoYXQgd2F5IHdlIGNhbiBwbGFuIG91ciBtYXJrZXRpbmcgc3RyYXRlZ3kgYW5kIHNlZSB3aGF0IGZlYXR1cmVzIHdvdWxkIGJlbmVmaXQgdGhlIHVzZSBvZiBzbWFydCBkZXZpY2VzLg0KDQpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHVzZXJzIHRoYXQgdXNlIHRoZWlyIHNtYXJ0IGRldmljZSBvbiBhIGRhaWx5IGJhc2lzLCBjbGFzc2lmeWluZyBvdXIgc2FtcGxlIGludG8gdGhyZWUgY2F0ZWdvcmllcyBrbm93aW5nIHRoYXQgdGhlIGRhdGUgaW50ZXJ2YWwgaXMgMzEgZGF5czoNCg0KKiBoaWdoIHVzZSAtIHVzZXJzIHdobyB1c2UgdGhlaXIgZGV2aWNlIGJldHdlZW4gMjEgYW5kIDMxIGRheXMuIA0KKiBtb2RlcmF0ZSB1c2UgLSB1c2VycyB3aG8gdXNlIHRoZWlyIGRldmljZSBiZXR3ZWVuIDExIGFuZCAyMCBkYXlzLiANCiogbG93IHVzZSAtIHVzZXJzIHdobyB1c2UgdGhlaXIgZGV2aWNlIGJldHdlZW4gMSBhbmQgMTAgZGF5cy4gDQoNCkZpcnN0IEkgd2lsbCBtYWtlIGEgdGVtcCB0YWJsZS4NCg0KYGBge3NxbCBjb25uZWN0aW9uPX0NCg0KV0lUSA0KICAtLU1lcmdpbmcgdHdvIHRhYmxlcyB3aXRoIHR3byBwcmltYXJ5IGtleQ0KICBkYWlseV9hY3Rpdml0eV9hbmRfc2xlZXAgQVMgKA0KICAgIFNFTEVDVA0KICAgIGRhaWx5X2FjdGl2aXR5LklkIGFzIElkLA0KICAgIENPVU5UKCopIGFzIG51bV9vZl91c2UNCiAgICBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2AgYXMgZGFpbHlfYWN0aXZpdHkNCiAgICBJTk5FUiBKT0lOIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwX25ld2AgYXMgZGFpbHlfc2xlZXANCiAgICBPTiBkYWlseV9hY3Rpdml0eS5JZCA9IGRhaWx5X3NsZWVwLklkIEFORCBkYWlseV9hY3Rpdml0eS5EYXRlID0gZGFpbHlfc2xlZXAuRGF0ZQ0KICAgIEdST1VQIEJZIElkDQogICksDQogICNGaWx0ZXJpbmcgdXNlciB1c2FnZSBiYXNlZCBvbiBkYWlseSBzbGVlcCBhbmQgYWN0aXZpdHkgb2YgYSB1c2Vycw0KICB1c2FnZXMgQVMgKA0KICAgIFNFTEVDVCANCiAgSWQsIA0KICBTVU0obnVtX29mX3VzZSkgQVMgZGF5X3VzZWQsIA0KICBDQVNFIA0KICAgIFdIRU4gU1VNKG51bV9vZl91c2UpIEJFVFdFRU4gMSBBTkQgMTAgVEhFTiAnbG93IHVzZScNCiAgICBXSEVOIFNVTShudW1fb2ZfdXNlKSBCRVRXRUVOIDExIEFORCAyMCBUSEVOICdtb2RlcmF0ZSB1c2UnDQogICAgV0hFTiBTVU0obnVtX29mX3VzZSkgQkVUV0VFTiAyMSBBTkQgMzEgVEhFTiAnaGlnaCB1c2UnDQogIEVORCBBUyB1c2FnZQ0KRlJPTSBkYWlseV9hY3Rpdml0eV9hbmRfc2xlZXANCkdST1VQIEJZIElkDQogICksDQogIC0tIENvdW50aW5nIHRoZSBudW1iZXIgb2YgdXNhZ2UNCiAgdXNhZ2Vfc3VtbWFyeSBBUyAoDQogICAgU0VMRUNUIA0KICAgICAgdXNhZ2UsIA0KICAgICAgQ09VTlQoKikgQVMgdG90YWwNCiAgICBGUk9NIHVzYWdlcw0KICAgIEdST1VQIEJZIHVzYWdlDQogICksDQogIC0tIEdldHRpbmcgdGhlIGF2ZXJhZ2Ugb2YgbnVtYmVyIG9mIHVzYWdlIGFuZCB0b3RhbCB1c2FnZQ0KICB1c2FnZV9wZXJjZW50YWdlIEFTICgNCiAgICBTRUxFQ1QgDQogICAgICB1c2FnZSwgDQogICAgICB0b3RhbCwgDQogICAgICB0b3RhbF91c2FnZSwgDQogICAgICBDQVNUKHRvdGFsIEFTIEZMT0FUNjQpIC8gdG90YWxfdXNhZ2UgQVMgdG90YWxfcGVyY2VudGFnZQ0KICAgLS0gU2VsZWN0aW5nIGl0IEZST00gdXNhZ2Ugc3VtbWFyeSwgYW5kIGZpbmRpbmcgdGhlIHRvdGFsIHVzYWdlIA0KICAgIEZST00gKA0KICAgICAgU0VMRUNUIA0KICAgICAgICB1c2FnZSwgDQogICAgICAgIHRvdGFsLCANCiAgICAgICAgU1VNKHRvdGFsKSBPVkVSICgpIEFTIHRvdGFsX3VzYWdlDQogICAgICBGUk9NIHVzYWdlX3N1bW1hcnkNCiAgICApIA0KICApDQpTRUxFQ1QgDQogIHVzYWdlLCANCiAgdG90YWxfcGVyY2VudGFnZSwgDQogIENPTkNBVChDQVNUKFJPVU5EKHRvdGFsX3BlcmNlbnRhZ2UgKiAxMDAsIDEpIEFTIElOVDY0KSwgJyUgKCcsIENBU1QodG90YWwgQVMgSU5UNjQpLCAnKScpIEFTIGxhYmVscw0KRlJPTSB1c2FnZV9wZXJjZW50YWdlDQoNCg0KYGBgDQoNCiFbVG90YWwgZGF5cyB1c2VkIGJ5IHVzZXJzXShodHRwczovL2kuaWJiLmNvL2dkQ1RNODMvaW1hZ2UucG5nKQ0KDQpbU3ByZWVkc2hlZXQgZGF0YV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMUJqUkFhbmdseVdJVF9lREtKZjRVTjVxelRiS2ZiRGdfS2dzWEdSVnZyTncvZWRpdD91c3A9c2hhcmluZykNCg0KDQpUaGUgcmVzdWx0cyBvbiBvdXQgZ3JhcGggYXJlOiANCi0gQmV0d2VlbiAyMSBhbmQgMzEgZGF5cywgNTAlIG9mIHVzZXJzIGZyZXF1ZW50bHkgdXNlIHRoZWlyIHBob25lLg0KLSAzOCUgb2YgdXNlcnMgYmFsYW5jZSB0aGVpciBwaG9uZSB1c2FnZSBiZXR3ZWVuIDExIGFuZCAyMCBkYXlzLiANCi0gMTIlIG9mIHRoZSB1c2VycyBhcmUgcmFyZWx5IHVzZWQgdGhlaXIgcGhvbmUgMSB0byAxMCBkYXlzDQoNCiMjIyBUaW1lIHVzZWQgc21hcnQgZGV2aWNlDQpCZWluZyBtb3JlIHByZWNpc2Ugd2Ugd2FudCB0byBzZWUgaG93IG1hbnkgbWludXRlcyBkbyB1c2VycyB3ZWFyIHRoZWlyIGRldmljZSBwZXIgZGF5LiBGb3IgdGhhdCB3ZSB3aWxsIG1lcmdlIHRoZSBjcmVhdGVkIGRhaWx5X3VzZSBkYXRhIGZyYW1lIGFuZCBkYWlseV9hY3Rpdml0eSB0byBiZSBhYmxlIHRvIGZpbHRlciByZXN1bHRzIGJ5IGRhaWx5IHVzZSBvZiBkZXZpY2UgYXMgd2VsbC4NCg0KYGBge3NxbCBjb25uZWN0aW9uPX0NCg0KV0lUSA0KICAtLU1lcmdpbmcgdHdvIHRhYmxlcyB3aXRoIHR3byBwcmltYXJ5IGtleQ0KICBkYWlseV9hY3Rpdml0eV9hbmRfc2xlZXAgQVMgKA0KICAgIFNFTEVDVA0KICAgIGRhaWx5X2FjdGl2aXR5LklkIGFzIElkLA0KICAgIENPVU5UKCopIGFzIG51bV9vZl91c2UNCiAgICBGUk9NIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2AgYXMgZGFpbHlfYWN0aXZpdHkNCiAgICBJTk5FUiBKT0lOIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X3NsZWVwX25ld2AgYXMgZGFpbHlfc2xlZXANCiAgICBPTiBkYWlseV9hY3Rpdml0eS5JZCA9IGRhaWx5X3NsZWVwLklkIEFORCBkYWlseV9hY3Rpdml0eS5EYXRlID0gZGFpbHlfc2xlZXAuRGF0ZQ0KICAgIEdST1VQIEJZIElkDQogICksDQogIC0tRmlsdGVyaW5nIHVzZXIgdXNhZ2UgYmFzZWQgb24gZGFpbHkgc2xlZXAgYW5kIGFjdGl2aXR5IG9mIGEgdXNlcnMNCiAgdXNhZ2VzIEFTICgNCiAgICBTRUxFQ1QgDQogIElkLCANCiAgU1VNKG51bV9vZl91c2UpIEFTIGRheV91c2VkLCANCiAgQ0FTRSANCiAgICBXSEVOIFNVTShudW1fb2ZfdXNlKSBCRVRXRUVOIDEgQU5EIDEwIFRIRU4gJ2xvdyB1c2UnDQogICAgV0hFTiBTVU0obnVtX29mX3VzZSkgQkVUV0VFTiAxMSBBTkQgMjAgVEhFTiAnbW9kZXJhdGUgdXNlJw0KICAgIFdIRU4gU1VNKG51bV9vZl91c2UpIEJFVFdFRU4gMjEgQU5EIDMxIFRIRU4gJ2hpZ2ggdXNlJw0KICBFTkQgQVMgdXNhZ2UNCkZST00gZGFpbHlfYWN0aXZpdHlfYW5kX3NsZWVwDQpHUk9VUCBCWSBJZA0KICApLA0KICAtLSBDb3VudGluZyB0aGUgbnVtYmVyIG9mIHVzYWdlDQogIHVzYWdlX3N1bW1hcnkgQVMgKA0KICAgIFNFTEVDVCANCiAgICAgIHVzYWdlLCANCiAgICAgIENPVU5UKCopIEFTIHRvdGFsDQogICAgRlJPTSB1c2FnZXMNCiAgICBHUk9VUCBCWSB1c2FnZQ0KICApLA0KICAtLSBHZXR0aW5nIHRoZSBhdmVyYWdlIG9mIG51bWJlciBvZiB1c2FnZSBhbmQgdG90YWwgdXNhZ2UNCiAgdXNhZ2VfcGVyY2VudGFnZSBBUyAoDQogICAgU0VMRUNUIA0KICAgICAgdXNhZ2UsIA0KICAgICAgdG90YWwsIA0KICAgICAgdG90YWxfdXNhZ2UsIA0KICAgICAgQ0FTVCh0b3RhbCBBUyBGTE9BVDY0KSAvIHRvdGFsX3VzYWdlIEFTIHRvdGFsX3BlcmNlbnRhZ2UNCiAgIC0tIFNlbGVjdGluZyBpdCBGUk9NIHVzYWdlIHN1bW1hcnksIGFuZCBmaW5kaW5nIHRoZSB0b3RhbCB1c2FnZSANCiAgICBGUk9NICgNCiAgICAgIFNFTEVDVCANCiAgICAgICAgdXNhZ2UsIA0KICAgICAgICB0b3RhbCwgDQogICAgICAgIFNVTSh0b3RhbCkgT1ZFUiAoKSBBUyB0b3RhbF91c2FnZQ0KICAgICAgRlJPTSB1c2FnZV9zdW1tYXJ5DQogICAgKSANCiAgKSwgDQogIC0tIENyZWF0aW5nIG5ldyBzdWJxdWVyeSBmb3IgZGFpbHkgdXNlZA0KICBkYWlseV9hY3Rpdml0eV91c2VkIEFTICgNCiAgICBTRUxFQ1QgKg0KICAgIEZST00gIGBmaXJzdC1hbmFseXN0LmJlbGxhYmVhdF9kYXRhLmRhaWx5X2FjdGl2aXR5X25ld2AsIHVzYWdlX3N1bW1hcnkNCiAgKSwNCg0KICBtaW51dGVzX3dvcm4gQVMgKA0KICAgU0VMRUNUICosDQogICBDQVNFIA0KICAgIFdIRU4gbWludXRlc193b3JuX3BlcmNlbnRhZ2UgPSAxMDAgVEhFTiAnQWxsIGRheScNCiAgICBXSEVOIG1pbnV0ZXNfd29ybl9wZXJjZW50YWdlID49IDUwIEFORCBtaW51dGVzX3dvcm5fcGVyY2VudGFnZSA8IDEwMCBUSEVOICdNb3JlIHRoYW4gaGFsZiBkYXknDQogICAgV0hFTiBtaW51dGVzX3dvcm5fcGVyY2VudGFnZSA+IDAgQU5EIG1pbnV0ZXNfd29ybl9wZXJjZW50YWdlIDwgNTAgVEhFTiAnTGVzcyB0aGFuIGhhbGYgZGF5Jw0KICAgRU5EIGFzIHdvcm4NCg0KICBGUk9NICgNCiAgICAgU0VMRUNUICosIA0KICAgICAgKFZlcnlfQWN0aXZlX01pbnV0ZXMgKyBGYWlybHlfQWN0aXZlX01pbnV0ZXMgKyBMaWdodGx5X0FjdGl2ZV9NaW51dGVzICsNClNlZGVudGFyeV9NaW51dGVzKSBhcyB0b3RhbF93b3JuX21pbnV0ZXMsDQogIChWZXJ5X0FjdGl2ZV9NaW51dGVzICsgRmFpcmx5X0FjdGl2ZV9NaW51dGVzICsgTGlnaHRseV9BY3RpdmVfTWludXRlcyArDQpTZWRlbnRhcnlfTWludXRlcykgLyAxNDQwICogMTAwIGFzIG1pbnV0ZXNfd29ybl9wZXJjZW50YWdlDQogICAgIEZST00gZGFpbHlfYWN0aXZpdHlfdXNlZA0KICAgKQ0KDQogICksDQoNCi0tIEFzIHdlIGhhdmUgZG9uZSBiZWZvcmUsIHRvIGJldHRlciB2aXN1YWxpemUgb3VyIHJlc3VsdHMgd2Ugd2lsbCBjcmVhdGUgbmV3IHN1YnF1ZXJpZXMuIA0KDQp3b3JuX3N1bW1hcnkgQVMgKA0KICBTRUxFQ1QgDQogIHdvcm4sDQogIENPVU5UKCopIGFzIHRvdGFsDQogIEZST00gbWludXRlc193b3JuDQogIEdST1VQIEJZIHdvcm4NCiksDQp3b3JuX3BlcmNlbnRhZ2UgQVMgKA0KICBTRUxFQ1QNCiAgd29ybiwNCiAgdG90YWwsDQogIHRvdGFsX3dvcm4sDQoNCiAgRlJPTSAoDQogICAgU0VMRUNUDQogICAgd29ybiwNCiAgICB0b3RhbCwNCiAgICBTVU0odG90YWwpIE9WRVIoKSB0b3RhbF93b3JuDQogICAgRlJPTSB3b3JuX3N1bW1hcnkNCiAgKQ0KDQopLA0KDQoNCg0KICBtaW51dGVzX3dvcm5faGlnaHVzZSBBUyAoDQogICAgU0VMRUNUDQogICAgd29ybiwNCiAgICB0b3RhbC90b3RhbHMgQVMgdG90YWxfcGVyY2VudGFnZSwNCiAgICBDT05DQVQoUk9VTkQodG90YWwgLyB0b3RhbHMgKiAxMDAsIDIpLCAnJScpIEFTIGxhYmVscywNCiAgICBGUk9NICgNCiAgICAgIFNFTEVDVCANCiAgICAgIHdvcm4sDQogICAgICBDT1VOVCgqKSBBUyB0b3RhbCwNCiAgICAgIFNVTShDT1VOVCgqKSkgT1ZFUiAoKSBBUyB0b3RhbHMgICAtLSBDYWxjdWxhdGluZyB0aGUgc3VtIG9mIHRoZSBudW1iZXIgb2Ygcm93cyAod2hpY2ggaXMgdG90YWwpDQogICAgICBGUk9NIG1pbnV0ZXNfd29ybg0KICAgICAgV0hFUkUgdXNhZ2UgPSAnaGlnaCB1c2UnDQogICAgICBHUk9VUCBCWSB3b3JuDQogICAgKQ0KICAgIEdST1VQIEJZIHdvcm4sIHRvdGFsX3BlcmNlbnRhZ2UsbGFiZWxzDQogICksDQogIG1pbnV0ZXNfd29ybl9tb2RlcmF0ZXVzZSBBUyAoDQogICAgU0VMRUNUDQogICAgd29ybiwNCiAgICB0b3RhbCAvIHRvdGFscyBhcyB0b3RhbF9wZXJjZW50YWdlLA0KICAgIENPTkNBVChST1VORCh0b3RhbC90b3RhbHMgKiAxMDAsIDIpLCAnJScpIGFzIGxhYmVscw0KICAgIEZST00gKA0KICAgICAgU0VMRUNUDQogICAgICB3b3JuLA0KICAgICAgQ09VTlQoKikgYXMgdG90YWwsDQogICAgICBTVU0oQ09VTlQoKikpIE9WRVIoKSBhcyB0b3RhbHMgDQogICAgICBGUk9NIG1pbnV0ZXNfd29ybg0KICAgICAgV0hFUkUgdXNhZ2UgPSAnbW9kZXJhdGUgdXNlJw0KICAgICAgR1JPVVAgQlkgd29ybg0KDQogICAgKQ0KICAgIEdST1VQIEJZIHdvcm4sIHRvdGFsX3BlcmNlbnRhZ2UsbGFiZWxzDQogICksDQogICBtaW51dGVzX3dvcm5fbG93dXNlIEFTICgNCiAgICBTRUxFQ1QNCiAgICB3b3JuLA0KICAgIHRvdGFsIC8gdG90YWxzIGFzIHRvdGFsX3BlcmNlbnRhZ2UsDQogICAgQ09OQ0FUKFJPVU5EKHRvdGFsL3RvdGFscyAqIDEwMCwgMiksICclJykgYXMgbGFiZWxzDQogICAgRlJPTSAoDQogICAgICBTRUxFQ1QNCiAgICAgIHdvcm4sDQogICAgICBDT1VOVCgqKSBhcyB0b3RhbCwNCiAgICAgIFNVTShDT1VOVCgqKSkgT1ZFUigpIGFzIHRvdGFscyANCiAgICAgIEZST00gbWludXRlc193b3JuDQogICAgICBXSEVSRSB1c2FnZSA9ICdsb3cgdXNlJw0KICAgICAgR1JPVVAgQlkgd29ybg0KDQogICAgKQ0KICAgIEdST1VQIEJZIHdvcm4sIHRvdGFsX3BlcmNlbnRhZ2UsbGFiZWxzDQogICkNCg0KLS0gU0hPV0lORyBUSEUgVE9UQUwgVVNBR0UgT0YgQUxMIFVTRVINCi0tIFNFTEVDVCANCi0tIHdvcm4sDQotLSB0b3RhbF9wZXJjZW50YWdlLA0KLS0gIENPTkNBVChDQVNUKFJPVU5EKHRvdGFsX3BlcmNlbnRhZ2UgKiAxMDAsIDEpIEFTIElOVDY0KSwgJyUgKCcsIENBU1QodG90YWwgQVMgSU5UNjQpLCAnKScpIEFTIGxhYmVscw0KLS0gRlJPTSB3b3JuX3BlcmNlbnRhZ2UNCg0KDQpTRUxFQ1QNCioNCkZST00gbWludXRlc193b3JuX2xvd3VzZQ0KDQoNCg0KDQpgYGANCiMgQ29uY2x1c2lvbiBhbmQgUmVjb21tZW5kYXRpb24NCg0KQmFzZWQgb24gb3VyIGZpbmRpbmdzLCBJIHdvdWxkIHJlY29tbWVuZCB0aGF0IHdlIHVzZSBvdXIgb3duIHRyYWNraW5nIGRhdGEgZm9yIGZ1cnRoZXIgYW5hbHlzaXMgaW4gb3JkZXIgdG8gcmVzcG9uZCB0byBvdXIgYnVzaW5lc3MgdGFzayBhbmQgYXNzaXN0IEJlbGxhYmVhdCB3aXRoIHRoZWlyIG1pc3Npb24uIEJlY2F1c2Ugd2UgZGlkbid0IGhhdmUgYW55IGRlbW9ncmFwaGljIGluZm9ybWF0aW9uIGFib3V0IHVzZXJzLCB0aGUgZGF0YSBzZXRzIHdlIHVzZWQgaGFkIGEgc21hbGwgc2FtcGxlIHNpemUgYW5kIGNvdWxkIGJlIGJpYXNlZC4gS25vd2luZyB0aGF0IG91ciBwcmltYXJ5IGRlbW9ncmFwaGljIGlzIHlvdW5nIGFuZCBhZHVsdCB3b21lbiwgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGNvbnRpbnVlIGxvb2tpbmcgZm9yIHRyZW5kcyBpbiBvcmRlciB0byBkZXZlbG9wIGEgbWFya2V0aW5nIHN0cmF0ZWd5IGNlbnRlcmVkIG9uIHRoZW0uDQoNClRoYXQgYmVpbmcgc2FpZCwgYWZ0ZXIgb3VyIGFuYWx5c2lzIHdlIGhhdmUgZm91bmQgZGlmZmVyZW50IHRyZW5kcyB0aGF0IG1heSBoZWxwIG91ciBvbmxpbmUgY2FtcGFpZ24gYW5kIGltcHJvdmUgQmVsbGFiZWF0IGFwcDoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShrbml0cikNCnJlY29tbWVuZGF0aW9uIDwtIGMoIkFkZGluZyBhICdnb2FsJyBvbiB0aGUgYXBwIiwgIlNsZWVwaW5nIHJlY29tbWVuZGF0aW9uIGZvciB1c2VycyIsICJMZXZlbCBvciByYW5rIGJhZGdlIHN5c3RlbSIpDQpkZXNjcmlwdGlvbiA8LSBjKCJQdXR0aW5nIGEgZ29hbCB0byB0cmFjayBkYWlseSBzdGVwcyBhbmQgY2Fsb3JpZXMgaGVscHMgdXNlcnMgbW9uaXRvciB0aGVpciBwcm9ncmVzcyB0b3dhcmRzIHRoZWlyIGZpdG5lc3MgZ29hbHMuIiwgDQogICAgICAgICAgICAgICAgICJBIHNsZWVwIHJlY29tbWVuZGF0aW9uIGZlYXR1cmUgY2FuIHJlbWluZCB1c2VycyB0byBtYWludGFpbiBhIGhlYWx0aHkgc2xlZXAgcm91dGluZSBhbmQgcHJvdmlkZSBoZWxwZnVsIHRpcHMgZm9yIGJldHRlciBzbGVlcC4iLA0KICAgICAgICAgICAgICAgICAiQSBsZXZlbCBvciByYW5rIHN5c3RlbSBjYW4gbW90aXZhdGUgdXNlcnMgdG8gYmUgbW9yZSBhY3RpdmUgYnkgYWxsb3dpbmcgdGhlbSB0byB0cmFjayB0aGVpciBwcm9ncmVzcyBhbmQgZWFybiBiYWRnZXMgYXMgcmV3YXJkcy4iKQ0KdGJsIDwtIGRhdGEuZnJhbWUoUmVjb21tZW5kYXRpb24gPSByZWNvbW1lbmRhdGlvbiwgRGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbikNCmthYmxlKHRibCkNCg0KDQpgYGANCg0KT24gb3VyIGFuYWx5c2lzIHdlIGRpbnQganVzdCBjaGVjayBmb3IgdGhlIHRyZW5kcyBidXQgYWxzbyB3ZSBzZWUgdGhhdCBoZWFsdGh5IHVzZXJzIHRlbmQgdG8gYmUgdXNlIHRoZWlyIGRldmljZSBhbmQgMzYlIG9mIHRoZSB1c2VycyB3ZWFyIHRoZSBkZXZpY2UgYWxsIHRpbWUuDQoNCiogSXQgY291bGQgYmUgZ29vZCB0byBtYXJrZXQgdGhpcyBkZXZpY2Ugd2hvIGFyZSBtb3JlIGFjdGl2ZSBhbmQgd2hvIHdhbnQgdG8gdHJhY2sgdGhlaXIgZGFpbHkgYWN0aXZpdGllcw0KIFdlIGNhbiBjb250aW51ZSBwcm9tb3RlIEJlbGxhYmVhdCdzIHByb2R1Y3RzIGZlYXR1cmVzOg0KDQoqIFdvcmFibGUgZGV2aWNlIGZvciBtZW4NCiogV2F0ZXItcmVzaXN0YW50DQoqIExvbmctbGFzdGluZyBiYXR0ZXJpZXMNCiogRmFzaGlvbi8gZWxlZ2FudCBwcm9kdWN0cw0KDQo=