This dataset is too large to view in a spreadsheet, so this notebook is a changelog for using SQL to clean the health_fitness_dataset on google’s BigQuery.

1. Investigating NULL Values

Variations of the following script were run for every column to discover if there were any NULL values.

SELECT  (*)
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
WHERE 
  particpant_id IS NULL;

As expected from a synthetic dataset, there were no rows containing NULL values that needed to be excluded from the dataset.

2. Summarizing Data

The following queries were run to summarize the data. This summary table was created in Google Sheets to compile these results.

Summarizing Gender

SELECT  
  gender,
  COUNT(DISTINCT participant_id) AS user_count
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
GROUP BY gender;

Summarizing Activity Types

First, this query was run to summarize the activity types, split up by intensity:

SELECT
  activity_type, intensity,
  COUNT(DISTINCT participant_id) AS activity_type_count,
  COUNT(participant_id) AS activity_session_count,
  SUM(duration_minutes) AS activity_duration_count,
  ROUND(AVG(duration_minutes), 2) AS activity_duration_average_in_minutes,
  ROUND(MIN(duration_minutes), 2) AS activity_duration_min_in_minutes,
  ROUND(MAX(duration_minutes), 2) AS activity_duration_max_in_minutes,
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife` 
GROUP BY activity_type, intensity
ORDER BY activity_type,
  CASE intensity
        WHEN 'Low' THEN 1
        WHEN 'Medium' THEN 2
        WHEN 'High' THEN 3
        ELSE NULL
        END

Intensity minutes breakdown

SELECT
  intensity,
  COUNT(intensity) AS intensity_session_total_count
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
GROUP BY  
  intensity
ORDER BY  
  CASE intensity
        WHEN 'Low' THEN 1
        WHEN 'Medium' THEN 2
        WHEN 'High' THEN 3
        ELSE NULL
        END

Min, Max, Avg Summaries by User

SELECT
  intensity,
  DISTINCT participant_id,
  ROUND(AVG(stress_level), 2) AS stress_average,
  ROUND(MIN(stress_level), 2) AS stress_min,
  ROUND(MAX(stress_level), 2) AS stress_max,
  ROUND(AVG(hours_sleep), 2) AS hours_sleep_average,
  ROUND(MIN(hours_sleep), 2) AS hours_sleep_min,
  ROUND(MAX(hours_sleep), 2) AS hours_sleep_max,
  ROUND(AVG(weight_kg), 2) AS weight_kg_average,
  ROUND(MIN(weight_kg), 2) AS weight_kg_min,
  ROUND(MAX(weight_kg), 2) AS weight_kg_max,
  ROUND(AVG(hydration_level), 2) AS hydration_level_average,
  ROUND(MIN(hydration_level), 2) AS hydration_level_min,
  ROUND(MAX(hydration_level), 2) AS hydration_level_max,
  ROUND(AVG(daily_steps)) AS daily_steps_average,
  ROUND(MIN(daily_steps)) AS daily_steps_min,
  ROUND(MAX(daily_steps)) AS daily_steps_max,
  ROUND(AVG(age), 2) AS average_age,
  ROUND(AVG(duration_minutes)) AS duration_average_in_minutes,
  ROUND(MIN(duration_minutes)) AS duration_min_in_minutes,
  ROUND(MAX(duration_minutes)) AS duration_max_in_minutes,
  ROUND(AVG(bmi)) AS bmi_average,
  ROUND(MIN(bmi)) AS bmi_min,
  ROUND(MAX(bmi)) AS bmi_max,
  ROUND(AVG(resting_heart_rate)) AS resting_heart_rate_average,
  ROUND(MIN(resting_heart_rate)) AS resting_heart_rate_min,
  ROUND(MAX(resting_heart_rate)) AS resting_heart_rate_max,
  ROUND(AVG(blood_pressure_diastolic)) AS blood_pressure_diastolic_average,
  ROUND(MIN(blood_pressure_diastolic)) AS blood_pressure_diastolic_min,
  ROUND(MAX(blood_pressure_diastolic)) AS blood_pressure_diastolic_max,
  ROUND(AVG(blood_pressure_systolic)) AS blood_pressure_systolic_average,
  ROUND(MIN(blood_pressure_systolic)) AS blood_pressure_systolic_min,
  ROUND(MAX(blood_pressure_systolic)) AS blood_pressure_systolic_max,
  ROUND(AVG(calories_burned)) AS calories_burned_average,
  ROUND(MIN(calories_burned)) AS calories_burned_min,
  ROUND(MAX(calories_burned)) AS calories_burned_max,
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife` 
GROUP BY activity_type, intensity
ORDER BY activity_type,
  CASE intensity
        WHEN 'Low' THEN 1
        WHEN 'Medium' THEN 2
        WHEN 'High' THEN 3
        ELSE NULL
        END

Min, Max, Avg Summaries by Date

SELECT
  DISTINCT date,
  ROUND(AVG(stress_level), 2) AS stress_average,
  ROUND(MIN(stress_level), 2) AS stress_min,
  ROUND(MAX(stress_level), 2) AS stress_max,
  ROUND(AVG(hours_sleep), 2) AS hours_sleep_average,
  ROUND(MIN(hours_sleep), 2) AS hours_sleep_min,
  ROUND(MAX(hours_sleep), 2) AS hours_sleep_max,
  ROUND(AVG(weight_kg), 2) AS weight_kg_average,
  ROUND(MIN(weight_kg), 2) AS weight_kg_min,
  ROUND(MAX(weight_kg), 2) AS weight_kg_max,
  ROUND(AVG(hydration_level), 2) AS hydration_level_average,
  ROUND(MIN(hydration_level), 2) AS hydration_level_min,
  ROUND(MAX(hydration_level), 2) AS hydration_level_max,
  ROUND(AVG(daily_steps)) AS daily_steps_average,
  ROUND(MIN(daily_steps)) AS daily_steps_min,
  ROUND(MAX(daily_steps)) AS daily_steps_max,
  ROUND(AVG(age), 2) AS average_age,
  ROUND(AVG(duration_minutes)) AS duration_average_in_minutes,
  ROUND(MIN(duration_minutes)) AS duration_min_in_minutes,
  ROUND(MAX(duration_minutes)) AS duration_max_in_minutes,
  ROUND(AVG(bmi)) AS bmi_average,
  ROUND(MIN(bmi)) AS bmi_min,
  ROUND(MAX(bmi)) AS bmi_max,
  ROUND(AVG(resting_heart_rate)) AS resting_heart_rate_average,
  ROUND(MIN(resting_heart_rate)) AS resting_heart_rate_min,
  ROUND(MAX(resting_heart_rate)) AS resting_heart_rate_max,
  ROUND(AVG(blood_pressure_diastolic)) AS blood_pressure_diastolic_average,
  ROUND(MIN(blood_pressure_diastolic)) AS blood_pressure_diastolic_min,
  ROUND(MAX(blood_pressure_diastolic)) AS blood_pressure_diastolic_max,
  ROUND(AVG(blood_pressure_systolic)) AS blood_pressure_systolic_average,
  ROUND(MIN(blood_pressure_systolic)) AS blood_pressure_systolic_min,
  ROUND(MAX(blood_pressure_systolic)) AS blood_pressure_systolic_max,
  ROUND(AVG(calories_burned)) AS calories_burned_average,
  ROUND(MIN(calories_burned)) AS calories_burned_min,
  ROUND(MAX(calories_burned)) AS calories_burned_max,
  ROUND(AVG(duration_minutes)) AS duration_minutes_average,
  ROUND(MIN(duration_minutes)) AS duration_minutes_min,
  ROUND(MAX(duration_minutes)) AS duration_minutes_max,
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife` 
GROUP BY date;

3. Summarizing While Filtering for Gender

Bellabeat has positioned itself as a health & wellness company for women, so the data has been filtered to exclude men by adding the following to each summary query written in the previous section to filter the men out of the dataset without altering the dataset itself.

WHERE gender <> "M" 

Summing activities by user and date without dividing by intensity

Breaking the sums up yesterday created a potential for confusing data as each user could be counted in each intensity category, meaning just summing those values would not be accurate in counting unique users for each activity.

SELECT
  activity_type,
  COUNT(DISTINCT participant_id) AS unique_users

FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
GROUP BY
  activity_type
ORDER BY
  activity_type;

Activity Session Counts

SELECT
  activity_type,
  COUNT(activity_type) AS activity_session_count
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
GROUP BY
  activity_type
ORDER BY
  activity_type;

Activity Duration Summary

SELECT
  activity_type,
  SUM(duration_minutes) AS activity_duration_in_minutes
FROM `complete-will-468115-p2.fitlife360_synthetic_health_data.fitlife`
GROUP BY
  activity_type
ORDER BY
  activity_type;

Data Visualization

The data was visualized using various tables in Tableau Public. This dataset was found to only display trends that were steady and show no growth or decrease. This makes sense as the data is synthetic, and thus wouldn’t have any surprising trends to be discovered. These visualiztions were not used in the final report.

Conclusion

This dataset is not useful for this case study but was a good chance to practice cleaning and analyzing data using various tools such as BigQuery, spreadsheets, and Tableau Public.

LS0tCnRpdGxlOiAiRml0TGlmZSBEYXRhc2V0IENoYW5nZWxvZyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBkYXRhc2V0IGlzIHRvbyBsYXJnZSB0byB2aWV3IGluIGEgc3ByZWFkc2hlZXQsIHNvIHRoaXMgbm90ZWJvb2sgaXMgYSBjaGFuZ2Vsb2cgZm9yIHVzaW5nIFNRTCB0byBjbGVhbiB0aGUgaGVhbHRoX2ZpdG5lc3NfZGF0YXNldCBvbiBnb29nbGUncyBCaWdRdWVyeS4KCiMjIDEuIEludmVzdGlnYXRpbmcgTlVMTCBWYWx1ZXMKClZhcmlhdGlvbnMgb2YgdGhlIGZvbGxvd2luZyBzY3JpcHQgd2VyZSBydW4gZm9yIGV2ZXJ5IGNvbHVtbiB0byBkaXNjb3ZlciBpZiB0aGVyZSB3ZXJlIGFueSBOVUxMIHZhbHVlcy4KCmBgYHtzcWwgY29ubmVjdGlvbj19ClNFTEVDVCAgKCopCkZST00gYGNvbXBsZXRlLXdpbGwtNDY4MTE1LXAyLmZpdGxpZmUzNjBfc3ludGhldGljX2hlYWx0aF9kYXRhLmZpdGxpZmVgCldIRVJFIAogIHBhcnRpY3BhbnRfaWQgSVMgTlVMTDsKCmBgYAoKQXMgZXhwZWN0ZWQgZnJvbSBhIHN5bnRoZXRpYyBkYXRhc2V0LCB0aGVyZSB3ZXJlIG5vIHJvd3MgY29udGFpbmluZyBOVUxMIHZhbHVlcyB0aGF0IG5lZWRlZCB0byBiZSBleGNsdWRlZCBmcm9tIHRoZSBkYXRhc2V0LgoKCiMjIDIuIFN1bW1hcml6aW5nIERhdGEKVGhlIGZvbGxvd2luZyBxdWVyaWVzIHdlcmUgcnVuIHRvIHN1bW1hcml6ZSB0aGUgZGF0YS4gW1RoaXMgc3VtbWFyeSB0YWJsZV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMXlVWi05bTNWamM4RHQyV0JScWhFNTlnYm5ST0x2bkd0czNmcHBrT1dhZlEvZWRpdD91c3A9c2hhcmluZykgd2FzIGNyZWF0ZWQgaW4gR29vZ2xlIFNoZWV0cyB0byBjb21waWxlIHRoZXNlIHJlc3VsdHMuCgojIyMgU3VtbWFyaXppbmcgR2VuZGVyCmBgYHtzcWwgY29ubmVjdGlvbj1zdW1tYXJpemluZ19nZW5kZXJ9ClNFTEVDVCAgCiAgZ2VuZGVyLAogIENPVU5UKERJU1RJTkNUIHBhcnRpY2lwYW50X2lkKSBBUyB1c2VyX2NvdW50CkZST00gYGNvbXBsZXRlLXdpbGwtNDY4MTE1LXAyLmZpdGxpZmUzNjBfc3ludGhldGljX2hlYWx0aF9kYXRhLmZpdGxpZmVgCkdST1VQIEJZIGdlbmRlcjsKCmBgYAoKIyMjIFN1bW1hcml6aW5nIEFjdGl2aXR5IFR5cGVzCgpGaXJzdCwgdGhpcyBxdWVyeSB3YXMgcnVuIHRvIHN1bW1hcml6ZSB0aGUgYWN0aXZpdHkgdHlwZXMsIHNwbGl0IHVwIGJ5IGludGVuc2l0eToKCmBgYHtzcWwgY29ubmVjdGlvbj1hY3Rpdml0eV9kdXJhdGlvbl9ieV9pbnRlbnNpdHlfaW5fbWludXRlc30KU0VMRUNUCiAgYWN0aXZpdHlfdHlwZSwgaW50ZW5zaXR5LAogIENPVU5UKERJU1RJTkNUIHBhcnRpY2lwYW50X2lkKSBBUyBhY3Rpdml0eV90eXBlX2NvdW50LAogIENPVU5UKHBhcnRpY2lwYW50X2lkKSBBUyBhY3Rpdml0eV9zZXNzaW9uX2NvdW50LAogIFNVTShkdXJhdGlvbl9taW51dGVzKSBBUyBhY3Rpdml0eV9kdXJhdGlvbl9jb3VudCwKICBST1VORChBVkcoZHVyYXRpb25fbWludXRlcyksIDIpIEFTIGFjdGl2aXR5X2R1cmF0aW9uX2F2ZXJhZ2VfaW5fbWludXRlcywKICBST1VORChNSU4oZHVyYXRpb25fbWludXRlcyksIDIpIEFTIGFjdGl2aXR5X2R1cmF0aW9uX21pbl9pbl9taW51dGVzLAogIFJPVU5EKE1BWChkdXJhdGlvbl9taW51dGVzKSwgMikgQVMgYWN0aXZpdHlfZHVyYXRpb25fbWF4X2luX21pbnV0ZXMsCkZST00gYGNvbXBsZXRlLXdpbGwtNDY4MTE1LXAyLmZpdGxpZmUzNjBfc3ludGhldGljX2hlYWx0aF9kYXRhLmZpdGxpZmVgIApHUk9VUCBCWSBhY3Rpdml0eV90eXBlLCBpbnRlbnNpdHkKT1JERVIgQlkgYWN0aXZpdHlfdHlwZSwKICBDQVNFIGludGVuc2l0eQogICAgICAgIFdIRU4gJ0xvdycgVEhFTiAxCiAgICAgICAgV0hFTiAnTWVkaXVtJyBUSEVOIDIKICAgICAgICBXSEVOICdIaWdoJyBUSEVOIDMKICAgICAgICBFTFNFIE5VTEwKICAgICAgICBFTkQKYGBgCiMjIyBJbnRlbnNpdHkgbWludXRlcyBicmVha2Rvd24KYGBge3NxbCBjb25uZWN0aW9uPWludGVuc2l0eV9taW51dGVzfQpTRUxFQ1QKICBpbnRlbnNpdHksCiAgQ09VTlQoaW50ZW5zaXR5KSBBUyBpbnRlbnNpdHlfc2Vzc2lvbl90b3RhbF9jb3VudApGUk9NIGBjb21wbGV0ZS13aWxsLTQ2ODExNS1wMi5maXRsaWZlMzYwX3N5bnRoZXRpY19oZWFsdGhfZGF0YS5maXRsaWZlYApHUk9VUCBCWSAgCiAgaW50ZW5zaXR5Ck9SREVSIEJZICAKICBDQVNFIGludGVuc2l0eQogICAgICAgIFdIRU4gJ0xvdycgVEhFTiAxCiAgICAgICAgV0hFTiAnTWVkaXVtJyBUSEVOIDIKICAgICAgICBXSEVOICdIaWdoJyBUSEVOIDMKICAgICAgICBFTFNFIE5VTEwKICAgICAgICBFTkQKYGBgCiMjIyBNaW4sIE1heCwgQXZnIFN1bW1hcmllcyBieSBVc2VyCmBgYHtzcWwgY29ubmVjdGlvbj1zdHJlc3NfYW5kX3NsZWVwX3N1bW1hcnl9ClNFTEVDVAogIGludGVuc2l0eSwKICBESVNUSU5DVCBwYXJ0aWNpcGFudF9pZCwKICBST1VORChBVkcoc3RyZXNzX2xldmVsKSwgMikgQVMgc3RyZXNzX2F2ZXJhZ2UsCiAgUk9VTkQoTUlOKHN0cmVzc19sZXZlbCksIDIpIEFTIHN0cmVzc19taW4sCiAgUk9VTkQoTUFYKHN0cmVzc19sZXZlbCksIDIpIEFTIHN0cmVzc19tYXgsCiAgUk9VTkQoQVZHKGhvdXJzX3NsZWVwKSwgMikgQVMgaG91cnNfc2xlZXBfYXZlcmFnZSwKICBST1VORChNSU4oaG91cnNfc2xlZXApLCAyKSBBUyBob3Vyc19zbGVlcF9taW4sCiAgUk9VTkQoTUFYKGhvdXJzX3NsZWVwKSwgMikgQVMgaG91cnNfc2xlZXBfbWF4LAogIFJPVU5EKEFWRyh3ZWlnaHRfa2cpLCAyKSBBUyB3ZWlnaHRfa2dfYXZlcmFnZSwKICBST1VORChNSU4od2VpZ2h0X2tnKSwgMikgQVMgd2VpZ2h0X2tnX21pbiwKICBST1VORChNQVgod2VpZ2h0X2tnKSwgMikgQVMgd2VpZ2h0X2tnX21heCwKICBST1VORChBVkcoaHlkcmF0aW9uX2xldmVsKSwgMikgQVMgaHlkcmF0aW9uX2xldmVsX2F2ZXJhZ2UsCiAgUk9VTkQoTUlOKGh5ZHJhdGlvbl9sZXZlbCksIDIpIEFTIGh5ZHJhdGlvbl9sZXZlbF9taW4sCiAgUk9VTkQoTUFYKGh5ZHJhdGlvbl9sZXZlbCksIDIpIEFTIGh5ZHJhdGlvbl9sZXZlbF9tYXgsCiAgUk9VTkQoQVZHKGRhaWx5X3N0ZXBzKSkgQVMgZGFpbHlfc3RlcHNfYXZlcmFnZSwKICBST1VORChNSU4oZGFpbHlfc3RlcHMpKSBBUyBkYWlseV9zdGVwc19taW4sCiAgUk9VTkQoTUFYKGRhaWx5X3N0ZXBzKSkgQVMgZGFpbHlfc3RlcHNfbWF4LAogIFJPVU5EKEFWRyhhZ2UpLCAyKSBBUyBhdmVyYWdlX2FnZSwKICBST1VORChBVkcoZHVyYXRpb25fbWludXRlcykpIEFTIGR1cmF0aW9uX2F2ZXJhZ2VfaW5fbWludXRlcywKICBST1VORChNSU4oZHVyYXRpb25fbWludXRlcykpIEFTIGR1cmF0aW9uX21pbl9pbl9taW51dGVzLAogIFJPVU5EKE1BWChkdXJhdGlvbl9taW51dGVzKSkgQVMgZHVyYXRpb25fbWF4X2luX21pbnV0ZXMsCiAgUk9VTkQoQVZHKGJtaSkpIEFTIGJtaV9hdmVyYWdlLAogIFJPVU5EKE1JTihibWkpKSBBUyBibWlfbWluLAogIFJPVU5EKE1BWChibWkpKSBBUyBibWlfbWF4LAogIFJPVU5EKEFWRyhyZXN0aW5nX2hlYXJ0X3JhdGUpKSBBUyByZXN0aW5nX2hlYXJ0X3JhdGVfYXZlcmFnZSwKICBST1VORChNSU4ocmVzdGluZ19oZWFydF9yYXRlKSkgQVMgcmVzdGluZ19oZWFydF9yYXRlX21pbiwKICBST1VORChNQVgocmVzdGluZ19oZWFydF9yYXRlKSkgQVMgcmVzdGluZ19oZWFydF9yYXRlX21heCwKICBST1VORChBVkcoYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljKSkgQVMgYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljX2F2ZXJhZ2UsCiAgUk9VTkQoTUlOKGJsb29kX3ByZXNzdXJlX2RpYXN0b2xpYykpIEFTIGJsb29kX3ByZXNzdXJlX2RpYXN0b2xpY19taW4sCiAgUk9VTkQoTUFYKGJsb29kX3ByZXNzdXJlX2RpYXN0b2xpYykpIEFTIGJsb29kX3ByZXNzdXJlX2RpYXN0b2xpY19tYXgsCiAgUk9VTkQoQVZHKGJsb29kX3ByZXNzdXJlX3N5c3RvbGljKSkgQVMgYmxvb2RfcHJlc3N1cmVfc3lzdG9saWNfYXZlcmFnZSwKICBST1VORChNSU4oYmxvb2RfcHJlc3N1cmVfc3lzdG9saWMpKSBBUyBibG9vZF9wcmVzc3VyZV9zeXN0b2xpY19taW4sCiAgUk9VTkQoTUFYKGJsb29kX3ByZXNzdXJlX3N5c3RvbGljKSkgQVMgYmxvb2RfcHJlc3N1cmVfc3lzdG9saWNfbWF4LAogIFJPVU5EKEFWRyhjYWxvcmllc19idXJuZWQpKSBBUyBjYWxvcmllc19idXJuZWRfYXZlcmFnZSwKICBST1VORChNSU4oY2Fsb3JpZXNfYnVybmVkKSkgQVMgY2Fsb3JpZXNfYnVybmVkX21pbiwKICBST1VORChNQVgoY2Fsb3JpZXNfYnVybmVkKSkgQVMgY2Fsb3JpZXNfYnVybmVkX21heCwKRlJPTSBgY29tcGxldGUtd2lsbC00NjgxMTUtcDIuZml0bGlmZTM2MF9zeW50aGV0aWNfaGVhbHRoX2RhdGEuZml0bGlmZWAgCkdST1VQIEJZIGFjdGl2aXR5X3R5cGUsIGludGVuc2l0eQpPUkRFUiBCWSBhY3Rpdml0eV90eXBlLAogIENBU0UgaW50ZW5zaXR5CiAgICAgICAgV0hFTiAnTG93JyBUSEVOIDEKICAgICAgICBXSEVOICdNZWRpdW0nIFRIRU4gMgogICAgICAgIFdIRU4gJ0hpZ2gnIFRIRU4gMwogICAgICAgIEVMU0UgTlVMTAogICAgICAgIEVORApgYGAKIyMjIE1pbiwgTWF4LCBBdmcgU3VtbWFyaWVzIGJ5IERhdGUKYGBge3NxbCBjb25uZWN0aW9uPWJ5X2RhdGVfc3VtbWFyaWVzfQpTRUxFQ1QKICBESVNUSU5DVCBkYXRlLAogIFJPVU5EKEFWRyhzdHJlc3NfbGV2ZWwpLCAyKSBBUyBzdHJlc3NfYXZlcmFnZSwKICBST1VORChNSU4oc3RyZXNzX2xldmVsKSwgMikgQVMgc3RyZXNzX21pbiwKICBST1VORChNQVgoc3RyZXNzX2xldmVsKSwgMikgQVMgc3RyZXNzX21heCwKICBST1VORChBVkcoaG91cnNfc2xlZXApLCAyKSBBUyBob3Vyc19zbGVlcF9hdmVyYWdlLAogIFJPVU5EKE1JTihob3Vyc19zbGVlcCksIDIpIEFTIGhvdXJzX3NsZWVwX21pbiwKICBST1VORChNQVgoaG91cnNfc2xlZXApLCAyKSBBUyBob3Vyc19zbGVlcF9tYXgsCiAgUk9VTkQoQVZHKHdlaWdodF9rZyksIDIpIEFTIHdlaWdodF9rZ19hdmVyYWdlLAogIFJPVU5EKE1JTih3ZWlnaHRfa2cpLCAyKSBBUyB3ZWlnaHRfa2dfbWluLAogIFJPVU5EKE1BWCh3ZWlnaHRfa2cpLCAyKSBBUyB3ZWlnaHRfa2dfbWF4LAogIFJPVU5EKEFWRyhoeWRyYXRpb25fbGV2ZWwpLCAyKSBBUyBoeWRyYXRpb25fbGV2ZWxfYXZlcmFnZSwKICBST1VORChNSU4oaHlkcmF0aW9uX2xldmVsKSwgMikgQVMgaHlkcmF0aW9uX2xldmVsX21pbiwKICBST1VORChNQVgoaHlkcmF0aW9uX2xldmVsKSwgMikgQVMgaHlkcmF0aW9uX2xldmVsX21heCwKICBST1VORChBVkcoZGFpbHlfc3RlcHMpKSBBUyBkYWlseV9zdGVwc19hdmVyYWdlLAogIFJPVU5EKE1JTihkYWlseV9zdGVwcykpIEFTIGRhaWx5X3N0ZXBzX21pbiwKICBST1VORChNQVgoZGFpbHlfc3RlcHMpKSBBUyBkYWlseV9zdGVwc19tYXgsCiAgUk9VTkQoQVZHKGFnZSksIDIpIEFTIGF2ZXJhZ2VfYWdlLAogIFJPVU5EKEFWRyhkdXJhdGlvbl9taW51dGVzKSkgQVMgZHVyYXRpb25fYXZlcmFnZV9pbl9taW51dGVzLAogIFJPVU5EKE1JTihkdXJhdGlvbl9taW51dGVzKSkgQVMgZHVyYXRpb25fbWluX2luX21pbnV0ZXMsCiAgUk9VTkQoTUFYKGR1cmF0aW9uX21pbnV0ZXMpKSBBUyBkdXJhdGlvbl9tYXhfaW5fbWludXRlcywKICBST1VORChBVkcoYm1pKSkgQVMgYm1pX2F2ZXJhZ2UsCiAgUk9VTkQoTUlOKGJtaSkpIEFTIGJtaV9taW4sCiAgUk9VTkQoTUFYKGJtaSkpIEFTIGJtaV9tYXgsCiAgUk9VTkQoQVZHKHJlc3RpbmdfaGVhcnRfcmF0ZSkpIEFTIHJlc3RpbmdfaGVhcnRfcmF0ZV9hdmVyYWdlLAogIFJPVU5EKE1JTihyZXN0aW5nX2hlYXJ0X3JhdGUpKSBBUyByZXN0aW5nX2hlYXJ0X3JhdGVfbWluLAogIFJPVU5EKE1BWChyZXN0aW5nX2hlYXJ0X3JhdGUpKSBBUyByZXN0aW5nX2hlYXJ0X3JhdGVfbWF4LAogIFJPVU5EKEFWRyhibG9vZF9wcmVzc3VyZV9kaWFzdG9saWMpKSBBUyBibG9vZF9wcmVzc3VyZV9kaWFzdG9saWNfYXZlcmFnZSwKICBST1VORChNSU4oYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljKSkgQVMgYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljX21pbiwKICBST1VORChNQVgoYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljKSkgQVMgYmxvb2RfcHJlc3N1cmVfZGlhc3RvbGljX21heCwKICBST1VORChBVkcoYmxvb2RfcHJlc3N1cmVfc3lzdG9saWMpKSBBUyBibG9vZF9wcmVzc3VyZV9zeXN0b2xpY19hdmVyYWdlLAogIFJPVU5EKE1JTihibG9vZF9wcmVzc3VyZV9zeXN0b2xpYykpIEFTIGJsb29kX3ByZXNzdXJlX3N5c3RvbGljX21pbiwKICBST1VORChNQVgoYmxvb2RfcHJlc3N1cmVfc3lzdG9saWMpKSBBUyBibG9vZF9wcmVzc3VyZV9zeXN0b2xpY19tYXgsCiAgUk9VTkQoQVZHKGNhbG9yaWVzX2J1cm5lZCkpIEFTIGNhbG9yaWVzX2J1cm5lZF9hdmVyYWdlLAogIFJPVU5EKE1JTihjYWxvcmllc19idXJuZWQpKSBBUyBjYWxvcmllc19idXJuZWRfbWluLAogIFJPVU5EKE1BWChjYWxvcmllc19idXJuZWQpKSBBUyBjYWxvcmllc19idXJuZWRfbWF4LAogIFJPVU5EKEFWRyhkdXJhdGlvbl9taW51dGVzKSkgQVMgZHVyYXRpb25fbWludXRlc19hdmVyYWdlLAogIFJPVU5EKE1JTihkdXJhdGlvbl9taW51dGVzKSkgQVMgZHVyYXRpb25fbWludXRlc19taW4sCiAgUk9VTkQoTUFYKGR1cmF0aW9uX21pbnV0ZXMpKSBBUyBkdXJhdGlvbl9taW51dGVzX21heCwKRlJPTSBgY29tcGxldGUtd2lsbC00NjgxMTUtcDIuZml0bGlmZTM2MF9zeW50aGV0aWNfaGVhbHRoX2RhdGEuZml0bGlmZWAgCkdST1VQIEJZIGRhdGU7CmBgYAoKCiMjIyAzLiBTdW1tYXJpemluZyBXaGlsZSBGaWx0ZXJpbmcgZm9yIEdlbmRlcgpCZWxsYWJlYXQgaGFzIHBvc2l0aW9uZWQgaXRzZWxmIGFzIGEgaGVhbHRoICYgd2VsbG5lc3MgY29tcGFueSBmb3Igd29tZW4sIHNvIHRoZSBkYXRhIGhhcyBiZWVuIGZpbHRlcmVkIHRvIGV4Y2x1ZGUgbWVuIGJ5IGFkZGluZyB0aGUgZm9sbG93aW5nIHRvIGVhY2ggc3VtbWFyeSBxdWVyeSB3cml0dGVuIGluIHRoZSBwcmV2aW91cyBzZWN0aW9uIHRvIGZpbHRlciB0aGUgbWVuIG91dCBvZiB0aGUgZGF0YXNldCB3aXRob3V0IGFsdGVyaW5nIHRoZSBkYXRhc2V0IGl0c2VsZi4KCmBgYHtzcWwgY29ubmVjdGlvbj1leGNsdWRpbmdfbWVufQpXSEVSRSBnZW5kZXIgPD4gIk0iIApgYGAKCiMjIFN1bW1pbmcgYWN0aXZpdGllcyBieSB1c2VyIGFuZCBkYXRlIHdpdGhvdXQgZGl2aWRpbmcgYnkgaW50ZW5zaXR5CkJyZWFraW5nIHRoZSBzdW1zIHVwIHllc3RlcmRheSBjcmVhdGVkIGEgcG90ZW50aWFsIGZvciBjb25mdXNpbmcgZGF0YSBhcyBlYWNoIHVzZXIgY291bGQgYmUgY291bnRlZCBpbiBlYWNoIGludGVuc2l0eSBjYXRlZ29yeSwgbWVhbmluZyBqdXN0IHN1bW1pbmcgdGhvc2UgdmFsdWVzIHdvdWxkIG5vdCBiZSBhY2N1cmF0ZSBpbiBjb3VudGluZyB1bmlxdWUgdXNlcnMgZm9yIGVhY2ggYWN0aXZpdHkuCgpgYGB7c3FsIGNvbm5lY3Rpb249c3VtbWluZ19ieV9hY3Rpdml0eX0KU0VMRUNUCiAgYWN0aXZpdHlfdHlwZSwKICBDT1VOVChESVNUSU5DVCBwYXJ0aWNpcGFudF9pZCkgQVMgdW5pcXVlX3VzZXJzCgpGUk9NIGBjb21wbGV0ZS13aWxsLTQ2ODExNS1wMi5maXRsaWZlMzYwX3N5bnRoZXRpY19oZWFsdGhfZGF0YS5maXRsaWZlYApHUk9VUCBCWQogIGFjdGl2aXR5X3R5cGUKT1JERVIgQlkKICBhY3Rpdml0eV90eXBlOwpgYGAKCiMjIyBBY3Rpdml0eSBTZXNzaW9uIENvdW50cwpgYGB7c3FsIGNvbm5lY3Rpb249YWN0aXZpdHlfc2Vzc2lvbl9jb3VudH0KU0VMRUNUCiAgYWN0aXZpdHlfdHlwZSwKICBDT1VOVChhY3Rpdml0eV90eXBlKSBBUyBhY3Rpdml0eV9zZXNzaW9uX2NvdW50CkZST00gYGNvbXBsZXRlLXdpbGwtNDY4MTE1LXAyLmZpdGxpZmUzNjBfc3ludGhldGljX2hlYWx0aF9kYXRhLmZpdGxpZmVgCkdST1VQIEJZCiAgYWN0aXZpdHlfdHlwZQpPUkRFUiBCWQogIGFjdGl2aXR5X3R5cGU7CgpgYGAKIyMjIEFjdGl2aXR5IER1cmF0aW9uIFN1bW1hcnkKYGBge3NxbCBjb25uZWN0aW9uPWFjdGl2aXR5X2R1cmF0aW9uX2luX21pbnV0ZXN9ClNFTEVDVAogIGFjdGl2aXR5X3R5cGUsCiAgU1VNKGR1cmF0aW9uX21pbnV0ZXMpIEFTIGFjdGl2aXR5X2R1cmF0aW9uX2luX21pbnV0ZXMKRlJPTSBgY29tcGxldGUtd2lsbC00NjgxMTUtcDIuZml0bGlmZTM2MF9zeW50aGV0aWNfaGVhbHRoX2RhdGEuZml0bGlmZWAKR1JPVVAgQlkKICBhY3Rpdml0eV90eXBlCk9SREVSIEJZCiAgYWN0aXZpdHlfdHlwZTsKYGBgCgojIyBEYXRhIFZpc3VhbGl6YXRpb24KVGhlIGRhdGEgd2FzIHZpc3VhbGl6ZWQgdXNpbmcgdmFyaW91cyB0YWJsZXMgaW4gVGFibGVhdSBQdWJsaWMuIFRoaXMgZGF0YXNldCB3YXMgZm91bmQgdG8gb25seSBkaXNwbGF5IHRyZW5kcyB0aGF0IHdlcmUgc3RlYWR5IGFuZCBzaG93IG5vIGdyb3d0aCBvciBkZWNyZWFzZS4gVGhpcyBtYWtlcyBzZW5zZSBhcyB0aGUgZGF0YSBpcyBzeW50aGV0aWMsIGFuZCB0aHVzIHdvdWxkbid0IGhhdmUgYW55IHN1cnByaXNpbmcgdHJlbmRzIHRvIGJlIGRpc2NvdmVyZWQuIFRoZXNlIHZpc3VhbGl6dGlvbnMgd2VyZSBub3QgdXNlZCBpbiB0aGUgZmluYWwgcmVwb3J0LgoKIyMgQ29uY2x1c2lvbgpUaGlzIGRhdGFzZXQgaXMgbm90IHVzZWZ1bCBmb3IgdGhpcyBjYXNlIHN0dWR5IGJ1dCB3YXMgYSBnb29kIGNoYW5jZSB0byBwcmFjdGljZSBjbGVhbmluZyBhbmQgYW5hbHl6aW5nIGRhdGEgdXNpbmcgdmFyaW91cyB0b29scyBzdWNoIGFzIEJpZ1F1ZXJ5LCBzcHJlYWRzaGVldHMsIGFuZCBUYWJsZWF1IFB1YmxpYy4KCgoK